2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "InspectorProfilerAgent.h"
33 #if ENABLE(JAVASCRIPT_DEBUGGER)
36 #include "InspectorController.h"
37 #include "InspectorFrontend.h"
38 #include "InspectorValues.h"
41 #include "ScriptDebugServer.h"
42 #include "ScriptHeapSnapshot.h"
43 #include "ScriptProfile.h"
44 #include "ScriptProfiler.h"
45 #include <wtf/OwnPtr.h>
46 #include <wtf/text/StringConcatenate.h>
49 #include "JSDOMWindow.h"
54 static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
55 static const char* const CPUProfileType = "CPU";
56 static const char* const HeapProfileType = "HEAP";
58 PassOwnPtr<InspectorProfilerAgent> InspectorProfilerAgent::create(InspectorController* inspectorController)
60 OwnPtr<InspectorProfilerAgent> agent = adoptPtr(new InspectorProfilerAgent(inspectorController));
61 return agent.release();
64 InspectorProfilerAgent::InspectorProfilerAgent(InspectorController* inspectorController)
65 : m_inspectorController(inspectorController)
67 , m_enabled(ScriptProfiler::isProfilerAlwaysEnabled())
68 , m_recordingUserInitiatedProfile(false)
69 , m_currentUserInitiatedProfileNumber(-1)
70 , m_nextUserInitiatedProfileNumber(1)
71 , m_nextUserInitiatedHeapSnapshotNumber(1)
75 InspectorProfilerAgent::~InspectorProfilerAgent()
79 void InspectorProfilerAgent::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
81 RefPtr<ScriptProfile> profile = prpProfile;
82 m_profiles.add(profile->uid(), profile);
84 m_frontend->addProfileHeader(createProfileHeader(*profile));
85 addProfileFinishedMessageToConsole(profile, lineNumber, sourceURL);
88 void InspectorProfilerAgent::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL)
90 RefPtr<ScriptProfile> profile = prpProfile;
91 String title = profile->title();
92 String message = makeString("Profile \"webkit-profile://", CPUProfileType, '/', encodeWithURLEscapeSequences(title), '#', String::number(profile->uid()), "\" finished.");
93 m_inspectorController->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
96 void InspectorProfilerAgent::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL)
98 String message = makeString("Profile \"webkit-profile://", CPUProfileType, '/', encodeWithURLEscapeSequences(title), "#0\" started.");
99 m_inspectorController->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL);
102 PassRefPtr<InspectorObject> InspectorProfilerAgent::createProfileHeader(const ScriptProfile& profile)
104 RefPtr<InspectorObject> header = InspectorObject::create();
105 header->setString("title", profile.title());
106 header->setNumber("uid", profile.uid());
107 header->setString("typeId", String(CPUProfileType));
111 PassRefPtr<InspectorObject> InspectorProfilerAgent::createSnapshotHeader(const ScriptHeapSnapshot& snapshot)
113 RefPtr<InspectorObject> header = InspectorObject::create();
114 header->setString("title", snapshot.title());
115 header->setNumber("uid", snapshot.uid());
116 header->setString("typeId", String(HeapProfileType));
120 void InspectorProfilerAgent::disable()
125 ScriptDebugServer::shared().recompileAllJSFunctionsSoon();
127 m_frontend->profilerWasDisabled();
130 void InspectorProfilerAgent::enable(bool skipRecompile)
136 ScriptDebugServer::shared().recompileAllJSFunctionsSoon();
138 m_frontend->profilerWasEnabled();
141 String InspectorProfilerAgent::getCurrentUserInitiatedProfileName(bool incrementProfileNumber)
143 if (incrementProfileNumber)
144 m_currentUserInitiatedProfileNumber = m_nextUserInitiatedProfileNumber++;
146 return makeString(UserInitiatedProfileName, '.', String::number(m_currentUserInitiatedProfileNumber));
149 void InspectorProfilerAgent::getProfileHeaders(RefPtr<InspectorArray>* headers)
151 ProfilesMap::iterator profilesEnd = m_profiles.end();
152 for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it)
153 (*headers)->pushObject(createProfileHeader(*it->second));
154 HeapSnapshotsMap::iterator snapshotsEnd = m_snapshots.end();
155 for (HeapSnapshotsMap::iterator it = m_snapshots.begin(); it != snapshotsEnd; ++it)
156 (*headers)->pushObject(createSnapshotHeader(*it->second));
159 void InspectorProfilerAgent::getProfile(const String& type, unsigned uid, RefPtr<InspectorObject>* profileObject)
161 if (type == CPUProfileType) {
162 ProfilesMap::iterator it = m_profiles.find(uid);
163 if (it != m_profiles.end()) {
164 *profileObject = createProfileHeader(*it->second);
165 (*profileObject)->setObject("head", it->second->buildInspectorObjectForHead());
167 } else if (type == HeapProfileType) {
168 HeapSnapshotsMap::iterator it = m_snapshots.find(uid);
169 if (it != m_snapshots.end()) {
170 *profileObject = createSnapshotHeader(*it->second);
171 (*profileObject)->setObject("head", it->second->buildInspectorObjectForHead());
176 void InspectorProfilerAgent::removeProfile(const String& type, unsigned uid)
178 if (type == CPUProfileType) {
179 if (m_profiles.contains(uid))
180 m_profiles.remove(uid);
181 } else if (type == HeapProfileType) {
182 if (m_snapshots.contains(uid))
183 m_snapshots.remove(uid);
187 void InspectorProfilerAgent::resetState()
191 m_currentUserInitiatedProfileNumber = 1;
192 m_nextUserInitiatedProfileNumber = 1;
193 m_nextUserInitiatedHeapSnapshotNumber = 1;
195 m_frontend->resetProfilesPanel();
198 void InspectorProfilerAgent::startUserInitiatedProfiling()
200 if (m_recordingUserInitiatedProfile)
204 ScriptDebugServer::shared().recompileAllJSFunctions();
206 m_recordingUserInitiatedProfile = true;
207 String title = getCurrentUserInitiatedProfileName(true);
209 JSC::ExecState* scriptState = toJSDOMWindow(m_inspectorController->inspectedPage()->mainFrame(), debuggerWorld())->globalExec();
211 ScriptState* scriptState = 0;
213 ScriptProfiler::start(scriptState, title);
214 addStartProfilingMessageToConsole(title, 0, String());
215 toggleRecordButton(true);
218 void InspectorProfilerAgent::stopUserInitiatedProfiling(bool ignoreProfile)
220 if (!m_recordingUserInitiatedProfile)
222 m_recordingUserInitiatedProfile = false;
223 String title = getCurrentUserInitiatedProfileName();
225 JSC::ExecState* scriptState = toJSDOMWindow(m_inspectorController->inspectedPage()->mainFrame(), debuggerWorld())->globalExec();
227 // Use null script state to avoid filtering by context security token.
228 // All functions from all iframes should be visible from Inspector UI.
229 ScriptState* scriptState = 0;
231 RefPtr<ScriptProfile> profile = ScriptProfiler::stop(scriptState, title);
234 addProfile(profile, 0, String());
236 addProfileFinishedMessageToConsole(profile, 0, String());
238 toggleRecordButton(false);
241 void InspectorProfilerAgent::takeHeapSnapshot()
243 String title = makeString(UserInitiatedProfileName, '.', String::number(m_nextUserInitiatedHeapSnapshotNumber));
244 ++m_nextUserInitiatedHeapSnapshotNumber;
246 RefPtr<ScriptHeapSnapshot> snapshot = ScriptProfiler::takeHeapSnapshot(title);
248 m_snapshots.add(snapshot->uid(), snapshot);
250 m_frontend->addProfileHeader(createSnapshotHeader(*snapshot));
254 void InspectorProfilerAgent::toggleRecordButton(bool isProfiling)
257 m_frontend->setRecordingProfile(isProfiling);
260 } // namespace WebCore
262 #endif // ENABLE(JAVASCRIPT_DEBUGGER)