slice.html revision edfe2194ee8a857cc1e78b4e4020f9b5e7210029
1<!DOCTYPE html>
2<!--
3Copyright (c) 2013 The Chromium Authors. All rights reserved.
4Use of this source code is governed by a BSD-style license that can be
5found in the LICENSE file.
6-->
7
8<link rel="import" href="/tracing/base/units/time_stamp.html">
9<link rel="import" href="/tracing/model/timed_event.html">
10
11<script>
12'use strict';
13
14/**
15 * @fileoverview Provides the Slice class.
16 */
17tr.exportTo('tr.model', function() {
18  /**
19   * A Slice represents an interval of time plus parameters associated
20   * with that interval.
21   *
22   * @constructor
23   */
24  function Slice(category, title, colorId, start, args, opt_duration,
25                 opt_cpuStart, opt_cpuDuration, opt_argsStripped,
26                 opt_bind_id) {
27    tr.model.TimedEvent.call(this, start);
28
29    this.category = category || '';
30    this.title = title;
31    this.colorId = colorId;
32    this.args = args;
33    this.startStackFrame = undefined;
34    this.endStackFrame = undefined;
35    this.didNotFinish = false;
36    this.inFlowEvents = [];
37    this.outFlowEvents = [];
38    this.subSlices = [];
39    this.selfTime = undefined;
40    this.cpuSelfTime = undefined;
41    this.important = false;
42    this.parentContainer = undefined;
43    this.argsStripped = false;
44
45    this.bind_id_ = opt_bind_id;
46
47    // parentSlice and isTopLevel will be set by SliceGroup.
48    this.parentSlice = undefined;
49    this.isTopLevel = false;
50    // After SliceGroup processes Slices, isTopLevel should be equivalent to
51    // !parentSlice.
52
53    if (opt_duration !== undefined)
54      this.duration = opt_duration;
55
56    if (opt_cpuStart !== undefined)
57      this.cpuStart = opt_cpuStart;
58
59    if (opt_cpuDuration !== undefined)
60      this.cpuDuration = opt_cpuDuration;
61
62    if (opt_argsStripped !== undefined)
63      this.argsStripped = true;
64  }
65
66  Slice.prototype = {
67    __proto__: tr.model.TimedEvent.prototype,
68
69
70    get analysisTypeName() {
71      return this.title;
72    },
73
74    get userFriendlyName() {
75      return 'Slice ' + this.title + ' at ' +
76          tr.b.units.TimeStamp.format(this.start);
77    },
78
79    findDescendentSlice: function(targetTitle) {
80      if (!this.subSlices)
81        return undefined;
82
83      for (var i = 0; i < this.subSlices.length; i++) {
84        if (this.subSlices[i].title == targetTitle)
85          return this.subSlices[i];
86        var slice = this.subSlices[i].findDescendentSlice(targetTitle);
87        if (slice) return slice;
88      }
89      return undefined;
90    },
91
92    get mostTopLevelSlice() {
93      var curSlice = this;
94      while (curSlice.parentSlice)
95        curSlice = curSlice.parentSlice;
96
97      return curSlice;
98    },
99
100    /**
101     * Obtains all subsequent slices of this slice.
102     *
103     * Subsequent slices are slices that get executed after a particular
104     * slice, i.e., all the functions that are called after the current one.
105     *
106     * For instance, E.iterateAllSubsequentSlices() in the following example:
107     * [     A          ]
108     * [ B][  D   ][ G  ]
109     *  [C] [E][F]  [H]
110     * will pass F, G, then H to the provided callback.
111     *
112     * The reason we need subsequent slices of a particular slice is that
113     * when there is flow event goes into, e.g., E, we only want to highlight
114     * E's subsequent slices to indicate the execution order.
115     *
116     * The idea to calculate the subsequent slices of slice E is to view
117     * the slice group as a tree where the top-level slice A is the root node.
118     * The preorder depth-first-search (DFS) order is naturally equivalent
119     * to the function call order. We just need to perform a DFS, and start
120     * recording the slices after we see the occurance of E.
121     */
122    iterateAllSubsequentSlices: function(callback, opt_this) {
123      var parentStack = [];
124      var started = false;
125
126      // get the root node and push it to the DFS stack
127      var topmostSlice = this.mostTopLevelSlice;
128      parentStack.push(topmostSlice);
129
130      // Using the stack to perform DFS
131      while (parentStack.length !== 0) {
132        var curSlice = parentStack.pop();
133
134        if (started)
135          callback.call(opt_this, curSlice);
136        else
137          started = (curSlice.guid === this.guid);
138
139        for (var i = curSlice.subSlices.length - 1; i >= 0; i--) {
140          parentStack.push(curSlice.subSlices[i]);
141        }
142      }
143    },
144
145    get subsequentSlices() {
146      var res = [];
147
148      this.iterateAllSubsequentSlices(function(subseqSlice) {
149        res.push(subseqSlice);
150      });
151
152      return res;
153    },
154
155    /**
156     * Obtains the parents of a slice, from the most immediate to the root.
157     *
158     * For instance, E.iterateAllAncestors() in the following example:
159     * [     A          ]
160     * [ B][  D   ][ G  ]
161     *  [C] [E][F]  [H]
162     * will pass D, then A to the provided callback, in the order from the
163     * leaves to the root.
164     */
165    iterateAllAncestors: function(callback, opt_this) {
166      var curSlice = this;
167
168      while (curSlice.parentSlice) {
169        curSlice = curSlice.parentSlice;
170        callback.call(opt_this, curSlice);
171      }
172    },
173
174    get ancestorSlices() {
175      var res = [];
176
177      this.iterateAllAncestors(function(ancestor) {
178        res.push(ancestor);
179      });
180
181      return res;
182    },
183
184    iterateEntireHierarchy: function(callback, opt_this) {
185      var mostTopLevelSlice = this.mostTopLevelSlice;
186      callback.call(opt_this, mostTopLevelSlice);
187      mostTopLevelSlice.iterateAllSubsequentSlices(callback, opt_this);
188    },
189
190    get entireHierarchy() {
191      var res = [];
192
193      this.iterateEntireHierarchy(function(slice) {
194        res.push(slice);
195      });
196
197      return res;
198    },
199
200    /**
201     * Returns this slice, and its ancestor and subsequent slices.
202     *
203     * For instance, E.ancestorAndSubsequentSlices in the following example:
204     * [     A          ]
205     * [ B][  D   ][ G  ]
206     *  [C] [E][F]  [H]
207     * will return E, D, A, F, G, and H, where E is itself, D and A are
208     * E's ancestors, and F, G, and H are subsequent slices of E
209     */
210    get ancestorAndSubsequentSlices() {
211      var res = [];
212
213      res.push(this);
214
215      this.iterateAllAncestors(function(aSlice) {
216        res.push(aSlice);
217      });
218
219      this.iterateAllSubsequentSlices(function(sSlice) {
220        res.push(sSlice);
221      });
222
223      return res;
224    },
225
226    iterateAllDescendents: function(callback, opt_this) {
227      this.subSlices.forEach(callback, opt_this);
228      this.subSlices.forEach(function(subSlice) {
229        subSlice.iterateAllDescendents(callback, opt_this);
230      }, opt_this);
231    },
232
233    get descendentSlices() {
234      var res = [];
235
236      this.iterateAllDescendents(function(des) {
237        res.push(des);
238      });
239
240      return res;
241    }
242
243  };
244
245  return {
246    Slice: Slice
247  };
248});
249</script>
250
251