Changeset 129586 in webkit for trunk/Source/JavaScriptCore/heap


Ignore:
Timestamp:
Sep 25, 2012, 7:27:54 PM (13 years ago)
Author:
[email protected]
Message:

JSC should dump object size inference statistics
https://bugs.webkit.org/show_bug.cgi?id=97618

Reviewed by Filip Pizlo.

Added an option to dump object size inference statistics.

To see statistics on live objects:

jsc --showHeapStatistics=1

To see cumulative statistics on all objects ever allocated:

jsc --showHeapStatistics=1 --objectsAreImmortal=1

(This is useful for showing GC churn caused by over-allocation.)

To support this second mode, I refactored Zombies to separate out their
immortality feature so I could reuse it.

  • heap/Heap.cpp:

(JSC::MarkObject): Helper for making things immortal. We have to checked
for being zapped because blocks start out in this state.

(JSC::StorageStatistics): Gather statistics by walking the heap. Ignore
arrays and hash tables for now because they're not our focus. (We'll
remove these exceptions in future.)

(JSC::Heap::collect): Moved zombify to the end so it wouldn't interfere
with statistics gathering.

(JSC::Heap::showStatistics):
(JSC::Heap::markAllObjects): Factored out helper, so statistics could
take advantage of immortal objects.

(Zombify): Don't mark immortal objects -- that's another class's job now.

(JSC::Zombify::operator()):
(JSC::Heap::zombifyDeadObjects): Take advantage of forEachDeadCell instead
of rolling our own.

  • heap/Heap.h:

(Heap):

  • heap/MarkedSpace.h:

(MarkedSpace):
(JSC::MarkedSpace::forEachDeadCell): Added, so clients don't have to do
the iteration logic themselves.

  • runtime/Options.cpp:

(JSC::Options::initialize):

  • runtime/Options.h: New options, listed above. Make sure to initialize

based on environment variable first, so we can override with specific settings.

Location:
trunk/Source/JavaScriptCore/heap
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r128851 r129586  
    177177}
    178178
     179struct MarkObject : public MarkedBlock::VoidFunctor {
     180    void operator()(JSCell* cell)
     181    {
     182        if (cell->isZapped())
     183            return;
     184        Heap::heap(cell)->setMarked(cell);
     185    }
     186};
     187
    179188struct Count : public MarkedBlock::CountFunctor {
    180189    void operator()(JSCell*) { count(1); }
     
    225234{
    226235    return m_typeCountSet.release();
     236}
     237
     238class StorageStatistics : public MarkedBlock::VoidFunctor {
     239public:
     240    StorageStatistics();
     241
     242    void operator()(JSCell*);
     243
     244    size_t objectWithOutOfLineStorageCount();
     245    size_t objectCount();
     246
     247    size_t storageSize();
     248    size_t storageCapacity();
     249
     250private:
     251    size_t m_objectWithOutOfLineStorageCount;
     252    size_t m_objectCount;
     253    size_t m_storageSize;
     254    size_t m_storageCapacity;
     255};
     256
     257inline StorageStatistics::StorageStatistics()
     258    : m_objectWithOutOfLineStorageCount(0)
     259    , m_objectCount(0)
     260    , m_storageSize(0)
     261    , m_storageCapacity(0)
     262{
     263}
     264
     265inline void StorageStatistics::operator()(JSCell* cell)
     266{
     267    if (!cell->isObject())
     268        return;
     269
     270    JSObject* object = jsCast<JSObject*>(cell);
     271    if (hasIndexedProperties(object->structure()->indexingType()))
     272        return;
     273
     274    if (object->structure()->isUncacheableDictionary())
     275        return;
     276
     277    ++m_objectCount;
     278    if (!object->hasInlineStorage())
     279        ++m_objectWithOutOfLineStorageCount;
     280    m_storageSize += object->structure()->totalStorageSize() * sizeof(WriteBarrierBase<Unknown>);
     281    m_storageCapacity += object->structure()->totalStorageCapacity() * sizeof(WriteBarrierBase<Unknown>);
     282}
     283
     284inline size_t StorageStatistics::objectWithOutOfLineStorageCount()
     285{
     286    return m_objectWithOutOfLineStorageCount;
     287}
     288
     289inline size_t StorageStatistics::objectCount()
     290{
     291    return m_objectCount;
     292}
     293
     294
     295inline size_t StorageStatistics::storageSize()
     296{
     297    return m_storageSize;
     298}
     299
     300
     301inline size_t StorageStatistics::storageCapacity()
     302{
     303    return m_storageCapacity;
    227304}
    228305
     
    754831    }
    755832   
    756     if (Options::useZombieMode())
    757         zombifyDeadObjects();
    758 
    759833    size_t currentHeapSize = size();
    760834    if (fullGC) {
     
    770844    double lastGCEndTime = WTF::currentTime();
    771845    m_lastGCLength = lastGCEndTime - lastGCStartTime;
     846
    772847    if (m_operationInProgress != Collection)
    773848        CRASH();
    774849    m_operationInProgress = NoOperation;
    775850    JAVASCRIPTCORE_GC_END();
     851
     852    if (Options::useZombieMode())
     853        zombifyDeadObjects();
     854
     855    if (Options::objectsAreImmortal())
     856        markDeadObjects();
     857
     858    if (Options::showHeapStatistics())
     859        showStatistics();
     860}
     861
     862void Heap::showStatistics()
     863{
     864    dataLog("\n=== Heap Statistics: ===\n");
     865    dataLog("size: %ldkB\n", static_cast<long>(m_sizeAfterLastCollect / KB));
     866    dataLog("capacity: %ldkB\n", static_cast<long>(capacity() / KB));
     867    dataLog("pause time: %lfms\n\n", m_lastGCLength);
     868
     869    StorageStatistics storageStatistics;
     870    m_objectSpace.forEachLiveCell(storageStatistics);
     871    dataLog("wasted .property storage: %ldkB (%ld%%)\n",
     872        static_cast<long>(
     873            (storageStatistics.storageCapacity() - storageStatistics.storageSize()) / KB),
     874        static_cast<long>(
     875            (storageStatistics.storageCapacity() - storageStatistics.storageSize()) * 100
     876                / storageStatistics.storageCapacity()));
     877    dataLog("objects with out-of-line .property storage: %ld (%ld%%)\n",
     878        static_cast<long>(
     879            storageStatistics.objectWithOutOfLineStorageCount()),
     880        static_cast<long>(
     881            storageStatistics.objectWithOutOfLineStorageCount() * 100
     882                / storageStatistics.objectCount()));
     883}
     884
     885void Heap::markDeadObjects()
     886{
     887    m_objectSpace.forEachDeadCell<MarkObject>();
    776888}
    777889
     
    845957}
    846958
    847 class ZombifyCellFunctor : public MarkedBlock::VoidFunctor {
     959class Zombify : public MarkedBlock::VoidFunctor {
    848960public:
    849     ZombifyCellFunctor(size_t cellSize)
    850         : m_cellSize(cellSize)
    851     {
    852     }
    853 
    854961    void operator()(JSCell* cell)
    855962    {
    856         if (Options::zombiesAreImmortal())
    857             MarkedBlock::blockFor(cell)->setMarked(cell);
    858 
    859963        void** current = reinterpret_cast<void**>(cell);
    860964
     
    864968            current++;
    865969
    866         void* limit = static_cast<void*>(reinterpret_cast<char*>(cell) + m_cellSize);
     970        void* limit = static_cast<void*>(reinterpret_cast<char*>(cell) + MarkedBlock::blockFor(cell)->cellSize());
    867971        for (; current < limit; current++)
    868972            *current = reinterpret_cast<void*>(0xbbadbeef);
    869973    }
    870 
    871 private:
    872     size_t m_cellSize;
    873974};
    874975
    875 class ZombifyBlockFunctor : public MarkedBlock::VoidFunctor {
    876 public:
    877     void operator()(MarkedBlock* block)
    878     {
    879         ZombifyCellFunctor functor(block->cellSize());
    880         block->forEachDeadCell(functor);
    881     }
    882 };
    883 
    884976void Heap::zombifyDeadObjects()
    885977{
     978    // Sweep now because destructors will crash once we're zombified.
    886979    m_objectSpace.sweep();
    887 
    888     ZombifyBlockFunctor functor;
    889     m_objectSpace.forEachBlock(functor);
     980    m_objectSpace.forEachDeadCell<Zombify>();
    890981}
    891982
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r128851 r129586  
    146146        JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> protectedObjectTypeCounts();
    147147        JS_EXPORT_PRIVATE PassOwnPtr<TypeCountSet> objectTypeCounts();
     148        void showStatistics();
    148149
    149150        void pushTempSortVector(Vector<ValueStringPair>*);
     
    206207        void deleteUnmarkedCompiledCode();
    207208        void zombifyDeadObjects();
    208  
     209        void markDeadObjects();
     210
    209211        RegisterFile& registerFile();
    210212        BlockAllocator& blockAllocator();
  • trunk/Source/JavaScriptCore/heap/MarkedSpace.h

    r128851 r129586  
    9696    template<typename Functor> typename Functor::ReturnType forEachLiveCell(Functor&);
    9797    template<typename Functor> typename Functor::ReturnType forEachLiveCell();
     98    template<typename Functor> typename Functor::ReturnType forEachDeadCell(Functor&);
     99    template<typename Functor> typename Functor::ReturnType forEachDeadCell();
    98100    template<typename Functor> typename Functor::ReturnType forEachBlock(Functor&);
    99101    template<typename Functor> typename Functor::ReturnType forEachBlock();
     
    157159}
    158160
     161template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachDeadCell(Functor& functor)
     162{
     163    canonicalizeCellLivenessData();
     164
     165    BlockIterator end = m_blocks.set().end();
     166    for (BlockIterator it = m_blocks.set().begin(); it != end; ++it)
     167        (*it)->forEachDeadCell(functor);
     168    return functor.returnValue();
     169}
     170
     171template<typename Functor> inline typename Functor::ReturnType MarkedSpace::forEachDeadCell()
     172{
     173    Functor functor;
     174    return forEachDeadCell(functor);
     175}
     176
    159177inline MarkedAllocator& MarkedSpace::firstAllocator()
    160178{
Note: See TracChangeset for help on using the changeset viewer.