Title: [195376] trunk
Revision
195376
Author
sbar...@apple.com
Date
2016-01-20 13:51:00 -0800 (Wed, 20 Jan 2016)

Log Message

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.

Source/_javascript_Core:

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):

Source/WebInspectorUI:

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:

LayoutTests:

* 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:

Modified Paths

Added Paths

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";
 
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to