2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "InspectorMemoryAgent.h"
37 #include "BindingVisitors.h"
38 #include "CharacterData.h"
40 #include "EventListenerMap.h"
42 #include "HeapGraphSerializer.h"
43 #include "InspectorClient.h"
44 #include "InspectorDOMStorageAgent.h"
45 #include "InspectorFrontend.h"
46 #include "InspectorState.h"
47 #include "InspectorValues.h"
48 #include "InstrumentingAgents.h"
49 #include "MemoryCache.h"
50 #include "MemoryInstrumentationImpl.h"
51 #include "MemoryUsageSupport.h"
53 #include "NodeTraversal.h"
55 #include "ScriptGCEvent.h"
56 #include "ScriptProfiler.h"
57 #include "StyledElement.h"
58 #include <wtf/ArrayBufferView.h>
59 #include <wtf/HashSet.h>
60 #include <wtf/MemoryInstrumentationArrayBufferView.h>
61 #include <wtf/NonCopyingSort.h>
62 #include <wtf/OwnPtr.h>
63 #include <wtf/PassOwnPtr.h>
64 #include <wtf/Vector.h>
65 #include <wtf/text/StringBuilder.h>
66 #include <wtf/text/StringImpl.h>
67 #include <wtf/text/WTFString.h>
69 // Use a type alias instead of 'using' here which would cause a conflict on Mac.
70 typedef WebCore::TypeBuilder::Memory::MemoryBlock InspectorMemoryBlock;
71 typedef WebCore::TypeBuilder::Array<InspectorMemoryBlock> InspectorMemoryBlocks;
77 class MemoryUsageStatsGenerator {
79 MemoryUsageStatsGenerator() { }
81 void dump(const TypeNameToSizeMap& sizesMap, InspectorMemoryBlocks* children)
83 m_sizesMap = sizesMap;
85 // FIXME: We filter out Rendering type because the coverage is not good enough at the moment
86 // and report RenderArena size instead.
87 for (TypeNameToSizeMap::iterator i = m_sizesMap.begin(); i != m_sizesMap.end(); ++i) {
88 if (i->key == PlatformMemoryTypes::Rendering) {
93 Vector<String> objectTypes;
94 objectTypes.appendRange(m_sizesMap.keys().begin(), m_sizesMap.keys().end());
96 for (Vector<String>::const_iterator i = objectTypes.begin(); i != objectTypes.end(); ++i)
97 updateParentSizes(*i, m_sizesMap.get(*i));
100 objectTypes.appendRange(m_sizesMap.keys().begin(), m_sizesMap.keys().end());
101 nonCopyingSort(objectTypes.begin(), objectTypes.end(), stringCompare);
104 while (index < objectTypes.size())
105 index = buildObjectForIndex(index, objectTypes, children);
110 static bool stringCompare(const String& a, const String& b) { return WTF::codePointCompare(a, b) < 0; }
112 void updateParentSizes(String objectType, const size_t size)
114 for (size_t dotPosition = objectType.reverseFind('.'); dotPosition != notFound; dotPosition = objectType.reverseFind('.', dotPosition)) {
115 objectType = objectType.substring(0, dotPosition);
116 TypeNameToSizeMap::AddResult result = m_sizesMap.add(objectType, size);
117 if (!result.isNewEntry)
118 result.iterator->value += size;
122 size_t buildObjectForIndex(size_t index, const Vector<String>& objectTypes, InspectorMemoryBlocks* array)
124 String typeName = objectTypes[index];
125 size_t dotPosition = typeName.reverseFind('.');
126 String blockName = (dotPosition == notFound) ? typeName : typeName.substring(dotPosition + 1);
127 RefPtr<InspectorMemoryBlock> block = InspectorMemoryBlock::create().setName(blockName);
128 block->setSize(m_sizesMap.get(typeName));
129 String prefix = typeName;
131 array->addItem(block);
133 RefPtr<InspectorMemoryBlocks> children;
134 while (index < objectTypes.size() && objectTypes[index].startsWith(prefix)) {
136 children = InspectorMemoryBlocks::create();
137 index = buildObjectForIndex(index, objectTypes, children.get());
140 block->setChildren(children.release());
144 TypeNameToSizeMap m_sizesMap;
147 class ExternalStringsRoot : public ExternalStringVisitor {
149 ExternalStringsRoot() : m_memoryClassInfo(0) { }
151 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
153 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::ExternalStrings);
154 m_memoryClassInfo = &info;
155 ScriptProfiler::visitExternalStrings(const_cast<ExternalStringsRoot*>(this));
156 m_memoryClassInfo = 0;
157 info.ignoreMember(m_memoryClassInfo);
161 virtual void visitJSExternalString(StringImpl* string)
163 m_memoryClassInfo->addMember(string, "externalString");
166 mutable MemoryClassInfo* m_memoryClassInfo;
169 class ExternalArraysRoot : public ExternalArrayVisitor {
171 ExternalArraysRoot() : m_memoryClassInfo(0) { }
173 void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
175 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::ExternalArrays);
176 m_memoryClassInfo = &info;
177 ScriptProfiler::visitExternalArrays(const_cast<ExternalArraysRoot*>(this));
178 m_memoryClassInfo = 0;
179 info.ignoreMember(m_memoryClassInfo);
183 virtual void visitJSExternalArray(ArrayBufferView* arrayBufferView)
185 m_memoryClassInfo->addMember(arrayBufferView, "externalArray");
188 mutable MemoryClassInfo* m_memoryClassInfo;
193 InspectorMemoryAgent::~InspectorMemoryAgent()
197 void InspectorMemoryAgent::getDOMCounters(ErrorString*, int* documents, int* nodes, int* jsEventListeners)
199 *documents = InspectorCounters::counterValue(InspectorCounters::DocumentCounter);
200 *nodes = InspectorCounters::counterValue(InspectorCounters::NodeCounter);
201 *jsEventListeners = ThreadLocalInspectorCounters::current().counterValue(ThreadLocalInspectorCounters::JSEventListenerCounter);
204 static void reportJSHeapInfo(WTF::MemoryInstrumentationClient& memoryInstrumentationClient)
207 ScriptGCEvent::getHeapSize(info);
209 memoryInstrumentationClient.countObjectSize(0, WebCoreMemoryTypes::JSHeapUsed, info.usedJSHeapSize);
210 memoryInstrumentationClient.countObjectSize(0, WebCoreMemoryTypes::JSHeapUnused, info.totalJSHeapSize - info.usedJSHeapSize);
213 static void reportRenderTreeInfo(WTF::MemoryInstrumentationClient& memoryInstrumentationClient, Page* page)
215 ArenaSize arenaSize = page->renderTreeSize();
217 memoryInstrumentationClient.countObjectSize(0, WebCoreMemoryTypes::RenderTreeUsed, arenaSize.treeSize);
218 memoryInstrumentationClient.countObjectSize(0, WebCoreMemoryTypes::RenderTreeUnused, arenaSize.allocated - arenaSize.treeSize);
223 class DOMTreesIterator : public WrappedNodeVisitor {
225 DOMTreesIterator(MemoryInstrumentationImpl& memoryInstrumentation, Page* page)
227 , m_memoryInstrumentation(memoryInstrumentation)
231 virtual void visitNode(Node* node) OVERRIDE
233 if (node->document() && node->document()->frame() && m_page != node->document()->frame()->page())
236 while (Node* parentNode = node->parentNode())
239 m_memoryInstrumentation.addRootObject(node);
242 void visitFrame(Frame* frame)
244 m_memoryInstrumentation.addRootObject(frame);
249 ScriptProfiler::collectBindingMemoryInfo(&m_memoryInstrumentation);
252 void visitMemoryCache()
254 m_memoryInstrumentation.addRootObject(memoryCache());
260 MemoryInstrumentationImpl& m_memoryInstrumentation;
265 static void collectDomTreeInfo(MemoryInstrumentationImpl& memoryInstrumentation, Page* page)
267 ExternalStringsRoot stringsRoot;
268 memoryInstrumentation.addRootObject(stringsRoot);
270 ExternalArraysRoot arraysRoot;
271 memoryInstrumentation.addRootObject(arraysRoot);
273 DOMTreesIterator domTreesIterator(memoryInstrumentation, page);
275 ScriptProfiler::visitNodeWrappers(&domTreesIterator);
277 // Make sure all documents reachable from the main frame are accounted.
278 for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
279 if (Document* doc = frame->document()) {
280 domTreesIterator.visitNode(doc);
281 domTreesIterator.visitFrame(frame);
285 domTreesIterator.visitBindings();
286 domTreesIterator.visitMemoryCache();
289 static void addPlatformComponentsInfo(TypeNameToSizeMap* memoryInfo)
291 Vector<MemoryUsageSupport::ComponentInfo> components;
292 MemoryUsageSupport::memoryUsageByComponents(components);
293 for (Vector<MemoryUsageSupport::ComponentInfo>::iterator it = components.begin(); it != components.end(); ++it)
294 memoryInfo->add(it->m_name, it->m_sizeInBytes);
297 static void addMemoryInstrumentationDebugData(MemoryInstrumentationClientImpl* client, TypeNameToSizeMap* memoryInfo)
299 if (client->checkInstrumentedObjects()) {
300 memoryInfo->add("InstrumentedObjectsCount", client->totalCountedObjects());
301 memoryInfo->add("InstrumentedButNotAllocatedObjectsCount", client->totalObjectsNotInAllocatedSet());
305 void InspectorMemoryAgent::getProcessMemoryDistributionMap(TypeNameToSizeMap* memoryInfo)
307 getProcessMemoryDistributionImpl(false, memoryInfo);
310 void InspectorMemoryAgent::getProcessMemoryDistribution(ErrorString*, const bool* reportGraph, RefPtr<InspectorMemoryBlock>& processMemory)
312 TypeNameToSizeMap memoryInfo;
313 getProcessMemoryDistributionImpl(reportGraph && *reportGraph, &memoryInfo);
315 MemoryUsageStatsGenerator statsGenerator;
316 RefPtr<InspectorMemoryBlocks> children = InspectorMemoryBlocks::create();
317 statsGenerator.dump(memoryInfo, children.get());
319 processMemory = InspectorMemoryBlock::create().setName(WebCoreMemoryTypes::ProcessPrivateMemory);
320 processMemory->setChildren(children);
322 size_t privateBytes = 0;
323 size_t sharedBytes = 0;
324 MemoryUsageSupport::processMemorySizesInBytes(&privateBytes, &sharedBytes);
325 processMemory->setSize(privateBytes);
328 void InspectorMemoryAgent::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
330 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::Inspector);
331 InspectorBaseAgent<InspectorMemoryAgent>::reportMemoryUsage(memoryObjectInfo);
332 info.addWeakPointer(m_inspectorClient);
333 info.addMember(m_page, "page");
338 class FrontendWrapper : public HeapGraphSerializer::Client {
340 explicit FrontendWrapper(InspectorFrontend::Memory* frontend) : m_frontend(frontend) { }
341 virtual void addNativeSnapshotChunk(PassRefPtr<TypeBuilder::Memory::HeapSnapshotChunk> heapSnapshotChunk) OVERRIDE
343 m_frontend->addNativeSnapshotChunk(heapSnapshotChunk);
346 InspectorFrontend::Memory* m_frontend;
351 void InspectorMemoryAgent::getProcessMemoryDistributionImpl(bool reportGraph, TypeNameToSizeMap* memoryInfo)
353 OwnPtr<HeapGraphSerializer> graphSerializer;
354 OwnPtr<FrontendWrapper> frontendWrapper;
357 frontendWrapper = adoptPtr(new FrontendWrapper(m_frontend));
358 graphSerializer = adoptPtr(new HeapGraphSerializer(frontendWrapper.get()));
361 MemoryInstrumentationClientImpl memoryInstrumentationClient(graphSerializer.get());
362 m_inspectorClient->getAllocatedObjects(memoryInstrumentationClient.allocatedObjects());
363 MemoryInstrumentationImpl memoryInstrumentation(&memoryInstrumentationClient);
365 reportJSHeapInfo(memoryInstrumentationClient);
366 reportRenderTreeInfo(memoryInstrumentationClient, m_page);
367 collectDomTreeInfo(memoryInstrumentation, m_page); // FIXME: collect for all pages?
369 PlatformMemoryInstrumentation::reportStaticMembersMemoryUsage(&memoryInstrumentation);
370 WebCoreMemoryInstrumentation::reportStaticMembersMemoryUsage(&memoryInstrumentation);
372 memoryInstrumentation.addRootObject(this);
373 memoryInstrumentation.addRootObject(memoryInstrumentation);
374 memoryInstrumentation.addRootObject(memoryInstrumentationClient);
375 if (graphSerializer) {
376 memoryInstrumentation.addRootObject(graphSerializer.get());
377 graphSerializer->finish();
378 graphSerializer.release(); // Release it earlier than frontendWrapper
379 frontendWrapper.release();
382 m_inspectorClient->dumpUncountedAllocatedObjects(memoryInstrumentationClient.countedObjects());
384 *memoryInfo = memoryInstrumentationClient.sizesMap();
385 addPlatformComponentsInfo(memoryInfo);
386 addMemoryInstrumentationDebugData(&memoryInstrumentationClient, memoryInfo);
389 InspectorMemoryAgent::InspectorMemoryAgent(InstrumentingAgents* instrumentingAgents, InspectorClient* client, InspectorCompositeState* state, Page* page)
390 : InspectorBaseAgent<InspectorMemoryAgent>("Memory", instrumentingAgents, state)
391 , m_inspectorClient(client)
397 void InspectorMemoryAgent::setFrontend(InspectorFrontend* frontend)
400 m_frontend = frontend->memory();
403 void InspectorMemoryAgent::clearFrontend()
408 } // namespace WebCore
410 #endif // ENABLE(INSPECTOR)