]> git.saurik.com Git - apple/javascriptcore.git/blob - inspector/agents/InspectorProfilerAgent.cpp
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / inspector / agents / 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 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 #include "InspectorProfilerAgent.h"
32
33 #if ENABLE(INSPECTOR)
34
35 #include "InspectorValues.h"
36 #include "LegacyProfiler.h"
37 #include "Profile.h"
38 #include "ScriptDebugServer.h"
39 #include "ScriptObject.h"
40 #include <wtf/CurrentTime.h>
41 #include <wtf/text/StringConcatenate.h>
42
43 namespace Inspector {
44
45 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
46 static const char* const CPUProfileType = "CPU";
47
48 InspectorProfilerAgent::InspectorProfilerAgent()
49 : InspectorAgentBase(ASCIILiteral("Profiler"))
50 , m_scriptDebugServer(nullptr)
51 , m_enabled(false)
52 , m_profileHeadersRequested(false)
53 , m_recordingProfileCount(0)
54 , m_nextUserInitiatedProfileNumber(1)
55 {
56 }
57
58 InspectorProfilerAgent::~InspectorProfilerAgent()
59 {
60 }
61
62 void InspectorProfilerAgent::didCreateFrontendAndBackend(InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
63 {
64 m_frontendDispatcher = std::make_unique<InspectorProfilerFrontendDispatcher>(frontendChannel);
65 m_backendDispatcher = InspectorProfilerBackendDispatcher::create(backendDispatcher, this);
66 }
67
68 void InspectorProfilerAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason reason)
69 {
70 m_frontendDispatcher = nullptr;
71 m_backendDispatcher.clear();
72
73 reset();
74
75 disable(reason == InspectorDisconnectReason::InspectedTargetDestroyed ? SkipRecompile : Recompile);
76 }
77
78 void InspectorProfilerAgent::addProfile(PassRefPtr<JSC::Profile> prpProfile)
79 {
80 RefPtr<JSC::Profile> profile = prpProfile;
81 m_profiles.add(profile->uid(), profile);
82
83 if (m_frontendDispatcher && m_profileHeadersRequested)
84 m_frontendDispatcher->addProfileHeader(createProfileHeader(*profile));
85 }
86
87 PassRefPtr<TypeBuilder::Profiler::ProfileHeader> InspectorProfilerAgent::createProfileHeader(const JSC::Profile& profile)
88 {
89 return TypeBuilder::Profiler::ProfileHeader::create()
90 .setTypeId(TypeBuilder::Profiler::ProfileHeader::TypeId::CPU)
91 .setUid(profile.uid())
92 .setTitle(profile.title())
93 .release();
94 }
95
96 void InspectorProfilerAgent::enable(ErrorString*)
97 {
98 enable(Recompile);
99 }
100
101 void InspectorProfilerAgent::disable(ErrorString*)
102 {
103 disable(Recompile);
104 }
105
106 void InspectorProfilerAgent::enable(ShouldRecompile shouldRecompile)
107 {
108 if (m_enabled)
109 return;
110
111 m_enabled = true;
112
113 if (shouldRecompile == Recompile)
114 m_scriptDebugServer->recompileAllJSFunctions();
115 }
116
117 void InspectorProfilerAgent::disable(ShouldRecompile shouldRecompile)
118 {
119 if (!m_enabled)
120 return;
121
122 m_enabled = false;
123 m_profileHeadersRequested = false;
124
125 if (shouldRecompile == Recompile)
126 m_scriptDebugServer->recompileAllJSFunctions();
127 }
128
129 String InspectorProfilerAgent::getUserInitiatedProfileName()
130 {
131 return makeString(UserInitiatedProfileName, '.', String::number(m_nextUserInitiatedProfileNumber++));
132 }
133
134 void InspectorProfilerAgent::getProfileHeaders(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader>>& headers)
135 {
136 m_profileHeadersRequested = true;
137 headers = TypeBuilder::Array<TypeBuilder::Profiler::ProfileHeader>::create();
138
139 for (auto& profile : m_profiles.values())
140 headers->addItem(createProfileHeader(*profile.get()));
141 }
142
143 static PassRefPtr<TypeBuilder::Profiler::CPUProfileNodeCall> buildInspectorObject(const JSC::ProfileNode::Call& call)
144 {
145 RefPtr<TypeBuilder::Profiler::CPUProfileNodeCall> result = TypeBuilder::Profiler::CPUProfileNodeCall::create()
146 .setStartTime(call.startTime())
147 .setTotalTime(call.totalTime());
148 return result.release();
149 }
150
151 static PassRefPtr<TypeBuilder::Profiler::CPUProfileNode> buildInspectorObject(const JSC::ProfileNode* node)
152 {
153 RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNodeCall>> calls = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNodeCall>::create();
154 for (const JSC::ProfileNode::Call& call : node->calls())
155 calls->addItem(buildInspectorObject(call));
156
157 RefPtr<TypeBuilder::Profiler::CPUProfileNode> result = TypeBuilder::Profiler::CPUProfileNode::create()
158 .setId(node->id())
159 .setCalls(calls.release());
160
161 if (!node->functionName().isEmpty())
162 result->setFunctionName(node->functionName());
163
164 if (!node->url().isEmpty()) {
165 result->setUrl(node->url());
166 result->setLineNumber(node->lineNumber());
167 result->setColumnNumber(node->columnNumber());
168 }
169
170 if (!node->children().isEmpty()) {
171 RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>> children = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create();
172 for (RefPtr<JSC::ProfileNode> profileNode : node->children())
173 children->addItem(buildInspectorObject(profileNode.get()));
174 result->setChildren(children);
175 }
176
177 return result.release();
178 }
179
180 PassRefPtr<TypeBuilder::Profiler::CPUProfile> InspectorProfilerAgent::buildProfileInspectorObject(const JSC::Profile* profile)
181 {
182 RefPtr<TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>> rootNodes = TypeBuilder::Array<TypeBuilder::Profiler::CPUProfileNode>::create();
183 for (RefPtr<JSC::ProfileNode> profileNode : profile->head()->children())
184 rootNodes->addItem(buildInspectorObject(profileNode.get()));
185
186 RefPtr<TypeBuilder::Profiler::CPUProfile> result = TypeBuilder::Profiler::CPUProfile::create()
187 .setRootNodes(rootNodes);
188
189 if (profile->idleTime())
190 result->setIdleTime(profile->idleTime());
191
192 return result.release();
193 }
194
195 void InspectorProfilerAgent::getCPUProfile(ErrorString* errorString, int rawUid, RefPtr<TypeBuilder::Profiler::CPUProfile>& profileObject)
196 {
197 unsigned uid = static_cast<unsigned>(rawUid);
198 auto it = m_profiles.find(uid);
199 if (it == m_profiles.end()) {
200 *errorString = ASCIILiteral("Profile wasn't found");
201 return;
202 }
203
204 profileObject = buildProfileInspectorObject(it->value.get());
205 }
206
207 void InspectorProfilerAgent::removeProfile(ErrorString*, const String& type, int rawUid)
208 {
209 unsigned uid = static_cast<unsigned>(rawUid);
210 if (type == CPUProfileType)
211 m_profiles.remove(uid);
212 }
213
214 void InspectorProfilerAgent::reset()
215 {
216 stop();
217
218 m_profiles.clear();
219 m_nextUserInitiatedProfileNumber = 1;
220 m_profileHeadersRequested = false;
221
222 if (m_frontendDispatcher && m_profileHeadersRequested)
223 m_frontendDispatcher->resetProfiles();
224 }
225
226 void InspectorProfilerAgent::start(ErrorString*)
227 {
228 startProfiling();
229 }
230
231 void InspectorProfilerAgent::stop(ErrorString*)
232 {
233 stopProfiling();
234 }
235
236 void InspectorProfilerAgent::setRecordingProfile(bool isProfiling)
237 {
238 if (m_frontendDispatcher)
239 m_frontendDispatcher->setRecordingProfile(isProfiling);
240 }
241
242 String InspectorProfilerAgent::startProfiling(const String &title, JSC::ExecState* exec)
243 {
244 if (!enabled())
245 enable(Recompile);
246
247 bool wasNotRecording = !m_recordingProfileCount;
248 ++m_recordingProfileCount;
249
250 String resolvedTitle = title;
251 if (title.isEmpty())
252 resolvedTitle = getUserInitiatedProfileName();
253
254 if (!exec)
255 exec = profilingGlobalExecState();
256 ASSERT(exec);
257
258 JSC::LegacyProfiler::profiler()->startProfiling(exec, resolvedTitle);
259
260 if (wasNotRecording)
261 setRecordingProfile(true);
262
263 return resolvedTitle;
264 }
265
266 PassRefPtr<JSC::Profile> InspectorProfilerAgent::stopProfiling(const String& title, JSC::ExecState* exec)
267 {
268 if (!m_recordingProfileCount)
269 return nullptr;
270
271 --m_recordingProfileCount;
272
273 if (!exec)
274 exec = profilingGlobalExecState();
275 ASSERT(exec);
276
277 RefPtr<JSC::Profile> profile = JSC::LegacyProfiler::profiler()->stopProfiling(exec, title);
278 if (profile)
279 addProfile(profile);
280
281 if (!m_recordingProfileCount)
282 setRecordingProfile(false);
283
284 return profile.release();
285 }
286
287 } // namespace Inspector
288
289 #endif // ENABLE(INSPECTOR)