Changeset 195376 in webkit
- Timestamp:
- Jan 20, 2016 1:51:00 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 12 added
- 30 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r195374 r195376 1 2016-01-20 Saam barati <sbarati@apple.com> 2 3 Web Inspector: Hook the sampling profiler into the Timelines UI 4 https://bugs.webkit.org/show_bug.cgi?id=152766 5 <rdar://problem/24066360> 6 7 Reviewed by Joseph Pecoraro. 8 9 * inspector/sampling-profiler: Added. 10 * inspector/sampling-profiler/basic-expected.txt: Added. 11 * inspector/sampling-profiler/basic.html: Added. 12 * inspector/sampling-profiler/call-frame-with-dom-functions-expected.txt: Added. 13 * inspector/sampling-profiler/call-frame-with-dom-functions.html: Added. 14 * inspector/sampling-profiler/eval-source-url-expected.txt: Added. 15 * inspector/sampling-profiler/eval-source-url.html: Added. 16 * inspector/sampling-profiler/many-call-frames-expected.txt: Added. 17 * inspector/sampling-profiler/many-call-frames.html: Added. 18 * inspector/sampling-profiler/named-function-expression-expected.txt: Added. 19 * inspector/sampling-profiler/named-function-expression.html: Added. 20 * inspector/script-profiler/event-type-API-expected.txt: 21 * inspector/script-profiler/event-type-API.html: 22 * inspector/script-profiler/event-type-Microtask-expected.txt: 23 * inspector/script-profiler/event-type-Microtask.html: 24 * inspector/script-profiler/event-type-Other-expected.txt: 25 * inspector/script-profiler/event-type-Other.html: 26 * inspector/script-profiler/tracking-expected.txt: 27 * inspector/script-profiler/tracking.html: 28 1 29 2016-01-20 Daniel Bates <dabates@apple.com> 2 30 -
trunk/LayoutTests/inspector/script-profiler/event-type-API-expected.txt
r194242 r195376 9 9 PASS: Event type should be API. 10 10 ScriptProfiler.trackingComplete 11 PASS: Profiles should exist when complete.12 PASS: Should be 1 profile for this session.13 11 -
trunk/LayoutTests/inspector/script-profiler/event-type-API.html
r194242 r195376 28 28 InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => { 29 29 ProtocolTest.log("ScriptProfiler.trackingComplete"); 30 ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");31 ProtocolTest.expectThat(messageObject.params.profiles.length === 1, "Should be 1 profile for this session.");32 30 resolve(); 33 31 }); 34 32 35 InspectorProtocol.sendCommand("ScriptProfiler.startTracking", { profile: true});33 InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {}); 36 34 ProtocolTest.evaluateInPage("triggerAPIScript();"); // This ultimately uses the JSEvaluateScript API on the Page's context. 37 35 InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {}); -
trunk/LayoutTests/inspector/script-profiler/event-type-Microtask-expected.txt
r194242 r195376 9 9 PASS: Event type should be Microtask. 10 10 ScriptProfiler.trackingComplete 11 PASS: Profiles should exist when complete.12 PASS: Should be 1 profile for this session.13 11 -
trunk/LayoutTests/inspector/script-profiler/event-type-Microtask.html
r194242 r195376 29 29 InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => { 30 30 ProtocolTest.log("ScriptProfiler.trackingComplete"); 31 ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");32 ProtocolTest.expectThat(messageObject.params.profiles.length === 1, "Should be 1 profile for this session.");33 31 resolve(); 34 32 }); 35 33 36 InspectorProtocol.sendCommand("ScriptProfiler.startTracking", { profile: true});34 InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {}); 37 35 ProtocolTest.evaluateInPage("triggerMicrotask()"); 38 36 InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {}); -
trunk/LayoutTests/inspector/script-profiler/event-type-Other-expected.txt
r194871 r195376 15 15 PASS: Event type should be Other. 16 16 ScriptProfiler.trackingComplete 17 PASS: Profiles should exist when complete.18 PASS: Should be 3 profiles for this session.19 17 -
trunk/LayoutTests/inspector/script-profiler/event-type-Other.html
r195147 r195376 42 42 InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => { 43 43 ProtocolTest.log("ScriptProfiler.trackingComplete"); 44 ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");45 ProtocolTest.expectThat(messageObject.params.profiles.length === 3, "Should be 3 profiles for this session.");46 44 resolve(); 47 45 }); 48 46 49 InspectorProtocol.sendCommand("ScriptProfiler.startTracking", { profile: true});47 InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {}); 50 48 ProtocolTest.evaluateInPage("triggerScriptEvaluation()"); 51 49 ProtocolTest.evaluateInPage("triggerEventDispatchEvaluation()"); -
trunk/LayoutTests/inspector/script-profiler/tracking-expected.txt
r194242 r195376 7 7 PASS: Should have a timestamp when starting. 8 8 ScriptProfiler.trackingComplete 9 PASS: Profiles should exist when complete.10 PASS: Should be no profiles for this session.11 9 -
trunk/LayoutTests/inspector/script-profiler/tracking.html
r194242 r195376 19 19 InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => { 20 20 ProtocolTest.log("ScriptProfiler.trackingComplete"); 21 ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");22 ProtocolTest.expectThat(!messageObject.params.profiles.length, "Should be no profiles for this session.");23 21 resolve(); 24 22 }); 25 23 26 InspectorProtocol.sendCommand("ScriptProfiler.startTracking", { profile: true});24 InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {}); 27 25 InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {}); 28 26 } -
trunk/Source/JavaScriptCore/ChangeLog
r195375 r195376 1 2016-01-20 Saam barati <sbarati@apple.com> 2 3 Web Inspector: Hook the sampling profiler into the Timelines UI 4 https://bugs.webkit.org/show_bug.cgi?id=152766 5 <rdar://problem/24066360> 6 7 Reviewed by Joseph Pecoraro. 8 9 This patch adds some necessary functions to SamplingProfiler::StackFrame 10 to allow it to give data to the Inspector for the timelines UI. i.e, the 11 sourceID of the executable of a stack frame. 12 13 This patch also swaps in the SamplingProfiler in place of the 14 LegacyProfiler inside InspectorScriptProfilerAgent. It adds 15 the necessary protocol data to allow the SamplingProfiler's 16 data to hook into the timelines UI. 17 18 * debugger/Debugger.cpp: 19 (JSC::Debugger::setProfilingClient): 20 (JSC::Debugger::willEvaluateScript): 21 (JSC::Debugger::didEvaluateScript): 22 (JSC::Debugger::toggleBreakpoint): 23 * debugger/Debugger.h: 24 * debugger/ScriptProfilingScope.h: 25 (JSC::ScriptProfilingScope::ScriptProfilingScope): 26 (JSC::ScriptProfilingScope::~ScriptProfilingScope): 27 * inspector/agents/InspectorScriptProfilerAgent.cpp: 28 (Inspector::InspectorScriptProfilerAgent::willDestroyFrontendAndBackend): 29 (Inspector::InspectorScriptProfilerAgent::startTracking): 30 (Inspector::InspectorScriptProfilerAgent::stopTracking): 31 (Inspector::InspectorScriptProfilerAgent::isAlreadyProfiling): 32 (Inspector::InspectorScriptProfilerAgent::willEvaluateScript): 33 (Inspector::InspectorScriptProfilerAgent::didEvaluateScript): 34 (Inspector::InspectorScriptProfilerAgent::addEvent): 35 (Inspector::buildSamples): 36 (Inspector::InspectorScriptProfilerAgent::trackingComplete): 37 (Inspector::buildAggregateCallInfoInspectorObject): Deleted. 38 (Inspector::buildInspectorObject): Deleted. 39 (Inspector::buildProfileInspectorObject): Deleted. 40 * inspector/agents/InspectorScriptProfilerAgent.h: 41 * inspector/protocol/ScriptProfiler.json: 42 * jsc.cpp: 43 (functionSamplingProfilerStackTraces): 44 * runtime/SamplingProfiler.cpp: 45 (JSC::SamplingProfiler::start): 46 (JSC::SamplingProfiler::stop): 47 (JSC::SamplingProfiler::clearData): 48 (JSC::SamplingProfiler::StackFrame::displayName): 49 (JSC::SamplingProfiler::StackFrame::displayNameForJSONTests): 50 (JSC::SamplingProfiler::StackFrame::startLine): 51 (JSC::SamplingProfiler::StackFrame::startColumn): 52 (JSC::SamplingProfiler::StackFrame::sourceID): 53 (JSC::SamplingProfiler::StackFrame::url): 54 (JSC::SamplingProfiler::stackTraces): 55 (JSC::SamplingProfiler::stackTracesAsJSON): 56 (JSC::displayName): Deleted. 57 (JSC::SamplingProfiler::stacktracesAsJSON): Deleted. 58 * runtime/SamplingProfiler.h: 59 (JSC::SamplingProfiler::StackFrame::StackFrame): 60 (JSC::SamplingProfiler::getLock): 61 (JSC::SamplingProfiler::setTimingInterval): 62 (JSC::SamplingProfiler::totalTime): 63 (JSC::SamplingProfiler::setStopWatch): 64 (JSC::SamplingProfiler::stackTraces): Deleted. 65 * tests/stress/sampling-profiler-anonymous-function.js: 66 (platformSupportsSamplingProfiler.baz): 67 (platformSupportsSamplingProfiler): 68 * tests/stress/sampling-profiler-basic.js: 69 (platformSupportsSamplingProfiler.nothing): 70 (platformSupportsSamplingProfiler.top): 71 * tests/stress/sampling-profiler/samplingProfiler.js: 72 (doesTreeHaveStackTrace): 73 1 74 2016-01-20 Keith Miller <keith_miller@apple.com> 2 75 -
trunk/Source/JavaScriptCore/debugger/Debugger.cpp
r194704 r195376 235 235 } 236 236 237 double Debugger::willEvaluateScript( JSGlobalObject& globalObject)238 { 239 return m_profilingClient->willEvaluateScript( globalObject);240 } 241 242 void Debugger::didEvaluateScript( JSGlobalObject& globalObject,double startTime, ProfilingReason reason)243 { 244 m_profilingClient->didEvaluateScript( globalObject,startTime, reason);237 double Debugger::willEvaluateScript() 238 { 239 return m_profilingClient->willEvaluateScript(); 240 } 241 242 void Debugger::didEvaluateScript(double startTime, ProfilingReason reason) 243 { 244 m_profilingClient->didEvaluateScript(startTime, reason); 245 245 } 246 246 -
trunk/Source/JavaScriptCore/debugger/Debugger.h
r194242 r195376 133 133 virtual ~ProfilingClient() { } 134 134 virtual bool isAlreadyProfiling() const = 0; 135 virtual double willEvaluateScript( JSGlobalObject&) = 0;136 virtual void didEvaluateScript( JSGlobalObject&,double startTime, ProfilingReason) = 0;135 virtual double willEvaluateScript() = 0; 136 virtual void didEvaluateScript(double startTime, ProfilingReason) = 0; 137 137 }; 138 138 … … 140 140 bool hasProfilingClient() const { return m_profilingClient != nullptr; } 141 141 bool isAlreadyProfiling() const { return m_profilingClient && m_profilingClient->isAlreadyProfiling(); } 142 double willEvaluateScript( JSGlobalObject&);143 void didEvaluateScript( JSGlobalObject&,double startTime, ProfilingReason);142 double willEvaluateScript(); 143 void didEvaluateScript(double startTime, ProfilingReason); 144 144 145 145 protected: -
trunk/Source/JavaScriptCore/debugger/ScriptProfilingScope.h
r194242 r195376 40 40 { 41 41 if (shouldStartProfile()) 42 m_startTime = m_globalObject->debugger()->willEvaluateScript( *m_globalObject);42 m_startTime = m_globalObject->debugger()->willEvaluateScript(); 43 43 } 44 44 … … 46 46 { 47 47 if (shouldEndProfile()) 48 m_globalObject->debugger()->didEvaluateScript( *m_globalObject,m_startTime.value(), m_reason);48 m_globalObject->debugger()->didEvaluateScript(m_startTime.value(), m_reason); 49 49 } 50 50 -
trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.cpp
r194496 r195376 28 28 29 29 #include "InspectorEnvironment.h" 30 #include " LegacyProfiler.h"30 #include "SamplingProfiler.h" 31 31 #include <wtf/RunLoop.h> 32 32 #include <wtf/Stopwatch.h> … … 58 58 } 59 59 60 void InspectorScriptProfilerAgent::startTracking(ErrorString&, const bool* profile)60 void InspectorScriptProfilerAgent::startTracking(ErrorString&, const bool* includeSamples) 61 61 { 62 62 if (m_tracking) … … 65 65 m_tracking = true; 66 66 67 if (profile && *profile) 68 m_enableLegacyProfiler = true; 67 #if ENABLE(SAMPLING_PROFILER) 68 if (includeSamples && *includeSamples) { 69 VM& vm = m_environment.scriptDebugServer().vm(); 70 vm.ensureSamplingProfiler(m_environment.executionStopwatch()); 71 72 SamplingProfiler& samplingProfiler = *vm.samplingProfiler(); 73 LockHolder locker(samplingProfiler.getLock()); 74 75 samplingProfiler.setStopWatch(locker, m_environment.executionStopwatch()); 76 samplingProfiler.noticeCurrentThreadAsJSCExecutionThread(locker); 77 samplingProfiler.start(locker); 78 m_enabledSamplingProfiler = true; 79 } 80 #else 81 UNUSED_PARAM(includeSamples); 82 #endif // ENABLE(SAMPLING_PROFILER) 69 83 70 84 m_environment.scriptDebugServer().setProfilingClient(this); … … 79 93 80 94 m_tracking = false; 81 m_enableLegacyProfiler = false;82 95 m_activeEvaluateScript = false; 83 96 … … 92 105 } 93 106 94 double InspectorScriptProfilerAgent::willEvaluateScript( JSGlobalObject& globalObject)107 double InspectorScriptProfilerAgent::willEvaluateScript() 95 108 { 96 109 m_activeEvaluateScript = true; 97 110 98 if (m_enableLegacyProfiler) 99 LegacyProfiler::profiler()->startProfiling(globalObject.globalExec(), ASCIILiteral("ScriptProfiler"), m_environment.executionStopwatch()); 111 #if ENABLE(SAMPLING_PROFILER) 112 if (m_enabledSamplingProfiler) { 113 SamplingProfiler* samplingProfiler = m_environment.scriptDebugServer().vm().samplingProfiler(); 114 RELEASE_ASSERT(samplingProfiler); 115 samplingProfiler->noticeCurrentThreadAsJSCExecutionThread(); 116 } 117 #endif 100 118 101 119 return m_environment.executionStopwatch()->elapsedTime(); 102 120 } 103 121 104 void InspectorScriptProfilerAgent::didEvaluateScript( JSGlobalObject& globalObject,double startTime, ProfilingReason reason)122 void InspectorScriptProfilerAgent::didEvaluateScript(double startTime, ProfilingReason reason) 105 123 { 106 124 m_activeEvaluateScript = false; 107 108 if (m_enableLegacyProfiler)109 m_profiles.append(LegacyProfiler::profiler()->stopProfiling(globalObject.globalExec(), ASCIILiteral("ScriptProfiler")));110 125 111 126 double endTime = m_environment.executionStopwatch()->elapsedTime(); … … 142 157 } 143 158 144 static Ref<Protocol::Timeline::CPUProfileNodeAggregateCallInfo> buildAggregateCallInfoInspectorObject(const JSC::ProfileNode* node) 145 { 146 double startTime = node->calls()[0].startTime(); 147 double endTime = node->calls().last().startTime() + node->calls().last().elapsedTime(); 148 149 double totalTime = 0; 150 for (const JSC::ProfileNode::Call& call : node->calls()) 151 totalTime += call.elapsedTime(); 152 153 return Protocol::Timeline::CPUProfileNodeAggregateCallInfo::create() 154 .setCallCount(node->calls().size()) 155 .setStartTime(startTime) 156 .setEndTime(endTime) 159 #if ENABLE(SAMPLING_PROFILER) 160 static Ref<Protocol::ScriptProfiler::Samples> buildSamples(Vector<SamplingProfiler::StackTrace>& samplingProfilerStackTraces, double totalTime) 161 { 162 Ref<Protocol::Array<Protocol::ScriptProfiler::StackTrace>> stackTraces = Protocol::Array<Protocol::ScriptProfiler::StackTrace>::create(); 163 for (SamplingProfiler::StackTrace& stackTrace : samplingProfilerStackTraces) { 164 Ref<Protocol::Array<Protocol::ScriptProfiler::StackFrame>> frames = Protocol::Array<Protocol::ScriptProfiler::StackFrame>::create(); 165 for (SamplingProfiler::StackFrame& stackFrame : stackTrace.frames) { 166 Ref<Protocol::ScriptProfiler::StackFrame> frame = Protocol::ScriptProfiler::StackFrame::create() 167 .setSourceID(String::number(stackFrame.sourceID())) 168 .setName(stackFrame.displayName()) 169 .setLine(stackFrame.startLine()) 170 .setColumn(stackFrame.startColumn()) 171 .setUrl(stackFrame.url()) 172 .release(); 173 frames->addItem(WTFMove(frame)); 174 } 175 Ref<Protocol::ScriptProfiler::StackTrace> inspectorStackTrace = Protocol::ScriptProfiler::StackTrace::create() 176 .setTimestamp(stackTrace.timestamp) 177 .setStackFrames(WTFMove(frames)) 178 .release(); 179 stackTraces->addItem(WTFMove(inspectorStackTrace)); 180 } 181 182 return Protocol::ScriptProfiler::Samples::create() 183 .setStackTraces(WTFMove(stackTraces)) 157 184 .setTotalTime(totalTime) 158 185 .release(); 159 186 } 160 161 static Ref<Protocol::Timeline::CPUProfileNode> buildInspectorObject(const JSC::ProfileNode* node) 162 { 163 auto result = Protocol::Timeline::CPUProfileNode::create() 164 .setId(node->id()) 165 .setCallInfo(buildAggregateCallInfoInspectorObject(node)) 166 .release(); 167 168 if (!node->functionName().isEmpty()) 169 result->setFunctionName(node->functionName()); 170 171 if (!node->url().isEmpty()) { 172 result->setUrl(node->url()); 173 result->setLineNumber(node->lineNumber()); 174 result->setColumnNumber(node->columnNumber()); 175 } 176 177 if (!node->children().isEmpty()) { 178 auto children = Protocol::Array<Protocol::Timeline::CPUProfileNode>::create(); 179 for (RefPtr<JSC::ProfileNode> profileNode : node->children()) 180 children->addItem(buildInspectorObject(profileNode.get())); 181 result->setChildren(WTFMove(children)); 182 } 183 184 return result; 185 } 186 187 static Ref<Protocol::Timeline::CPUProfile> buildProfileInspectorObject(const JSC::Profile* profile) 188 { 189 auto rootNodes = Protocol::Array<Protocol::Timeline::CPUProfileNode>::create(); 190 for (RefPtr<JSC::ProfileNode> profileNode : profile->rootNode()->children()) 191 rootNodes->addItem(buildInspectorObject(profileNode.get())); 192 193 return Protocol::Timeline::CPUProfile::create() 194 .setRootNodes(WTFMove(rootNodes)) 195 .release(); 196 } 187 #endif // ENABLE(SAMPLING_PROFILER) 197 188 198 189 void InspectorScriptProfilerAgent::trackingComplete() 199 190 { 200 RefPtr<Inspector::Protocol::Array<InspectorValue>> profiles = Inspector::Protocol::Array<InspectorValue>::create(); 201 for (auto& profile : m_profiles) { 202 Ref<InspectorValue> value = buildProfileInspectorObject(profile.get()); 203 profiles->addItem(WTFMove(value)); 204 } 205 206 m_frontendDispatcher->trackingComplete(profiles); 207 208 m_profiles.clear(); 191 #if ENABLE(SAMPLING_PROFILER) 192 if (m_enabledSamplingProfiler) { 193 SamplingProfiler* samplingProfiler = m_environment.scriptDebugServer().vm().samplingProfiler(); 194 RELEASE_ASSERT(samplingProfiler); 195 LockHolder locker(samplingProfiler->getLock()); 196 samplingProfiler->stop(locker); 197 Ref<Protocol::ScriptProfiler::Samples> samples = buildSamples(samplingProfiler->stackTraces(locker), samplingProfiler->totalTime(locker)); 198 samplingProfiler->clearData(locker); 199 200 locker.unlockEarly(); 201 202 m_enabledSamplingProfiler = false; 203 204 m_frontendDispatcher->trackingComplete(WTFMove(samples)); 205 } else 206 m_frontendDispatcher->trackingComplete(nullptr); 207 #else 208 m_frontendDispatcher->trackingComplete(nullptr); 209 #endif // ENABLE(SAMPLING_PROFILER) 209 210 } 210 211 -
trunk/Source/JavaScriptCore/inspector/agents/InspectorScriptProfilerAgent.h
r194242 r195376 51 51 52 52 // ScriptProfilerBackendDispatcherHandler 53 virtual void startTracking(ErrorString&, const bool* profile) override;53 virtual void startTracking(ErrorString&, const bool* includeSamples) override; 54 54 virtual void stopTracking(ErrorString&) override; 55 55 56 56 // Debugger::ProfilingClient 57 57 virtual bool isAlreadyProfiling() const override; 58 virtual double willEvaluateScript( JSC::JSGlobalObject&) override;59 virtual void didEvaluateScript( JSC::JSGlobalObject&,double, JSC::ProfilingReason) override;58 virtual double willEvaluateScript() override; 59 virtual void didEvaluateScript(double, JSC::ProfilingReason) override; 60 60 61 61 private: … … 71 71 std::unique_ptr<ScriptProfilerFrontendDispatcher> m_frontendDispatcher; 72 72 RefPtr<ScriptProfilerBackendDispatcher> m_backendDispatcher; 73 Vector<RefPtr<JSC::Profile>> m_profiles;74 73 InspectorEnvironment& m_environment; 75 74 bool m_tracking { false }; 76 bool m_enable LegacyProfiler { false };75 bool m_enabledSamplingProfiler { false }; 77 76 bool m_activeEvaluateScript { false }; 78 77 }; -
trunk/Source/JavaScriptCore/inspector/protocol/ScriptProfiler.json
r194242 r195376 16 16 { "name": "type", "$ref": "EventType" } 17 17 ] 18 }, 19 { 20 "id": "StackFrame", 21 "type": "object", 22 "properties": [ 23 { "name": "sourceID", "$ref": "Debugger.ScriptId", "description": "Unique script identifier." }, 24 { "name": "name", "type": "string", "description": "A displayable name for the stack frame. i.e function name, (program), etc." }, 25 { "name": "line", "type": "integer" }, 26 { "name": "column", "type": "integer" }, 27 { "name": "url", "type": "string" } 28 ] 29 }, 30 { 31 "id": "StackTrace", 32 "type": "object", 33 "properties": [ 34 { "name": "timestamp", "type": "number" }, 35 { "name": "stackFrames", "type": "array", "items": { "$ref": "StackFrame" }, "description": "First array item is the bottom of the call stack and last array item is the top of the call stack." } 36 ] 37 }, 38 { 39 "id": "Samples", 40 "type": "object", 41 "properties": [ 42 { "name": "totalTime", "type": "number", "description": "Total execution time of the profiler's data. (Note: not total elapsed time.)" }, 43 { "name": "stackTraces", "type": "array", "items": { "$ref": "StackTrace" } } 44 ] 18 45 } 19 46 ], … … 23 50 "description": "Start tracking script evaluations.", 24 51 "parameters": [ 25 { "name": " profile", "type": "boolean", "optional": true, "description": "Profile script evaluations, defaults to false." }52 { "name": "includeSamples", "type": "boolean", "optional": true, "description": "Start the sampling profiler, defaults to false." } 26 53 ] 27 54 }, … … 50 77 "description": "When tracking is complete the backend will send any buffered data, such as profiling information.", 51 78 "parameters": [ 52 { "name": " profiles", "type": "array", "items": { "type": "any" }, "optional": true}79 { "name": "samples", "$ref": "Samples", "optional": true, "description": "Stack traces." } 53 80 ] 54 81 } -
trunk/Source/JavaScriptCore/jsc.cpp
r195233 r195376 1643 1643 { 1644 1644 RELEASE_ASSERT(exec->vm().samplingProfiler()); 1645 String jsonString = exec->vm().samplingProfiler()->stack tracesAsJSON();1645 String jsonString = exec->vm().samplingProfiler()->stackTracesAsJSON(); 1646 1646 exec->vm().samplingProfiler()->clearData(); 1647 1647 EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString)); -
trunk/Source/JavaScriptCore/runtime/SamplingProfiler.cpp
r194840 r195376 406 406 { 407 407 LockHolder locker(m_lock); 408 start(locker); 409 } 410 411 void SamplingProfiler::start(const LockHolder& locker) 412 { 413 ASSERT(m_lock.isLocked()); 408 414 m_isActive = true; 409 415 dispatchIfNecessary(locker); … … 413 419 { 414 420 LockHolder locker(m_lock); 421 stop(locker); 422 } 423 424 void SamplingProfiler::stop(const LockHolder&) 425 { 426 ASSERT(m_lock.isLocked()); 415 427 m_isActive = false; 416 428 reportStats(); … … 470 482 { 471 483 LockHolder locker(m_lock); 484 clearData(locker); 485 } 486 487 void SamplingProfiler::clearData(const LockHolder&) 488 { 489 ASSERT(m_lock.isLocked()); 472 490 m_stackTraces.clear(); 473 491 m_seenExecutables.clear(); … … 475 493 } 476 494 477 static String displayName(const SamplingProfiler::StackFrame& stackFrame)478 { 479 if ( stackFrame.frameType == FrameType::Unknown)480 return ASCIILiteral(" <unknown>");481 if ( stackFrame.frameType == FrameType::Host)482 return ASCIILiteral(" <host>");483 RELEASE_ASSERT( stackFrame.frameType != FrameType::UnverifiedCallee);484 485 ExecutableBase* executable = stackFrame.u.verifiedExecutable;495 String SamplingProfiler::StackFrame::displayName() 496 { 497 if (frameType == FrameType::Unknown) 498 return ASCIILiteral("(unknown)"); 499 if (frameType == FrameType::Host) 500 return ASCIILiteral("(host)"); 501 RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee); 502 503 ExecutableBase* executable = u.verifiedExecutable; 486 504 if (executable->isHostFunction()) 487 return ASCIILiteral("<host>"); 505 return static_cast<NativeExecutable*>(executable)->name(); 506 507 if (executable->isFunctionExecutable()) 508 return static_cast<FunctionExecutable*>(executable)->inferredName().string(); 509 if (executable->isProgramExecutable() || executable->isEvalExecutable()) 510 return ASCIILiteral("(program)"); 511 if (executable->isModuleProgramExecutable()) 512 return ASCIILiteral("(module)"); 513 514 RELEASE_ASSERT_NOT_REACHED(); 515 return String(); 516 } 517 518 String SamplingProfiler::StackFrame::displayNameForJSONTests() 519 { 520 if (frameType == FrameType::Unknown) 521 return ASCIILiteral("(unknown)"); 522 if (frameType == FrameType::Host) 523 return ASCIILiteral("(host)"); 524 RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee); 525 526 ExecutableBase* executable = u.verifiedExecutable; 527 if (executable->isHostFunction()) 528 return static_cast<NativeExecutable*>(executable)->name(); 488 529 489 530 if (executable->isFunctionExecutable()) { 490 531 String result = static_cast<FunctionExecutable*>(executable)->inferredName().string(); 491 if ( !result.isEmpty())492 return result;493 return ASCIILiteral("<anonymous-function>");532 if (result.isEmpty()) 533 return ASCIILiteral("(anonymous function)"); 534 return result; 494 535 } 495 536 if (executable->isEvalExecutable()) 496 return ASCIILiteral(" <eval>");537 return ASCIILiteral("(eval)"); 497 538 if (executable->isProgramExecutable()) 498 return ASCIILiteral(" <global>");539 return ASCIILiteral("(program)"); 499 540 if (executable->isModuleProgramExecutable()) 500 return ASCIILiteral(" <module>");541 return ASCIILiteral("(module)"); 501 542 502 543 RELEASE_ASSERT_NOT_REACHED(); 503 return ""; 504 } 505 506 String SamplingProfiler::stacktracesAsJSON() 507 { 508 m_lock.lock(); 544 return String(); 545 } 546 547 int SamplingProfiler::StackFrame::startLine() 548 { 549 if (frameType == FrameType::Unknown || frameType == FrameType::Host) 550 return -1; 551 RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee); 552 553 ExecutableBase* executable = u.verifiedExecutable; 554 if (executable->isHostFunction()) 555 return -1; 556 return static_cast<ScriptExecutable*>(executable)->firstLine(); 557 } 558 559 unsigned SamplingProfiler::StackFrame::startColumn() 560 { 561 if (frameType == FrameType::Unknown || frameType == FrameType::Host) 562 return -1; 563 RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee); 564 565 ExecutableBase* executable = u.verifiedExecutable; 566 if (executable->isHostFunction()) 567 return -1; 568 569 return static_cast<ScriptExecutable*>(executable)->startColumn(); 570 } 571 572 intptr_t SamplingProfiler::StackFrame::sourceID() 573 { 574 if (frameType == FrameType::Unknown || frameType == FrameType::Host) 575 return -1; 576 RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee); 577 578 ExecutableBase* executable = u.verifiedExecutable; 579 if (executable->isHostFunction()) 580 return -1; 581 582 return static_cast<ScriptExecutable*>(executable)->sourceID(); 583 } 584 585 String SamplingProfiler::StackFrame::url() 586 { 587 if (frameType == FrameType::Unknown || frameType == FrameType::Host) 588 return emptyString(); 589 RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee); 590 591 ExecutableBase* executable = u.verifiedExecutable; 592 if (executable->isHostFunction()) 593 return emptyString(); 594 595 String url = static_cast<ScriptExecutable*>(executable)->sourceURL(); 596 if (url.isEmpty()) 597 return static_cast<ScriptExecutable*>(executable)->source().provider()->sourceURL(); // Fall back to sourceURL directive. 598 return url; 599 } 600 601 Vector<SamplingProfiler::StackTrace>& SamplingProfiler::stackTraces(const LockHolder&) 602 { 603 ASSERT(m_lock.isLocked()); 604 { 605 HeapIterationScope heapIterationScope(m_vm.heap); 606 processUnverifiedStackTraces(); 607 } 608 609 return m_stackTraces; 610 } 611 612 String SamplingProfiler::stackTracesAsJSON() 613 { 614 LockHolder locker(m_lock); 615 509 616 { 510 617 HeapIterationScope heapIterationScope(m_vm.heap); … … 520 627 json.appendLiteral(","); 521 628 }; 522 for ( constStackTrace& stackTrace : m_stackTraces) {629 for (StackTrace& stackTrace : m_stackTraces) { 523 630 comma(); 524 631 json.appendLiteral("["); 525 632 loopedOnce = false; 526 for ( constStackFrame& stackFrame : stackTrace.frames) {633 for (StackFrame& stackFrame : stackTrace.frames) { 527 634 comma(); 528 635 json.appendLiteral("\""); 529 json.append( displayName(stackFrame));636 json.append(stackFrame.displayNameForJSONTests()); 530 637 json.appendLiteral("\""); 531 638 loopedOnce = true; … … 536 643 537 644 json.appendLiteral("]"); 538 539 m_lock.unlock();540 645 541 646 return json.toString(); -
trunk/Source/JavaScriptCore/runtime/SamplingProfiler.h
r194840 r195376 51 51 Unknown 52 52 }; 53 53 54 struct StackFrame { 54 55 StackFrame(FrameType frameType, EncodedJSValue callee) … … 73 74 ExecutableBase* verifiedExecutable; 74 75 } u; 76 77 String displayName(); 78 String displayNameForJSONTests(); // Used for JSC stress tests because they want the "(anonymous function)" string for anonymous functions and they want "(eval)" for eval'd code. 79 int startLine(); 80 unsigned startColumn(); 81 intptr_t sourceID(); 82 String url(); 75 83 }; 84 76 85 struct StackTrace { 77 86 bool needsVerification; … … 89 98 void setTimingInterval(std::chrono::microseconds interval) { m_timingInterval = interval; } 90 99 JS_EXPORT_PRIVATE void start(); 100 void start(const LockHolder&); 91 101 void stop(); 92 const Vector<StackTrace>& stackTraces() const { return m_stackTraces; } 93 JS_EXPORT_PRIVATE String stacktracesAsJSON(); 102 void stop(const LockHolder&); 103 Vector<StackTrace>& stackTraces(const LockHolder&); 104 JS_EXPORT_PRIVATE String stackTracesAsJSON(); 94 105 JS_EXPORT_PRIVATE void noticeCurrentThreadAsJSCExecutionThread(); 95 106 void noticeCurrentThreadAsJSCExecutionThread(const LockHolder&); 96 107 JS_EXPORT_PRIVATE void clearData(); 108 void clearData(const LockHolder&); 97 109 void processUnverifiedStackTraces(); // You should call this only after acquiring the lock. 110 double totalTime(const LockHolder&) { return m_totalTime; } 111 void setStopWatch(const LockHolder&, Ref<Stopwatch>&& stopwatch) { m_stopwatch = WTFMove(stopwatch); } 98 112 99 113 private: -
trunk/Source/JavaScriptCore/tests/stress/sampling-profiler-anonymous-function.js
r194840 r195376 19 19 } 20 20 21 runTest(baz, [" <anonymous-function>", "foo", "baz"]);21 runTest(baz, ["(anonymous function)", "foo", "baz"]); 22 22 } -
trunk/Source/JavaScriptCore/tests/stress/sampling-profiler-basic.js
r194840 r195376 18 18 noInline(nothing); 19 19 20 runTest(foo, [" <host>", "bar", "foo"]);20 runTest(foo, ["(host)", "bar", "foo"]); 21 21 22 22 function top() { -
trunk/Source/JavaScriptCore/tests/stress/sampling-profiler/samplingProfiler.js
r194840 r195376 39 39 // call frame at index 0. 40 40 if (isRunFromRunTest) 41 stackTrace = [...stackTrace, "runTest", " <global>"];41 stackTrace = [...stackTrace, "runTest", "(program)"]; 42 42 else 43 43 stackTrace = [...stackTrace]; -
trunk/Source/WebInspectorUI/ChangeLog
r195344 r195376 1 2016-01-20 Saam barati <sbarati@apple.com> 2 3 Web Inspector: Hook the sampling profiler into the Timelines UI 4 https://bugs.webkit.org/show_bug.cgi?id=152766 5 <rdar://problem/24066360> 6 7 Reviewed by Joseph Pecoraro. 8 9 The main change in this patch is to swap in the SamplingProfiler 10 in place of the LegacyProfiler. To do this, we've created a data 11 structure called CallingContextTree which aggregates the SamplingProfiler's 12 data into an easy to manage tree. To see how the data structure works, 13 consider the following program: 14 ``` 15 function bar() { // run code here for a long time. } 16 function baz() { // run code here for a long time. } 17 function foo() { bar(); baz(); } 18 foo(); 19 ``` 20 From this program, we will create a tree like this: 21 (program) 22 | 23 | 24 foo 25 | | 26 / \ 27 / \ 28 bar baz 29 30 From this type of tree, we can easily create a CPUProfile payload 31 object. Because the Timelines UI knows how to interact with the 32 CPUProfile object and display it, we currently map the tree to this object 33 to make it trivially easy to display the SamplingProfiler's data. In the future, 34 we may want to find ways to work directly with the CallingContextTree instead 35 of mapping it into another object. 36 37 * Localizations/en.lproj/localizedStrings.js: 38 * UserInterface/Controllers/TimelineManager.js: 39 * UserInterface/Main.html: 40 * UserInterface/Models/CallingContextTree.js: Added. 41 * UserInterface/Models/ScriptInstrument.js: 42 * UserInterface/Protocol/ScriptProfilerObserver.js: 43 * UserInterface/TestStub.html: 44 * UserInterface/Views/ScriptTimelineView.js: 45 1 46 2016-01-19 Joseph Pecoraro <pecoraro@apple.com> 2 47 -
trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
r194977 r195376 545 545 localizedStrings["Right"] = "Right"; 546 546 localizedStrings["Role"] = "Role"; 547 localizedStrings["Samples"] = "Samples"; 547 548 localizedStrings["Scheme"] = "Scheme"; 548 549 localizedStrings["Scope Chain"] = "Scope Chain"; -
trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js
r194871 r195376 46 46 this._scriptProfilerRecords = null; 47 47 48 this._callingContextTree = null; 49 48 50 this.reset(); 49 51 } … … 683 685 } 684 686 685 scriptProfilerTrackingCompleted( profiles)687 scriptProfilerTrackingCompleted(samples) 686 688 { 687 689 console.assert(!this._webTimelineScriptRecordsExpectingScriptProfilerEvents || this._scriptProfilerRecords.length >= this._webTimelineScriptRecordsExpectingScriptProfilerEvents.length); 688 690 689 // Associate the profiles with the ScriptProfiler created records. 690 if (profiles) { 691 console.assert(this._scriptProfilerRecords.length === profiles.length, this._scriptProfilerRecords.length, profiles.length); 692 for (let i = 0; i < this._scriptProfilerRecords.length; ++i) 693 this._scriptProfilerRecords[i].profilePayload = profiles[i]; 691 if (samples) { 692 if (!this._callingContextTree) 693 this._callingContextTree = new WebInspector.CallingContextTree; 694 695 // Associate the stackTraces with the ScriptProfiler created records. 696 let stackTraces = samples.stackTraces; 697 for (let i = 0; i < stackTraces.length; i++) 698 this._callingContextTree.updateTreeWithStackTrace(stackTraces[i]); 699 700 for (let i = 0; i < this._scriptProfilerRecords.length; ++i) { 701 let record = this._scriptProfilerRecords[i]; 702 record.profilePayload = this._callingContextTree.toCPUProfilePayload(record.startTime, record.endTime); 703 } 694 704 } 695 705 -
trunk/Source/WebInspectorUI/UserInterface/Main.html
r195305 r195376 270 270 <script src="Models/Branch.js"></script> 271 271 <script src="Models/Breakpoint.js"></script> 272 <script src="Models/CallingContextTree.js"></script> 272 273 <script src="Models/CSSCompletions.js"></script> 273 274 <script src="Models/CSSKeywordCompletions.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js
r194871 r195376 42 42 43 43 // FIXME: Make this some UI visible option. 44 const include Profiles = true;44 const includeSamples = true; 45 45 46 ScriptProfilerAgent.startTracking(include Profiles);46 ScriptProfilerAgent.startTracking(includeSamples); 47 47 } 48 48 -
trunk/Source/WebInspectorUI/UserInterface/Protocol/ScriptProfilerObserver.js
r194242 r195376 38 38 } 39 39 40 trackingComplete( profiles)40 trackingComplete(samples) 41 41 { 42 WebInspector.timelineManager.scriptProfilerTrackingCompleted( profiles);42 WebInspector.timelineManager.scriptProfilerTrackingCompleted(samples); 43 43 } 44 44 }; -
trunk/Source/WebInspectorUI/UserInterface/TestStub.html
r195305 r195376 34 34 <script src="Base/ListMultimap.js"></script> 35 35 <script src="Base/Object.js"></script> 36 <script src="Base/Utilities.js"></script> 37 38 <script src="Models/CallingContextTree.js"></script> 36 39 37 40 <script src="Test/TestSuite.js"></script> -
trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js
r194878 r195376 39 39 columns.location.width = "15%"; 40 40 41 columns.callCount.title = WebInspector.UIString("Calls"); 41 let isSamplingProfiler = !!window.ScriptProfilerAgent; 42 if (isSamplingProfiler) 43 columns.callCount.title = WebInspector.UIString("Samples"); 44 else { 45 // COMPATIBILITY(iOS 9): ScriptProfilerAgent did not exist yet, we had call counts, not samples. 46 columns.callCount.title = WebInspector.UIString("Calls"); 47 } 42 48 columns.callCount.width = "5%"; 43 49 columns.callCount.aligned = "right";
Note: See TracChangeset
for help on using the changeset viewer.