<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[202010] trunk/Source/WebInspectorUI</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/202010">202010</a></dd>
<dt>Author</dt> <dd>sbarati@apple.com</dd>
<dt>Date</dt> <dd>2016-06-13 15:43:20 -0700 (Mon, 13 Jun 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Call Trees view should have a 'Top Functions'-like mode
https://bugs.webkit.org/show_bug.cgi?id=158555
&lt;rdar://problem/26712544&gt;

Reviewed by Timothy Hatcher.

This patch adds a Top Functions view that is similar to Instruments'
Top Functions view. I really wanted to add this view because I've
been doing a lot of performance debugging and I've exclusively
used the Top Functions view and I want the Inspector to also have
this view. I like to think of it as a more sophisticated version of the bottom-up view.

Top Functions works by treating every frame as a root in the tree.
Top functions view then presents a list of &quot;roots&quot;. This is the same
as all other views, which also present a list of roots, but in this case,
every frame is a root. Bottom Up is great for nailing in specific performance
problems in exactly one frame. But Bottom Up doesn't give you good context about where
a specific frame is in the call tree and how frames are related by having
a caller or some path of shared callers. For example, consider this call tree:
         (program)
         /        \
        /          \
   (many nodes...)
      /
     /
    (parent)
    /   \
   /     \
 (leaf1)  (leaf2)

Suppose that 'leaf1' is super hot, and 'leaf2' is moderately hot.
If we look at this through Bottom Up view, we will see 'leaf1'
is super hot, but it will take more scrolling to see that 'leaf2'
is moderately hot. Lets say that 'parent' is also moderately hot,
but that the majority of its time isn't self time. With Bottom Up view,
there is no good way to see that 'leaf1' and 'leaf2' are both nodes under 'parent'.
With Top Down, you can find this information, but it requires a ton of drilling down into
the tree (i.e, you must expand past the 'many nodes...' I drew above). It's inconvenient to
use Top Down here for indentation alone. Bottom up will tell you that 'leaf1' is super hot,
and that 'leaf2' and 'parent' are moderately hot, but it doesn't show how they're related
in the original tree. It's important to see that 'parent's total time is very high
because it itself is moderately hot, and it has a child node that is super hot, and
another child that's moderately 'hot'. For the sake of this example, let's pretend
that 85% of the program's time is spent inside 'parent'. Seeing this information through
'Top Functions' is easy because this information filters to the top of the list. Specifically,
when using 'Top Functions' sorted by Total Time. Because every node is a root, there will be
a top-level entry for every frame in the program. Specifically, there will be a top-level node
for 'parent' in my above example. Because I've sorted this view by Total Time, I will see '(program)'
first. That's because 100% of execution time is under the '(program)' frame. Then, I might see
a few other nodes that also run the entire time because '(program)' calls them, and they eventually
call into other things that never leave the stack. These will also have time ranges near 100%.
But, only a few nodes after that, I'll see 'parent' in the list because it accounts for 85% of
execution time. Immediately, I will see that it has some self time, and that it has two child
nodes that have self time. This is really helpful.

Let's consider another example where it's not easy in Top Down to get the full picture of 'parent':
           (program)
            /  |  \
         (... many nodes...)
          /           \
    (many nodes...)   (many nodes...)
         /             \
       parent         parent
         |              |
        leaf1          leaf2

If we viewed this program in Top Down, we don't get a full picture of 'parent'
because it has its time distributed in two different subsections of the tree.
Specifically, lets say it has 70% of time in the leaf1 path, and 30% of the
time in the leaf2 path. We want a way to see these things together. It's impossible
to do this in Top Down or Bottom Up. But, in Top Functions view, we get the view that
we want to see because we treat 'parent' as a root of the tree. Because we do this,
we will create the following sub tree in the Top Functions view:
        parent
       /      \
     leaf1   leaf2
This happens naturally because when 'parent' is a root, we add all its children
to its subtree.

Constructing this tree is really easy. What we do is take any arbitrary stack
trace of length n, and treat is as n separate stack traces. Specifically, we
perform the following operation for any stack trace S.

S = [A, B, C, D]
(A is the entry frame, and D is the top of the stack).
We will transform this into a list of stack traces S' like so:
S' = [[A, B, C, D], [B, C, D], [C, D], [D]]

If we then run the normal top down tree algorithm on this set of stack
traces, all nodes get treated as roots, and voila, we get the Top Functions view.

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Controllers/TimelineManager.js:
* UserInterface/Main.html:
* UserInterface/Models/CallingContextTree.js:
* UserInterface/Models/TimelineRecording.js:
* UserInterface/Views/ScriptProfileTimelineView.js:
* UserInterface/Views/TextToggleButtonNavigationItem.css: Added.
* UserInterface/Views/TextToggleButtonNavigationItem.js: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs">trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersTimelineManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceMainhtml">trunk/Source/WebInspectorUI/UserInterface/Main.html</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsCallingContextTreejs">trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsTimelineRecordingjs">trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsScriptProfileTimelineViewjs">trunk/Source/WebInspectorUI/UserInterface/Views/ScriptProfileTimelineView.js</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTextToggleButtonNavigationItemcss">trunk/Source/WebInspectorUI/UserInterface/Views/TextToggleButtonNavigationItem.css</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsTextToggleButtonNavigationItemjs">trunk/Source/WebInspectorUI/UserInterface/Views/TextToggleButtonNavigationItem.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (202009 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog        2016-06-13 22:41:54 UTC (rev 202009)
+++ trunk/Source/WebInspectorUI/ChangeLog        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -1,3 +1,106 @@
</span><ins>+2016-06-13  Saam Barati  &lt;sbarati@apple.com&gt;
+
+        Web Inspector: Call Trees view should have a 'Top Functions'-like mode
+        https://bugs.webkit.org/show_bug.cgi?id=158555
+        &lt;rdar://problem/26712544&gt;
+
+        Reviewed by Timothy Hatcher.
+
+        This patch adds a Top Functions view that is similar to Instruments'
+        Top Functions view. I really wanted to add this view because I've
+        been doing a lot of performance debugging and I've exclusively 
+        used the Top Functions view and I want the Inspector to also have
+        this view. I like to think of it as a more sophisticated version of the bottom-up view.
+        
+        Top Functions works by treating every frame as a root in the tree.
+        Top functions view then presents a list of &quot;roots&quot;. This is the same
+        as all other views, which also present a list of roots, but in this case,
+        every frame is a root. Bottom Up is great for nailing in specific performance
+        problems in exactly one frame. But Bottom Up doesn't give you good context about where
+        a specific frame is in the call tree and how frames are related by having
+        a caller or some path of shared callers. For example, consider this call tree:
+                 (program)
+                 /        \
+                /          \
+           (many nodes...)  
+              / 
+             /
+            (parent)
+            /   \
+           /     \
+         (leaf1)  (leaf2)
+        
+        Suppose that 'leaf1' is super hot, and 'leaf2' is moderately hot.
+        If we look at this through Bottom Up view, we will see 'leaf1'
+        is super hot, but it will take more scrolling to see that 'leaf2'
+        is moderately hot. Lets say that 'parent' is also moderately hot,
+        but that the majority of its time isn't self time. With Bottom Up view,
+        there is no good way to see that 'leaf1' and 'leaf2' are both nodes under 'parent'.
+        With Top Down, you can find this information, but it requires a ton of drilling down into
+        the tree (i.e, you must expand past the 'many nodes...' I drew above). It's inconvenient to
+        use Top Down here for indentation alone. Bottom up will tell you that 'leaf1' is super hot,
+        and that 'leaf2' and 'parent' are moderately hot, but it doesn't show how they're related
+        in the original tree. It's important to see that 'parent's total time is very high
+        because it itself is moderately hot, and it has a child node that is super hot, and
+        another child that's moderately 'hot'. For the sake of this example, let's pretend
+        that 85% of the program's time is spent inside 'parent'. Seeing this information through
+        'Top Functions' is easy because this information filters to the top of the list. Specifically,
+        when using 'Top Functions' sorted by Total Time. Because every node is a root, there will be
+        a top-level entry for every frame in the program. Specifically, there will be a top-level node
+        for 'parent' in my above example. Because I've sorted this view by Total Time, I will see '(program)'
+        first. That's because 100% of execution time is under the '(program)' frame. Then, I might see
+        a few other nodes that also run the entire time because '(program)' calls them, and they eventually
+        call into other things that never leave the stack. These will also have time ranges near 100%.
+        But, only a few nodes after that, I'll see 'parent' in the list because it accounts for 85% of
+        execution time. Immediately, I will see that it has some self time, and that it has two child
+        nodes that have self time. This is really helpful.
+        
+        Let's consider another example where it's not easy in Top Down to get the full picture of 'parent':
+                   (program)
+                    /  |  \
+                 (... many nodes...)
+                  /           \
+            (many nodes...)   (many nodes...)
+                 /             \
+               parent         parent
+                 |              |
+                leaf1          leaf2
+        
+        
+        If we viewed this program in Top Down, we don't get a full picture of 'parent'
+        because it has its time distributed in two different subsections of the tree.
+        Specifically, lets say it has 70% of time in the leaf1 path, and 30% of the
+        time in the leaf2 path. We want a way to see these things together. It's impossible
+        to do this in Top Down or Bottom Up. But, in Top Functions view, we get the view that
+        we want to see because we treat 'parent' as a root of the tree. Because we do this,
+        we will create the following sub tree in the Top Functions view:
+                parent
+               /      \
+             leaf1   leaf2
+        This happens naturally because when 'parent' is a root, we add all its children
+        to its subtree.
+        
+        Constructing this tree is really easy. What we do is take any arbitrary stack
+        trace of length n, and treat is as n separate stack traces. Specifically, we
+        perform the following operation for any stack trace S.
+        
+        S = [A, B, C, D]
+        (A is the entry frame, and D is the top of the stack).
+        We will transform this into a list of stack traces S' like so:
+        S' = [[A, B, C, D], [B, C, D], [C, D], [D]]
+        
+        If we then run the normal top down tree algorithm on this set of stack
+        traces, all nodes get treated as roots, and voila, we get the Top Functions view.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Controllers/TimelineManager.js:
+        * UserInterface/Main.html:
+        * UserInterface/Models/CallingContextTree.js:
+        * UserInterface/Models/TimelineRecording.js:
+        * UserInterface/Views/ScriptProfileTimelineView.js:
+        * UserInterface/Views/TextToggleButtonNavigationItem.css: Added.
+        * UserInterface/Views/TextToggleButtonNavigationItem.js: Added.
+
</ins><span class="cx"> 2016-06-13  Matt Baker  &lt;mattbaker@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Web Inspector: Add ability to show/hide DataGird columns
</span></span></pre></div>
<a id="trunkSourceWebInspectorUILocalizationsenlprojlocalizedStringsjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js (202009 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js        2016-06-13 22:41:54 UTC (rev 202009)
+++ trunk/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -104,7 +104,6 @@
</span><span class="cx"> localizedStrings[&quot;Blur&quot;] = &quot;Blur&quot;;
</span><span class="cx"> localizedStrings[&quot;Border&quot;] = &quot;Border&quot;;
</span><span class="cx"> localizedStrings[&quot;Bottom&quot;] = &quot;Bottom&quot;;
</span><del>-localizedStrings[&quot;Bottom Up&quot;] = &quot;Bottom Up&quot;;
</del><span class="cx"> localizedStrings[&quot;Boundary&quot;] = &quot;Boundary&quot;;
</span><span class="cx"> localizedStrings[&quot;Box Model&quot;] = &quot;Box Model&quot;;
</span><span class="cx"> localizedStrings[&quot;Box Shadow&quot;] = &quot;Box Shadow&quot;;
</span><span class="lines">@@ -398,6 +397,7 @@
</span><span class="cx"> localizedStrings[&quot;Inset&quot;] = &quot;Inset&quot;;
</span><span class="cx"> localizedStrings[&quot;Instances&quot;] = &quot;Instances&quot;;
</span><span class="cx"> localizedStrings[&quot;Invalid&quot;] = &quot;Invalid&quot;;
</span><ins>+localizedStrings[&quot;Inverted&quot;] = &quot;Inverted&quot;;
</ins><span class="cx"> localizedStrings[&quot;Invoke getter&quot;] = &quot;Invoke getter&quot;;
</span><span class="cx"> localizedStrings[&quot;Iterations&quot;] = &quot;Iterations&quot;;
</span><span class="cx"> localizedStrings[&quot;JavaScript&quot;] = &quot;JavaScript&quot;;
</span><span class="lines">@@ -713,7 +713,7 @@
</span><span class="cx"> localizedStrings[&quot;Timing&quot;] = &quot;Timing&quot;;
</span><span class="cx"> localizedStrings[&quot;Toggle Classes&quot;] = &quot;Toggle Classes&quot;;
</span><span class="cx"> localizedStrings[&quot;Top&quot;] = &quot;Top&quot;;
</span><del>-localizedStrings[&quot;Top Down&quot;] = &quot;Top Down&quot;;
</del><ins>+localizedStrings[&quot;Top Functions&quot;] = &quot;Top Functions&quot;;
</ins><span class="cx"> localizedStrings[&quot;Total Time&quot;] = &quot;Total Time&quot;;
</span><span class="cx"> localizedStrings[&quot;Total memory size at the end of the selected time range&quot;] = &quot;Total memory size at the end of the selected time range&quot;;
</span><span class="cx"> localizedStrings[&quot;Total number of resources, click to show the Resources tab&quot;] = &quot;Total number of resources, click to show the Resources tab&quot;;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersTimelineManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js (202009 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js        2016-06-13 22:41:54 UTC (rev 202009)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/TimelineManager.js        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -865,6 +865,8 @@
</span><span class="cx">             let {stackTraces} = samples;
</span><span class="cx">             let topDownCallingContextTree = this.activeRecording.topDownCallingContextTree;
</span><span class="cx">             let bottomUpCallingContextTree = this.activeRecording.bottomUpCallingContextTree;
</span><ins>+            let topFunctionsTopDownCallingContextTree = this.activeRecording.topFunctionsTopDownCallingContextTree;
+            let topFunctionsBottomUpCallingContextTree = this.activeRecording.topFunctionsBottomUpCallingContextTree;
</ins><span class="cx"> 
</span><span class="cx">             // Calculate a per-sample duration.
</span><span class="cx">             let timestampIndex = 0;
</span><span class="lines">@@ -901,6 +903,8 @@
</span><span class="cx">             for (let i = 0; i &lt; stackTraces.length; i++) {
</span><span class="cx">                 topDownCallingContextTree.updateTreeWithStackTrace(stackTraces[i], sampleDurations[i]);
</span><span class="cx">                 bottomUpCallingContextTree.updateTreeWithStackTrace(stackTraces[i], sampleDurations[i]);
</span><ins>+                topFunctionsTopDownCallingContextTree.updateTreeWithStackTrace(stackTraces[i], sampleDurations[i]);
+                topFunctionsBottomUpCallingContextTree.updateTreeWithStackTrace(stackTraces[i], sampleDurations[i]);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             // FIXME: This transformation should not be needed after introducing ProfileView.
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceMainhtml"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Main.html (202009 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Main.html        2016-06-13 22:41:54 UTC (rev 202009)
+++ trunk/Source/WebInspectorUI/UserInterface/Main.html        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -161,6 +161,7 @@
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TextEditor.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TextNavigationItem.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TextResourceContentView.css&quot;&gt;
</span><ins>+    &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TextToggleButtonNavigationItem.css&quot;&gt;
</ins><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineDataGrid.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineIcons.css&quot;&gt;
</span><span class="cx">     &lt;link rel=&quot;stylesheet&quot; href=&quot;Views/TimelineOverview.css&quot;&gt;
</span><span class="lines">@@ -629,6 +630,7 @@
</span><span class="cx">     &lt;script src=&quot;Views/TimelineRecordingProgressView.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/TimelineRuler.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/ToggleButtonNavigationItem.js&quot;&gt;&lt;/script&gt;
</span><ins>+    &lt;script src=&quot;Views/TextToggleButtonNavigationItem.js&quot;&gt;&lt;/script&gt;
</ins><span class="cx">     &lt;script src=&quot;Views/ToggleControlToolbarItem.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/Toolbar.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;Views/TreeElementStatusButton.js&quot;&gt;&lt;/script&gt;
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsCallingContextTreejs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js (202009 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js        2016-06-13 22:41:54 UTC (rev 202009)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/CallingContextTree.js        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -63,12 +63,31 @@
</span><span class="cx">                 node = node.findOrMakeChild(stackFrame);
</span><span class="cx">                 node.addTimestampAndExpressionLocation(timestamp, duration, stackFrame.expressionLocation || null, i === 0);
</span><span class="cx">             }
</span><del>-        } else {
</del><ins>+        } else if (this._type === WebInspector.CallingContextTree.Type.BottomUp) {
</ins><span class="cx">             for (let i = 0; i &lt; stackFrames.length; ++i) {
</span><span class="cx">                 let stackFrame = stackFrames[i];
</span><span class="cx">                 node = node.findOrMakeChild(stackFrame);
</span><span class="cx">                 node.addTimestampAndExpressionLocation(timestamp, duration, stackFrame.expressionLocation || null, i === 0);
</span><span class="cx">             }
</span><ins>+        } else if (this._type === WebInspector.CallingContextTree.Type.TopFunctionsTopDown){
+            for (let i = stackFrames.length; i--; ) {
+                node = this._root;
+                for (let j = i + 1; j--; ) {
+                    let stackFrame = stackFrames[j];
+                    node = node.findOrMakeChild(stackFrame);
+                    node.addTimestampAndExpressionLocation(timestamp, duration, stackFrame.expressionLocation || null, j === 0);
+                }
+            }
+        } else {
+            console.assert(this._type === WebInspector.CallingContextTree.Type.TopFunctionsBottomUp);
+            for (let i = 0; i &lt; stackFrames.length; i++) {
+                node = this._root;
+                for (let j = i; j &lt; stackFrames.length; j++) {
+                    let stackFrame = stackFrames[j];
+                    node = node.findOrMakeChild(stackFrame);
+                    node.addTimestampAndExpressionLocation(timestamp, duration, stackFrame.expressionLocation || null, j === 0);
+                }
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -362,4 +381,6 @@
</span><span class="cx"> WebInspector.CallingContextTree.Type = {
</span><span class="cx">     TopDown: Symbol(&quot;TopDown&quot;),
</span><span class="cx">     BottomUp: Symbol(&quot;BottomUp&quot;),
</span><ins>+    TopFunctionsTopDown: Symbol(&quot;TopFunctionsTopDown&quot;),
+    TopFunctionsBottomUp: Symbol(&quot;TopFunctionsTopDown&quot;),
</ins><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsTimelineRecordingjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js (202009 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js        2016-06-13 22:41:54 UTC (rev 202009)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/TimelineRecording.js        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -37,6 +37,8 @@
</span><span class="cx">         this._instruments = instruments || [];
</span><span class="cx">         this._topDownCallingContextTree = new WebInspector.CallingContextTree(WebInspector.CallingContextTree.Type.TopDown);
</span><span class="cx">         this._bottomUpCallingContextTree = new WebInspector.CallingContextTree(WebInspector.CallingContextTree.Type.BottomUp);
</span><ins>+        this._topFunctionsTopDownCallingContextTree = new WebInspector.CallingContextTree(WebInspector.CallingContextTree.Type.TopFunctionsTopDown);
+        this._topFunctionsBottomUpCallingContextTree = new WebInspector.CallingContextTree(WebInspector.CallingContextTree.Type.TopFunctionsBottomUp);
</ins><span class="cx"> 
</span><span class="cx">         for (let type of WebInspector.TimelineManager.availableTimelineTypes()) {
</span><span class="cx">             let timeline = WebInspector.Timeline.create(type);
</span><span class="lines">@@ -104,6 +106,16 @@
</span><span class="cx">         return this._bottomUpCallingContextTree;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    get topFunctionsTopDownCallingContextTree()
+    {
+        return this._topFunctionsTopDownCallingContextTree;
+    }
+
+    get topFunctionsBottomUpCallingContextTree()
+    {
+        return this._topFunctionsBottomUpCallingContextTree;
+    }
+
</ins><span class="cx">     start()
</span><span class="cx">     {
</span><span class="cx">         console.assert(!this._capturing, &quot;Attempted to start an already started session.&quot;);
</span><span class="lines">@@ -163,6 +175,8 @@
</span><span class="cx"> 
</span><span class="cx">         this._topDownCallingContextTree.reset();
</span><span class="cx">         this._bottomUpCallingContextTree.reset();
</span><ins>+        this._topFunctionsTopDownCallingContextTree.reset();
+        this._topFunctionsBottomUpCallingContextTree.reset();
</ins><span class="cx"> 
</span><span class="cx">         for (var timeline of this._timelines.values())
</span><span class="cx">             timeline.reset(suppressEvents);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsScriptProfileTimelineViewjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/ScriptProfileTimelineView.js (202009 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/ScriptProfileTimelineView.js        2016-06-13 22:41:54 UTC (rev 202009)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/ScriptProfileTimelineView.js        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -41,22 +41,30 @@
</span><span class="cx"> 
</span><span class="cx">         if (!WebInspector.ScriptProfileTimelineView.profileOrientationSetting)
</span><span class="cx">             WebInspector.ScriptProfileTimelineView.profileOrientationSetting = new WebInspector.Setting(&quot;script-profile-timeline-view-profile-orientation-setting&quot;, WebInspector.ScriptProfileTimelineView.ProfileOrientation.TopDown);
</span><ins>+        if (!WebInspector.ScriptProfileTimelineView.profileTypeSetting)
+            WebInspector.ScriptProfileTimelineView.profileTypeSetting = new WebInspector.Setting(&quot;script-profile-timeline-view-profile-type-setting&quot;, WebInspector.ScriptProfileTimelineView.ProfileViewType.Hierarchy);
</ins><span class="cx"> 
</span><del>-        this._showProfileViewForOrientation(WebInspector.ScriptProfileTimelineView.profileOrientationSetting.value);
</del><ins>+        this._showProfileViewForOrientation(WebInspector.ScriptProfileTimelineView.profileOrientationSetting.value, WebInspector.ScriptProfileTimelineView.profileTypeSetting.value);
</ins><span class="cx"> 
</span><del>-        let scopeBarItems = [
-            new WebInspector.ScopeBarItem(WebInspector.ScriptProfileTimelineView.ProfileOrientation.TopDown, WebInspector.UIString(&quot;Top Down&quot;), true),
-            new WebInspector.ScopeBarItem(WebInspector.ScriptProfileTimelineView.ProfileOrientation.BottomUp, WebInspector.UIString(&quot;Bottom Up&quot;), true),
-        ];
-        let defaultScopeBarItem = WebInspector.ScriptProfileTimelineView.profileOrientationSetting.value === WebInspector.ScriptProfileTimelineView.ProfileOrientation.TopDown ? scopeBarItems[0] : scopeBarItems[1];
-        this._profileOrientationScopeBar = new WebInspector.ScopeBar(&quot;profile-orientation&quot;, scopeBarItems, defaultScopeBarItem);
-        this._profileOrientationScopeBar.addEventListener(WebInspector.ScopeBar.Event.SelectionChanged, this._scopeBarSelectionDidChange, this);
-
</del><span class="cx">         let clearTooltip = WebInspector.UIString(&quot;Clear focus&quot;);
</span><span class="cx">         this._clearFocusNodesButtonItem = new WebInspector.ButtonNavigationItem(&quot;clear-profile-focus&quot;, clearTooltip, &quot;Images/Close.svg&quot;, 16, 16);
</span><span class="cx">         this._clearFocusNodesButtonItem.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._clearFocusNodes, this);
</span><span class="cx">         this._updateClearFocusNodesButtonItem();
</span><span class="cx"> 
</span><ins>+        this._profileOrientationButton = new WebInspector.TextToggleButtonNavigationItem(&quot;profile-orientation&quot;, WebInspector.UIString(&quot;Inverted&quot;));
+        this._profileOrientationButton.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._profileOrientationButtonClicked, this);
+        if (WebInspector.ScriptProfileTimelineView.profileOrientationSetting.value == WebInspector.ScriptProfileTimelineView.ProfileOrientation.TopDown)
+            this._profileOrientationButton.activated = false;
+        else
+            this._profileOrientationButton.activated = true;
+
+        this._topFunctionsButton = new WebInspector.TextToggleButtonNavigationItem(&quot;top-functions&quot;, WebInspector.UIString(&quot;Top Functions&quot;));
+        this._topFunctionsButton.addEventListener(WebInspector.ButtonNavigationItem.Event.Clicked, this._topFunctionsButtonClicked, this);
+        if (WebInspector.ScriptProfileTimelineView.profileTypeSetting.value == WebInspector.ScriptProfileTimelineView.ProfileViewType.Hierarchy)
+            this._topFunctionsButton.activated = false;
+        else
+            this._topFunctionsButton.activated = true;
+
</ins><span class="cx">         timeline.addEventListener(WebInspector.Timeline.Event.Refreshed, this._scriptTimelineRecordRefreshed, this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -76,7 +84,7 @@
</span><span class="cx"> 
</span><span class="cx">     get navigationItems()
</span><span class="cx">     {
</span><del>-        return [this._clearFocusNodesButtonItem, this._profileOrientationScopeBar];
</del><ins>+        return [this._clearFocusNodesButtonItem, this._profileOrientationButton, this._topFunctionsButton];
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get selectionPathComponents()
</span><span class="lines">@@ -98,14 +106,17 @@
</span><span class="cx"> 
</span><span class="cx">     // Private
</span><span class="cx"> 
</span><del>-    _callingContextTreeForOrientation(orientation)
</del><ins>+    _callingContextTreeForOrientation(profileOrientation, profileViewType)
</ins><span class="cx">     {
</span><del>-        switch (orientation) {
</del><ins>+        switch (profileOrientation) {
</ins><span class="cx">         case WebInspector.ScriptProfileTimelineView.ProfileOrientation.TopDown:
</span><del>-            return this._recording.topDownCallingContextTree;
</del><ins>+            return profileViewType === WebInspector.ScriptProfileTimelineView.ProfileViewType.Hierarchy ? this._recording.topDownCallingContextTree : this._recording.topFunctionsTopDownCallingContextTree;
</ins><span class="cx">         case WebInspector.ScriptProfileTimelineView.ProfileOrientation.BottomUp:
</span><del>-            return this._recording.bottomUpCallingContextTree;
</del><ins>+            return profileViewType === WebInspector.ScriptProfileTimelineView.ProfileViewType.Hierarchy ? this._recording.bottomUpCallingContextTree : this._recording.topFunctionsBottomUpCallingContextTree;
</ins><span class="cx">         }
</span><ins>+
+        console.assert(false, &quot;Should not be reached.&quot;);
+        return this._recording.topDownCallingContextTree;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _profileViewSelectionPathComponentsDidChange(event)
</span><span class="lines">@@ -120,13 +131,18 @@
</span><span class="cx">         this.needsLayout();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _scopeBarSelectionDidChange()
</del><ins>+    _profileOrientationButtonClicked()
</ins><span class="cx">     {
</span><del>-        let currentOrientation = WebInspector.ScriptProfileTimelineView.profileOrientationSetting.value;
-        let newOrientation = this._profileOrientationScopeBar.selectedItems[0].id;
</del><ins>+        this._profileOrientationButton.activated = !this._profileOrientationButton.activated;
+        let isInverted = this._profileOrientationButton.activated;
+        let newOrientation;
+        if (isInverted)
+            newOrientation = WebInspector.ScriptProfileTimelineView.ProfileOrientation.BottomUp;
+        else
+            newOrientation = WebInspector.ScriptProfileTimelineView.ProfileOrientation.TopDown;
</ins><span class="cx"> 
</span><span class="cx">         WebInspector.ScriptProfileTimelineView.profileOrientationSetting.value = newOrientation;
</span><del>-        this._showProfileViewForOrientation(newOrientation);
</del><ins>+        this._showProfileViewForOrientation(newOrientation, WebInspector.ScriptProfileTimelineView.profileTypeSetting);
</ins><span class="cx"> 
</span><span class="cx">         this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
</span><span class="cx"> 
</span><span class="lines">@@ -134,8 +150,27 @@
</span><span class="cx">         this.needsLayout();
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    _showProfileViewForOrientation(orientation)
</del><ins>+    _topFunctionsButtonClicked()
</ins><span class="cx">     {
</span><ins>+        this._topFunctionsButton.activated = !this._topFunctionsButton.activated;
+        let isTopFunctionsEnabled = this._topFunctionsButton.activated;
+        let newOrientation;
+        if (isTopFunctionsEnabled)
+            newOrientation = WebInspector.ScriptProfileTimelineView.ProfileViewType.TopFunctions;
+        else
+            newOrientation = WebInspector.ScriptProfileTimelineView.ProfileViewType.Hierarchy;
+
+        WebInspector.ScriptProfileTimelineView.profileTypeSetting.value = newOrientation;
+        this._showProfileViewForOrientation(WebInspector.ScriptProfileTimelineView.profileOrientationSetting.value, newOrientation);
+
+        this.dispatchEventToListeners(WebInspector.ContentView.Event.SelectionPathComponentsDidChange);
+
+        this._forceNextLayout = true;
+        this.needsLayout();
+    }
+
+    _showProfileViewForOrientation(profileOrientation, profileViewType)
+    {
</ins><span class="cx">         let filterText;
</span><span class="cx">         if (this._profileView) {
</span><span class="cx">             this._profileView.removeEventListener(WebInspector.ContentView.Event.SelectionPathComponentsDidChange, this._profileViewSelectionPathComponentsDidChange, this);
</span><span class="lines">@@ -143,7 +178,7 @@
</span><span class="cx">             filterText = this._profileView.dataGrid.filterText;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        let callingContextTree = this._callingContextTreeForOrientation(orientation);
</del><ins>+        let callingContextTree = this._callingContextTreeForOrientation(profileOrientation, profileViewType);
</ins><span class="cx">         this._profileView = new WebInspector.ProfileView(callingContextTree);
</span><span class="cx">         this._profileView.addEventListener(WebInspector.ContentView.Event.SelectionPathComponentsDidChange, this._profileViewSelectionPathComponentsDidChange, this);
</span><span class="cx"> 
</span><span class="lines">@@ -169,3 +204,8 @@
</span><span class="cx">     BottomUp: &quot;bottom-up&quot;,
</span><span class="cx">     TopDown: &quot;top-down&quot;,
</span><span class="cx"> };
</span><ins>+
+WebInspector.ScriptProfileTimelineView.ProfileViewType = {
+    Hierarchy: &quot;hierarchy&quot;,
+    TopFunctions: &quot;top-functions&quot;,
+};
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTextToggleButtonNavigationItemcss"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/TextToggleButtonNavigationItem.css (0 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TextToggleButtonNavigationItem.css                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TextToggleButtonNavigationItem.css        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+/*
+ * 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.
+ */
+
+.navigation-bar .item.text-toggle.button.text-only {
+    width: auto;
+    height: 17px;
+    margin: auto;
+    margin-left: 8px;
+    margin-right: 8px;
+}
+
+.navigation-bar .item.text-toggle.button.text-only:hover {
+    color: var(--selected-foreground-color);
+    background-color: var(--selected-background-color-hover);
+}
+
+.navigation-bar .item.text-toggle.button.text-only.selected {
+    color: var(--selected-foreground-color);
+    background-color: var(--selected-background-color);
+}
+
+.navigation-bar .item.text-toggle.button.text-only:active {
+    color: var(--selected-foreground-color);
+    background-color: hsla(212, 92%, 54%, 0.55);
+}
+
+.navigation-bar .item.text-toggle.button.text-only.selected:active {
+    background-color: var(--selected-background-color-active);
+}
</ins></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsTextToggleButtonNavigationItemjs"></a>
<div class="addfile"><h4>Added: trunk/Source/WebInspectorUI/UserInterface/Views/TextToggleButtonNavigationItem.js (0 => 202010)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/TextToggleButtonNavigationItem.js                                (rev 0)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/TextToggleButtonNavigationItem.js        2016-06-13 22:43:20 UTC (rev 202010)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+/*
+ * 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.
+ */
+
+{
+    const selectedStyleClassName = &quot;selected&quot;;
+
+    WebInspector.TextToggleButtonNavigationItem = class TextToggleButtonNavigationItem extends WebInspector.ButtonNavigationItem
+    {
+        constructor(identifier, title)
+        {
+            super(identifier, title);
+
+            this._title = title;
+        }
+
+        // Public
+
+        get title()
+        {
+            return this._title;
+        }
+
+        get activated()
+        {
+            return this.element.classList.contains(selectedStyleClassName);
+        }
+
+        set activated(flag)
+        {
+            this.element.classList.toggle(selectedStyleClassName, flag);
+        }
+
+        // Protected
+
+        get additionalClassNames()
+        {
+            return [&quot;text-toggle&quot;, &quot;button&quot;];
+        }
+    };
+}
</ins></span></pre>
</div>
</div>

</body>
</html>