• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/model/timed_event.html">
9<link rel="import" href="/tracing/value/unit.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.v.Unit.byName.timeStampInMs.format(this.start);
77    },
78
79    get stableId() {
80      var parentSliceGroup = this.parentContainer.sliceGroup;
81      return parentSliceGroup.stableId + '.' +
82          parentSliceGroup.slices.indexOf(this);
83    },
84
85    findDescendentSlice: function(targetTitle) {
86      if (!this.subSlices)
87        return undefined;
88
89      for (var i = 0; i < this.subSlices.length; i++) {
90        if (this.subSlices[i].title == targetTitle)
91          return this.subSlices[i];
92        var slice = this.subSlices[i].findDescendentSlice(targetTitle);
93        if (slice) return slice;
94      }
95      return undefined;
96    },
97
98    get mostTopLevelSlice() {
99      var curSlice = this;
100      while (curSlice.parentSlice)
101        curSlice = curSlice.parentSlice;
102
103      return curSlice;
104    },
105
106    getProcess: function() {
107      var thread = this.parentContainer;
108      if (thread && thread.getProcess)
109        return thread.getProcess();
110      return undefined;
111    },
112
113    get model() {
114      var process = this.getProcess();
115      if (process !== undefined)
116        return this.getProcess().model;
117      return undefined;
118    },
119
120    /**
121     * Obtains all subsequent slices of this slice.
122     *
123     * Subsequent slices are slices that get executed after a particular
124     * slice, i.e., all the functions that are called after the current one.
125     *
126     * For instance, E.iterateAllSubsequentSlices() in the following example:
127     * [     A          ]
128     * [ B][  D   ][ G  ]
129     *  [C] [E][F]  [H]
130     * will pass F, G, then H to the provided callback.
131     *
132     * The reason we need subsequent slices of a particular slice is that
133     * when there is flow event goes into, e.g., E, we only want to highlight
134     * E's subsequent slices to indicate the execution order.
135     *
136     * The idea to calculate the subsequent slices of slice E is to view
137     * the slice group as a tree where the top-level slice A is the root node.
138     * The preorder depth-first-search (DFS) order is naturally equivalent
139     * to the function call order. We just need to perform a DFS, and start
140     * recording the slices after we see the occurance of E.
141     */
142    iterateAllSubsequentSlices: function(callback, opt_this) {
143      var parentStack = [];
144      var started = false;
145
146      // get the root node and push it to the DFS stack
147      var topmostSlice = this.mostTopLevelSlice;
148      parentStack.push(topmostSlice);
149
150      // Using the stack to perform DFS
151      while (parentStack.length !== 0) {
152        var curSlice = parentStack.pop();
153
154        if (started)
155          callback.call(opt_this, curSlice);
156        else
157          started = (curSlice.guid === this.guid);
158
159        for (var i = curSlice.subSlices.length - 1; i >= 0; i--) {
160          parentStack.push(curSlice.subSlices[i]);
161        }
162      }
163    },
164
165    get subsequentSlices() {
166      var res = [];
167
168      this.iterateAllSubsequentSlices(function(subseqSlice) {
169        res.push(subseqSlice);
170      });
171
172      return res;
173    },
174
175    /**
176     * Obtains the parents of a slice, from the most immediate to the root.
177     *
178     * For instance, E.iterateAllAncestors() in the following example:
179     * [     A          ]
180     * [ B][  D   ][ G  ]
181     *  [C] [E][F]  [H]
182     * will pass D, then A to the provided callback, in the order from the
183     * leaves to the root.
184     */
185    iterateAllAncestors: function(callback, opt_this) {
186      var curSlice = this;
187
188      while (curSlice.parentSlice) {
189        curSlice = curSlice.parentSlice;
190        callback.call(opt_this, curSlice);
191      }
192    },
193
194    get ancestorSlices() {
195      var res = [];
196
197      this.iterateAllAncestors(function(ancestor) {
198        res.push(ancestor);
199      });
200
201      return res;
202    },
203
204    iterateEntireHierarchy: function(callback, opt_this) {
205      var mostTopLevelSlice = this.mostTopLevelSlice;
206      callback.call(opt_this, mostTopLevelSlice);
207      mostTopLevelSlice.iterateAllSubsequentSlices(callback, opt_this);
208    },
209
210    get entireHierarchy() {
211      var res = [];
212
213      this.iterateEntireHierarchy(function(slice) {
214        res.push(slice);
215      });
216
217      return res;
218    },
219
220    /**
221     * Returns this slice, and its ancestor and subsequent slices.
222     *
223     * For instance, E.ancestorAndSubsequentSlices in the following example:
224     * [     A          ]
225     * [ B][  D   ][ G  ]
226     *  [C] [E][F]  [H]
227     * will return E, D, A, F, G, and H, where E is itself, D and A are
228     * E's ancestors, and F, G, and H are subsequent slices of E
229     */
230    get ancestorAndSubsequentSlices() {
231      var res = [];
232
233      res.push(this);
234
235      this.iterateAllAncestors(function(aSlice) {
236        res.push(aSlice);
237      });
238
239      this.iterateAllSubsequentSlices(function(sSlice) {
240        res.push(sSlice);
241      });
242
243      return res;
244    },
245
246    iterateAllDescendents: function(callback, opt_this) {
247      this.subSlices.forEach(callback, opt_this);
248      this.subSlices.forEach(function(subSlice) {
249        subSlice.iterateAllDescendents(callback, opt_this);
250      }, opt_this);
251    },
252
253    get descendentSlices() {
254      var res = [];
255
256      this.iterateAllDescendents(function(des) {
257        res.push(des);
258      });
259
260      return res;
261    }
262
263  };
264
265  return {
266    Slice: Slice
267  };
268});
269</script>
270
271