Run clang-modernize and let it add a bunch of missing overrides in WebCore/inspector
[WebKit-https.git] / Source / WebCore / inspector / InspectorProfilerAgent.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31
32 #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)
33
34 #include "InspectorProfilerAgent.h"
35
36 #include "CommandLineAPIHost.h"
37 #include "Console.h"
38 #include "ConsoleAPITypes.h"
39 #include "ConsoleTypes.h"
40 #include "InspectorConsoleAgent.h"
41 #include "InspectorWebFrontendDispatchers.h"
42 #include "InstrumentingAgents.h"
43 #include "URL.h"
44 #include "Page.h"
45 #include "PageInjectedScriptManager.h"
46 #include "PageScriptDebugServer.h"
47 #include "ScriptHeapSnapshot.h"
48 #include "ScriptProfile.h"
49 #include "ScriptProfiler.h"
50 #include "WorkerScriptDebugServer.h"
51 #include <bindings/ScriptObject.h>
52 #include <inspector/InjectedScript.h>
53 #include <inspector/InspectorValues.h>
54 #include <wtf/CurrentTime.h>
55 #include <wtf/OwnPtr.h>
56 #include <wtf/text/StringConcatenate.h>
57
58 using namespace Inspector;
59
60 namespace WebCore {
61
62 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
63 static const char* const CPUProfileType = "CPU";
64 static const char* const HeapProfileType = "HEAP";
65
66
67 class PageProfilerAgent : public InspectorProfilerAgent {
68 public:
69     PageProfilerAgent(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, Page* inspectedPage, PageInjectedScriptManager* injectedScriptManager)
70         : InspectorProfilerAgent(instrumentingAgents, consoleAgent, injectedScriptManager), m_inspectedPage(inspectedPage) { }
71     virtual ~PageProfilerAgent() { }
72
73 private:
74     virtual void recompileScript() override
75     {
76         PageScriptDebugServer::shared().recompileAllJSFunctionsSoon();
77     }
78
79     virtual void startProfiling(const String& title) override
80     {
81         ScriptProfiler::startForPage(m_inspectedPage, title);
82     }
83
84     virtual PassRefPtr<ScriptProfile> stopProfiling(const String& title) override
85     {
86         return ScriptProfiler::stopForPage(m_inspectedPage, title);
87     }
88
89     Page* m_inspectedPage;
90 };
91
92 std::unique_ptr<InspectorProfilerAgent> InspectorProfilerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, Page* inspectedPage, PageInjectedScriptManager* injectedScriptManager)
93 {
94     return std::make_unique<PageProfilerAgent>(instrumentingAgents, consoleAgent, inspectedPage, injectedScriptManager);
95 }
96
97 class WorkerProfilerAgent : public InspectorProfilerAgent {
98 public:
99     WorkerProfilerAgent(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, WorkerGlobalScope* workerGlobalScope, PageInjectedScriptManager* injectedScriptManager)
100         : InspectorProfilerAgent(instrumentingAgents, consoleAgent, injectedScriptManager), m_workerGlobalScope(workerGlobalScope) { }
101     virtual ~WorkerProfilerAgent() { }
102
103 private:
104     virtual void recompileScript() override { }
105
106     virtual void startProfiling(const String& title) override
107     {
108         ScriptProfiler::startForWorkerGlobalScope(m_workerGlobalScope, title);
109     }
110
111     virtual PassRefPtr<ScriptProfile> stopProfiling(const String& title) override
112     {
113         return ScriptProfiler::stopForWorkerGlobalScope(m_workerGlobalScope, title);
114     }
115
116     WorkerGlobalScope* m_workerGlobalScope;
117 };
118
119 std::unique_ptr<InspectorProfilerAgent> InspectorProfilerAgent::create(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, WorkerGlobalScope* workerGlobalScope, PageInjectedScriptManager* injectedScriptManager)
120 {
121     return std::make_unique<WorkerProfilerAgent>(instrumentingAgents, consoleAgent, workerGlobalScope, injectedScriptManager);
122 }
123
124 InspectorProfilerAgent::InspectorProfilerAgent(InstrumentingAgents* instrumentingAgents, InspectorConsoleAgent* consoleAgent, PageInjectedScriptManager* injectedScriptManager)
125     : InspectorAgentBase(ASCIILiteral("Profiler"), instrumentingAgents)
126     , m_consoleAgent(consoleAgent)
127     , m_injectedScriptManager(injectedScriptManager)
128     , m_enabled(false)
129     , m_profileHeadersRequested(false)
130     , m_recordingCPUProfile(false)
131     , m_currentUserInitiatedProfileNumber(-1)
132     , m_nextUserInitiatedProfileNumber(1)
133     , m_nextUserInitiatedHeapSnapshotNumber(1)
134     , m_profileNameIdleTimeMap(ScriptProfiler::currentProfileNameIdleTimeMap())
135 {
136     m_instrumentingAgents->setInspectorProfilerAgent(this);
137 }
138
139 InspectorProfilerAgent::~InspectorProfilerAgent()
140 {
141     m_instrumentingAgents->setInspectorProfilerAgent(0);
142 }
143
144 void InspectorProfilerAgent::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, unsigned columnNumber, const String& sourceURL)
145 {
146     RefPtr<ScriptProfile> profile = prpProfile;
147     m_profiles.add(profile->uid(), profile);
148     if (m_frontendDispatcher && m_profileHeadersRequested)
149         m_frontendDispatcher->addProfileHeader(createProfileHeader(*profile));
150     addProfileFinishedMessageToConsole(profile, lineNumber, columnNumber, sourceURL);
151 }
152
153 void InspectorProfilerAgent::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, unsigned columnNumber, const String& sourceURL)
154 {
155     if (!m_frontendDispatcher)
156         return;
157     RefPtr<ScriptProfile> profile = prpProfile;
158     String message = makeString(profile->title(), '#', String::number(profile->uid()));
159     m_consoleAgent->addMessageToConsole(ConsoleAPIMessageSource, ProfileEndMessageType, DebugMessageLevel, message, sourceURL, lineNumber, columnNumber);
160 }
161
162 void InspectorProfilerAgent::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, unsigned columnNumber, const String& sourceURL)
163 {
164     if (!m_frontendDispatcher)
165         return;
166     m_consoleAgent->addMessageToConsole(ConsoleAPIMessageSource, ProfileMessageType, DebugMessageLevel, title, sourceURL, lineNumber, columnNumber);
167 }
168
169 void InspectorProfilerAgent::collectGarbage(WebCore::ErrorString*)
170 {
171     ScriptProfiler::collectGarbage();
172 }
173
174 PassRefPtr<Inspector::TypeBuilder::Profiler::ProfileHeader> InspectorProfilerAgent::createProfileHeader(const ScriptProfile& profile)
175 {
176     return Inspector::TypeBuilder::Profiler::ProfileHeader::create()
177         .setTypeId(Inspector::TypeBuilder::Profiler::ProfileHeader::TypeId::CPU)
178         .setUid(profile.uid())
179         .setTitle(profile.title())
180         .release();
181 }
182
183 PassRefPtr<Inspector::TypeBuilder::Profiler::ProfileHeader> InspectorProfilerAgent::createSnapshotHeader(const ScriptHeapSnapshot& snapshot)
184 {
185     RefPtr<Inspector::TypeBuilder::Profiler::ProfileHeader> header = Inspector::TypeBuilder::Profiler::ProfileHeader::create()
186         .setTypeId(Inspector::TypeBuilder::Profiler::ProfileHeader::TypeId::HEAP)
187         .setUid(snapshot.uid())
188         .setTitle(snapshot.title());
189     header->setMaxJSObjectId(snapshot.maxSnapshotJSObjectId());
190     return header.release();
191 }
192
193 void InspectorProfilerAgent::isSampling(ErrorString*, bool* result)
194 {
195     *result = ScriptProfiler::isSampling();
196 }
197
198 void InspectorProfilerAgent::hasHeapProfiler(ErrorString*, bool* result)
199 {
200     *result = ScriptProfiler::hasHeapProfiler();
201 }
202
203 void InspectorProfilerAgent::enable(ErrorString*)
204 {
205     if (enabled())
206         return;
207     enable(false);
208 }
209
210 void InspectorProfilerAgent::disable(ErrorString*)
211 {
212     disable();
213 }
214
215 void InspectorProfilerAgent::disable()
216 {
217     if (!m_enabled)
218         return;
219     m_enabled = false;
220     m_profileHeadersRequested = false;
221     recompileScript();
222 }
223
224 void InspectorProfilerAgent::enable(bool skipRecompile)
225 {
226     if (m_enabled)
227         return;
228     m_enabled = true;
229     if (!skipRecompile)
230         recompileScript();
231 }
232
233 String InspectorProfilerAgent::getCurrentUserInitiatedProfileName(bool incrementProfileNumber)
234 {
235     if (incrementProfileNumber)
236         m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
237
238     return makeString(UserInitiatedProfileName, '.', String::number(m_currentUserInitiatedProfileNumber));
239 }
240
241 void InspectorProfilerAgent::getProfileHeaders(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Profiler::ProfileHeader>>& headers)
242 {
243     m_profileHeadersRequested = true;
244     headers = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Profiler::ProfileHeader>::create();
245
246     ProfilesMap::iterator profilesEnd = m_profiles.end();
247     for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it)
248         headers->addItem(createProfileHeader(*it->value));
249     HeapSnapshotsMap::iterator snapshotsEnd = m_snapshots.end();
250     for (HeapSnapshotsMap::iterator it = m_snapshots.begin(); it != snapshotsEnd; ++it)
251         headers->addItem(createSnapshotHeader(*it->value));
252 }
253
254 namespace {
255
256 class OutputStream : public ScriptHeapSnapshot::OutputStream {
257 public:
258     OutputStream(InspectorProfilerFrontendDispatcher* frontend, unsigned uid)
259         : m_frontendDispatcher(frontend), m_uid(uid) { }
260     void Write(const String& chunk) override { m_frontendDispatcher->addHeapSnapshotChunk(m_uid, chunk); }
261     void Close() override { m_frontendDispatcher->finishHeapSnapshot(m_uid); }
262 private:
263     InspectorProfilerFrontendDispatcher* m_frontendDispatcher;
264     int m_uid;
265 };
266
267 } // namespace
268
269 void InspectorProfilerAgent::getCPUProfile(ErrorString* errorString, int rawUid, RefPtr<Inspector::TypeBuilder::Profiler::CPUProfile>& profileObject)
270 {
271     unsigned uid = static_cast<unsigned>(rawUid);
272     ProfilesMap::iterator it = m_profiles.find(uid);
273     if (it == m_profiles.end()) {
274         *errorString = "Profile wasn't found";
275         return;
276     }
277     profileObject = Inspector::TypeBuilder::Profiler::CPUProfile::create();
278     profileObject->setHead(it->value->buildInspectorObjectForHead());
279     profileObject->setIdleTime(it->value->idleTime());
280 }
281
282 void InspectorProfilerAgent::getHeapSnapshot(ErrorString* errorString, int rawUid)
283 {
284     unsigned uid = static_cast<unsigned>(rawUid);
285     HeapSnapshotsMap::iterator it = m_snapshots.find(uid);
286     if (it == m_snapshots.end()) {
287         *errorString = "Profile wasn't found";
288         return;
289     }
290     RefPtr<ScriptHeapSnapshot> snapshot = it->value;
291     if (m_frontendDispatcher) {
292         OutputStream stream(m_frontendDispatcher.get(), uid);
293         snapshot->writeJSON(&stream);
294     }
295 }
296
297 void InspectorProfilerAgent::removeProfile(ErrorString*, const String& type, int rawUid)
298 {
299     unsigned uid = static_cast<unsigned>(rawUid);
300     if (type == CPUProfileType)
301         m_profiles.remove(uid);
302     else if (type == HeapProfileType)
303         m_snapshots.remove(uid);
304 }
305
306 void InspectorProfilerAgent::resetState()
307 {
308     stop();
309     m_profiles.clear();
310     m_snapshots.clear();
311     m_currentUserInitiatedProfileNumber = 1;
312     m_nextUserInitiatedProfileNumber = 1;
313     m_nextUserInitiatedHeapSnapshotNumber = 1;
314     resetFrontendProfiles();
315
316     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
317         commandLineAPIHost->clearInspectedObjects();
318 }
319
320 void InspectorProfilerAgent::resetFrontendProfiles()
321 {
322     if (!m_frontendDispatcher)
323         return;
324     if (!m_profileHeadersRequested)
325         return;
326     if (m_profiles.isEmpty() && m_snapshots.isEmpty())
327         m_frontendDispatcher->resetProfiles();
328 }
329
330 void InspectorProfilerAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
331 {
332     m_frontendDispatcher = std::make_unique<InspectorProfilerFrontendDispatcher>(frontendChannel);
333     m_backendDispatcher = InspectorProfilerBackendDispatcher::create(backendDispatcher, this);
334 }
335
336 void InspectorProfilerAgent::willDestroyFrontendAndBackend()
337 {
338     m_frontendDispatcher = nullptr;
339     m_backendDispatcher.clear();
340
341     stop();
342     ErrorString error;
343     disable(&error);
344 }
345
346 void InspectorProfilerAgent::start(ErrorString*)
347 {
348     if (m_recordingCPUProfile)
349         return;
350     if (!enabled()) {
351         enable(true);
352         PageScriptDebugServer::shared().recompileAllJSFunctions();
353     }
354     m_recordingCPUProfile = true;
355     String title = getCurrentUserInitiatedProfileName(true);
356     startProfiling(title);
357     addStartProfilingMessageToConsole(title, 0, 0, String());
358     toggleRecordButton(true);
359 }
360
361 void InspectorProfilerAgent::stop(ErrorString*)
362 {
363     if (!m_recordingCPUProfile)
364         return;
365     m_recordingCPUProfile = false;
366     String title = getCurrentUserInitiatedProfileName();
367     RefPtr<ScriptProfile> profile = stopProfiling(title);
368     if (profile)
369         addProfile(profile, 0, 0, String());
370     toggleRecordButton(false);
371 }
372
373 namespace {
374
375 class HeapSnapshotProgress: public ScriptProfiler::HeapSnapshotProgress {
376 public:
377     explicit HeapSnapshotProgress(InspectorProfilerFrontendDispatcher* frontend)
378         : m_frontendDispatcher(frontend) { }
379     void Start(int totalWork) override
380     {
381         m_totalWork = totalWork;
382     }
383     void Worked(int workDone) override
384     {
385         if (m_frontendDispatcher)
386             m_frontendDispatcher->reportHeapSnapshotProgress(workDone, m_totalWork);
387     }
388     void Done() override { }
389     bool isCanceled() { return false; }
390 private:
391     InspectorProfilerFrontendDispatcher* m_frontendDispatcher;
392     int m_totalWork;
393 };
394
395 };
396
397 void InspectorProfilerAgent::takeHeapSnapshot(ErrorString*, const bool* reportProgress)
398 {
399     String title = makeString(UserInitiatedProfileName, '.', String::number(m_nextUserInitiatedHeapSnapshotNumber));
400     ++m_nextUserInitiatedHeapSnapshotNumber;
401
402     HeapSnapshotProgress progress(reportProgress && *reportProgress ? m_frontendDispatcher.get() : nullptr);
403     RefPtr<ScriptHeapSnapshot> snapshot = ScriptProfiler::takeHeapSnapshot(title, &progress);
404     if (snapshot) {
405         m_snapshots.add(snapshot->uid(), snapshot);
406         if (m_frontendDispatcher)
407             m_frontendDispatcher->addProfileHeader(createSnapshotHeader(*snapshot));
408     }
409 }
410
411 void InspectorProfilerAgent::toggleRecordButton(bool isProfiling)
412 {
413     if (m_frontendDispatcher)
414         m_frontendDispatcher->setRecordingProfile(isProfiling);
415 }
416
417 void InspectorProfilerAgent::getObjectByHeapObjectId(ErrorString* error, const String& heapSnapshotObjectId, const String* objectGroup, RefPtr<Inspector::TypeBuilder::Runtime::RemoteObject>& result)
418 {
419     bool ok;
420     unsigned id = heapSnapshotObjectId.toUInt(&ok);
421     if (!ok) {
422         *error = "Invalid heap snapshot object id";
423         return;
424     }
425     Deprecated::ScriptObject heapObject = ScriptProfiler::objectByHeapObjectId(id);
426     if (heapObject.hasNoValue()) {
427         *error = "Object is not available";
428         return;
429     }
430     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(heapObject.scriptState());
431     if (injectedScript.hasNoValue()) {
432         *error = "Object is not available. Inspected context is gone";
433         return;
434     }
435     result = injectedScript.wrapObject(heapObject, objectGroup ? *objectGroup : "");
436     if (!result)
437         *error = "Failed to wrap object";
438 }
439
440 void InspectorProfilerAgent::getHeapObjectId(ErrorString* errorString, const String& objectId, String* heapSnapshotObjectId)
441 {
442     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
443     if (injectedScript.hasNoValue()) {
444         *errorString = "Inspected context has gone";
445         return;
446     }
447     Deprecated::ScriptValue value = injectedScript.findObjectById(objectId);
448     if (value.hasNoValue() || value.isUndefined()) {
449         *errorString = "Object with given id not found";
450         return;
451     }
452     unsigned id = ScriptProfiler::getHeapObjectId(value);
453     *heapSnapshotObjectId = String::number(id);
454 }
455
456 } // namespace WebCore
457
458 #endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR)