Changeset 202394 in webkit


Ignore:
Timestamp:
Jun 23, 2016 1:05:23 PM (8 years ago)
Author:
commit-queue@webkit.org
Message:

Web Inspector: Memory Timeline sometimes shows impossible value for bmalloc size (underflowed)
https://bugs.webkit.org/show_bug.cgi?id=158110
<rdar://problem/26498584>

Patch by Joseph Pecoraro <Joseph Pecoraro> on 2016-06-23
Reviewed by Andreas Kling.

Source/JavaScriptCore:

  • heap/Heap.cpp:

(JSC::Heap::willStartCollection):
(JSC::Heap::didFinishCollection):

  • heap/Heap.h:

(JSC::Heap::externalMemorySize):

  • heap/HeapInlines.h:

(JSC::Heap::reportExternalMemoryVisited):
Keep count of external memory we visit.

  • heap/SlotVisitor.h:
  • heap/SlotVisitorInlines.h:

(JSC::SlotVisitor::reportExternalMemoryVisited):
Report external memory visited like we do extra memory, since
it will be some subset of extra memory that is external.

Source/WebCore:

IOSurface memory backing Canvas element buffers should be classified as "GC Owned",
but should not be considered a part of bmalloc. In fact, the actual memory cost is
external to the Web Content Process. The majority of extra memory reporters tend
to report extra memory that is also allocated in bmalloc. However, some report
non-bmalloc memory, such as the IOSurfaces here.

Continue to report the memory cost without changes to inform the Heap for garbage
collection. However, also keep better accounting of GCOwned memory that is external
to the process for better accounting for the Resource Usage overlay and Web Inspector
Memory timeline.

This is a bit of a game where we want to display the best possible number for
"GCOwned memory" in the tools, but some of that memory shows up in the other
regions (bmalloc, system malloc, etc). Already many sizes are estimates
(ReportExtraMemory, reportExtraMemory ignores small allocations), so we just focus
on getting the largest sources of allocations, such as Canvas IOSurfaces here,
into the right bucket. ResourceUsageThreadCocoa continues to subtract the "extra"
memory from bmalloc. So, we should address other large sources of "extra memory"
not in bmalloc. A likely candidate is HTMLMediaElement which uses the deprecated
reporting right now.

  • bindings/scripts/CodeGeneratorJS.pm:

(GenerateImplementation):

  • bindings/scripts/IDLAttributes.txt:

Add a way to report External memory, dependent on reporting Extra memory.

  • html/HTMLCanvasElement.cpp:

(WebCore::HTMLCanvasElement::externalMemoryCost):

  • html/HTMLCanvasElement.h:
  • html/HTMLCanvasElement.idl:

Report external memory cost just like extra memory.

  • page/ResourceUsageData.cpp:

(WebCore::ResourceUsageData::ResourceUsageData):

  • page/ResourceUsageData.h:

(WebCore::MemoryCategoryInfo::totalSize):

  • page/cocoa/ResourceUsageOverlayCocoa.mm:

(WebCore::RingBuffer::at):
(WebCore::appendDataToHistory):
(WebCore::ResourceUsageOverlay::platformDraw):

  • page/cocoa/ResourceUsageThreadCocoa.mm:

(WebCore::categoryForVMTag):
(WebCore::ResourceUsageThread::platformThreadBody):
Do not count the GCOwned External memory as dirty memory.
Include External memory output in the overlay.

  • inspector/InspectorMemoryAgent.cpp:

(WebCore::InspectorMemoryAgent::collectSample):
When sizing the JavaScript portion, include both the GC Owned
category's dirty and external memory. Ultimately we will
want this everywhere in case things change.

  • platform/graphics/ImageBuffer.cpp:

(WebCore::memoryCost):
(WebCore::externalMemoryCost):

  • platform/graphics/ImageBuffer.h:
  • platform/graphics/cg/ImageBufferCG.cpp:

(WebCore::ImageBuffer::memoryCost):
(WebCore::ImageBuffer::externalMemoryCost):
Report IOSurface total bytes as extra memory and external memory
so that it can be tracked as GC Owned memory that is separate from
regular (bmalloc/other) in process memory.

Location:
trunk/Source
Files:
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/ChangeLog

    r202383 r202394  
     12016-06-23  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Memory Timeline sometimes shows impossible value for bmalloc size (underflowed)
     4        https://bugs.webkit.org/show_bug.cgi?id=158110
     5        <rdar://problem/26498584>
     6
     7        Reviewed by Andreas Kling.
     8
     9        * heap/Heap.cpp:
     10        (JSC::Heap::willStartCollection):
     11        (JSC::Heap::didFinishCollection):
     12        * heap/Heap.h:
     13        (JSC::Heap::externalMemorySize):
     14        * heap/HeapInlines.h:
     15        (JSC::Heap::reportExternalMemoryVisited):
     16        Keep count of external memory we visit.
     17
     18        * heap/SlotVisitor.h:
     19        * heap/SlotVisitorInlines.h:
     20        (JSC::SlotVisitor::reportExternalMemoryVisited):
     21        Report external memory visited like we do extra memory, since
     22        it will be some subset of extra memory that is external.
     23
    1242016-06-23  Joseph Pecoraro  <pecoraro@apple.com>
    225
  • trunk/Source/JavaScriptCore/heap/Heap.cpp

    r202299 r202394  
    12411241        m_extraMemorySize = 0;
    12421242        m_deprecatedExtraMemorySize = 0;
     1243#if ENABLE(RESOURCE_USAGE)
     1244        m_externalMemorySize = 0;
     1245#endif
    12431246
    12441247        if (m_fullActivityCallback)
     
    14531456        m_lastEdenGCLength = gcEndTime - gcStartTime;
    14541457
     1458#if ENABLE(RESOURCE_USAGE)
     1459    ASSERT(externalMemorySize() <= extraMemorySize());
     1460#endif
     1461
    14551462    if (Options::recordGCPauseTimes())
    14561463        HeapStatistics::recordGCPauseTime(gcStartTime, gcEndTime);
  • trunk/Source/JavaScriptCore/heap/Heap.h

    r202299 r202394  
    180180    void reportExtraMemoryVisited(CellState cellStateBeforeVisiting, size_t);
    181181
     182#if ENABLE(RESOURCE_USAGE)
     183    // Use this API to report the subset of extra memory that lives outside this process.
     184    void reportExternalMemoryVisited(CellState cellStateBeforeVisiting, size_t);
     185    size_t externalMemorySize() { return m_extraMemorySize; }
     186#endif
     187
    182188    // Use this API to report non-GC memory if you can't use the better API above.
    183189    void deprecatedReportExtraMemory(size_t);
     
    463469#if ENABLE(RESOURCE_USAGE)
    464470    size_t m_blockBytesAllocated { 0 };
     471    size_t m_externalMemorySize { 0 };
    465472#endif
    466473};
  • trunk/Source/JavaScriptCore/heap/HeapInlines.h

    r202157 r202394  
    142142}
    143143
     144#if ENABLE(RESOURCE_USAGE)
     145inline void Heap::reportExternalMemoryVisited(CellState dataBeforeVisiting, size_t size)
     146{
     147    // We don't want to double-count the external memory that was reported in previous collections.
     148    if (operationInProgress() == EdenCollection && dataBeforeVisiting == CellState::OldGrey)
     149        return;
     150
     151    size_t* counter = &m_externalMemorySize;
     152
     153    for (;;) {
     154        size_t oldSize = *counter;
     155        if (WTF::weakCompareAndSwap(counter, oldSize, oldSize + size))
     156            return;
     157    }
     158}
     159#endif
     160
    144161inline void Heap::deprecatedReportExtraMemory(size_t size)
    145162{
  • trunk/Source/JavaScriptCore/heap/SlotVisitor.h

    r197712 r202394  
    110110   
    111111    void reportExtraMemoryVisited(size_t);
     112#if ENABLE(RESOURCE_USAGE)
     113    void reportExternalMemoryVisited(size_t);
     114#endif
    112115   
    113116    void addWeakReferenceHarvester(WeakReferenceHarvester*);
  • trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h

    r197712 r202394  
    110110}
    111111
     112#if ENABLE(RESOURCE_USAGE)
     113inline void SlotVisitor::reportExternalMemoryVisited(size_t size)
     114{
     115    heap()->reportExternalMemoryVisited(m_currentObjectCellStateBeforeVisiting, size);
     116}
     117#endif
     118
    112119inline Heap* SlotVisitor::heap() const
    113120{
  • trunk/Source/WebCore/ChangeLog

    r202390 r202394  
     12016-06-23  Joseph Pecoraro  <pecoraro@apple.com>
     2
     3        Web Inspector: Memory Timeline sometimes shows impossible value for bmalloc size (underflowed)
     4        https://bugs.webkit.org/show_bug.cgi?id=158110
     5        <rdar://problem/26498584>
     6
     7        Reviewed by Andreas Kling.
     8
     9        IOSurface memory backing Canvas element buffers should be classified as "GC Owned",
     10        but should not be considered a part of bmalloc. In fact, the actual memory cost is
     11        external to the Web Content Process. The majority of extra memory reporters tend
     12        to report extra memory that is also allocated in bmalloc. However, some report
     13        non-bmalloc memory, such as the IOSurfaces here.
     14       
     15        Continue to report the memory cost without changes to inform the Heap for garbage
     16        collection. However, also keep better accounting of GCOwned memory that is external
     17        to the process for better accounting for the Resource Usage overlay and Web Inspector
     18        Memory timeline.
     19       
     20        This is a bit of a game where we want to display the best possible number for
     21        "GCOwned memory" in the tools, but some of that memory shows up in the other
     22        regions (bmalloc, system malloc, etc). Already many sizes are estimates
     23        (ReportExtraMemory, reportExtraMemory ignores small allocations), so we just focus
     24        on getting the largest sources of allocations, such as Canvas IOSurfaces here,
     25        into the right bucket. ResourceUsageThreadCocoa continues to subtract the "extra"
     26        memory from bmalloc. So, we should address other large sources of "extra memory"
     27        not in bmalloc. A likely candidate is HTMLMediaElement which uses the deprecated
     28        reporting right now.
     29
     30        * bindings/scripts/CodeGeneratorJS.pm:
     31        (GenerateImplementation):
     32        * bindings/scripts/IDLAttributes.txt:
     33        Add a way to report External memory, dependent on reporting Extra memory.
     34
     35        * html/HTMLCanvasElement.cpp:
     36        (WebCore::HTMLCanvasElement::externalMemoryCost):
     37        * html/HTMLCanvasElement.h:
     38        * html/HTMLCanvasElement.idl:
     39        Report external memory cost just like extra memory.
     40
     41        * page/ResourceUsageData.cpp:
     42        (WebCore::ResourceUsageData::ResourceUsageData):
     43        * page/ResourceUsageData.h:
     44        (WebCore::MemoryCategoryInfo::totalSize):
     45        * page/cocoa/ResourceUsageOverlayCocoa.mm:
     46        (WebCore::RingBuffer::at):
     47        (WebCore::appendDataToHistory):
     48        (WebCore::ResourceUsageOverlay::platformDraw):
     49        * page/cocoa/ResourceUsageThreadCocoa.mm:
     50        (WebCore::categoryForVMTag):
     51        (WebCore::ResourceUsageThread::platformThreadBody):
     52        Do not count the GCOwned External memory as dirty memory.
     53        Include External memory output in the overlay.
     54
     55        * inspector/InspectorMemoryAgent.cpp:
     56        (WebCore::InspectorMemoryAgent::collectSample):
     57        When sizing the JavaScript portion, include both the GC Owned
     58        category's dirty and external memory. Ultimately we will
     59        want this everywhere in case things change.
     60
     61        * platform/graphics/ImageBuffer.cpp:
     62        (WebCore::memoryCost):
     63        (WebCore::externalMemoryCost):
     64        * platform/graphics/ImageBuffer.h:
     65        * platform/graphics/cg/ImageBufferCG.cpp:
     66        (WebCore::ImageBuffer::memoryCost):
     67        (WebCore::ImageBuffer::externalMemoryCost):
     68        Report IOSurface total bytes as extra memory and external memory
     69        so that it can be tracked as GC Owned memory that is separate from
     70        regular (bmalloc/other) in process memory.
     71
    1722016-06-23  Alexey Proskuryakov  <ap@apple.com>
    273
  • trunk/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm

    r202307 r202394  
    32463246        if ($interface->extendedAttributes->{"ReportExtraMemoryCost"}) {
    32473247            push(@implContent, "    visitor.reportExtraMemoryVisited(thisObject->wrapped().memoryCost());\n");
     3248            if ($interface->extendedAttributes->{"ReportExternalMemoryCost"}) {;
     3249                push(@implContent, "#if ENABLE(RESOURCE_USAGE)\n");
     3250                push(@implContent, "    visitor.reportExternalMemoryVisited(thisObject->wrapped().externalMemoryCost());\n");
     3251                push(@implContent, "#endif\n");
     3252            }
    32483253        }
    32493254        if ($numCachedAttributes > 0) {
  • trunk/Source/WebCore/bindings/scripts/IDLAttributes.txt

    r202275 r202394  
    115115Replaceable
    116116ReportExtraMemoryCost
     117ReportExternalMemoryCost
    117118RequiresExistingAtomicString
    118119SetterRaisesException
  • trunk/Source/WebCore/html/HTMLCanvasElement.cpp

    r201588 r202394  
    590590}
    591591
     592size_t HTMLCanvasElement::externalMemoryCost() const
     593{
     594    if (!m_imageBuffer)
     595        return 0;
     596    return 4 * m_imageBuffer->internalSize().width() * m_imageBuffer->internalSize().height();
     597}
     598
    592599void HTMLCanvasElement::setUsesDisplayListDrawing(bool usesDisplayListDrawing)
    593600{
  • trunk/Source/WebCore/html/HTMLCanvasElement.h

    r201588 r202394  
    137137
    138138    size_t memoryCost() const;
     139    size_t externalMemoryCost() const;
    139140
    140141private:
  • trunk/Source/WebCore/html/HTMLCanvasElement.idl

    r199969 r202394  
    2727[
    2828    JSGenerateToNativeObject,
    29     ReportExtraMemoryCost
     29    ReportExtraMemoryCost,
     30    ReportExternalMemoryCost,
    3031] interface HTMLCanvasElement : HTMLElement {
    3132#if defined(LANGUAGE_OBJECTIVE_C) && LANGUAGE_OBJECTIVE_C || defined(LANGUAGE_GOBJECT) && LANGUAGE_GOBJECT
  • trunk/Source/WebCore/inspector/InspectorMemoryAgent.cpp

    r197827 r202394  
    108108    auto javascriptCategory = Protocol::Memory::CategoryData::create()
    109109        .setType(Protocol::Memory::CategoryData::Type::Javascript)
    110         .setSize(data.categories[MemoryCategory::GCHeap].dirtySize + data.categories[MemoryCategory::GCOwned].dirtySize)
     110        .setSize(data.categories[MemoryCategory::GCHeap].totalSize() + data.categories[MemoryCategory::GCOwned].totalSize())
    111111        .release();
    112112
    113113    auto jitCategory = Protocol::Memory::CategoryData::create()
    114114        .setType(Protocol::Memory::CategoryData::Type::JIT)
    115         .setSize(data.categories[MemoryCategory::JSJIT].dirtySize)
     115        .setSize(data.categories[MemoryCategory::JSJIT].totalSize())
    116116        .release();
    117117
    118118    auto imagesCategory = Protocol::Memory::CategoryData::create()
    119119        .setType(Protocol::Memory::CategoryData::Type::Images)
    120         .setSize(data.categories[MemoryCategory::Images].dirtySize)
     120        .setSize(data.categories[MemoryCategory::Images].totalSize())
    121121        .release();
    122122
    123123    auto layersCategory = Protocol::Memory::CategoryData::create()
    124124        .setType(Protocol::Memory::CategoryData::Type::Layers)
    125         .setSize(data.categories[MemoryCategory::Layers].dirtySize)
     125        .setSize(data.categories[MemoryCategory::Layers].totalSize())
    126126        .release();
    127127
    128128    auto pageCategory = Protocol::Memory::CategoryData::create()
    129129        .setType(Protocol::Memory::CategoryData::Type::Page)
    130         .setSize(data.categories[MemoryCategory::bmalloc].dirtySize + data.categories[MemoryCategory::LibcMalloc].dirtySize)
     130        .setSize(data.categories[MemoryCategory::bmalloc].totalSize() + data.categories[MemoryCategory::LibcMalloc].totalSize())
    131131        .release();
    132132
    133133    auto otherCategory = Protocol::Memory::CategoryData::create()
    134134        .setType(Protocol::Memory::CategoryData::Type::Other)
    135         .setSize(data.categories[MemoryCategory::Other].dirtySize)
     135        .setSize(data.categories[MemoryCategory::Other].totalSize())
    136136        .release();
    137137
  • trunk/Source/WebCore/page/ResourceUsageData.cpp

    r195644 r202394  
    4949    : cpu(other.cpu)
    5050    , totalDirtySize(other.totalDirtySize)
     51    , totalExternalSize(other.totalExternalSize)
    5152    , timeOfNextEdenCollection(other.timeOfNextEdenCollection)
    5253    , timeOfNextFullCollection(other.timeOfNextFullCollection)
  • trunk/Source/WebCore/page/ResourceUsageData.h

    r195644 r202394  
    5353    }
    5454
     55    size_t totalSize() const { return dirtySize + externalSize; }
     56
    5557    size_t dirtySize { 0 };
    5658    size_t reclaimableSize { 0 };
     59    size_t externalSize { 0 };
    5760    bool isSubcategory { false };
    5861    unsigned type { MemoryCategory::NumberOfCategories };
     
    6568    float cpu { 0 };
    6669    size_t totalDirtySize { 0 };
     70    size_t totalExternalSize { 0 };
    6771    std::array<MemoryCategoryInfo, MemoryCategory::NumberOfCategories> categories;
    6872    double timeOfNextEdenCollection { 0 };
  • trunk/Source/WebCore/page/cocoa/ResourceUsageOverlayCocoa.mm

    r202005 r202394  
    139139    RingBuffer<size_t> dirtySize;
    140140    RingBuffer<size_t> reclaimableSize;
     141    RingBuffer<size_t> externalSize;
    141142    bool isSubcategory { false };
    142143    unsigned type { MemoryCategory::NumberOfCategories };
     
    148149    RingBuffer<float> cpu;
    149150    RingBuffer<size_t> totalDirtySize;
     151    RingBuffer<size_t> totalExternalSize;
    150152    RingBuffer<size_t> gcHeapSize;
    151153    std::array<HistoricMemoryCategoryInfo, MemoryCategory::NumberOfCategories> categories;
     
    190192    historicData.cpu.append(data.cpu);
    191193    historicData.totalDirtySize.append(data.totalDirtySize);
     194    historicData.totalExternalSize.append(data.totalExternalSize);
    192195    for (auto& category : historicData.categories) {
    193196        category.dirtySize.append(data.categories[category.type].dirtySize);
    194197        category.reclaimableSize.append(data.categories[category.type].reclaimableSize);
     198        category.externalSize.append(data.categories[category.type].externalSize);
    195199    }
    196200    historicData.timeOfNextEdenCollection = data.timeOfNextEdenCollection;
     
    449453    showText(context, 10, 20, colorForLabels, String::format("        CPU: %g", data.cpu.last()));
    450454    showText(context, 10, 30, colorForLabels, "  Footprint: " + formatByteNumber(data.totalDirtySize.last()));
    451 
    452     float y = 50;
     455    showText(context, 10, 40, colorForLabels, "   External: " + formatByteNumber(data.totalExternalSize.last()));
     456
     457    float y = 55;
    453458    for (auto& category : data.categories) {
    454         String label = String::format("% 11s: %s", category.name.ascii().data(), formatByteNumber(category.dirtySize.last()).ascii().data());
     459        size_t dirty = category.dirtySize.last();
    455460        size_t reclaimable = category.reclaimableSize.last();
     461        size_t external = category.externalSize.last();
     462       
     463        String label = String::format("% 11s: %s", category.name.ascii().data(), formatByteNumber(dirty).ascii().data());
     464        if (external)
     465            label = label + String::format(" + %s", formatByteNumber(external).ascii().data());
    456466        if (reclaimable)
    457467            label = label + String::format(" [%s]", formatByteNumber(reclaimable).ascii().data());
     
    461471        y += 10;
    462472    }
     473    y -= 5;
    463474
    464475    double now = WTF::currentTime();
  • trunk/Source/WebCore/page/cocoa/ResourceUsageThreadCocoa.mm

    r196780 r202394  
    196196        return MemoryCategory::Other;
    197197    }
    198 };
     198}
    199199
    200200void ResourceUsageThread::platformThreadBody(JSC::VM* vm, ResourceUsageData& data)
     
    220220
    221221    size_t currentGCHeapCapacity = vm->heap.blockBytesAllocated();
    222     size_t currentGCOwned = vm->heap.extraMemorySize();
     222    size_t currentGCOwnedExtra = vm->heap.extraMemorySize();
     223    size_t currentGCOwnedExternal = vm->heap.externalMemorySize();
     224    ASSERT(currentGCOwnedExternal <= currentGCOwnedExtra);
    223225
    224226    data.categories[MemoryCategory::GCHeap].dirtySize = currentGCHeapCapacity;
    225     data.categories[MemoryCategory::GCOwned].dirtySize = currentGCOwned;
     227    data.categories[MemoryCategory::GCOwned].dirtySize = currentGCOwnedExtra - currentGCOwnedExternal;
     228    data.categories[MemoryCategory::GCOwned].externalSize = currentGCOwnedExternal;
    226229
    227230    // Subtract known subchunks from the bmalloc bucket.
    228231    // FIXME: Handle running with bmalloc disabled.
    229     data.categories[MemoryCategory::bmalloc].dirtySize -= currentGCHeapCapacity + currentGCOwned;
     232    size_t currentGCOwnedGenerallyInBmalloc = currentGCOwnedExtra - currentGCOwnedExternal;
     233    ASSERT(currentGCOwnedGenerallyInBmalloc < data.categories[MemoryCategory::bmalloc].dirtySize);
     234    data.categories[MemoryCategory::bmalloc].dirtySize -= currentGCHeapCapacity + currentGCOwnedGenerallyInBmalloc;
     235
     236    data.totalExternalSize = currentGCOwnedExternal;
    230237
    231238    data.timeOfNextEdenCollection = vm->heap.edenActivityCallback()->nextFireTime();
  • trunk/Source/WebCore/platform/graphics/ImageBuffer.cpp

    r202348 r202394  
    198198}
    199199
    200 }
     200#if !USE(IOSURFACE_CANVAS_BACKING_STORE)
     201size_t ImageBuffer::memoryCost() const
     202{
     203    return 4 * internalSize().width() * internalSize().height();
     204}
     205
     206size_t ImageBuffer::externalMemoryCost() const
     207{
     208    return 0;
     209}
     210#endif
     211
     212}
  • trunk/Source/WebCore/platform/graphics/ImageBuffer.h

    r202348 r202394  
    128128#endif
    129129
     130    size_t memoryCost() const;
     131    size_t externalMemoryCost() const;
     132
    130133    // FIXME: current implementations of this method have the restriction that they only work
    131134    // with textures that are RGB or RGBA format, and UNSIGNED_BYTE type.
  • trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp

    r201334 r202394  
    161161}
    162162
     163#if USE(IOSURFACE_CANVAS_BACKING_STORE)
     164size_t ImageBuffer::memoryCost() const
     165{
     166    if (m_data.surface)
     167        return m_data.surface->totalBytes();
     168    return 4 * internalSize().width() * internalSize().height();
     169}
     170
     171size_t ImageBuffer::externalMemoryCost() const
     172{
     173    if (m_data.surface)
     174        return m_data.surface->totalBytes();
     175    return 0;
     176}
     177#endif
     178
    163179GraphicsContext& ImageBuffer::context() const
    164180{
  • trunk/Source/WebCore/platform/graphics/cocoa/IOSurface.h

    r202142 r202394  
    3131#include "GraphicsContext.h"
    3232#include "IntSize.h"
    33 #include <wtf/PassRefPtr.h>
    3433
    3534namespace WebCore {
Note: See TracChangeset for help on using the changeset viewer.