Changeset 115915 in webkit
- Timestamp:
- May 2, 2012 5:14:05 PM (12 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r115867 r115915 1 2012-05-02 Mark Hahnenberg <mhahnenberg@apple.com> 2 3 Opportunistic GC should give up if the Heap is paged out 4 https://bugs.webkit.org/show_bug.cgi?id=85411 5 6 Reviewed by Filip Pizlo. 7 8 Opportunistic GC is punishing us severely in limited memory situations because its 9 assumptions about how much time a collection will take are way out of whack when the Heap 10 has been paged out by the OS. We should add a simple detection function to the Heap that 11 detects if its is paged out. It will do this by iterating each block of both the MarkedSpace 12 and CopiedSpace. If that operation takes longer than a fixed amount of time (e.g. 100ms), 13 the function returns true. This function will only be run prior to an opportunistic 14 collection (i.e. it will not run during our normal allocation-triggered collections). 15 16 In my tests, steady state was drastically improved in high memory pressure situations (i.e. 17 the browser was still usable, significant reduction in SPODs). Occasionally, a normal GC 18 would be triggered due to pages doing things in the background, which would cause a 19 significant pause. As we close pages we now cause normal collections rather than full 20 collections, which prevents us from collecting all of the dead memory immediately. One 21 nice way to deal with this issue might be to do incremental sweeping. 22 23 24 * heap/CopiedSpace.cpp: 25 (JSC::isBlockListPagedOut): Helper function to reduce code duplication when iterating over 26 to-space, from-space, and the oversize blocks. 27 (JSC): 28 (JSC::CopiedSpace::isPagedOut): Tries to determine whether or not CopiedSpace is paged out 29 by iterating all of the blocks. 30 * heap/CopiedSpace.h: 31 (CopiedSpace): 32 * heap/Heap.cpp: 33 (JSC::Heap::isPagedOut): Tries to determine whether the Heap is paged out by asking the 34 MarkedSpace and CopiedSpace if they are paged out. 35 (JSC): 36 * heap/Heap.h: 37 (Heap): 38 (JSC::Heap::increaseLastGCLength): Added this so that the GC timer can linearly back off 39 each time it determines that the Heap is paged out. 40 * heap/MarkedAllocator.cpp: 41 (JSC::MarkedAllocator::isPagedOut): Tries to determine if this particular MarkedAllocator's 42 list of blocks are paged out. 43 (JSC): 44 * heap/MarkedAllocator.h: 45 (MarkedAllocator): 46 * heap/MarkedSpace.cpp: 47 (JSC::MarkedSpace::isPagedOut): For each MarkedAllocator, check to see if they're paged out. 48 * heap/MarkedSpace.h: 49 (MarkedSpace): 50 * runtime/GCActivityCallback.cpp: 51 (JSC::DefaultGCActivityCallback::cancel): 52 (JSC): 53 * runtime/GCActivityCallback.h: 54 (JSC::GCActivityCallback::cancel): 55 (DefaultGCActivityCallback): 56 * runtime/GCActivityCallbackCF.cpp: Added a constant of 100ms for the timeout in determining 57 whether the Heap is paged out or not. 58 (JSC): 59 (JSC::DefaultGCActivityCallbackPlatformData::timerDidFire): Added the check to see if we 60 should attempt a collection based on whether or not we can iterate the blocks of the Heap in 61 100ms. If we can't, we cancel the timer and tell the Heap we just wasted 100ms more trying to 62 do a collection. This gives us a nice linear backoff so we're not constantly re-trying in 63 steady state paged-out-ness. 64 (JSC::DefaultGCActivityCallback::cancel): Added this function which, while currently doing 65 exactly the same thing as willCollect, is more obvious as to what it's doing when we call it 66 in timerDidFire. 67 1 68 2012-05-02 Yong Li <yoli@rim.com> 2 69 -
trunk/Source/JavaScriptCore/heap/CopiedSpace.cpp
r115590 r115915 282 282 } 283 283 284 static bool isBlockListPagedOut(double deadline, DoublyLinkedList<HeapBlock>* list) 285 { 286 unsigned itersSinceLastTimeCheck = 0; 287 HeapBlock* current = list->head(); 288 while (current) { 289 current = current->next(); 290 ++itersSinceLastTimeCheck; 291 if (itersSinceLastTimeCheck >= Heap::s_timeCheckResolution) { 292 double currentTime = WTF::monotonicallyIncreasingTime(); 293 if (currentTime > deadline) 294 return true; 295 itersSinceLastTimeCheck = 0; 296 } 297 } 298 299 return false; 300 } 301 302 bool CopiedSpace::isPagedOut(double deadline) 303 { 304 return isBlockListPagedOut(deadline, m_toSpace) 305 || isBlockListPagedOut(deadline, m_fromSpace) 306 || isBlockListPagedOut(deadline, &m_oversizeBlocks); 307 } 308 284 309 } // namespace JSC -
trunk/Source/JavaScriptCore/heap/CopiedSpace.h
r115579 r115915 71 71 72 72 void freeAllBlocks(); 73 bool isPagedOut(double deadline); 73 74 74 75 static CopiedBlock* blockFor(void*); -
trunk/Source/JavaScriptCore/heap/Heap.cpp
r115861 r115915 346 346 } 347 347 348 bool Heap::isPagedOut(double deadline) 349 { 350 return m_objectSpace.isPagedOut(deadline) || m_storageSpace.isPagedOut(deadline); 351 } 352 348 353 // The JSGlobalData is being destroyed and the collector will never run again. 349 354 // Run all pending finalizers now because we won't get another chance. -
trunk/Source/JavaScriptCore/heap/Heap.h
r115590 r115915 77 77 static Heap* heap(const JSCell*); 78 78 79 // This constant determines how many blocks we iterate between checks of our 80 // deadline when calling Heap::isPagedOut. Decreasing it will cause us to detect 81 // overstepping our deadline more quickly, while increasing it will cause 82 // our scan to run faster. 83 static const unsigned s_timeCheckResolution = 16; 84 79 85 static bool isMarked(const void*); 80 86 static bool testAndSetMarked(const void*); … … 150 156 151 157 double lastGCLength() { return m_lastGCLength; } 158 void increaseLastGCLength(double amount) { m_lastGCLength += amount; } 152 159 153 160 JS_EXPORT_PRIVATE void discardAllCompiledCode(); 154 161 155 162 void didAllocate(size_t); 163 164 bool isPagedOut(double deadline); 156 165 157 166 private: -
trunk/Source/JavaScriptCore/heap/MarkedAllocator.cpp
r115590 r115915 4 4 #include "GCActivityCallback.h" 5 5 #include "Heap.h" 6 #include <wtf/CurrentTime.h> 6 7 7 8 namespace JSC { 9 10 bool MarkedAllocator::isPagedOut(double deadline) 11 { 12 unsigned itersSinceLastTimeCheck = 0; 13 HeapBlock* block = m_blockList.head(); 14 while (block) { 15 block = block->next(); 16 ++itersSinceLastTimeCheck; 17 if (itersSinceLastTimeCheck >= Heap::s_timeCheckResolution) { 18 double currentTime = WTF::monotonicallyIncreasingTime(); 19 if (currentTime > deadline) 20 return true; 21 itersSinceLastTimeCheck = 0; 22 } 23 } 24 25 return false; 26 } 8 27 9 28 inline void* MarkedAllocator::tryAllocateHelper() -
trunk/Source/JavaScriptCore/heap/MarkedAllocator.h
r115156 r115915 33 33 void removeBlock(MarkedBlock*); 34 34 void init(Heap*, MarkedSpace*, size_t cellSize, bool cellsNeedDestruction); 35 35 36 bool isPagedOut(double deadline); 37 36 38 private: 37 39 friend class LLIntOffsetsExtractor; -
trunk/Source/JavaScriptCore/heap/MarkedSpace.cpp
r115590 r115915 71 71 } 72 72 73 bool MarkedSpace::isPagedOut(double deadline) 74 { 75 for (size_t cellSize = preciseStep; cellSize <= preciseCutoff; cellSize += preciseStep) { 76 if (allocatorFor(cellSize).isPagedOut(deadline) || destructorAllocatorFor(cellSize).isPagedOut(deadline)) 77 return true; 78 } 79 80 for (size_t cellSize = impreciseStep; cellSize <= impreciseCutoff; cellSize += impreciseStep) { 81 if (allocatorFor(cellSize).isPagedOut(deadline) || destructorAllocatorFor(cellSize).isPagedOut(deadline)) 82 return true; 83 } 84 85 return false; 86 } 73 87 74 88 void MarkedSpace::freeBlocks(MarkedBlock* head) -
trunk/Source/JavaScriptCore/heap/MarkedSpace.h
r114698 r115915 78 78 void didAddBlock(MarkedBlock*); 79 79 void didConsumeFreeList(MarkedBlock*); 80 81 bool isPagedOut(double deadline); 80 82 81 83 private: -
trunk/Source/JavaScriptCore/runtime/GCActivityCallback.cpp
r115156 r115915 55 55 } 56 56 57 void DefaultGCActivityCallback::cancel() 58 { 57 59 } 58 60 61 } 62 -
trunk/Source/JavaScriptCore/runtime/GCActivityCallback.h
r115156 r115915 47 47 virtual void willCollect() { } 48 48 virtual void synchronize() { } 49 virtual void cancel() { } 49 50 50 51 protected: … … 64 65 virtual void willCollect(); 65 66 virtual void synchronize(); 67 virtual void cancel(); 66 68 67 69 #if USE(CF) -
trunk/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
r115156 r115915 57 57 const double maxGCTimeSlice = 0.05; // The maximum amount of CPU time we want to use for opportunistic timer-triggered collections. 58 58 const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer. 59 const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out. 59 60 const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10; 60 61 const CFTimeInterval hour = 60 * 60; … … 64 65 Heap* heap = static_cast<Heap*>(info); 65 66 APIEntryShim shim(heap->globalData()); 67 #if !PLATFORM(IOS) 68 double startTime = WTF::monotonicallyIncreasingTime(); 69 if (heap->isPagedOut(startTime + pagingTimeOut)) { 70 heap->activityCallback()->cancel(); 71 heap->increaseLastGCLength(pagingTimeOut); 72 return; 73 } 74 #endif 66 75 heap->collectAllGarbage(); 67 76 } … … 136 145 } 137 146 147 void DefaultGCActivityCallback::cancel() 148 { 149 cancelTimer(d.get()); 138 150 } 151 152 }
Note: See TracChangeset
for help on using the changeset viewer.