Remove ENABLE(JAVASCRIPT_DEBUGGER) guards
[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(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().recompileAllJSFunctions();
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(nullptr);
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     enable(false);
206 }
207
208 void InspectorProfilerAgent::disable(ErrorString*)
209 {
210     disable(false);
211 }
212
213 void InspectorProfilerAgent::disable(bool skipRecompile)
214 {
215     if (!m_enabled)
216         return;
217     m_enabled = false;
218     m_profileHeadersRequested = false;
219     if (!skipRecompile)
220         recompileScript();
221 }
222
223 void InspectorProfilerAgent::enable(bool skipRecompile)
224 {
225     if (m_enabled)
226         return;
227     m_enabled = true;
228     if (!skipRecompile)
229         recompileScript();
230 }
231
232 String InspectorProfilerAgent::getCurrentUserInitiatedProfileName(bool incrementProfileNumber)
233 {
234     if (incrementProfileNumber)
235         m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
236
237     return makeString(UserInitiatedProfileName, '.', String::number(m_currentUserInitiatedProfileNumber));
238 }
239
240 void InspectorProfilerAgent::getProfileHeaders(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Profiler::ProfileHeader>>& headers)
241 {
242     m_profileHeadersRequested = true;
243     headers = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Profiler::ProfileHeader>::create();
244
245     ProfilesMap::iterator profilesEnd = m_profiles.end();
246     for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it)
247         headers->addItem(createProfileHeader(*it->value));
248     HeapSnapshotsMap::iterator snapshotsEnd = m_snapshots.end();
249     for (HeapSnapshotsMap::iterator it = m_snapshots.begin(); it != snapshotsEnd; ++it)
250         headers->addItem(createSnapshotHeader(*it->value));
251 }
252
253 namespace {
254
255 class OutputStream : public ScriptHeapSnapshot::OutputStream {
256 public:
257     OutputStream(InspectorProfilerFrontendDispatcher* frontend, unsigned uid)
258         : m_frontendDispatcher(frontend), m_uid(uid) { }
259     void Write(const String& chunk) override { m_frontendDispatcher->addHeapSnapshotChunk(m_uid, chunk); }
260     void Close() override { m_frontendDispatcher->finishHeapSnapshot(m_uid); }
261 private:
262     InspectorProfilerFrontendDispatcher* m_frontendDispatcher;
263     int m_uid;
264 };
265
266 } // namespace
267
268 void InspectorProfilerAgent::getCPUProfile(ErrorString* errorString, int rawUid, RefPtr<Inspector::TypeBuilder::Profiler::CPUProfile>& profileObject)
269 {
270     unsigned uid = static_cast<unsigned>(rawUid);
271     ProfilesMap::iterator it = m_profiles.find(uid);
272     if (it == m_profiles.end()) {
273         *errorString = "Profile wasn't found";
274         return;
275     }
276     profileObject = Inspector::TypeBuilder::Profiler::CPUProfile::create();
277     profileObject->setHead(it->value->buildInspectorObjectForHead());
278     profileObject->setIdleTime(it->value->idleTime());
279 }
280
281 void InspectorProfilerAgent::getHeapSnapshot(ErrorString* errorString, int rawUid)
282 {
283     unsigned uid = static_cast<unsigned>(rawUid);
284     HeapSnapshotsMap::iterator it = m_snapshots.find(uid);
285     if (it == m_snapshots.end()) {
286         *errorString = "Profile wasn't found";
287         return;
288     }
289     RefPtr<ScriptHeapSnapshot> snapshot = it->value;
290     if (m_frontendDispatcher) {
291         OutputStream stream(m_frontendDispatcher.get(), uid);
292         snapshot->writeJSON(&stream);
293     }
294 }
295
296 void InspectorProfilerAgent::removeProfile(ErrorString*, const String& type, int rawUid)
297 {
298     unsigned uid = static_cast<unsigned>(rawUid);
299     if (type == CPUProfileType)
300         m_profiles.remove(uid);
301     else if (type == HeapProfileType)
302         m_snapshots.remove(uid);
303 }
304
305 void InspectorProfilerAgent::resetState()
306 {
307     stop();
308     m_profiles.clear();
309     m_snapshots.clear();
310     m_currentUserInitiatedProfileNumber = 1;
311     m_nextUserInitiatedProfileNumber = 1;
312     m_nextUserInitiatedHeapSnapshotNumber = 1;
313     resetFrontendProfiles();
314
315     if (CommandLineAPIHost* commandLineAPIHost = m_injectedScriptManager->commandLineAPIHost())
316         commandLineAPIHost->clearInspectedObjects();
317 }
318
319 void InspectorProfilerAgent::resetFrontendProfiles()
320 {
321     if (!m_frontendDispatcher)
322         return;
323     if (!m_profileHeadersRequested)
324         return;
325     if (m_profiles.isEmpty() && m_snapshots.isEmpty())
326         m_frontendDispatcher->resetProfiles();
327 }
328
329 void InspectorProfilerAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
330 {
331     m_frontendDispatcher = std::make_unique<InspectorProfilerFrontendDispatcher>(frontendChannel);
332     m_backendDispatcher = InspectorProfilerBackendDispatcher::create(backendDispatcher, this);
333 }
334
335 void InspectorProfilerAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason reason)
336 {
337     m_frontendDispatcher = nullptr;
338     m_backendDispatcher.clear();
339
340     stop();
341
342     bool skipRecompile = reason == InspectorDisconnectReason::InspectedTargetDestroyed;
343     disable(skipRecompile);
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(INSPECTOR)