blob: 533a7d842db9884e4c2cbfff2d5846c18db9420c [file] [log] [blame]
<!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>