Upstream version 11.39.244.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / inspector / InspectorHeapProfilerAgent.cpp
1 /*
2  * Copyright (C) 2013 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 #include "config.h"
32 #include "core/inspector/InspectorHeapProfilerAgent.h"
33
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"
40
41 namespace blink {
42
43 typedef uint32_t SnapshotObjectId;
44
45 namespace HeapProfilerAgentState {
46 static const char heapProfilerEnabled[] = "heapProfilerEnabled";
47 static const char heapObjectsTrackingEnabled[] = "heapObjectsTrackingEnabled";
48 static const char allocationTrackingEnabled[] = "allocationTrackingEnabled";
49 }
50
51 class InspectorHeapProfilerAgent::HeapStatsUpdateTask FINAL : public NoBaseWillBeGarbageCollectedFinalized<InspectorHeapProfilerAgent::HeapStatsUpdateTask> {
52 public:
53     explicit HeapStatsUpdateTask(InspectorHeapProfilerAgent*);
54     void startTimer();
55     void resetTimer() { m_timer.stop(); }
56     void onTimer(Timer<HeapStatsUpdateTask>*);
57     void trace(Visitor*);
58
59 private:
60     RawPtrWillBeMember<InspectorHeapProfilerAgent> m_heapProfilerAgent;
61     Timer<HeapStatsUpdateTask> m_timer;
62 };
63
64
65 class InspectorHeapProfilerAgent::HeapXDKUpdateTask FINAL : public NoBaseWillBeGarbageCollectedFinalized<InspectorHeapProfilerAgent::HeapXDKUpdateTask> {
66 public:
67     HeapXDKUpdateTask(InspectorHeapProfilerAgent*);
68     void startTimer(float sav);
69     void resetTimer() { m_timer.stop(); }
70     void onTimer(Timer<HeapXDKUpdateTask>*);
71
72 private:
73     InspectorHeapProfilerAgent* m_heapProfilerAgent;
74     Timer<HeapXDKUpdateTask> m_timer;
75 };
76
77
78 PassOwnPtrWillBeRawPtr<InspectorHeapProfilerAgent> InspectorHeapProfilerAgent::create(InjectedScriptManager* injectedScriptManager)
79 {
80     return adoptPtrWillBeNoop(new InspectorHeapProfilerAgent(injectedScriptManager));
81 }
82
83 InspectorHeapProfilerAgent::InspectorHeapProfilerAgent(InjectedScriptManager* injectedScriptManager)
84     : InspectorBaseAgent<InspectorHeapProfilerAgent>("HeapProfiler")
85     , m_injectedScriptManager(injectedScriptManager)
86     , m_frontend(0)
87     , m_nextUserInitiatedHeapSnapshotNumber(1)
88 {
89 }
90
91 InspectorHeapProfilerAgent::~InspectorHeapProfilerAgent()
92 {
93 }
94
95 void InspectorHeapProfilerAgent::setFrontend(InspectorFrontend* frontend)
96 {
97     m_frontend = frontend->heapprofiler();
98 }
99
100 void InspectorHeapProfilerAgent::clearFrontend()
101 {
102     m_frontend = 0;
103
104     m_nextUserInitiatedHeapSnapshotNumber = 1;
105     stopTrackingHeapObjectsInternal();
106     m_injectedScriptManager->injectedScriptHost()->clearInspectedObjects();
107
108     ErrorString error;
109     disable(&error);
110 }
111
112 void InspectorHeapProfilerAgent::restore()
113 {
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));
118 }
119
120 void InspectorHeapProfilerAgent::collectGarbage(blink::ErrorString*)
121 {
122     ScriptProfiler::collectGarbage();
123 }
124
125 InspectorHeapProfilerAgent::HeapStatsUpdateTask::HeapStatsUpdateTask(InspectorHeapProfilerAgent* heapProfilerAgent)
126     : m_heapProfilerAgent(heapProfilerAgent)
127     , m_timer(this, &HeapStatsUpdateTask::onTimer)
128 {
129 }
130
131 void InspectorHeapProfilerAgent::HeapStatsUpdateTask::onTimer(Timer<HeapStatsUpdateTask>*)
132 {
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();
136 }
137
138 void InspectorHeapProfilerAgent::HeapStatsUpdateTask::startTimer()
139 {
140     ASSERT(!m_timer.isActive());
141     m_timer.startRepeating(0.05, FROM_HERE);
142 }
143
144 void InspectorHeapProfilerAgent::HeapStatsUpdateTask::trace(Visitor* visitor)
145 {
146     visitor->trace(m_heapProfilerAgent);
147 }
148
149 class InspectorHeapProfilerAgent::HeapStatsStream FINAL : public ScriptProfiler::OutputStream {
150 public:
151     HeapStatsStream(InspectorHeapProfilerAgent* heapProfilerAgent)
152         : m_heapProfilerAgent(heapProfilerAgent)
153     {
154     }
155
156     virtual void write(const uint32_t* chunk, const int size) OVERRIDE
157     {
158         ASSERT(chunk);
159         ASSERT(size > 0);
160         m_heapProfilerAgent->pushHeapStatsUpdate(chunk, size);
161     }
162 private:
163     InspectorHeapProfilerAgent* m_heapProfilerAgent;
164 };
165
166 void InspectorHeapProfilerAgent::startTrackingHeapObjects(ErrorString*, const bool* trackAllocations)
167 {
168     m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true);
169     bool allocationTrackingEnabled = asBool(trackAllocations);
170     m_state->setBoolean(HeapProfilerAgentState::allocationTrackingEnabled, allocationTrackingEnabled);
171     startTrackingHeapObjectsInternal(allocationTrackingEnabled);
172 }
173
174 void InspectorHeapProfilerAgent::requestHeapStatsUpdate()
175 {
176     if (!m_frontend)
177         return;
178     HeapStatsStream stream(this);
179     SnapshotObjectId lastSeenObjectId = ScriptProfiler::requestHeapStatsUpdate(&stream);
180     m_frontend->lastSeenObjectId(lastSeenObjectId, WTF::currentTimeMS());
181 }
182
183 void InspectorHeapProfilerAgent::pushHeapStatsUpdate(const uint32_t* const data, const int size)
184 {
185     if (!m_frontend)
186         return;
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());
191 }
192
193 void InspectorHeapProfilerAgent::stopTrackingHeapObjects(ErrorString* error, const bool* reportProgress)
194 {
195     if (!m_heapStatsUpdateTask) {
196         *error = "Heap object tracking is not started.";
197         return;
198     }
199     requestHeapStatsUpdate();
200     takeHeapSnapshot(error, reportProgress);
201     stopTrackingHeapObjectsInternal();
202 }
203
204 void InspectorHeapProfilerAgent::startTrackingHeapObjectsInternal(bool trackAllocations)
205 {
206     if (m_heapStatsUpdateTask)
207         return;
208     ScriptProfiler::startTrackingHeapObjects(trackAllocations);
209     m_heapStatsUpdateTask = adoptPtrWillBeNoop(new HeapStatsUpdateTask(this));
210     m_heapStatsUpdateTask->startTimer();
211 }
212
213 void InspectorHeapProfilerAgent::stopTrackingHeapObjectsInternal()
214 {
215     if (!m_heapStatsUpdateTask)
216         return;
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);
222 }
223
224 void InspectorHeapProfilerAgent::enable(ErrorString*)
225 {
226     m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, true);
227 }
228
229 void InspectorHeapProfilerAgent::disable(ErrorString* error)
230 {
231     stopTrackingHeapObjectsInternal();
232     ScriptProfiler::clearHeapObjectIds();
233     m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, false);
234 }
235
236 void InspectorHeapProfilerAgent::takeHeapSnapshot(ErrorString* errorString, const bool* reportProgress)
237 {
238     class HeapSnapshotProgress FINAL : public ScriptProfiler::HeapSnapshotProgress {
239     public:
240         explicit HeapSnapshotProgress(InspectorFrontend::HeapProfiler* frontend)
241             : m_frontend(frontend) { }
242         virtual void Start(int totalWork) OVERRIDE
243         {
244             m_totalWork = totalWork;
245         }
246         virtual void Worked(int workDone) OVERRIDE
247         {
248             if (m_frontend) {
249                 m_frontend->reportHeapSnapshotProgress(workDone, m_totalWork, 0);
250                 m_frontend->flush();
251             }
252         }
253         virtual void Done() OVERRIDE
254         {
255             const bool finished = true;
256             if (m_frontend) {
257                 m_frontend->reportHeapSnapshotProgress(m_totalWork, m_totalWork, &finished);
258                 m_frontend->flush();
259             }
260         }
261         virtual bool isCanceled() OVERRIDE { return false; }
262     private:
263         InspectorFrontend::HeapProfiler* m_frontend;
264         int m_totalWork;
265     };
266
267     String title = "Snapshot " + String::number(m_nextUserInitiatedHeapSnapshotNumber++);
268     HeapSnapshotProgress progress(asBool(reportProgress) ? m_frontend : 0);
269     RefPtr<ScriptHeapSnapshot> snapshot = ScriptProfiler::takeHeapSnapshot(title, &progress);
270     if (!snapshot) {
271         *errorString = "Failed to take heap snapshot";
272         return;
273     }
274
275     class OutputStream : public ScriptHeapSnapshot::OutputStream {
276     public:
277         explicit OutputStream(InspectorFrontend::HeapProfiler* frontend)
278             : m_frontend(frontend) { }
279         void Write(const String& chunk)
280         {
281             m_frontend->addHeapSnapshotChunk(chunk);
282             m_frontend->flush();
283         }
284         void Close() { }
285     private:
286         InspectorFrontend::HeapProfiler* m_frontend;
287     };
288
289     if (m_frontend) {
290         OutputStream stream(m_frontend);
291         snapshot->writeJSON(&stream);
292     }
293 }
294
295 void InspectorHeapProfilerAgent::getObjectByHeapObjectId(ErrorString* error, const String& heapSnapshotObjectId, const String* objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result)
296 {
297     bool ok;
298     unsigned id = heapSnapshotObjectId.toUInt(&ok);
299     if (!ok) {
300         *error = "Invalid heap snapshot object id";
301         return;
302     }
303     ScriptValue heapObject = ScriptProfiler::objectByHeapObjectId(id);
304     if (heapObject.isEmpty()) {
305         *error = "Object is not available";
306         return;
307     }
308     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(heapObject.scriptState());
309     if (injectedScript.isEmpty()) {
310         *error = "Object is not available. Inspected context is gone";
311         return;
312     }
313     result = injectedScript.wrapObject(heapObject, objectGroup ? *objectGroup : "");
314     if (!result)
315         *error = "Failed to wrap object";
316 }
317
318 void InspectorHeapProfilerAgent::getHeapObjectId(ErrorString* errorString, const String& objectId, String* heapSnapshotObjectId)
319 {
320     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
321     if (injectedScript.isEmpty()) {
322         *errorString = "Inspected context has gone";
323         return;
324     }
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";
329         return;
330     }
331     unsigned id = ScriptProfiler::getHeapObjectId(value);
332     *heapSnapshotObjectId = String::number(id);
333 }
334
335 void InspectorHeapProfilerAgent::trace(Visitor* visitor)
336 {
337     visitor->trace(m_injectedScriptManager);
338     visitor->trace(m_heapStatsUpdateTask);
339     InspectorBaseAgent::trace(visitor);
340 }
341
342 static PassRefPtr<TypeBuilder::HeapProfiler::HeapEventXDK> createHeapProfileXDK(const HeapProfileXDK& heapProfileXDK)
343 {
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();
352 }
353
354 InspectorHeapProfilerAgent::HeapXDKUpdateTask::HeapXDKUpdateTask(InspectorHeapProfilerAgent* heapProfilerAgent)
355     : m_heapProfilerAgent(heapProfilerAgent)
356     , m_timer(this, &HeapXDKUpdateTask::onTimer)
357 {
358 }
359
360 void InspectorHeapProfilerAgent::HeapXDKUpdateTask::onTimer(Timer<HeapXDKUpdateTask>*)
361 {
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();
365 }
366
367 void InspectorHeapProfilerAgent::HeapXDKUpdateTask::startTimer(float sav)
368 {
369     ASSERT(!m_timer.isActive());
370     m_timer.startRepeating(sav, FROM_HERE);
371 }
372
373 void InspectorHeapProfilerAgent::startTrackingHeapXDK(ErrorString*, 
374                                                       const int* stack_depth,
375                                                       const int* sav,
376                                                       const bool* retentions)
377 {
378     m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, true);
379
380     // inline of startTrackingHeapObjectsInternal(allocationTrackingEnabled);
381     if (m_heapXDKUpdateTask)
382         return;
383     int stackDepth = 8;
384     if (stack_depth) {
385       stackDepth = *stack_depth;
386     }
387     float sav_timer = 1;
388     if (sav) {
389       sav_timer = (float)*sav / 1000.;
390     }
391     bool needRetentions = retentions && *retentions;
392     ScriptProfiler::startTrackingHeapObjectsXDK(stackDepth, needRetentions );
393     m_heapXDKUpdateTask = adoptPtr(new HeapXDKUpdateTask(this));
394     m_heapXDKUpdateTask->startTimer(sav_timer);
395 }
396
397 class InspectorHeapProfilerAgent::HeapXDKStream FINAL : public ScriptProfiler::OutputStream {
398 public:
399     HeapXDKStream(InspectorHeapProfilerAgent* heapProfilerAgent)
400         : m_heapProfilerAgent(heapProfilerAgent)
401     {
402     }
403
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
410     {
411         m_heapProfilerAgent->pushHeapXDKUpdate(symbols, symbolsSize, frames, framesSize, 
412                                                types, typesSize, chunks, chunksSize,
413                                                retentions, retentionsSize);
414     }
415 private:
416     InspectorHeapProfilerAgent* m_heapProfilerAgent;
417 };
418
419 void InspectorHeapProfilerAgent::requestHeapXDKUpdate()
420 {
421     if (!m_frontend)
422         return;
423     HeapXDKStream stream(this);
424     ScriptProfiler::requestHeapXDKUpdate(&stream);
425 }
426
427 void InspectorHeapProfilerAgent::stopTrackingHeapXDK(ErrorString* error, RefPtr<TypeBuilder::HeapProfiler::HeapEventXDK>& profile)
428 {
429     if (!m_heapXDKUpdateTask) {
430         *error = "Heap object tracking is not started.";
431         return;
432     }
433
434     RefPtr<HeapProfileXDK> heapProfileXDK = ScriptProfiler::stopTrackingHeapObjectsXDK();
435     profile = createHeapProfileXDK(*heapProfileXDK);
436     
437     m_heapXDKUpdateTask->resetTimer();
438     m_heapXDKUpdateTask.clear();
439     m_state->setBoolean(HeapProfilerAgentState::heapObjectsTrackingEnabled, false);
440
441 }
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)
447 {
448     if (!m_frontend)
449         return;
450     m_frontend->heapXDKUpdate(String(symbols, symbolsSize), String(frames, framesSize), 
451                               String(types, typesSize), String(chunks, chunksSize), 
452                               String(retentions, retentionsSize));
453 }
454
455 } // namespace blink
456