2 * Copyright (C) 2013 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.
32 #include "core/inspector/InspectorHeapProfilerAgent.h"
34 #include "bindings/core/v8/ScriptProfiler.h"
35 #include "core/inspector/InjectedScript.h"
36 #include "core/inspector/InjectedScriptHost.h"
37 #include "core/inspector/InspectorState.h"
38 #include "platform/Timer.h"
39 #include "wtf/CurrentTime.h"
43 typedef uint32_t SnapshotObjectId;
45 namespace HeapProfilerAgentState {
46 static const char heapProfilerEnabled[] = "heapProfilerEnabled";
47 static const char heapObjectsTrackingEnabled[] = "heapObjectsTrackingEnabled";
48 static const char allocationTrackingEnabled[] = "allocationTrackingEnabled";
51 class InspectorHeapProfilerAgent::HeapStatsUpdateTask FINAL : public NoBaseWillBeGarbageCollectedFinalized<InspectorHeapProfilerAgent::HeapStatsUpdateTask> {
53 explicit HeapStatsUpdateTask(InspectorHeapProfilerAgent*);
55 void resetTimer() { m_timer.stop(); }
56 void onTimer(Timer<HeapStatsUpdateTask>*);
60 RawPtrWillBeMember<InspectorHeapProfilerAgent> m_heapProfilerAgent;
61 Timer<HeapStatsUpdateTask> m_timer;
65 class InspectorHeapProfilerAgent::HeapXDKUpdateTask FINAL : public NoBaseWillBeGarbageCollectedFinalized<InspectorHeapProfilerAgent::HeapXDKUpdateTask> {
67 HeapXDKUpdateTask(InspectorHeapProfilerAgent*);
68 void startTimer(float sav);
69 void resetTimer() { m_timer.stop(); }
70 void onTimer(Timer<HeapXDKUpdateTask>*);
73 InspectorHeapProfilerAgent* m_heapProfilerAgent;
74 Timer<HeapXDKUpdateTask> m_timer;
78 PassOwnPtrWillBeRawPtr<InspectorHeapProfilerAgent> InspectorHeapProfilerAgent::create(InjectedScriptManager* injectedScriptManager)
80 return adoptPtrWillBeNoop(new InspectorHeapProfilerAgent(injectedScriptManager));
83 InspectorHeapProfilerAgent::InspectorHeapProfilerAgent(InjectedScriptManager* injectedScriptManager)
84 : InspectorBaseAgent<InspectorHeapProfilerAgent>("HeapProfiler")
85 , m_injectedScriptManager(injectedScriptManager)
87 , m_nextUserInitiatedHeapSnapshotNumber(1)
91 InspectorHeapProfilerAgent::~InspectorHeapProfilerAgent()
95 void InspectorHeapProfilerAgent::setFrontend(InspectorFrontend* frontend)
97 m_frontend = frontend->heapprofiler();
100 void InspectorHeapProfilerAgent::clearFrontend()
104 m_nextUserInitiatedHeapSnapshotNumber = 1;
105 stopTrackingHeapObjectsInternal();
106 m_injectedScriptManager->injectedScriptHost()->clearInspectedObjects();
112 void InspectorHeapProfilerAgent::restore()
114 if (m_state->getBoolean(HeapProfilerAgentState::heapProfilerEnabled))
115 m_frontend->resetProfiles();
116 if (m_state->getBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled))
117 startTrackingHeapObjectsInternal(m_state->getBoolean(HeapProfilerAgentState::allocationTrackingEnabled));
120 void InspectorHeapProfilerAgent::collectGarbage(blink::ErrorString*)
122 ScriptProfiler::collectGarbage();
125 InspectorHeapProfilerAgent::HeapStatsUpdateTask::HeapStatsUpdateTask(InspectorHeapProfilerAgent* heapProfilerAgent)
126 : m_heapProfilerAgent(heapProfilerAgent)
127 , m_timer(this, &HeapStatsUpdateTask::onTimer)
131 void InspectorHeapProfilerAgent::HeapStatsUpdateTask::onTimer(Timer<HeapStatsUpdateTask>*)
133 // The timer is stopped on m_heapProfilerAgent destruction,
134 // so this method will never be called after m_heapProfilerAgent has been destroyed.
135 m_heapProfilerAgent->requestHeapStatsUpdate();
138 void InspectorHeapProfilerAgent::HeapStatsUpdateTask::startTimer()
140 ASSERT(!m_timer.isActive());
141 m_timer.startRepeating(0.05, FROM_HERE);
144 void InspectorHeapProfilerAgent::HeapStatsUpdateTask::trace(Visitor* visitor)
146 visitor->trace(m_heapProfilerAgent);
149 class InspectorHeapProfilerAgent::HeapStatsStream FINAL : public ScriptProfiler::OutputStream {
151 HeapStatsStream(InspectorHeapProfilerAgent* heapProfilerAgent)
152 : m_heapProfilerAgent(heapProfilerAgent)
156 virtual void write(const uint32_t* chunk, const int size) OVERRIDE
160 m_heapProfilerAgent->pushHeapStatsUpdate(chunk, size);
163 InspectorHeapProfilerAgent* m_heapProfilerAgent;
166 void InspectorHeapProfilerAgent::startTrackingHeapObjects(ErrorString*, const bool* trackAllocations)
168 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true);
169 bool allocationTrackingEnabled = asBool(trackAllocations);
170 m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled, allocationTrackingEnabled);
171 startTrackingHeapObjectsInternal(allocationTrackingEnabled);
174 void InspectorHeapProfilerAgent::requestHeapStatsUpdate()
178 HeapStatsStream stream(this);
179 SnapshotObjectId lastSeenObjectId = ScriptProfiler::requestHeapStatsUpdate(&stream);
180 m_frontend->lastSeenObjectId(lastSeenObjectId, WTF::currentTimeMS());
183 void InspectorHeapProfilerAgent::pushHeapStatsUpdate(const uint32_t* const data, const int size)
187 RefPtr<TypeBuilder::Array<int> > statsDiff = TypeBuilder::Array<int>::create();
188 for (int i = 0; i < size; ++i)
189 statsDiff->addItem(data[i]);
190 m_frontend->heapStatsUpdate(statsDiff.release());
193 void InspectorHeapProfilerAgent::stopTrackingHeapObjects(ErrorString* error, const bool* reportProgress)
195 if (!m_heapStatsUpdateTask) {
196 *error = "Heap object tracking is not started.";
199 requestHeapStatsUpdate();
200 takeHeapSnapshot(error, reportProgress);
201 stopTrackingHeapObjectsInternal();
204 void InspectorHeapProfilerAgent::startTrackingHeapObjectsInternal(bool trackAllocations)
206 if (m_heapStatsUpdateTask)
208 ScriptProfiler::startTrackingHeapObjects(trackAllocations);
209 m_heapStatsUpdateTask = adoptPtrWillBeNoop(new HeapStatsUpdateTask(this));
210 m_heapStatsUpdateTask->startTimer();
213 void InspectorHeapProfilerAgent::stopTrackingHeapObjectsInternal()
215 if (!m_heapStatsUpdateTask)
217 ScriptProfiler::stopTrackingHeapObjects();
218 m_heapStatsUpdateTask->resetTimer();
219 m_heapStatsUpdateTask.clear();
220 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, false);
221 m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled, false);
224 void InspectorHeapProfilerAgent::enable(ErrorString*)
226 m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, true);
229 void InspectorHeapProfilerAgent::disable(ErrorString* error)
231 stopTrackingHeapObjectsInternal();
232 ScriptProfiler::clearHeapObjectIds();
233 m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, false);
236 void InspectorHeapProfilerAgent::takeHeapSnapshot(ErrorString* errorString, const bool* reportProgress)
238 class HeapSnapshotProgress FINAL : public ScriptProfiler::HeapSnapshotProgress {
240 explicit HeapSnapshotProgress(InspectorFrontend::HeapProfiler* frontend)
241 : m_frontend(frontend) { }
242 virtual void Start(int totalWork) OVERRIDE
244 m_totalWork = totalWork;
246 virtual void Worked(int workDone) OVERRIDE
249 m_frontend->reportHeapSnapshotProgress(workDone, m_totalWork, 0);
253 virtual void Done() OVERRIDE
255 const bool finished = true;
257 m_frontend->reportHeapSnapshotProgress(m_totalWork, m_totalWork, &finished);
261 virtual bool isCanceled() OVERRIDE { return false; }
263 InspectorFrontend::HeapProfiler* m_frontend;
267 String title = "Snapshot " + String::number(m_nextUserInitiatedHeapSnapshotNumber++);
268 HeapSnapshotProgress progress(asBool(reportProgress) ? m_frontend : 0);
269 RefPtr<ScriptHeapSnapshot> snapshot = ScriptProfiler::takeHeapSnapshot(title, &progress);
271 *errorString = "Failed to take heap snapshot";
275 class OutputStream : public ScriptHeapSnapshot::OutputStream {
277 explicit OutputStream(InspectorFrontend::HeapProfiler* frontend)
278 : m_frontend(frontend) { }
279 void Write(const String& chunk)
281 m_frontend->addHeapSnapshotChunk(chunk);
286 InspectorFrontend::HeapProfiler* m_frontend;
290 OutputStream stream(m_frontend);
291 snapshot->writeJSON(&stream);
295 void InspectorHeapProfilerAgent::getObjectByHeapObjectId(ErrorString* error, const String& heapSnapshotObjectId, const String* objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result)
298 unsigned id = heapSnapshotObjectId.toUInt(&ok);
300 *error = "Invalid heap snapshot object id";
303 ScriptValue heapObject = ScriptProfiler::objectByHeapObjectId(id);
304 if (heapObject.isEmpty()) {
305 *error = "Object is not available";
308 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(heapObject.scriptState());
309 if (injectedScript.isEmpty()) {
310 *error = "Object is not available. Inspected context is gone";
313 result = injectedScript.wrapObject(heapObject, objectGroup ? *objectGroup : "");
315 *error = "Failed to wrap object";
318 void InspectorHeapProfilerAgent::getHeapObjectId(ErrorString* errorString, const String& objectId, String* heapSnapshotObjectId)
320 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
321 if (injectedScript.isEmpty()) {
322 *errorString = "Inspected context has gone";
325 ScriptValue value = injectedScript.findObjectById(objectId);
326 ScriptState::Scope scope(injectedScript.scriptState());
327 if (value.isEmpty() || value.isUndefined()) {
328 *errorString = "Object with given id not found";
331 unsigned id = ScriptProfiler::getHeapObjectId(value);
332 *heapSnapshotObjectId = String::number(id);
335 void InspectorHeapProfilerAgent::trace(Visitor* visitor)
337 visitor->trace(m_injectedScriptManager);
338 visitor->trace(m_heapStatsUpdateTask);
339 InspectorBaseAgent::trace(visitor);
342 static PassRefPtr<TypeBuilder::HeapProfiler::HeapEventXDK> createHeapProfileXDK(const HeapProfileXDK& heapProfileXDK)
344 RefPtr<TypeBuilder::HeapProfiler::HeapEventXDK> profile = TypeBuilder::HeapProfiler::HeapEventXDK::create()
345 .setDuration(heapProfileXDK.getDuration())
346 .setSymbols(heapProfileXDK.getSymbols())
347 .setFrames(heapProfileXDK.getFrames())
348 .setTypes(heapProfileXDK.getTypes())
349 .setChunks(heapProfileXDK.getChunks())
350 .setRetentions(heapProfileXDK.getRetentions());
351 return profile.release();
354 InspectorHeapProfilerAgent::HeapXDKUpdateTask::HeapXDKUpdateTask(InspectorHeapProfilerAgent* heapProfilerAgent)
355 : m_heapProfilerAgent(heapProfilerAgent)
356 , m_timer(this, &HeapXDKUpdateTask::onTimer)
360 void InspectorHeapProfilerAgent::HeapXDKUpdateTask::onTimer(Timer<HeapXDKUpdateTask>*)
362 // The timer is stopped on m_heapProfilerAgent destruction,
363 // so this method will never be called after m_heapProfilerAgent has been destroyed.
364 m_heapProfilerAgent->requestHeapXDKUpdate();
367 void InspectorHeapProfilerAgent::HeapXDKUpdateTask::startTimer(float sav)
369 ASSERT(!m_timer.isActive());
370 m_timer.startRepeating(sav, FROM_HERE);
373 void InspectorHeapProfilerAgent::startTrackingHeapXDK(ErrorString*,
374 const int* stack_depth,
376 const bool* retentions)
378 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true);
380 // inline of startTrackingHeapObjectsInternal(allocationTrackingEnabled);
381 if (m_heapXDKUpdateTask)
385 stackDepth = *stack_depth;
389 sav_timer = (float)*sav / 1000.;
391 bool needRetentions = retentions && *retentions;
392 ScriptProfiler::startTrackingHeapObjectsXDK(stackDepth, needRetentions );
393 m_heapXDKUpdateTask = adoptPtr(new HeapXDKUpdateTask(this));
394 m_heapXDKUpdateTask->startTimer(sav_timer);
397 class InspectorHeapProfilerAgent::HeapXDKStream FINAL : public ScriptProfiler::OutputStream {
399 HeapXDKStream(InspectorHeapProfilerAgent* heapProfilerAgent)
400 : m_heapProfilerAgent(heapProfilerAgent)
404 virtual void write(const uint32_t* chunk, const int size){}
405 virtual void write(const char* symbols, int symbolsSize,
406 const char* frames, int framesSize,
407 const char* types, int typesSize,
408 const char* chunks, int chunksSize,
409 const char* retentions, int retentionsSize) OVERRIDE
411 m_heapProfilerAgent->pushHeapXDKUpdate(symbols, symbolsSize, frames, framesSize,
412 types, typesSize, chunks, chunksSize,
413 retentions, retentionsSize);
416 InspectorHeapProfilerAgent* m_heapProfilerAgent;
419 void InspectorHeapProfilerAgent::requestHeapXDKUpdate()
423 HeapXDKStream stream(this);
424 ScriptProfiler::requestHeapXDKUpdate(&stream);
427 void InspectorHeapProfilerAgent::stopTrackingHeapXDK(ErrorString* error, RefPtr<TypeBuilder::HeapProfiler::HeapEventXDK>& profile)
429 if (!m_heapXDKUpdateTask) {
430 *error = "Heap object tracking is not started.";
434 RefPtr<HeapProfileXDK> heapProfileXDK = ScriptProfiler::stopTrackingHeapObjectsXDK();
435 profile = createHeapProfileXDK(*heapProfileXDK);
437 m_heapXDKUpdateTask->resetTimer();
438 m_heapXDKUpdateTask.clear();
439 m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, false);
442 void InspectorHeapProfilerAgent::pushHeapXDKUpdate( const char* symbols, int symbolsSize,
443 const char* frames, int framesSize,
444 const char* types, int typesSize,
445 const char* chunks, int chunksSize,
446 const char* retentions, int retentionsSize)
450 m_frontend->heapXDKUpdate(String(symbols, symbolsSize), String(frames, framesSize),
451 String(types, typesSize), String(chunks, chunksSize),
452 String(retentions, retentionsSize));