| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/tracing/base/unit.html"> |
| <link rel="import" href="/tracing/model/timed_event.html"> |
| |
| <script> |
| 'use strict'; |
| |
| /** |
| * @fileoverview Provides the Slice class. |
| */ |
| tr.exportTo('tr.model', function() { |
| /** |
| * A Slice represents an interval of time plus parameters associated |
| * with that interval. |
| * |
| * @constructor |
| */ |
| function Slice(category, title, colorId, start, args, opt_duration, |
| opt_cpuStart, opt_cpuDuration, opt_argsStripped, |
| opt_bind_id) { |
| if (new.target) { |
| throw new Error("Can't instantiate pure virtual class Slice"); |
| } |
| tr.model.TimedEvent.call(this, start); |
| |
| this.category = category || ''; |
| this.title = title; |
| this.colorId = colorId; |
| this.args = args; |
| this.startStackFrame = undefined; |
| this.endStackFrame = undefined; |
| this.didNotFinish = false; |
| this.inFlowEvents = []; |
| this.outFlowEvents = []; |
| this.subSlices = []; |
| this.selfTime = undefined; |
| this.cpuSelfTime = undefined; |
| this.important = false; |
| this.parentContainer = undefined; |
| this.argsStripped = false; |
| |
| this.bind_id_ = opt_bind_id; |
| |
| // parentSlice and isTopLevel will be set by SliceGroup. |
| this.parentSlice = undefined; |
| this.isTopLevel = false; |
| // After SliceGroup processes Slices, isTopLevel should be equivalent to |
| // !parentSlice. |
| |
| if (opt_duration !== undefined) |
| this.duration = opt_duration; |
| |
| if (opt_cpuStart !== undefined) |
| this.cpuStart = opt_cpuStart; |
| |
| if (opt_cpuDuration !== undefined) |
| this.cpuDuration = opt_cpuDuration; |
| |
| if (opt_argsStripped !== undefined) |
| this.argsStripped = true; |
| } |
| |
| Slice.prototype = { |
| __proto__: tr.model.TimedEvent.prototype, |
| |
| |
| get analysisTypeName() { |
| return this.title; |
| }, |
| |
| get userFriendlyName() { |
| return 'Slice ' + this.title + ' at ' + |
| tr.b.Unit.byName.timeStampInMs.format(this.start); |
| }, |
| |
| get stableId() { |
| var parentSliceGroup = this.parentContainer.sliceGroup; |
| return parentSliceGroup.stableId + '.' + |
| parentSliceGroup.slices.indexOf(this); |
| }, |
| |
| findDescendentSlice: function(targetTitle) { |
| if (!this.subSlices) |
| return undefined; |
| |
| for (var i = 0; i < this.subSlices.length; i++) { |
| if (this.subSlices[i].title == targetTitle) |
| return this.subSlices[i]; |
| var slice = this.subSlices[i].findDescendentSlice(targetTitle); |
| if (slice) return slice; |
| } |
| return undefined; |
| }, |
| |
| get mostTopLevelSlice() { |
| var curSlice = this; |
| while (curSlice.parentSlice) |
| curSlice = curSlice.parentSlice; |
| |
| return curSlice; |
| }, |
| |
| getProcess: function() { |
| var thread = this.parentContainer; |
| if (thread && thread.getProcess) |
| return thread.getProcess(); |
| return undefined; |
| }, |
| |
| get model() { |
| var process = this.getProcess(); |
| if (process !== undefined) |
| return this.getProcess().model; |
| return undefined; |
| }, |
| |
| /** |
| * Finds all topmost slices relative to this slice. |
| * |
| * Slices may have multiple direct descendants which satisfy |
| * |eventPredicate|, and in this case, all of them are topmost as long as |
| * this slice does not satisfy the predicate. |
| * |
| * For instance, suppose we are passing a predicate that checks whether |
| * events titles begin with 'C'. |
| * C1.findTopmostSlicesRelativeToThisSlice() returns C1 in this example: |
| * [ C1 ] |
| * [ C2 ] |
| * |
| * and D.findTopmostSlicesRelativeToThisSlice() returns C1 and C2 in this |
| * example: |
| * [ D ] |
| * [C1] [C2] |
| */ |
| findTopmostSlicesRelativeToThisSlice: function*(eventPredicate) { |
| if (eventPredicate(this)) { |
| yield this; |
| return; |
| } |
| for (var s of this.subSlices) |
| yield * s.findTopmostSlicesRelativeToThisSlice(eventPredicate); |
| }, |
| |
| /** |
| * Obtains all subsequent slices of this slice. |
| * |
| * Subsequent slices are slices that get executed after a particular |
| * slice, i.e., all the functions that are called after the current one. |
| * |
| * For instance, E.iterateAllSubsequentSlices() in the following example: |
| * [ A ] |
| * [ B][ D ][ G ] |
| * [C] [E][F] [H] |
| * will pass F, G, then H to the provided callback. |
| * |
| * The reason we need subsequent slices of a particular slice is that |
| * when there is flow event goes into, e.g., E, we only want to highlight |
| * E's subsequent slices to indicate the execution order. |
| * |
| * The idea to calculate the subsequent slices of slice E is to view |
| * the slice group as a tree where the top-level slice A is the root node. |
| * The preorder depth-first-search (DFS) order is naturally equivalent |
| * to the function call order. We just need to perform a DFS, and start |
| * recording the slices after we see the occurance of E. |
| */ |
| iterateAllSubsequentSlices: function(callback, opt_this) { |
| var parentStack = []; |
| var started = false; |
| |
| // get the root node and push it to the DFS stack |
| var topmostSlice = this.mostTopLevelSlice; |
| parentStack.push(topmostSlice); |
| |
| // Using the stack to perform DFS |
| while (parentStack.length !== 0) { |
| var curSlice = parentStack.pop(); |
| |
| if (started) |
| callback.call(opt_this, curSlice); |
| else |
| started = (curSlice.guid === this.guid); |
| |
| for (var i = curSlice.subSlices.length - 1; i >= 0; i--) { |
| parentStack.push(curSlice.subSlices[i]); |
| } |
| } |
| }, |
| |
| get subsequentSlices() { |
| var res = []; |
| |
| this.iterateAllSubsequentSlices(function(subseqSlice) { |
| res.push(subseqSlice); |
| }); |
| |
| return res; |
| }, |
| |
| /** |
| * Obtains the parents of a slice, from the most immediate to the root. |
| * |
| * For instance, E.enumerateAllAncestors() in the following example: |
| * [ A ] |
| * [ B][ D ][ G ] |
| * [C] [E][F] [H] |
| * will yield D, then A, in the order from the leaves to the root. |
| */ |
| enumerateAllAncestors: function*() { |
| var curSlice = this; |
| |
| while (curSlice.parentSlice) { |
| curSlice = curSlice.parentSlice; |
| yield curSlice; |
| } |
| }, |
| |
| get ancestorSlices() { |
| var res = []; |
| for (var slice of this.enumerateAllAncestors()) |
| res.push(slice); |
| return res; |
| }, |
| |
| iterateEntireHierarchy: function(callback, opt_this) { |
| var mostTopLevelSlice = this.mostTopLevelSlice; |
| callback.call(opt_this, mostTopLevelSlice); |
| mostTopLevelSlice.iterateAllSubsequentSlices(callback, opt_this); |
| }, |
| |
| get entireHierarchy() { |
| var res = []; |
| |
| this.iterateEntireHierarchy(function(slice) { |
| res.push(slice); |
| }); |
| |
| return res; |
| }, |
| |
| /** |
| * Returns this slice, and its ancestor and subsequent slices. |
| * |
| * For instance, E.ancestorAndSubsequentSlices in the following example: |
| * [ A ] |
| * [ B][ D ][ G ] |
| * [C] [E][F] [H] |
| * will return E, D, A, F, G, and H, where E is itself, D and A are |
| * E's ancestors, and F, G, and H are subsequent slices of E |
| */ |
| get ancestorAndSubsequentSlices() { |
| var res = []; |
| |
| res.push(this); |
| |
| for (var aSlice of this.enumerateAllAncestors()) |
| res.push(aSlice); |
| |
| this.iterateAllSubsequentSlices(function(sSlice) { |
| res.push(sSlice); |
| }); |
| |
| return res; |
| }, |
| |
| enumerateAllDescendents: function*() { |
| for (var slice of this.subSlices) |
| yield slice; |
| for (var slice of this.subSlices) |
| yield * slice.enumerateAllDescendents(); |
| }, |
| |
| get descendentSlices() { |
| var res = []; |
| for (var slice of this.enumerateAllDescendents()) |
| res.push(slice); |
| return res; |
| } |
| |
| }; |
| |
| return { |
| Slice: Slice |
| }; |
| }); |
| </script> |
| |