Diff
Modified: trunk/LayoutTests/ChangeLog (195375 => 195376)
--- trunk/LayoutTests/ChangeLog 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/ChangeLog 2016-01-20 21:51:00 UTC (rev 195376)
@@ -1,3 +1,31 @@
+2016-01-20 Saam barati <sbar...@apple.com>
+
+ Web Inspector: Hook the sampling profiler into the Timelines UI
+ https://bugs.webkit.org/show_bug.cgi?id=152766
+ <rdar://problem/24066360>
+
+ Reviewed by Joseph Pecoraro.
+
+ * inspector/sampling-profiler: Added.
+ * inspector/sampling-profiler/basic-expected.txt: Added.
+ * inspector/sampling-profiler/basic.html: Added.
+ * inspector/sampling-profiler/call-frame-with-dom-functions-expected.txt: Added.
+ * inspector/sampling-profiler/call-frame-with-dom-functions.html: Added.
+ * inspector/sampling-profiler/eval-source-url-expected.txt: Added.
+ * inspector/sampling-profiler/eval-source-url.html: Added.
+ * inspector/sampling-profiler/many-call-frames-expected.txt: Added.
+ * inspector/sampling-profiler/many-call-frames.html: Added.
+ * inspector/sampling-profiler/named-function-_expression_-expected.txt: Added.
+ * inspector/sampling-profiler/named-function-_expression_.html: Added.
+ * inspector/script-profiler/event-type-API-expected.txt:
+ * inspector/script-profiler/event-type-API.html:
+ * inspector/script-profiler/event-type-Microtask-expected.txt:
+ * inspector/script-profiler/event-type-Microtask.html:
+ * inspector/script-profiler/event-type-Other-expected.txt:
+ * inspector/script-profiler/event-type-Other.html:
+ * inspector/script-profiler/tracking-expected.txt:
+ * inspector/script-profiler/tracking.html:
+
2016-01-20 Daniel Bates <daba...@apple.com>
CSP: Add tests to ensure that alternative text of an image is rendered when CSP blocks its load
Added: trunk/LayoutTests/inspector/sampling-profiler/basic-expected.txt (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/basic-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/basic-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,13 @@
+
+== Running test suite: ScriptProfiler.Samples.Basic
+-- Running test case: Sampling Profiler basic
+PASS: Should have seen stacktrace:
+[
+ {
+ "name": "foo"
+ },
+ {
+ "name": "runFor"
+ }
+]
+
Added: trunk/LayoutTests/inspector/sampling-profiler/basic.html (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/basic.html (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/basic.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,53 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+
+function runFor(func, millis) {
+ let start = Date.now();
+ do {
+ func();
+ } while (Date.now() - start < millis);
+}
+
+function foo() {
+ for (let i = 0; i < 10000; i++) {
+ i++;
+ i--;
+ }
+}
+noInline(foo);
+
+function test()
+{
+ let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.Samples.Basic");
+
+ suite.addTestCase({
+ name: "Sampling Profiler basic",
+ description: "Sample some basic code.",
+ test: (resolve, reject) => {
+ InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
+ let tree = WebInspector.CallingContextTree.__test_makeTreeFromProtocolMessageObject(messageObject);
+ let trace = [
+ {name: "foo"},
+ {name: "runFor"}
+ ];
+ ProtocolTest.expectThat(tree.__test_matchesStackTrace(trace), "Should have seen stacktrace:\n" + JSON.stringify(trace, undefined, 2));
+ resolve();
+ });
+
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {includeSamples: true});
+ ProtocolTest.evaluateInPage("runFor(foo, 100)");
+ InspectorProtocol.sendCommand('ScriptProfiler.stopTracking', {});
+ }
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+</body>
+</html>
Added: trunk/LayoutTests/inspector/sampling-profiler/call-frame-with-dom-functions-expected.txt (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/call-frame-with-dom-functions-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/call-frame-with-dom-functions-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,28 @@
+
+== Running test suite: SciptProfiler.Samples.DOM
+-- Running test case: Sampling Profiler sourceURL directive.
+PASS: Should have seen stacktrace:
+[
+ {
+ "name": "createElement"
+ },
+ {
+ "name": "foo"
+ },
+ {
+ "name": "runFor"
+ }
+]
+PASS: Should have seen stacktrace:
+[
+ {
+ "name": "appendChild"
+ },
+ {
+ "name": "foo"
+ },
+ {
+ "name": "runFor"
+ }
+]
+
Added: trunk/LayoutTests/inspector/sampling-profiler/call-frame-with-dom-functions.html (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/call-frame-with-dom-functions.html (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/call-frame-with-dom-functions.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,64 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+
+function runFor(func, millis) {
+ let start = Date.now();
+ do {
+ func();
+ } while (Date.now() - start < millis);
+}
+
+function foo() {
+ let body = document.body;
+ for (let i = 0; i < 10000; i++) {
+ let p = document.createElement("p");
+ body.appendChild(p);
+ }
+}
+noInline(foo);
+
+function test()
+{
+ let suite = ProtocolTest.createAsyncSuite("SciptProfiler.Samples.DOM");
+
+ suite.addTestCase({
+ name: "Sampling Profiler sourceURL directive.",
+ description: "Sample some basic code.",
+ test: (resolve, reject) => {
+ InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
+ let tree = WebInspector.CallingContextTree.__test_makeTreeFromProtocolMessageObject(messageObject);
+
+ let trace = [
+ {name: "createElement"},
+ {name: "foo"},
+ {name: "runFor"}
+ ];
+ ProtocolTest.expectThat(tree.__test_matchesStackTrace(trace), "Should have seen stacktrace:\n" + JSON.stringify(trace, undefined, 2));
+
+ trace = [
+ {name: "appendChild"},
+ {name: "foo"},
+ {name: "runFor"}
+ ];
+ ProtocolTest.expectThat(tree.__test_matchesStackTrace(trace), "Should have seen stacktrace:\n" + JSON.stringify(trace, undefined, 2));
+
+ resolve();
+ });
+
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {includeSamples: true});
+ ProtocolTest.evaluateInPage("runFor(foo, 100)");
+ InspectorProtocol.sendCommand('ScriptProfiler.stopTracking', {});
+ }
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+</body>
+</html>
Added: trunk/LayoutTests/inspector/sampling-profiler/eval-source-url-expected.txt (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/eval-source-url-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/eval-source-url-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,23 @@
+
+== Running test suite: ScriptProfiler.Samples.SourceURL
+-- Running test case: Sampling Profiler sourceURL directive.
+PASS: Should have seen stacktrace:
+[
+ {
+ "name": "foo"
+ },
+ {
+ "name": "(program)",
+ "url": "eval.js"
+ },
+ {
+ "name": "eval"
+ },
+ {
+ "name": "bar"
+ },
+ {
+ "name": "runFor"
+ }
+]
+
Added: trunk/LayoutTests/inspector/sampling-profiler/eval-source-url.html (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/eval-source-url.html (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/eval-source-url.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,63 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+
+function runFor(func, millis) {
+ let start = Date.now();
+ do {
+ func();
+ } while (Date.now() - start < millis);
+}
+
+function foo() {
+ for (let i = 0; i < 10000; i++) {
+ i++;
+ i--;
+ }
+}
+noInline(foo);
+
+function bar() {
+ for (let i = 0; i < 2; i++)
+ eval("//# sourceURL=eval.js\nfoo();");
+}
+noInline(bar);
+
+function test()
+{
+ let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.Samples.SourceURL");
+
+ suite.addTestCase({
+ name: "Sampling Profiler sourceURL directive.",
+ description: "Sample some basic code.",
+ test: (resolve, reject) => {
+ InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
+ let tree = WebInspector.CallingContextTree.__test_makeTreeFromProtocolMessageObject(messageObject);
+
+ let trace = [
+ {name: "foo"},
+ {name: "(program)", url: "eval.js"},
+ {name: "eval"},
+ {name: "bar"},
+ {name: "runFor"}
+ ];
+ ProtocolTest.expectThat(tree.__test_matchesStackTrace(trace), "Should have seen stacktrace:\n" + JSON.stringify(trace, undefined, 2));
+ resolve();
+ });
+
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {includeSamples: true});
+ ProtocolTest.evaluateInPage("runFor(bar, 100)");
+ InspectorProtocol.sendCommand('ScriptProfiler.stopTracking', {});
+ }
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+</body>
+</html>
Added: trunk/LayoutTests/inspector/sampling-profiler/many-call-frames-expected.txt (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/many-call-frames-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/many-call-frames-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,34 @@
+
+== Running test suite: ScriptProfiler.Samples.ManyCallFrames
+-- Running test case: Sampling Profiler sourceURL directive.
+PASS: Should have seen stacktrace:
+[
+ {
+ "name": "top"
+ },
+ {
+ "name": "g"
+ },
+ {
+ "name": "f"
+ },
+ {
+ "name": "e"
+ },
+ {
+ "name": "d"
+ },
+ {
+ "name": "c"
+ },
+ {
+ "name": "b"
+ },
+ {
+ "name": "a"
+ },
+ {
+ "name": "runFor"
+ }
+]
+
Added: trunk/LayoutTests/inspector/sampling-profiler/many-call-frames.html (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/many-call-frames.html (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/many-call-frames.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,68 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+
+function runFor(func, millis) {
+ let start = Date.now();
+ do {
+ func();
+ } while (Date.now() - start < millis);
+}
+function a() { b(); }
+function b() { c(); }
+function c() { d(); }
+function d() { e(); }
+function e() { f(); }
+function f() { g(); }
+function g() { top(); }
+
+function top() {
+ for (let i = 0; i < 10000; i++) {
+ i++;
+ i--;
+ }
+}
+noInline(top);
+
+function test()
+{
+ let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.Samples.ManyCallFrames");
+
+ suite.addTestCase({
+ name: "Sampling Profiler sourceURL directive.",
+ description: "Sample some basic code.",
+ test: (resolve, reject) => {
+ InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
+ let tree = WebInspector.CallingContextTree.__test_makeTreeFromProtocolMessageObject(messageObject);
+
+ let trace = [
+ {name: "top"},
+ {name: "g"},
+ {name: "f"},
+ {name: "e"},
+ {name: "d"},
+ {name: "c"},
+ {name: "b"},
+ {name: "a"},
+ {name: "runFor"}
+ ];
+ ProtocolTest.expectThat(tree.__test_matchesStackTrace(trace), "Should have seen stacktrace:\n" + JSON.stringify(trace, undefined, 2));
+ resolve();
+ });
+
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {includeSamples: true});
+ ProtocolTest.evaluateInPage("runFor(a, 100)");
+ InspectorProtocol.sendCommand('ScriptProfiler.stopTracking', {});
+ }
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+</body>
+</html>
Added: trunk/LayoutTests/inspector/sampling-profiler/named-function-_expression_-expected.txt (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/named-function-_expression_-expected.txt (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/named-function-_expression_-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,16 @@
+
+== Running test suite: ScriptProfiler.Samples.NamedFunctionExpression
+-- Running test case: Sampling Profiler basic
+PASS: Should have seen stacktrace:
+[
+ {
+ "name": "bar"
+ },
+ {
+ "name": "foo"
+ },
+ {
+ "name": "runFor"
+ }
+]
+
Added: trunk/LayoutTests/inspector/sampling-profiler/named-function-_expression_.html (0 => 195376)
--- trunk/LayoutTests/inspector/sampling-profiler/named-function-_expression_.html (rev 0)
+++ trunk/LayoutTests/inspector/sampling-profiler/named-function-_expression_.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,58 @@
+<!doctype html>
+<html>
+<head>
+<script src=""
+<script src=""
+<script>
+
+function runFor(func, millis) {
+ let start = Date.now();
+ do {
+ func();
+ } while (Date.now() - start < millis);
+}
+
+function foo() {
+ let bar = function() {
+ for (let i = 0; i < 10000; i++) {
+ i++;
+ i--;
+ }
+ };
+ noInline(bar);
+ bar();
+}
+noInline(foo);
+
+function test()
+{
+ let suite = ProtocolTest.createAsyncSuite("ScriptProfiler.Samples.NamedFunctionExpression");
+
+ suite.addTestCase({
+ name: "Sampling Profiler basic",
+ description: "Sample some basic code.",
+ test: (resolve, reject) => {
+ InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
+ let tree = WebInspector.CallingContextTree.__test_makeTreeFromProtocolMessageObject(messageObject);
+ let trace = [
+ {name: "bar"},
+ {name: "foo"},
+ {name: "runFor"}
+ ];
+ ProtocolTest.expectThat(tree.__test_matchesStackTrace(trace), "Should have seen stacktrace:\n" + JSON.stringify(trace, undefined, 2));
+ resolve();
+ });
+
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {includeSamples: true});
+ ProtocolTest.evaluateInPage("runFor(foo, 100)");
+ InspectorProtocol.sendCommand('ScriptProfiler.stopTracking', {});
+ }
+ });
+
+ suite.runTestCasesAndFinish();
+}
+</script>
+</head>
+<body _onload_="runTest()">
+</body>
+</html>
Modified: trunk/LayoutTests/inspector/script-profiler/event-type-API-expected.txt (195375 => 195376)
--- trunk/LayoutTests/inspector/script-profiler/event-type-API-expected.txt 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-API-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -8,6 +8,4 @@
ScriptProfiler.trackingUpdate
PASS: Event type should be API.
ScriptProfiler.trackingComplete
-PASS: Profiles should exist when complete.
-PASS: Should be 1 profile for this session.
Modified: trunk/LayoutTests/inspector/script-profiler/event-type-API.html (195375 => 195376)
--- trunk/LayoutTests/inspector/script-profiler/event-type-API.html 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-API.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -27,12 +27,10 @@
InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
ProtocolTest.log("ScriptProfiler.trackingComplete");
- ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");
- ProtocolTest.expectThat(messageObject.params.profiles.length === 1, "Should be 1 profile for this session.");
resolve();
});
- InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {profile: true});
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {});
ProtocolTest.evaluateInPage("triggerAPIScript();"); // This ultimately uses the JSEvaluateScript API on the Page's context.
InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {});
}
Modified: trunk/LayoutTests/inspector/script-profiler/event-type-Microtask-expected.txt (195375 => 195376)
--- trunk/LayoutTests/inspector/script-profiler/event-type-Microtask-expected.txt 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-Microtask-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -8,6 +8,4 @@
ScriptProfiler.trackingUpdate
PASS: Event type should be Microtask.
ScriptProfiler.trackingComplete
-PASS: Profiles should exist when complete.
-PASS: Should be 1 profile for this session.
Modified: trunk/LayoutTests/inspector/script-profiler/event-type-Microtask.html (195375 => 195376)
--- trunk/LayoutTests/inspector/script-profiler/event-type-Microtask.html 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-Microtask.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -28,12 +28,10 @@
InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
ProtocolTest.log("ScriptProfiler.trackingComplete");
- ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");
- ProtocolTest.expectThat(messageObject.params.profiles.length === 1, "Should be 1 profile for this session.");
resolve();
});
- InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {profile: true});
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {});
ProtocolTest.evaluateInPage("triggerMicrotask()");
InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {});
}
Modified: trunk/LayoutTests/inspector/script-profiler/event-type-Other-expected.txt (195375 => 195376)
--- trunk/LayoutTests/inspector/script-profiler/event-type-Other-expected.txt 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-Other-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -14,6 +14,4 @@
ScriptProfiler.trackingUpdate
PASS: Event type should be Other.
ScriptProfiler.trackingComplete
-PASS: Profiles should exist when complete.
-PASS: Should be 3 profiles for this session.
Modified: trunk/LayoutTests/inspector/script-profiler/event-type-Other.html (195375 => 195376)
--- trunk/LayoutTests/inspector/script-profiler/event-type-Other.html 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/inspector/script-profiler/event-type-Other.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -41,12 +41,10 @@
InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
ProtocolTest.log("ScriptProfiler.trackingComplete");
- ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");
- ProtocolTest.expectThat(messageObject.params.profiles.length === 3, "Should be 3 profiles for this session.");
resolve();
});
- InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {profile: true});
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {});
ProtocolTest.evaluateInPage("triggerScriptEvaluation()");
ProtocolTest.evaluateInPage("triggerEventDispatchEvaluation()");
ProtocolTest.evaluateInPage("triggerTimerEvaluation()");
Modified: trunk/LayoutTests/inspector/script-profiler/tracking-expected.txt (195375 => 195376)
--- trunk/LayoutTests/inspector/script-profiler/tracking-expected.txt 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/inspector/script-profiler/tracking-expected.txt 2016-01-20 21:51:00 UTC (rev 195376)
@@ -6,6 +6,4 @@
ScriptProfiler.trackingStart
PASS: Should have a timestamp when starting.
ScriptProfiler.trackingComplete
-PASS: Profiles should exist when complete.
-PASS: Should be no profiles for this session.
Modified: trunk/LayoutTests/inspector/script-profiler/tracking.html (195375 => 195376)
--- trunk/LayoutTests/inspector/script-profiler/tracking.html 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/LayoutTests/inspector/script-profiler/tracking.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -18,12 +18,10 @@
InspectorProtocol.awaitEvent({event: "ScriptProfiler.trackingComplete"}).then((messageObject) => {
ProtocolTest.log("ScriptProfiler.trackingComplete");
- ProtocolTest.expectThat(Array.isArray(messageObject.params.profiles), "Profiles should exist when complete.");
- ProtocolTest.expectThat(!messageObject.params.profiles.length, "Should be no profiles for this session.");
resolve();
});
- InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {profile: true});
+ InspectorProtocol.sendCommand("ScriptProfiler.startTracking", {});
InspectorProtocol.sendCommand("ScriptProfiler.stopTracking", {});
}
});
Modified: trunk/Source/_javascript_Core/ChangeLog (195375 => 195376)
--- trunk/Source/_javascript_Core/ChangeLog 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-01-20 21:51:00 UTC (rev 195376)
@@ -1,3 +1,76 @@
+2016-01-20 Saam barati <sbar...@apple.com>
+
+ Web Inspector: Hook the sampling profiler into the Timelines UI
+ https://bugs.webkit.org/show_bug.cgi?id=152766
+ <rdar://problem/24066360>
+
+ Reviewed by Joseph Pecoraro.
+
+ This patch adds some necessary functions to SamplingProfiler::StackFrame
+ to allow it to give data to the Inspector for the timelines UI. i.e, the
+ sourceID of the executable of a stack frame.
+
+ This patch also swaps in the SamplingProfiler in place of the
+ LegacyProfiler inside InspectorScriptProfilerAgent. It adds
+ the necessary protocol data to allow the SamplingProfiler's
+ data to hook into the timelines UI.
+
+ * debugger/Debugger.cpp:
+ (JSC::Debugger::setProfilingClient):
+ (JSC::Debugger::willEvaluateScript):
+ (JSC::Debugger::didEvaluateScript):
+ (JSC::Debugger::toggleBreakpoint):
+ * debugger/Debugger.h:
+ * debugger/ScriptProfilingScope.h:
+ (JSC::ScriptProfilingScope::ScriptProfilingScope):
+ (JSC::ScriptProfilingScope::~ScriptProfilingScope):
+ * inspector/agents/InspectorScriptProfilerAgent.cpp:
+ (Inspector::InspectorScriptProfilerAgent::willDestroyFrontendAndBackend):
+ (Inspector::InspectorScriptProfilerAgent::startTracking):
+ (Inspector::InspectorScriptProfilerAgent::stopTracking):
+ (Inspector::InspectorScriptProfilerAgent::isAlreadyProfiling):
+ (Inspector::InspectorScriptProfilerAgent::willEvaluateScript):
+ (Inspector::InspectorScriptProfilerAgent::didEvaluateScript):
+ (Inspector::InspectorScriptProfilerAgent::addEvent):
+ (Inspector::buildSamples):
+ (Inspector::InspectorScriptProfilerAgent::trackingComplete):
+ (Inspector::buildAggregateCallInfoInspectorObject): Deleted.
+ (Inspector::buildInspectorObject): Deleted.
+ (Inspector::buildProfileInspectorObject): Deleted.
+ * inspector/agents/InspectorScriptProfilerAgent.h:
+ * inspector/protocol/ScriptProfiler.json:
+ * jsc.cpp:
+ (functionSamplingProfilerStackTraces):
+ * runtime/SamplingProfiler.cpp:
+ (JSC::SamplingProfiler::start):
+ (JSC::SamplingProfiler::stop):
+ (JSC::SamplingProfiler::clearData):
+ (JSC::SamplingProfiler::StackFrame::displayName):
+ (JSC::SamplingProfiler::StackFrame::displayNameForJSONTests):
+ (JSC::SamplingProfiler::StackFrame::startLine):
+ (JSC::SamplingProfiler::StackFrame::startColumn):
+ (JSC::SamplingProfiler::StackFrame::sourceID):
+ (JSC::SamplingProfiler::StackFrame::url):
+ (JSC::SamplingProfiler::stackTraces):
+ (JSC::SamplingProfiler::stackTracesAsJSON):
+ (JSC::displayName): Deleted.
+ (JSC::SamplingProfiler::stacktracesAsJSON): Deleted.
+ * runtime/SamplingProfiler.h:
+ (JSC::SamplingProfiler::StackFrame::StackFrame):
+ (JSC::SamplingProfiler::getLock):
+ (JSC::SamplingProfiler::setTimingInterval):
+ (JSC::SamplingProfiler::totalTime):
+ (JSC::SamplingProfiler::setStopWatch):
+ (JSC::SamplingProfiler::stackTraces): Deleted.
+ * tests/stress/sampling-profiler-anonymous-function.js:
+ (platformSupportsSamplingProfiler.baz):
+ (platformSupportsSamplingProfiler):
+ * tests/stress/sampling-profiler-basic.js:
+ (platformSupportsSamplingProfiler.nothing):
+ (platformSupportsSamplingProfiler.top):
+ * tests/stress/sampling-profiler/samplingProfiler.js:
+ (doesTreeHaveStackTrace):
+
2016-01-20 Keith Miller <keith_mil...@apple.com>
TypedArray's .buffer does not return the JSArrayBuffer that was passed to it on creation.
Modified: trunk/Source/_javascript_Core/debugger/Debugger.cpp (195375 => 195376)
--- trunk/Source/_javascript_Core/debugger/Debugger.cpp 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/debugger/Debugger.cpp 2016-01-20 21:51:00 UTC (rev 195376)
@@ -234,14 +234,14 @@
recompileAllJSFunctions();
}
-double Debugger::willEvaluateScript(JSGlobalObject& globalObject)
+double Debugger::willEvaluateScript()
{
- return m_profilingClient->willEvaluateScript(globalObject);
+ return m_profilingClient->willEvaluateScript();
}
-void Debugger::didEvaluateScript(JSGlobalObject& globalObject, double startTime, ProfilingReason reason)
+void Debugger::didEvaluateScript(double startTime, ProfilingReason reason)
{
- m_profilingClient->didEvaluateScript(globalObject, startTime, reason);
+ m_profilingClient->didEvaluateScript(startTime, reason);
}
void Debugger::toggleBreakpoint(CodeBlock* codeBlock, Breakpoint& breakpoint, BreakpointState enabledOrNot)
Modified: trunk/Source/_javascript_Core/debugger/Debugger.h (195375 => 195376)
--- trunk/Source/_javascript_Core/debugger/Debugger.h 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/debugger/Debugger.h 2016-01-20 21:51:00 UTC (rev 195376)
@@ -132,15 +132,15 @@
public:
virtual ~ProfilingClient() { }
virtual bool isAlreadyProfiling() const = 0;
- virtual double willEvaluateScript(JSGlobalObject&) = 0;
- virtual void didEvaluateScript(JSGlobalObject&, double startTime, ProfilingReason) = 0;
+ virtual double willEvaluateScript() = 0;
+ virtual void didEvaluateScript(double startTime, ProfilingReason) = 0;
};
void setProfilingClient(ProfilingClient*);
bool hasProfilingClient() const { return m_profilingClient != nullptr; }
bool isAlreadyProfiling() const { return m_profilingClient && m_profilingClient->isAlreadyProfiling(); }
- double willEvaluateScript(JSGlobalObject&);
- void didEvaluateScript(JSGlobalObject&, double startTime, ProfilingReason);
+ double willEvaluateScript();
+ void didEvaluateScript(double startTime, ProfilingReason);
protected:
virtual bool needPauseHandling(JSGlobalObject*) { return false; }
Modified: trunk/Source/_javascript_Core/debugger/ScriptProfilingScope.h (195375 => 195376)
--- trunk/Source/_javascript_Core/debugger/ScriptProfilingScope.h 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/debugger/ScriptProfilingScope.h 2016-01-20 21:51:00 UTC (rev 195376)
@@ -39,13 +39,13 @@
, m_reason(reason)
{
if (shouldStartProfile())
- m_startTime = m_globalObject->debugger()->willEvaluateScript(*m_globalObject);
+ m_startTime = m_globalObject->debugger()->willEvaluateScript();
}
~ScriptProfilingScope()
{
if (shouldEndProfile())
- m_globalObject->debugger()->didEvaluateScript(*m_globalObject, m_startTime.value(), m_reason);
+ m_globalObject->debugger()->didEvaluateScript(m_startTime.value(), m_reason);
}
private:
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.cpp (195375 => 195376)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.cpp 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.cpp 2016-01-20 21:51:00 UTC (rev 195376)
@@ -27,7 +27,7 @@
#include "InspectorScriptProfilerAgent.h"
#include "InspectorEnvironment.h"
-#include "LegacyProfiler.h"
+#include "SamplingProfiler.h"
#include <wtf/RunLoop.h>
#include <wtf/Stopwatch.h>
@@ -57,16 +57,30 @@
stopTracking(ignored);
}
-void InspectorScriptProfilerAgent::startTracking(ErrorString&, const bool* profile)
+void InspectorScriptProfilerAgent::startTracking(ErrorString&, const bool* includeSamples)
{
if (m_tracking)
return;
m_tracking = true;
- if (profile && *profile)
- m_enableLegacyProfiler = true;
+#if ENABLE(SAMPLING_PROFILER)
+ if (includeSamples && *includeSamples) {
+ VM& vm = m_environment.scriptDebugServer().vm();
+ vm.ensureSamplingProfiler(m_environment.executionStopwatch());
+ SamplingProfiler& samplingProfiler = *vm.samplingProfiler();
+ LockHolder locker(samplingProfiler.getLock());
+
+ samplingProfiler.setStopWatch(locker, m_environment.executionStopwatch());
+ samplingProfiler.noticeCurrentThreadAsJSCExecutionThread(locker);
+ samplingProfiler.start(locker);
+ m_enabledSamplingProfiler = true;
+ }
+#else
+ UNUSED_PARAM(includeSamples);
+#endif // ENABLE(SAMPLING_PROFILER)
+
m_environment.scriptDebugServer().setProfilingClient(this);
m_frontendDispatcher->trackingStart(m_environment.executionStopwatch()->elapsedTime());
@@ -78,7 +92,6 @@
return;
m_tracking = false;
- m_enableLegacyProfiler = false;
m_activeEvaluateScript = false;
m_environment.scriptDebugServer().setProfilingClient(nullptr);
@@ -91,23 +104,25 @@
return m_activeEvaluateScript;
}
-double InspectorScriptProfilerAgent::willEvaluateScript(JSGlobalObject& globalObject)
+double InspectorScriptProfilerAgent::willEvaluateScript()
{
m_activeEvaluateScript = true;
- if (m_enableLegacyProfiler)
- LegacyProfiler::profiler()->startProfiling(globalObject.globalExec(), ASCIILiteral("ScriptProfiler"), m_environment.executionStopwatch());
+#if ENABLE(SAMPLING_PROFILER)
+ if (m_enabledSamplingProfiler) {
+ SamplingProfiler* samplingProfiler = m_environment.scriptDebugServer().vm().samplingProfiler();
+ RELEASE_ASSERT(samplingProfiler);
+ samplingProfiler->noticeCurrentThreadAsJSCExecutionThread();
+ }
+#endif
return m_environment.executionStopwatch()->elapsedTime();
}
-void InspectorScriptProfilerAgent::didEvaluateScript(JSGlobalObject& globalObject, double startTime, ProfilingReason reason)
+void InspectorScriptProfilerAgent::didEvaluateScript(double startTime, ProfilingReason reason)
{
m_activeEvaluateScript = false;
- if (m_enableLegacyProfiler)
- m_profiles.append(LegacyProfiler::profiler()->stopProfiling(globalObject.globalExec(), ASCIILiteral("ScriptProfiler")));
-
double endTime = m_environment.executionStopwatch()->elapsedTime();
addEvent(startTime, endTime, reason);
@@ -141,71 +156,57 @@
m_frontendDispatcher->trackingUpdate(WTFMove(event));
}
-static Ref<Protocol::Timeline::CPUProfileNodeAggregateCallInfo> buildAggregateCallInfoInspectorObject(const JSC::ProfileNode* node)
+#if ENABLE(SAMPLING_PROFILER)
+static Ref<Protocol::ScriptProfiler::Samples> buildSamples(Vector<SamplingProfiler::StackTrace>& samplingProfilerStackTraces, double totalTime)
{
- double startTime = node->calls()[0].startTime();
- double endTime = node->calls().last().startTime() + node->calls().last().elapsedTime();
+ Ref<Protocol::Array<Protocol::ScriptProfiler::StackTrace>> stackTraces = Protocol::Array<Protocol::ScriptProfiler::StackTrace>::create();
+ for (SamplingProfiler::StackTrace& stackTrace : samplingProfilerStackTraces) {
+ Ref<Protocol::Array<Protocol::ScriptProfiler::StackFrame>> frames = Protocol::Array<Protocol::ScriptProfiler::StackFrame>::create();
+ for (SamplingProfiler::StackFrame& stackFrame : stackTrace.frames) {
+ Ref<Protocol::ScriptProfiler::StackFrame> frame = Protocol::ScriptProfiler::StackFrame::create()
+ .setSourceID(String::number(stackFrame.sourceID()))
+ .setName(stackFrame.displayName())
+ .setLine(stackFrame.startLine())
+ .setColumn(stackFrame.startColumn())
+ .setUrl(stackFrame.url())
+ .release();
+ frames->addItem(WTFMove(frame));
+ }
+ Ref<Protocol::ScriptProfiler::StackTrace> inspectorStackTrace = Protocol::ScriptProfiler::StackTrace::create()
+ .setTimestamp(stackTrace.timestamp)
+ .setStackFrames(WTFMove(frames))
+ .release();
+ stackTraces->addItem(WTFMove(inspectorStackTrace));
+ }
- double totalTime = 0;
- for (const JSC::ProfileNode::Call& call : node->calls())
- totalTime += call.elapsedTime();
-
- return Protocol::Timeline::CPUProfileNodeAggregateCallInfo::create()
- .setCallCount(node->calls().size())
- .setStartTime(startTime)
- .setEndTime(endTime)
+ return Protocol::ScriptProfiler::Samples::create()
+ .setStackTraces(WTFMove(stackTraces))
.setTotalTime(totalTime)
.release();
}
+#endif // ENABLE(SAMPLING_PROFILER)
-static Ref<Protocol::Timeline::CPUProfileNode> buildInspectorObject(const JSC::ProfileNode* node)
+void InspectorScriptProfilerAgent::trackingComplete()
{
- auto result = Protocol::Timeline::CPUProfileNode::create()
- .setId(node->id())
- .setCallInfo(buildAggregateCallInfoInspectorObject(node))
- .release();
+#if ENABLE(SAMPLING_PROFILER)
+ if (m_enabledSamplingProfiler) {
+ SamplingProfiler* samplingProfiler = m_environment.scriptDebugServer().vm().samplingProfiler();
+ RELEASE_ASSERT(samplingProfiler);
+ LockHolder locker(samplingProfiler->getLock());
+ samplingProfiler->stop(locker);
+ Ref<Protocol::ScriptProfiler::Samples> samples = buildSamples(samplingProfiler->stackTraces(locker), samplingProfiler->totalTime(locker));
+ samplingProfiler->clearData(locker);
- if (!node->functionName().isEmpty())
- result->setFunctionName(node->functionName());
+ locker.unlockEarly();
- if (!node->url().isEmpty()) {
- result->setUrl(node->url());
- result->setLineNumber(node->lineNumber());
- result->setColumnNumber(node->columnNumber());
- }
+ m_enabledSamplingProfiler = false;
- if (!node->children().isEmpty()) {
- auto children = Protocol::Array<Protocol::Timeline::CPUProfileNode>::create();
- for (RefPtr<JSC::ProfileNode> profileNode : node->children())
- children->addItem(buildInspectorObject(profileNode.get()));
- result->setChildren(WTFMove(children));
- }
-
- return result;
+ m_frontendDispatcher->trackingComplete(WTFMove(samples));
+ } else
+ m_frontendDispatcher->trackingComplete(nullptr);
+#else
+ m_frontendDispatcher->trackingComplete(nullptr);
+#endif // ENABLE(SAMPLING_PROFILER)
}
-static Ref<Protocol::Timeline::CPUProfile> buildProfileInspectorObject(const JSC::Profile* profile)
-{
- auto rootNodes = Protocol::Array<Protocol::Timeline::CPUProfileNode>::create();
- for (RefPtr<JSC::ProfileNode> profileNode : profile->rootNode()->children())
- rootNodes->addItem(buildInspectorObject(profileNode.get()));
-
- return Protocol::Timeline::CPUProfile::create()
- .setRootNodes(WTFMove(rootNodes))
- .release();
-}
-
-void InspectorScriptProfilerAgent::trackingComplete()
-{
- RefPtr<Inspector::Protocol::Array<InspectorValue>> profiles = Inspector::Protocol::Array<InspectorValue>::create();
- for (auto& profile : m_profiles) {
- Ref<InspectorValue> value = buildProfileInspectorObject(profile.get());
- profiles->addItem(WTFMove(value));
- }
-
- m_frontendDispatcher->trackingComplete(profiles);
-
- m_profiles.clear();
-}
-
} // namespace Inspector
Modified: trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.h (195375 => 195376)
--- trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.h 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/inspector/agents/InspectorScriptProfilerAgent.h 2016-01-20 21:51:00 UTC (rev 195376)
@@ -50,13 +50,13 @@
virtual void willDestroyFrontendAndBackend(DisconnectReason) override;
// ScriptProfilerBackendDispatcherHandler
- virtual void startTracking(ErrorString&, const bool* profile) override;
+ virtual void startTracking(ErrorString&, const bool* includeSamples) override;
virtual void stopTracking(ErrorString&) override;
// Debugger::ProfilingClient
virtual bool isAlreadyProfiling() const override;
- virtual double willEvaluateScript(JSC::JSGlobalObject&) override;
- virtual void didEvaluateScript(JSC::JSGlobalObject&, double, JSC::ProfilingReason) override;
+ virtual double willEvaluateScript() override;
+ virtual void didEvaluateScript(double, JSC::ProfilingReason) override;
private:
struct Event {
@@ -70,10 +70,9 @@
std::unique_ptr<ScriptProfilerFrontendDispatcher> m_frontendDispatcher;
RefPtr<ScriptProfilerBackendDispatcher> m_backendDispatcher;
- Vector<RefPtr<JSC::Profile>> m_profiles;
InspectorEnvironment& m_environment;
bool m_tracking { false };
- bool m_enableLegacyProfiler { false };
+ bool m_enabledSamplingProfiler { false };
bool m_activeEvaluateScript { false };
};
Modified: trunk/Source/_javascript_Core/inspector/protocol/ScriptProfiler.json (195375 => 195376)
--- trunk/Source/_javascript_Core/inspector/protocol/ScriptProfiler.json 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/inspector/protocol/ScriptProfiler.json 2016-01-20 21:51:00 UTC (rev 195376)
@@ -15,6 +15,33 @@
{ "name": "endTime", "type": "number" },
{ "name": "type", "$ref": "EventType" }
]
+ },
+ {
+ "id": "StackFrame",
+ "type": "object",
+ "properties": [
+ { "name": "sourceID", "$ref": "Debugger.ScriptId", "description": "Unique script identifier." },
+ { "name": "name", "type": "string", "description": "A displayable name for the stack frame. i.e function name, (program), etc." },
+ { "name": "line", "type": "integer" },
+ { "name": "column", "type": "integer" },
+ { "name": "url", "type": "string" }
+ ]
+ },
+ {
+ "id": "StackTrace",
+ "type": "object",
+ "properties": [
+ { "name": "timestamp", "type": "number" },
+ { "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." }
+ ]
+ },
+ {
+ "id": "Samples",
+ "type": "object",
+ "properties": [
+ { "name": "totalTime", "type": "number", "description": "Total execution time of the profiler's data. (Note: not total elapsed time.)" },
+ { "name": "stackTraces", "type": "array", "items": { "$ref": "StackTrace" } }
+ ]
}
],
"commands": [
@@ -22,7 +49,7 @@
"name": "startTracking",
"description": "Start tracking script evaluations.",
"parameters": [
- { "name": "profile", "type": "boolean", "optional": true, "description": "Profile script evaluations, defaults to false." }
+ { "name": "includeSamples", "type": "boolean", "optional": true, "description": "Start the sampling profiler, defaults to false." }
]
},
{
@@ -49,7 +76,7 @@
"name": "trackingComplete",
"description": "When tracking is complete the backend will send any buffered data, such as profiling information.",
"parameters": [
- { "name": "profiles", "type": "array", "items": { "type": "any" }, "optional": true }
+ { "name": "samples", "$ref": "Samples", "optional": true, "description": "Stack traces." }
]
}
]
Modified: trunk/Source/_javascript_Core/jsc.cpp (195375 => 195376)
--- trunk/Source/_javascript_Core/jsc.cpp 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/jsc.cpp 2016-01-20 21:51:00 UTC (rev 195376)
@@ -1642,7 +1642,7 @@
EncodedJSValue JSC_HOST_CALL functionSamplingProfilerStackTraces(ExecState* exec)
{
RELEASE_ASSERT(exec->vm().samplingProfiler());
- String jsonString = exec->vm().samplingProfiler()->stacktracesAsJSON();
+ String jsonString = exec->vm().samplingProfiler()->stackTracesAsJSON();
exec->vm().samplingProfiler()->clearData();
EncodedJSValue result = JSValue::encode(JSONParse(exec, jsonString));
RELEASE_ASSERT(!exec->hadException());
Modified: trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp (195375 => 195376)
--- trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/runtime/SamplingProfiler.cpp 2016-01-20 21:51:00 UTC (rev 195376)
@@ -405,6 +405,12 @@
void SamplingProfiler::start()
{
LockHolder locker(m_lock);
+ start(locker);
+}
+
+void SamplingProfiler::start(const LockHolder& locker)
+{
+ ASSERT(m_lock.isLocked());
m_isActive = true;
dispatchIfNecessary(locker);
}
@@ -412,6 +418,12 @@
void SamplingProfiler::stop()
{
LockHolder locker(m_lock);
+ stop(locker);
+}
+
+void SamplingProfiler::stop(const LockHolder&)
+{
+ ASSERT(m_lock.isLocked());
m_isActive = false;
reportStats();
}
@@ -469,48 +481,143 @@
void SamplingProfiler::clearData()
{
LockHolder locker(m_lock);
+ clearData(locker);
+}
+
+void SamplingProfiler::clearData(const LockHolder&)
+{
+ ASSERT(m_lock.isLocked());
m_stackTraces.clear();
m_seenExecutables.clear();
m_indexOfNextStackTraceToVerify = 0;
}
-static String displayName(const SamplingProfiler::StackFrame& stackFrame)
+String SamplingProfiler::StackFrame::displayName()
{
- if (stackFrame.frameType == FrameType::Unknown)
- return ASCIILiteral("<unknown>");
- if (stackFrame.frameType == FrameType::Host)
- return ASCIILiteral("<host>");
- RELEASE_ASSERT(stackFrame.frameType != FrameType::UnverifiedCallee);
+ if (frameType == FrameType::Unknown)
+ return ASCIILiteral("(unknown)");
+ if (frameType == FrameType::Host)
+ return ASCIILiteral("(host)");
+ RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee);
- ExecutableBase* executable = stackFrame.u.verifiedExecutable;
+ ExecutableBase* executable = u.verifiedExecutable;
if (executable->isHostFunction())
- return ASCIILiteral("<host>");
+ return static_cast<NativeExecutable*>(executable)->name();
+ if (executable->isFunctionExecutable())
+ return static_cast<FunctionExecutable*>(executable)->inferredName().string();
+ if (executable->isProgramExecutable() || executable->isEvalExecutable())
+ return ASCIILiteral("(program)");
+ if (executable->isModuleProgramExecutable())
+ return ASCIILiteral("(module)");
+
+ RELEASE_ASSERT_NOT_REACHED();
+ return String();
+}
+
+String SamplingProfiler::StackFrame::displayNameForJSONTests()
+{
+ if (frameType == FrameType::Unknown)
+ return ASCIILiteral("(unknown)");
+ if (frameType == FrameType::Host)
+ return ASCIILiteral("(host)");
+ RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee);
+
+ ExecutableBase* executable = u.verifiedExecutable;
+ if (executable->isHostFunction())
+ return static_cast<NativeExecutable*>(executable)->name();
+
if (executable->isFunctionExecutable()) {
String result = static_cast<FunctionExecutable*>(executable)->inferredName().string();
- if (!result.isEmpty())
- return result;
- return ASCIILiteral("<anonymous-function>");
+ if (result.isEmpty())
+ return ASCIILiteral("(anonymous function)");
+ return result;
}
if (executable->isEvalExecutable())
- return ASCIILiteral("<eval>");
+ return ASCIILiteral("(eval)");
if (executable->isProgramExecutable())
- return ASCIILiteral("<global>");
+ return ASCIILiteral("(program)");
if (executable->isModuleProgramExecutable())
- return ASCIILiteral("<module>");
+ return ASCIILiteral("(module)");
RELEASE_ASSERT_NOT_REACHED();
- return "";
+ return String();
}
-String SamplingProfiler::stacktracesAsJSON()
+int SamplingProfiler::StackFrame::startLine()
{
- m_lock.lock();
+ if (frameType == FrameType::Unknown || frameType == FrameType::Host)
+ return -1;
+ RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee);
+
+ ExecutableBase* executable = u.verifiedExecutable;
+ if (executable->isHostFunction())
+ return -1;
+ return static_cast<ScriptExecutable*>(executable)->firstLine();
+}
+
+unsigned SamplingProfiler::StackFrame::startColumn()
+{
+ if (frameType == FrameType::Unknown || frameType == FrameType::Host)
+ return -1;
+ RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee);
+
+ ExecutableBase* executable = u.verifiedExecutable;
+ if (executable->isHostFunction())
+ return -1;
+
+ return static_cast<ScriptExecutable*>(executable)->startColumn();
+}
+
+intptr_t SamplingProfiler::StackFrame::sourceID()
+{
+ if (frameType == FrameType::Unknown || frameType == FrameType::Host)
+ return -1;
+ RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee);
+
+ ExecutableBase* executable = u.verifiedExecutable;
+ if (executable->isHostFunction())
+ return -1;
+
+ return static_cast<ScriptExecutable*>(executable)->sourceID();
+}
+
+String SamplingProfiler::StackFrame::url()
+{
+ if (frameType == FrameType::Unknown || frameType == FrameType::Host)
+ return emptyString();
+ RELEASE_ASSERT(frameType != FrameType::UnverifiedCallee);
+
+ ExecutableBase* executable = u.verifiedExecutable;
+ if (executable->isHostFunction())
+ return emptyString();
+
+ String url = ""
+ if (url.isEmpty())
+ return static_cast<ScriptExecutable*>(executable)->source().provider()->sourceURL(); // Fall back to sourceURL directive.
+ return url;
+}
+
+Vector<SamplingProfiler::StackTrace>& SamplingProfiler::stackTraces(const LockHolder&)
+{
+ ASSERT(m_lock.isLocked());
{
HeapIterationScope heapIterationScope(m_vm.heap);
processUnverifiedStackTraces();
}
+ return m_stackTraces;
+}
+
+String SamplingProfiler::stackTracesAsJSON()
+{
+ LockHolder locker(m_lock);
+
+ {
+ HeapIterationScope heapIterationScope(m_vm.heap);
+ processUnverifiedStackTraces();
+ }
+
StringBuilder json;
json.appendLiteral("[");
@@ -519,14 +626,14 @@
if (loopedOnce)
json.appendLiteral(",");
};
- for (const StackTrace& stackTrace : m_stackTraces) {
+ for (StackTrace& stackTrace : m_stackTraces) {
comma();
json.appendLiteral("[");
loopedOnce = false;
- for (const StackFrame& stackFrame : stackTrace.frames) {
+ for (StackFrame& stackFrame : stackTrace.frames) {
comma();
json.appendLiteral("\"");
- json.append(displayName(stackFrame));
+ json.append(stackFrame.displayNameForJSONTests());
json.appendLiteral("\"");
loopedOnce = true;
}
@@ -536,8 +643,6 @@
json.appendLiteral("]");
- m_lock.unlock();
-
return json.toString();
}
Modified: trunk/Source/_javascript_Core/runtime/SamplingProfiler.h (195375 => 195376)
--- trunk/Source/_javascript_Core/runtime/SamplingProfiler.h 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/runtime/SamplingProfiler.h 2016-01-20 21:51:00 UTC (rev 195376)
@@ -50,6 +50,7 @@
Host,
Unknown
};
+
struct StackFrame {
StackFrame(FrameType frameType, EncodedJSValue callee)
: frameType(frameType)
@@ -72,7 +73,15 @@
EncodedJSValue unverifiedCallee;
ExecutableBase* verifiedExecutable;
} u;
+
+ String displayName();
+ 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.
+ int startLine();
+ unsigned startColumn();
+ intptr_t sourceID();
+ String url();
};
+
struct StackTrace {
bool needsVerification;
double timestamp;
@@ -88,13 +97,18 @@
Lock& getLock() { return m_lock; }
void setTimingInterval(std::chrono::microseconds interval) { m_timingInterval = interval; }
JS_EXPORT_PRIVATE void start();
+ void start(const LockHolder&);
void stop();
- const Vector<StackTrace>& stackTraces() const { return m_stackTraces; }
- JS_EXPORT_PRIVATE String stacktracesAsJSON();
+ void stop(const LockHolder&);
+ Vector<StackTrace>& stackTraces(const LockHolder&);
+ JS_EXPORT_PRIVATE String stackTracesAsJSON();
JS_EXPORT_PRIVATE void noticeCurrentThreadAsJSCExecutionThread();
void noticeCurrentThreadAsJSCExecutionThread(const LockHolder&);
JS_EXPORT_PRIVATE void clearData();
+ void clearData(const LockHolder&);
void processUnverifiedStackTraces(); // You should call this only after acquiring the lock.
+ double totalTime(const LockHolder&) { return m_totalTime; }
+ void setStopWatch(const LockHolder&, Ref<Stopwatch>&& stopwatch) { m_stopwatch = WTFMove(stopwatch); }
private:
void dispatchIfNecessary(const LockHolder&);
Modified: trunk/Source/_javascript_Core/tests/stress/sampling-profiler/samplingProfiler.js (195375 => 195376)
--- trunk/Source/_javascript_Core/tests/stress/sampling-profiler/samplingProfiler.js 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/tests/stress/sampling-profiler/samplingProfiler.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -38,7 +38,7 @@
// stack trace should be top-down array with the deepest
// call frame at index 0.
if (isRunFromRunTest)
- stackTrace = [...stackTrace, "runTest", "<global>"];
+ stackTrace = [...stackTrace, "runTest", "(program)"];
else
stackTrace = [...stackTrace];
Modified: trunk/Source/_javascript_Core/tests/stress/sampling-profiler-anonymous-function.js (195375 => 195376)
--- trunk/Source/_javascript_Core/tests/stress/sampling-profiler-anonymous-function.js 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/tests/stress/sampling-profiler-anonymous-function.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -18,5 +18,5 @@
});
}
- runTest(baz, ["<anonymous-function>", "foo", "baz"]);
+ runTest(baz, ["(anonymous function)", "foo", "baz"]);
}
Modified: trunk/Source/_javascript_Core/tests/stress/sampling-profiler-basic.js (195375 => 195376)
--- trunk/Source/_javascript_Core/tests/stress/sampling-profiler-basic.js 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/_javascript_Core/tests/stress/sampling-profiler-basic.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -17,7 +17,7 @@
function nothing(x) { return x; }
noInline(nothing);
- runTest(foo, ["<host>", "bar", "foo"]);
+ runTest(foo, ["(host)", "bar", "foo"]);
function top() {
let x = 0;
Modified: trunk/Source/WebInspectorUI/ChangeLog (195375 => 195376)
--- trunk/Source/WebInspectorUI/ChangeLog 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/WebInspectorUI/ChangeLog 2016-01-20 21:51:00 UTC (rev 195376)
@@ -1,3 +1,48 @@
+2016-01-20 Saam barati <sbar...@apple.com>
+
+ Web Inspector: Hook the sampling profiler into the Timelines UI
+ https://bugs.webkit.org/show_bug.cgi?id=152766
+ <rdar://problem/24066360>
+
+ Reviewed by Joseph Pecoraro.
+
+ The main change in this patch is to swap in the SamplingProfiler
+ in place of the LegacyProfiler. To do this, we've created a data
+ structure called CallingContextTree which aggregates the SamplingProfiler's
+ data into an easy to manage tree. To see how the data structure works,
+ consider the following program:
+ ```
+ function bar() { // run code here for a long time. }
+ function baz() { // run code here for a long time. }
+ function foo() { bar(); baz(); }
+ foo();
+ ```
+ From this program, we will create a tree like this:
+ (program)
+ |
+ |
+ foo
+ | |
+ / \
+ / \
+ bar baz
+
+ From this type of tree, we can easily create a CPUProfile payload
+ object. Because the Timelines UI knows how to interact with the
+ CPUProfile object and display it, we currently map the tree to this object
+ to make it trivially easy to display the SamplingProfiler's data. In the future,
+ we may want to find ways to work directly with the CallingContextTree instead
+ of mapping it into another object.
+
+ * Localizations/en.lproj/localizedStrings.js:
+ * UserInterface/Controllers/TimelineManager.js:
+ * UserInterface/Main.html:
+ * UserInterface/Models/CallingContextTree.js: Added.
+ * UserInterface/Models/ScriptInstrument.js:
+ * UserInterface/Protocol/ScriptProfilerObserver.js:
+ * UserInterface/TestStub.html:
+ * UserInterface/Views/ScriptTimelineView.js:
+
2016-01-19 Joseph Pecoraro <pecor...@apple.com>
Web Inspector: Uncaught exception when logging an Error object
Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (195375 => 195376)
--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -544,6 +544,7 @@
localizedStrings["Reveal in Original Resource"] = "Reveal in Original Resource";
localizedStrings["Right"] = "Right";
localizedStrings["Role"] = "Role";
+localizedStrings["Samples"] = "Samples";
localizedStrings["Scheme"] = "Scheme";
localizedStrings["Scope Chain"] = "Scope Chain";
localizedStrings["Script"] = "Script";
Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (195375 => 195376)
--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -45,6 +45,8 @@
this._webTimelineScriptRecordsExpectingScriptProfilerEvents = null;
this._scriptProfilerRecords = null;
+ this._callingContextTree = null;
+
this.reset();
}
@@ -682,15 +684,23 @@
this._addRecord(record);
}
- scriptProfilerTrackingCompleted(profiles)
+ scriptProfilerTrackingCompleted(samples)
{
console.assert(!this._webTimelineScriptRecordsExpectingScriptProfilerEvents || this._scriptProfilerRecords.length >= this._webTimelineScriptRecordsExpectingScriptProfilerEvents.length);
- // Associate the profiles with the ScriptProfiler created records.
- if (profiles) {
- console.assert(this._scriptProfilerRecords.length === profiles.length, this._scriptProfilerRecords.length, profiles.length);
- for (let i = 0; i < this._scriptProfilerRecords.length; ++i)
- this._scriptProfilerRecords[i].profilePayload = profiles[i];
+ if (samples) {
+ if (!this._callingContextTree)
+ this._callingContextTree = new WebInspector.CallingContextTree;
+
+ // Associate the stackTraces with the ScriptProfiler created records.
+ let stackTraces = samples.stackTraces;
+ for (let i = 0; i < stackTraces.length; i++)
+ this._callingContextTree.updateTreeWithStackTrace(stackTraces[i]);
+
+ for (let i = 0; i < this._scriptProfilerRecords.length; ++i) {
+ let record = this._scriptProfilerRecords[i];
+ record.profilePayload = this._callingContextTree.toCPUProfilePayload(record.startTime, record.endTime);
+ }
}
// Associate the ScriptProfiler created records with Web Timeline records.
Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (195375 => 195376)
--- trunk/Source/WebInspectorUI/UserInterface/Main.html 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -269,6 +269,7 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
<script src=""
<script src=""
<script src=""
Added: trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js (0 => 195376)
--- trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.CallingContextTree = class CallingContextTree extends WebInspector.Object
+{
+ constructor()
+ {
+ super();
+
+ this._root = new WebInspector.CCTNode(-1, -1, -1, "<root>", null);
+ this._totalNumberOfSamples = 0;
+ }
+
+ // Public
+
+ get totalNumberOfSamples() { return this._totalNumberOfSamples; }
+
+ updateTreeWithStackTrace({timestamp, stackFrames})
+ {
+ this._totalNumberOfSamples++;
+ let node = this._root;
+ node.addTimestamp(timestamp);
+ for (let i = stackFrames.length; i--; ) {
+ let stackFrame = stackFrames[i];
+ node = node.findOrMakeChild(stackFrame);
+ node.addTimestamp(timestamp);
+ }
+ }
+
+ toCPUProfilePayload(startTime, endTime)
+ {
+ let cpuProfile = {};
+ let roots = [];
+ let numSamplesInTimeRange = this._root.filteredTimestamps(startTime, endTime).length;
+
+ this._root.forEachChild((child) => {
+ if (child.hasStackTraceInTimeRange(startTime, endTime))
+ roots.push(child.toCPUProfileNode(numSamplesInTimeRange, startTime, endTime));
+ });
+
+ cpuProfile.rootNodes = roots;
+ return cpuProfile;
+ }
+
+ forEachNode(callback)
+ {
+ this._root.forEachNode(callback);
+ }
+
+ // Testing.
+
+ static __test_makeTreeFromProtocolMessageObject(messageObject)
+ {
+ let tree = new WebInspector.CallingContextTree;
+ let stackTraces = messageObject.params.samples.stackTraces;
+ for (let i = 0; i < stackTraces.length; i++)
+ tree.updateTreeWithStackTrace(stackTraces[i]);
+ return tree;
+ }
+
+ __test_matchesStackTrace(stackTrace)
+ {
+ // StackTrace should have top frame first in the array and bottom frame last.
+ // We don't look for a match that traces down the tree from the root; instead,
+ // we match by looking at all the leafs, and matching while walking up the tree
+ // towards the root. If we successfully make the walk, we've got a match that
+ // suffices for a particular test. A successful match doesn't mean we actually
+ // walk all the way up to the root; it just means we didn't fail while walking
+ // in the direction of the root.
+ let leaves = this.__test_buildLeafLinkedLists();
+
+ outer:
+ for (let node of leaves) {
+ for (let stackNode of stackTrace) {
+ for (let propertyName of Object.getOwnPropertyNames(stackNode)) {
+ if (stackNode[propertyName] !== node[propertyName])
+ continue outer;
+ }
+ node = node.parent;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ __test_buildLeafLinkedLists()
+ {
+ let result = [];
+ let parent = null;
+ this._root.__test_buildLeafLinkedLists(parent, result);
+ return result;
+ }
+};
+
+WebInspector.CCTNode = class CCTNode extends WebInspector.Object
+{
+ constructor(sourceID, line, column, name, url)
+ {
+ super();
+
+ this._children = {};
+ this._sourceID = sourceID;
+ this._line = line;
+ this._column = column;
+ this._name = name;
+ this._url = url;
+ this._timestamps = [];
+ this._uid = WebInspector.CCTNode.__uid++;
+ }
+
+ // Static and Private
+
+ static _hash(stackFrame)
+ {
+ return stackFrame.name + ":" + stackFrame.sourceID + ":" + stackFrame.line + ":" + stackFrame.column;
+ }
+
+ // Public
+
+ get sourceID() { return this._sourceID; }
+ get line() { return this._line; }
+ get column() { return this._column; }
+ get name() { return this._name; }
+ get uid() { return this._uid; }
+ get url() { return this._url; }
+
+ hasStackTraceInTimeRange(startTime, endTime)
+ {
+ console.assert(startTime <= endTime);
+ if (startTime > endTime)
+ return false;
+
+ let timestamps = this._timestamps;
+ let length = timestamps.length;
+ if (!length)
+ return false;
+
+ let index = timestamps.lowerBound(startTime);
+ if (index === length)
+ return false;
+ console.assert(startTime <= timestamps[index]);
+
+ let hasTimestampInRange = timestamps[index] <= endTime;
+ return hasTimestampInRange;
+ }
+
+ filteredTimestamps(startTime, endTime)
+ {
+ let index = this._timestamps.lowerBound(startTime); // The left-most (smallest) item that is >= startTime.
+ let result = [];
+ for (; index < this._timestamps.length; index++) {
+ let timestamp = this._timestamps[index];
+ console.assert(startTime <= timestamp);
+ if (!(timestamp <= endTime))
+ break;
+ result.push(timestamp);
+ }
+ return result;
+ }
+
+ hasChildren()
+ {
+ return !!Object.getOwnPropertyNames(this._children).length;
+ }
+
+ findOrMakeChild(stackFrame)
+ {
+ let hash = WebInspector.CCTNode._hash(stackFrame);
+ let node = this._children[hash];
+ if (node)
+ return node;
+ node = new WebInspector.CCTNode(stackFrame.sourceID, stackFrame.line, stackFrame.column, stackFrame.name, stackFrame.url);
+ this._children[hash] = node;
+ return node;
+ }
+
+ addTimestamp(timestamp)
+ {
+ console.assert(!this._timestamps.length || this._timestamps.lastValue <= timestamp, "Expected timestamps to be added in sorted, increasing, order.");
+ this._timestamps.push(timestamp);
+ }
+
+ forEachChild(callback)
+ {
+ for (let propertyName of Object.getOwnPropertyNames(this._children))
+ callback(this._children[propertyName]);
+ }
+
+ forEachNode(callback)
+ {
+ callback(this);
+ this.forEachChild(function(child) {
+ child.forEachNode(callback);
+ });
+ }
+
+ toCPUProfileNode(numSamples, startTime, endTime)
+ {
+ let children = [];
+ this.forEachChild((child) => {
+ if (child.hasStackTraceInTimeRange(startTime, endTime))
+ children.push(child.toCPUProfileNode(numSamples, startTime, endTime));
+ });
+ let cpuProfileNode = {
+ id: this._uid,
+ functionName: this._name,
+ url: this._url,
+ lineNumber: this._line,
+ columnNumber: this._column,
+ children: children
+ };
+
+ let timestamps = [];
+ let frameStartTime = Number.MAX_VALUE;
+ let frameEndTime = Number.MIN_VALUE;
+ for (let i = 0; i < this._timestamps.length; i++) {
+ let timestamp = this._timestamps[i];
+ if (startTime <= timestamp && timestamp <= endTime) {
+ timestamps.push(timestamp);
+ frameStartTime = Math.min(frameStartTime, timestamp);
+ frameEndTime = Math.max(frameEndTime, timestamp);
+ }
+ }
+
+ cpuProfileNode.callInfo = {
+ callCount: timestamps.length, // Totally not callCount, but oh well, this makes life easier because of field names.
+ startTime: frameStartTime,
+ endTime: frameEndTime,
+ totalTime: (timestamps.length / numSamples) * (endTime - startTime)
+ };
+
+ return cpuProfileNode;
+ }
+
+ // Testing.
+
+ __test_buildLeafLinkedLists(parent, result)
+ {
+ let linkedListNode = {
+ name: this._name,
+ url: this._url,
+ parent: parent
+ };
+ if (this.hasChildren()) {
+ this.forEachChild((child) => {
+ child.__test_buildLeafLinkedLists(linkedListNode, result);
+ });
+ } else {
+ // We're a leaf.
+ result.push(linkedListNode);
+ }
+ }
+};
+
+WebInspector.CCTNode.__uid = 0;
+
Modified: trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js (195375 => 195376)
--- trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/ScriptInstrument.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -41,9 +41,9 @@
}
// FIXME: Make this some UI visible option.
- const includeProfiles = true;
+ const includeSamples = true;
- ScriptProfilerAgent.startTracking(includeProfiles);
+ ScriptProfilerAgent.startTracking(includeSamples);
}
stopInstrumentation()
Modified: trunk/Source/WebInspectorUI/UserInterface/Protocol/ScriptProfilerObserver.js (195375 => 195376)
--- trunk/Source/WebInspectorUI/UserInterface/Protocol/ScriptProfilerObserver.js 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/WebInspectorUI/UserInterface/Protocol/ScriptProfilerObserver.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -37,8 +37,8 @@
WebInspector.timelineManager.scriptProfilerTrackingUpdated(event);
}
- trackingComplete(profiles)
+ trackingComplete(samples)
{
- WebInspector.timelineManager.scriptProfilerTrackingCompleted(profiles);
+ WebInspector.timelineManager.scriptProfilerTrackingCompleted(samples);
}
};
Modified: trunk/Source/WebInspectorUI/UserInterface/TestStub.html (195375 => 195376)
--- trunk/Source/WebInspectorUI/UserInterface/TestStub.html 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/WebInspectorUI/UserInterface/TestStub.html 2016-01-20 21:51:00 UTC (rev 195376)
@@ -33,7 +33,10 @@
<script src=""
<script src=""
<script src=""
+ <script src=""
+ <script src=""
+
<script src=""
<script src=""
<script src=""
Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js (195375 => 195376)
--- trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js 2016-01-20 21:49:09 UTC (rev 195375)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScriptTimelineView.js 2016-01-20 21:51:00 UTC (rev 195376)
@@ -38,7 +38,13 @@
columns.location.title = WebInspector.UIString("Location");
columns.location.width = "15%";
- columns.callCount.title = WebInspector.UIString("Calls");
+ let isSamplingProfiler = !!window.ScriptProfilerAgent;
+ if (isSamplingProfiler)
+ columns.callCount.title = WebInspector.UIString("Samples");
+ else {
+ // COMPATIBILITY(iOS 9): ScriptProfilerAgent did not exist yet, we had call counts, not samples.
+ columns.callCount.title = WebInspector.UIString("Calls");
+ }
columns.callCount.width = "5%";
columns.callCount.aligned = "right";