Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(573)

Side by Side Diff: Source/platform/heap/ThreadState.cpp

Issue 1272083003: Oilpan: Make the GC heuristics saner Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/platform/heap/ThreadState.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google Inc. All rights reserved. 2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 : m_thread(currentThread()) 90 : m_thread(currentThread())
91 , m_persistentRegion(adoptPtr(new PersistentRegion())) 91 , m_persistentRegion(adoptPtr(new PersistentRegion()))
92 , m_startOfStack(reinterpret_cast<intptr_t*>(StackFrameDepth::getStackStart( ))) 92 , m_startOfStack(reinterpret_cast<intptr_t*>(StackFrameDepth::getStackStart( )))
93 , m_endOfStack(reinterpret_cast<intptr_t*>(StackFrameDepth::getStackStart()) ) 93 , m_endOfStack(reinterpret_cast<intptr_t*>(StackFrameDepth::getStackStart()) )
94 , m_safePointScopeMarker(nullptr) 94 , m_safePointScopeMarker(nullptr)
95 , m_atSafePoint(false) 95 , m_atSafePoint(false)
96 , m_interruptors() 96 , m_interruptors()
97 , m_sweepForbidden(false) 97 , m_sweepForbidden(false)
98 , m_noAllocationCount(0) 98 , m_noAllocationCount(0)
99 , m_gcForbiddenCount(0) 99 , m_gcForbiddenCount(0)
100 , m_persistentAllocated(0) 100 , m_wrapperAllocated(0)
101 , m_persistentFreed(0) 101 , m_wrapperFreed(0)
102 , m_vectorBackingHeapIndex(Vector1HeapIndex) 102 , m_vectorBackingHeapIndex(Vector1HeapIndex)
103 , m_currentHeapAges(0) 103 , m_currentHeapAges(0)
104 , m_isTerminating(false) 104 , m_isTerminating(false)
105 , m_gcMixinMarker(nullptr) 105 , m_gcMixinMarker(nullptr)
106 , m_shouldFlushHeapDoesNotContainCache(false) 106 , m_shouldFlushHeapDoesNotContainCache(false)
107 , m_gcState(NoGCScheduled) 107 , m_gcState(NoGCScheduled)
108 , m_traceDOMWrappers(nullptr) 108 , m_traceDOMWrappers(nullptr)
109 #if defined(ADDRESS_SANITIZER) 109 #if defined(ADDRESS_SANITIZER)
110 , m_asanFakeStack(__asan_get_current_fake_stack()) 110 , m_asanFakeStack(__asan_get_current_fake_stack())
111 #endif 111 #endif
(...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after
551 if (isMainThread()) 551 if (isMainThread())
552 ScriptForbiddenScope::exit(); 552 ScriptForbiddenScope::exit();
553 } 553 }
554 554
555 CrossThreadPersistentRegion& ThreadState::crossThreadPersistentRegion() 555 CrossThreadPersistentRegion& ThreadState::crossThreadPersistentRegion()
556 { 556 {
557 AtomicallyInitializedStaticReference(CrossThreadPersistentRegion, persistent Region, new CrossThreadPersistentRegion()); 557 AtomicallyInitializedStaticReference(CrossThreadPersistentRegion, persistent Region, new CrossThreadPersistentRegion());
558 return persistentRegion; 558 return persistentRegion;
559 } 559 }
560 560
561 void ThreadState::updatePersistentCounters() 561 void ThreadState::updateWrapperCounters()
562 { 562 {
563 if (m_persistentAllocated >= m_persistentFreed) 563 if (m_wrapperAllocated >= m_wrapperFreed)
564 Heap::increasePersistentCount(m_persistentAllocated - m_persistentFreed) ; 564 Heap::increaseWrapperCount(m_wrapperAllocated - m_wrapperFreed);
565 else 565 else
566 Heap::decreasePersistentCount(m_persistentFreed - m_persistentAllocated) ; 566 Heap::decreaseWrapperCount(m_wrapperFreed - m_wrapperAllocated);
567 Heap::increaseCollectedPersistentCount(m_persistentFreed); 567 Heap::increaseCollectedWrapperCount(m_wrapperFreed);
568 m_persistentAllocated = 0; 568 m_wrapperAllocated = 0;
569 m_persistentFreed = 0; 569 m_wrapperFreed = 0;
570 } 570 }
571 571
572 size_t ThreadState::estimatedLiveObjectSize() 572 double ThreadState::partitionAllocGrowingRate()
573 { 573 {
574 // We estimate the live object size with the following equations. 574 size_t sizeAtLastGC = Heap::partitionAllocSizeAtLastGC();
575 // 575 size_t wrapperCountAtLastGC = Heap::wrapperCountAtLastGC();
576 // heapSizePerPersistent = (marked(t0, t1) + partitionAlloc(t0)) / persist entCount(t0) 576 size_t sizeRetainedByCollectedPersistents = wrapperCountAtLastGC ? Heap::col lectedWrapperCount() * sizeAtLastGC / wrapperCountAtLastGC : 0;
577 // estimatedLiveObjectSize = marked(t0, t) + allocated(t0, t) + partitionA lloc(t) - heapSizePerPersistent * collectedPersistentCount(t0, t) 577 size_t estimatedLiveSize = sizeAtLastGC > sizeRetainedByCollectedPersistents ? sizeAtLastGC - sizeRetainedByCollectedPersistents : 0;
578 // 578 double growingRate = estimatedLiveSize ? 1.0 * WTF::Partitions::totalSizeOfC ommittedPages() / estimatedLiveSize : 0;
579 // t0: The time when the last collectGarbage runs. 579 TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLivePartitionAllocSizeKB", std::min(estimatedLiveSize / 1024, static_cast<size_t>(INT_MAX)));
580 // t1: The time when the last completeSweep runs. 580 TRACE_COUNTER1("blink_gc", "ThreadState::partitionAllocGrowingRate", static_ cast<int>(100 * growingRate));
581 // t: The current time. 581 return growingRate;
582 // marked(t0, t): The size of marked objects between t0 and t.
583 // allocated(t0, t): The size of newly allocated objects between t0 and t.
584 // persistentCount(t): The number of existing persistent handles at t.
585 // collectedPersistentCount(t0, t):
586 // The number of persistent handles collected between
587 // t0 and t.
588 // partitionAlloc(t): The size of allocated memory in PartitionAlloc at t.
589 size_t currentHeapSize = currentObjectSize();
590 size_t heapSizeRetainedByCollectedPersistents = Heap::heapSizePerPersistent( ) * Heap::collectedPersistentCount();
591 size_t estimatedSize = 0;
592 if (currentHeapSize > heapSizeRetainedByCollectedPersistents)
593 estimatedSize = currentHeapSize - heapSizeRetainedByCollectedPersistents ;
594 TRACE_COUNTER1("blink_gc", "ThreadState::currentHeapSizeKB", std::min(curren tHeapSize / 1024, static_cast<size_t>(INT_MAX)));
595 TRACE_COUNTER1("blink_gc", "ThreadState::estimatedLiveObjectSizeKB", std::mi n(estimatedSize / 1024, static_cast<size_t>(INT_MAX)));
596 TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>( 100.0 * currentHeapSize / estimatedSize));
597 return estimatedSize;
598 } 582 }
599 583
600 size_t ThreadState::currentObjectSize() 584 double ThreadState::heapGrowingRate()
601 { 585 {
602 return Heap::allocatedObjectSize() + Heap::markedObjectSize() + WTF::Partiti ons::totalSizeOfCommittedPages(); 586 size_t markedObjectSize = Heap::markedObjectSizeAtLastCompleteSweep();
587 size_t currentObjectSize = Heap::allocatedObjectSize() + markedObjectSize;
588 double growingRate = markedObjectSize ? 1.0 * currentObjectSize / markedObje ctSize : 0;
589 TRACE_COUNTER1("blink_gc", "ThreadState::currentObjectSizeKB", std::min(curr entObjectSize / 1024, static_cast<size_t>(INT_MAX)));
590 TRACE_COUNTER1("blink_gc", "ThreadState::heapGrowingRate", static_cast<int>( 100 * growingRate));
591 return growingRate;
592 }
593
594 // TODO(haraken): We should improve the GC heuristics. These heuristics
595 // significantly affect performance.
596 bool ThreadState::judgeGCThreshold(size_t allocatedObjectSizeThreshold, double h eapGrowingRateThreshold, double partitionAllocGrowingRateThreshold)
597 {
598 if (Heap::allocatedObjectSize() < allocatedObjectSizeThreshold)
599 return false;
600 if (heapGrowingRate() >= heapGrowingRateThreshold)
601 return true;
602 return partitionAllocGrowingRate() >= partitionAllocGrowingRateThreshold;
603 } 603 }
604 604
605 bool ThreadState::shouldForceMemoryPressureGC() 605 bool ThreadState::shouldForceMemoryPressureGC()
606 { 606 {
607 // Avoid potential overflow by truncating to Kb. 607 size_t totalObjectSize = Heap::allocatedObjectSize() + Heap::markedObjectSiz eAtLastCompleteSweep() + WTF::Partitions::totalSizeOfCommittedPages();
608 size_t currentObjectSizeKb = currentObjectSize() >> 10; 608 if (totalObjectSize < 300 * 1024 * 1024)
609 if (currentObjectSizeKb < 300 * 1024)
610 return false; 609 return false;
611 610 return judgeGCThreshold(0, 1.5, 1.5);
612 size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10;
613 // If we're consuming too much memory, trigger a conservative GC
614 // aggressively. This is a safe guard to avoid OOM.
615 return currentObjectSizeKb > (estimatedLiveObjectSizeKb * 3) / 2;
616 } 611 }
617 612
618 // TODO(haraken): We should improve the GC heuristics.
619 // These heuristics affect performance significantly.
620 bool ThreadState::shouldScheduleIdleGC() 613 bool ThreadState::shouldScheduleIdleGC()
621 { 614 {
622 if (gcState() != NoGCScheduled) 615 if (gcState() != NoGCScheduled)
623 return false; 616 return false;
624 #if ENABLE(IDLE_GC) 617 #if ENABLE(IDLE_GC)
625 // Avoid potential overflow by truncating to Kb. 618 return judgeGCThreshold(1024 * 1024, 1.5, 1.5);
626 size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10;
627 // The estimated size is updated when the main thread finishes lazy
628 // sweeping. If this thread reaches here before the main thread finishes
629 // lazy sweeping, the thread will use the estimated size of the last GC.
630 size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10;
631 // Heap::markedObjectSize() may be underestimated if any thread has not
632 // finished completeSweep().
633 size_t currentObjectSizeKb = currentObjectSize() >> 10;
634 // Schedule an idle GC if Oilpan has allocated more than 1 MB since
635 // the last GC and the current memory usage is >50% larger than
636 // the estimated live memory usage.
637 return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLive ObjectSizeKb * 3) / 2;
638 #else 619 #else
639 return false; 620 return false;
640 #endif 621 #endif
641 } 622 }
642 623
643 // TODO(haraken): We should improve the GC heuristics.
644 // These heuristics affect performance significantly.
645 bool ThreadState::shouldSchedulePreciseGC() 624 bool ThreadState::shouldSchedulePreciseGC()
646 { 625 {
647 if (gcState() != NoGCScheduled) 626 if (isGCForbidden())
648 return false; 627 return false;
628
629 if (shouldForceMemoryPressureGC())
630 return true;
631
649 #if ENABLE(IDLE_GC) 632 #if ENABLE(IDLE_GC)
650 return false; 633 return judgeGCThreshold(32 * 1024 * 1024, 4.0, 4.0);
634 // return false;
651 #else 635 #else
652 // Avoid potential overflow by truncating to Kb. 636 return judgeGCThreshold(1024 * 1024, 1.5, 1.5);
653 size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10;
654 // The estimated size is updated when the main thread finishes lazy
655 // sweeping. If this thread reaches here before the main thread finishes
656 // lazy sweeping, the thread will use the estimated size of the last GC.
657 size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10;
658 // Heap::markedObjectSize() may be underestimated if any thread has not
659 // finished completeSweep().
660 size_t currentObjectSizeKb = currentObjectSize() >> 10;
661 // Schedule a precise GC if Oilpan has allocated more than 1 MB since
662 // the last GC and the current memory usage is >50% larger than
663 // the estimated live memory usage.
664 return allocatedObjectSizeKb >= 1024 && currentObjectSizeKb > (estimatedLive ObjectSizeKb * 3) / 2;
665 #endif 637 #endif
666 } 638 }
667 639
668 bool ThreadState::shouldSchedulePageNavigationGC(float estimatedRemovalRatio) 640 bool ThreadState::shouldSchedulePageNavigationGC(float estimatedRemovalRatio)
669 { 641 {
670 if (UNLIKELY(isGCForbidden())) 642 if (UNLIKELY(isGCForbidden()))
671 return false; 643 return false;
672 644
673 if (shouldForceMemoryPressureGC()) 645 if (shouldForceMemoryPressureGC())
674 return true; 646 return true;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
707 { 679 {
708 ASSERT(checkThread()); 680 ASSERT(checkThread());
709 ASSERT(!isSweepingInProgress()); 681 ASSERT(!isSweepingInProgress());
710 setGCState(PageNavigationGCScheduled); 682 setGCState(PageNavigationGCScheduled);
711 } 683 }
712 684
713 // TODO(haraken): We should improve the GC heuristics. 685 // TODO(haraken): We should improve the GC heuristics.
714 // These heuristics affect performance significantly. 686 // These heuristics affect performance significantly.
715 bool ThreadState::shouldForceConservativeGC() 687 bool ThreadState::shouldForceConservativeGC()
716 { 688 {
717 if (UNLIKELY(isGCForbidden())) 689 if (isGCForbidden())
718 return false; 690 return false;
719 691
720 if (shouldForceMemoryPressureGC()) 692 if (shouldForceMemoryPressureGC())
721 return true; 693 return true;
722 694
723 // Avoid potential overflow by truncating to Kb. 695 return judgeGCThreshold(32 * 1024 * 1024, 5.0, 5.0);
724 size_t allocatedObjectSizeKb = Heap::allocatedObjectSize() >> 10;
725 // The estimated size is updated when the main thread finishes lazy
726 // sweeping. If this thread reaches here before the main thread finishes
727 // lazy sweeping, the thread will use the estimated size of the last GC.
728 size_t estimatedLiveObjectSizeKb = estimatedLiveObjectSize() >> 10;
729 // Heap::markedObjectSize() may be underestimated if any thread has not
730 // finished completeSweep().
731 size_t currentObjectSizeKb = currentObjectSize() >> 10;
732 // Schedule a conservative GC if Oilpan has allocated more than 32 MB since
733 // the last GC and the current memory usage is >400% larger than
734 // the estimated live memory usage.
735 // TODO(haraken): 400% is too large. Lower the heap growing factor.
736 return allocatedObjectSizeKb >= 32 * 1024 && currentObjectSizeKb > 5 * estim atedLiveObjectSizeKb;
737 } 696 }
738 697
739 void ThreadState::scheduleGCIfNeeded() 698 void ThreadState::scheduleGCIfNeeded()
740 { 699 {
741 ASSERT(checkThread()); 700 ASSERT(checkThread());
742 // Allocation is allowed during sweeping, but those allocations should not 701 // Allocation is allowed during sweeping, but those allocations should not
743 // trigger nested GCs. 702 // trigger nested GCs.
744 if (isSweepingInProgress()) 703 if (isSweepingInProgress())
745 return; 704 return;
746 ASSERT(!sweepForbidden()); 705 ASSERT(!sweepForbidden());
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
931 #endif 890 #endif
932 } 891 }
933 892
934 #undef VERIFY_STATE_TRANSITION 893 #undef VERIFY_STATE_TRANSITION
935 894
936 ThreadState::GCState ThreadState::gcState() const 895 ThreadState::GCState ThreadState::gcState() const
937 { 896 {
938 return m_gcState; 897 return m_gcState;
939 } 898 }
940 899
941 void ThreadState::didV8MajorGC()
942 {
943 ASSERT(checkThread());
944 if (isMainThread()) {
945 if (shouldForceMemoryPressureGC()) {
946 // Under memory pressure, force a conservative GC.
947 Heap::collectGarbage(HeapPointersOnStack, GCWithoutSweep, Heap::Cons ervativeGC);
948 return;
949 }
950 }
951 }
952
953 void ThreadState::runScheduledGC(StackState stackState) 900 void ThreadState::runScheduledGC(StackState stackState)
954 { 901 {
955 ASSERT(checkThread()); 902 ASSERT(checkThread());
956 if (stackState != NoHeapPointersOnStack) 903 if (stackState != NoHeapPointersOnStack)
957 return; 904 return;
958 905
959 // If a safe point is entered while initiating a GC, we clearly do 906 // If a safe point is entered while initiating a GC, we clearly do
960 // not want to do another as part that -- the safe point is only 907 // not want to do another as part that -- the safe point is only
961 // entered after checking if a scheduled GC ought to run first. 908 // entered after checking if a scheduled GC ought to run first.
962 // Prevent that from happening by marking GCs as forbidden while 909 // Prevent that from happening by marking GCs as forbidden while
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1005 m_heaps[i]->makeConsistentForMutator(); 952 m_heaps[i]->makeConsistentForMutator();
1006 } 953 }
1007 954
1008 void ThreadState::preGC() 955 void ThreadState::preGC()
1009 { 956 {
1010 ASSERT(!isInGC()); 957 ASSERT(!isInGC());
1011 setGCState(GCRunning); 958 setGCState(GCRunning);
1012 makeConsistentForGC(); 959 makeConsistentForGC();
1013 flushHeapDoesNotContainCacheIfNeeded(); 960 flushHeapDoesNotContainCacheIfNeeded();
1014 clearHeapAges(); 961 clearHeapAges();
1015 updatePersistentCounters(); 962 updateWrapperCounters();
1016 } 963 }
1017 964
1018 void ThreadState::postGC(GCType gcType) 965 void ThreadState::postGC(GCType gcType)
1019 { 966 {
1020 ASSERT(isInGC()); 967 ASSERT(isInGC());
1021 968
1022 #if ENABLE(GC_PROFILING) 969 #if ENABLE(GC_PROFILING)
1023 // We snapshot the heap prior to sweeping to get numbers for both resources 970 // We snapshot the heap prior to sweeping to get numbers for both resources
1024 // that have been allocated since the last GC and for resources that are 971 // that have been allocated since the last GC and for resources that are
1025 // going to be freed. 972 // going to be freed.
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
1186 1133
1187 postSweep(); 1134 postSweep();
1188 } 1135 }
1189 1136
1190 void ThreadState::postSweep() 1137 void ThreadState::postSweep()
1191 { 1138 {
1192 ASSERT(checkThread()); 1139 ASSERT(checkThread());
1193 Heap::reportMemoryUsageForTracing(); 1140 Heap::reportMemoryUsageForTracing();
1194 1141
1195 if (isMainThread()) { 1142 if (isMainThread()) {
1196 // See the comment in estimatedLiveObjectSize() for what we're
1197 // calculating here.
1198 //
1199 // Heap::markedObjectSize() may be underestimated here if any other 1143 // Heap::markedObjectSize() may be underestimated here if any other
1200 // thread has not yet finished lazy sweeping. 1144 // thread has not yet finished lazy sweeping.
1201 if (Heap::persistentCountAtLastGC() > 0) { 1145 if (Heap::objectSizeAtLastGC()) {
1202 TRACE_EVENT1("blink_gc", "ThreadState::postSweep", "collection rate" , 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC()); 1146 TRACE_EVENT1("blink_gc", "ThreadState::postSweep", "collection rate" , 1 - 1.0 * Heap::markedObjectSize() / Heap::objectSizeAtLastGC());
1203 Heap::setHeapSizePerPersistent((Heap::markedObjectSize() + Heap::par titionAllocSizeAtLastGC()) / Heap::persistentCountAtLastGC()); 1147 Heap::setMarkedObjectSizeAtLastCompleteSweep(Heap::markedObjectSize( ));
1204 } 1148 }
1205 } 1149 }
1206 1150
1207 switch (gcState()) { 1151 switch (gcState()) {
1208 case Sweeping: 1152 case Sweeping:
1209 setGCState(NoGCScheduled); 1153 setGCState(NoGCScheduled);
1210 break; 1154 break;
1211 case SweepingAndPreciseGCScheduled: 1155 case SweepingAndPreciseGCScheduled:
1212 setGCState(PreciseGCScheduled); 1156 setGCState(PreciseGCScheduled);
1213 break; 1157 break;
(...skipping 418 matching lines...) Expand 10 before | Expand all | Expand 10 after
1632 json->beginArray(it->key.ascii().data()); 1576 json->beginArray(it->key.ascii().data());
1633 for (size_t age = 0; age <= maxHeapObjectAge; ++age) 1577 for (size_t age = 0; age <= maxHeapObjectAge; ++age)
1634 json->pushInteger(it->value.ages[age]); 1578 json->pushInteger(it->value.ages[age]);
1635 json->endArray(); 1579 json->endArray();
1636 } 1580 }
1637 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s tatsName, this, json.release()); 1581 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("blink_gc"), s tatsName, this, json.release());
1638 } 1582 }
1639 #endif 1583 #endif
1640 1584
1641 } // namespace blink 1585 } // namespace blink
OLDNEW
« no previous file with comments | « Source/platform/heap/ThreadState.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698