Upstream version 5.34.104.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/v8/ScriptProfiler.h"
35 #include "bindings/v8/ScriptScope.h"
36 #include "core/inspector/InjectedScript.h"
37 #include "core/inspector/InjectedScriptHost.h"
38 #include "core/inspector/InspectorState.h"
39 #include "platform/Timer.h"
40 #include "wtf/CurrentTime.h"
41
42 namespace WebCore {
43
44 typedef uint32_t SnapshotObjectId;
45
46 namespace HeapProfilerAgentState {
47 static const char heapProfilerEnabled[] = "heapProfilerEnabled";
48 }
49
50 class InspectorHeapProfilerAgent::HeapStatsUpdateTask {
51 public:
52     HeapStatsUpdateTask(InspectorHeapProfilerAgent*);
53     void startTimer();
54     void resetTimer() { m_timer.stop(); }
55     void onTimer(Timer<HeapStatsUpdateTask>*);
56
57 private:
58     InspectorHeapProfilerAgent* m_heapProfilerAgent;
59     Timer<HeapStatsUpdateTask> m_timer;
60 };
61
62 PassOwnPtr<InspectorHeapProfilerAgent> InspectorHeapProfilerAgent::create(InjectedScriptManager* injectedScriptManager)
63 {
64     return adoptPtr(new InspectorHeapProfilerAgent(injectedScriptManager));
65 }
66
67 InspectorHeapProfilerAgent::InspectorHeapProfilerAgent(InjectedScriptManager* injectedScriptManager)
68     : InspectorBaseAgent<InspectorHeapProfilerAgent>("HeapProfiler")
69     , m_injectedScriptManager(injectedScriptManager)
70     , m_frontend(0)
71     , m_nextUserInitiatedHeapSnapshotNumber(1)
72 {
73 }
74
75 InspectorHeapProfilerAgent::~InspectorHeapProfilerAgent()
76 {
77 }
78
79 void InspectorHeapProfilerAgent::setFrontend(InspectorFrontend* frontend)
80 {
81     m_frontend = frontend->heapprofiler();
82 }
83
84 void InspectorHeapProfilerAgent::clearFrontend()
85 {
86     m_frontend = 0;
87
88     m_nextUserInitiatedHeapSnapshotNumber = 1;
89     stopTrackingHeapObjectsInternal();
90     m_injectedScriptManager->injectedScriptHost()->clearInspectedObjects();
91
92     ErrorString error;
93     disable(&error);
94 }
95
96 void InspectorHeapProfilerAgent::restore()
97 {
98     if (m_state->getBoolean(HeapProfilerAgentState::heapProfilerEnabled))
99         m_frontend->resetProfiles();
100 }
101
102 void InspectorHeapProfilerAgent::collectGarbage(WebCore::ErrorString*)
103 {
104     ScriptProfiler::collectGarbage();
105 }
106
107 InspectorHeapProfilerAgent::HeapStatsUpdateTask::HeapStatsUpdateTask(InspectorHeapProfilerAgent* heapProfilerAgent)
108     : m_heapProfilerAgent(heapProfilerAgent)
109     , m_timer(this, &HeapStatsUpdateTask::onTimer)
110 {
111 }
112
113 void InspectorHeapProfilerAgent::HeapStatsUpdateTask::onTimer(Timer<HeapStatsUpdateTask>*)
114 {
115     // The timer is stopped on m_heapProfilerAgent destruction,
116     // so this method will never be called after m_heapProfilerAgent has been destroyed.
117     m_heapProfilerAgent->requestHeapStatsUpdate();
118 }
119
120 void InspectorHeapProfilerAgent::HeapStatsUpdateTask::startTimer()
121 {
122     ASSERT(!m_timer.isActive());
123     m_timer.startRepeating(0.05);
124 }
125
126 class InspectorHeapProfilerAgent::HeapStatsStream FINAL : public ScriptProfiler::OutputStream {
127 public:
128     HeapStatsStream(InspectorHeapProfilerAgent* heapProfilerAgent)
129         : m_heapProfilerAgent(heapProfilerAgent)
130     {
131     }
132
133     virtual void write(const uint32_t* chunk, const int size) OVERRIDE
134     {
135         ASSERT(chunk);
136         ASSERT(size > 0);
137         m_heapProfilerAgent->pushHeapStatsUpdate(chunk, size);
138     }
139 private:
140     InspectorHeapProfilerAgent* m_heapProfilerAgent;
141 };
142
143 void InspectorHeapProfilerAgent::startTrackingHeapObjects(ErrorString*, const bool* trackAllocations)
144 {
145     if (m_heapStatsUpdateTask)
146         return;
147     ScriptProfiler::startTrackingHeapObjects(trackAllocations && *trackAllocations);
148     m_heapStatsUpdateTask = adoptPtr(new HeapStatsUpdateTask(this));
149     m_heapStatsUpdateTask->startTimer();
150 }
151
152 void InspectorHeapProfilerAgent::requestHeapStatsUpdate()
153 {
154     if (!m_frontend)
155         return;
156     HeapStatsStream stream(this);
157     SnapshotObjectId lastSeenObjectId = ScriptProfiler::requestHeapStatsUpdate(&stream);
158     m_frontend->lastSeenObjectId(lastSeenObjectId, WTF::currentTimeMS());
159 }
160
161 void InspectorHeapProfilerAgent::pushHeapStatsUpdate(const uint32_t* const data, const int size)
162 {
163     if (!m_frontend)
164         return;
165     RefPtr<TypeBuilder::Array<int> > statsDiff = TypeBuilder::Array<int>::create();
166     for (int i = 0; i < size; ++i)
167         statsDiff->addItem(data[i]);
168     m_frontend->heapStatsUpdate(statsDiff.release());
169 }
170
171 void InspectorHeapProfilerAgent::stopTrackingHeapObjects(ErrorString* error, const bool* reportProgress)
172 {
173     if (!m_heapStatsUpdateTask) {
174         *error = "Heap object tracking is not started.";
175         return;
176     }
177     requestHeapStatsUpdate();
178     takeHeapSnapshot(error, reportProgress);
179     stopTrackingHeapObjectsInternal();
180 }
181
182 void InspectorHeapProfilerAgent::stopTrackingHeapObjectsInternal()
183 {
184     if (!m_heapStatsUpdateTask)
185         return;
186     ScriptProfiler::stopTrackingHeapObjects();
187     m_heapStatsUpdateTask->resetTimer();
188     m_heapStatsUpdateTask.clear();
189 }
190
191 void InspectorHeapProfilerAgent::enable(ErrorString*)
192 {
193     m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, true);
194 }
195
196 void InspectorHeapProfilerAgent::disable(ErrorString* error)
197 {
198     stopTrackingHeapObjectsInternal();
199     ScriptProfiler::clearHeapObjectIds();
200     m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, false);
201 }
202
203 void InspectorHeapProfilerAgent::takeHeapSnapshot(ErrorString* errorString, const bool* reportProgress)
204 {
205     class HeapSnapshotProgress FINAL : public ScriptProfiler::HeapSnapshotProgress {
206     public:
207         explicit HeapSnapshotProgress(InspectorFrontend::HeapProfiler* frontend)
208             : m_frontend(frontend) { }
209         virtual void Start(int totalWork) OVERRIDE
210         {
211             m_totalWork = totalWork;
212         }
213         virtual void Worked(int workDone) OVERRIDE
214         {
215             if (m_frontend)
216                 m_frontend->reportHeapSnapshotProgress(workDone, m_totalWork, 0);
217         }
218         virtual void Done() OVERRIDE
219         {
220             const bool finished = true;
221             if (m_frontend)
222                 m_frontend->reportHeapSnapshotProgress(m_totalWork, m_totalWork, &finished);
223         }
224         virtual bool isCanceled() OVERRIDE { return false; }
225     private:
226         InspectorFrontend::HeapProfiler* m_frontend;
227         int m_totalWork;
228     };
229
230     String title = "Snapshot " + String::number(m_nextUserInitiatedHeapSnapshotNumber++);
231     HeapSnapshotProgress progress(reportProgress && *reportProgress ? m_frontend : 0);
232     RefPtr<ScriptHeapSnapshot> snapshot = ScriptProfiler::takeHeapSnapshot(title, &progress);
233     if (!snapshot) {
234         *errorString = "Failed to take heap snapshot";
235         return;
236     }
237
238     class OutputStream : public ScriptHeapSnapshot::OutputStream {
239     public:
240         explicit OutputStream(InspectorFrontend::HeapProfiler* frontend)
241             : m_frontend(frontend) { }
242         void Write(const String& chunk) { m_frontend->addHeapSnapshotChunk(chunk); }
243         void Close() { }
244     private:
245         InspectorFrontend::HeapProfiler* m_frontend;
246     };
247
248     if (m_frontend) {
249         OutputStream stream(m_frontend);
250         snapshot->writeJSON(&stream);
251     }
252 }
253
254 void InspectorHeapProfilerAgent::getObjectByHeapObjectId(ErrorString* error, const String& heapSnapshotObjectId, const String* objectGroup, RefPtr<TypeBuilder::Runtime::RemoteObject>& result)
255 {
256     bool ok;
257     unsigned id = heapSnapshotObjectId.toUInt(&ok);
258     if (!ok) {
259         *error = "Invalid heap snapshot object id";
260         return;
261     }
262     ScriptObject heapObject = ScriptProfiler::objectByHeapObjectId(id);
263     if (heapObject.hasNoValue()) {
264         *error = "Object is not available";
265         return;
266     }
267     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(heapObject.scriptState());
268     if (injectedScript.hasNoValue()) {
269         *error = "Object is not available. Inspected context is gone";
270         return;
271     }
272     result = injectedScript.wrapObject(heapObject, objectGroup ? *objectGroup : "");
273     if (!result)
274         *error = "Failed to wrap object";
275 }
276
277 void InspectorHeapProfilerAgent::getHeapObjectId(ErrorString* errorString, const String& objectId, String* heapSnapshotObjectId)
278 {
279     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
280     if (injectedScript.hasNoValue()) {
281         *errorString = "Inspected context has gone";
282         return;
283     }
284     ScriptValue value = injectedScript.findObjectById(objectId);
285     ScriptScope scope(injectedScript.scriptState());
286     if (value.hasNoValue() || value.isUndefined()) {
287         *errorString = "Object with given id not found";
288         return;
289     }
290     unsigned id = ScriptProfiler::getHeapObjectId(value);
291     *heapSnapshotObjectId = String::number(id);
292 }
293
294 } // namespace WebCore
295