1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
8 * @fileoverview Provides the Thread class.
10 tvcm.require('tvcm.guid');
11 tvcm.require('tvcm.range');
12 tvcm.require('tracing.trace_model.slice');
13 tvcm.require('tracing.trace_model.slice_group');
14 tvcm.require('tracing.trace_model.async_slice_group');
16 tvcm.exportTo('tracing.trace_model', function() {
18 var Slice = tracing.trace_model.Slice;
19 var SliceGroup = tracing.trace_model.SliceGroup;
20 var AsyncSlice = tracing.trace_model.AsyncSlice;
21 var AsyncSliceGroup = tracing.trace_model.AsyncSliceGroup;
24 * A ThreadSlice represents an interval of time on a thread resource
25 * with associated nestinged slice information.
27 * ThreadSlices are typically associated with a specific trace event pair on a
30 * TRACE_EVENT_BEGIN1("x","myArg", 7) at time=0.1ms
31 * TRACE_EVENT_END0() at time=0.3ms
32 * This results in a single slice from 0.1 with duration 0.2 on a
37 function ThreadSlice(cat, title, colorId, start, args, opt_duration,
38 opt_cpuStart, opt_cpuDuration) {
39 Slice.call(this, cat, title, colorId, start, args, opt_duration,
40 opt_cpuStart, opt_cpuDuration);
41 // Do not modify this directly.
42 // subSlices is configured by SliceGroup.rebuildSubRows_.
46 ThreadSlice.prototype = {
47 __proto__: Slice.prototype
51 * A Thread stores all the trace events collected for a particular
52 * thread. We organize the synchronous slices on a thread by "subrows," where
53 * subrow 0 has all the root slices, subrow 1 those nested 1 deep, and so on.
54 * The asynchronous slices are stored in an AsyncSliceGroup object.
56 * The slices stored on a Thread should be instances of
61 function Thread(parent, tid) {
62 this.guid_ = tvcm.GUID.allocate();
64 throw new Error('Parent must be provided.');
68 this.name = undefined;
69 this.samples_ = undefined; // Set during createSubSlices
72 function ThreadSliceForThisThread(
73 cat, title, colorId, start, args, opt_duration,
74 opt_cpuStart, opt_cpuDuration) {
75 ThreadSlice.call(this, cat, title, colorId, start, args, opt_duration,
76 opt_cpuStart, opt_cpuDuration);
77 this.parentThread = that;
79 ThreadSliceForThisThread.prototype = {
80 __proto__: ThreadSlice.prototype
83 this.sliceGroup = new SliceGroup(ThreadSliceForThisThread);
84 this.timeSlices = undefined;
85 this.kernelSliceGroup = new SliceGroup();
86 this.asyncSliceGroup = new AsyncSliceGroup();
87 this.bounds = new tvcm.Range();
88 this.ephemeralSettings = {};
94 * @return {Number} A globally unique identifier for this counter.
100 compareTo: function(that) {
101 return Thread.compare(this, that);
105 var obj = new Object();
106 var keys = Object.keys(this);
107 for (var i = 0; i < keys.length; i++) {
109 if (typeof this[key] == 'function')
111 if (key == 'parent') {
112 obj[key] = this[key].guid;
115 obj[key] = this[key];
121 * Shifts all the timestamps inside this thread forward by the amount
124 shiftTimestampsForward: function(amount) {
125 this.sliceGroup.shiftTimestampsForward(amount);
127 if (this.timeSlices) {
128 for (var i = 0; i < this.timeSlices.length; i++) {
129 var slice = this.timeSlices[i];
130 slice.start += amount;
134 this.kernelSliceGroup.shiftTimestampsForward(amount);
135 this.asyncSliceGroup.shiftTimestampsForward(amount);
139 * Determines whether this thread is empty. If true, it usually implies
140 * that it should be pruned from the model.
143 if (this.sliceGroup.length)
145 if (this.sliceGroup.openSliceCount)
147 if (this.timeSlices && this.timeSlices.length)
149 if (this.kernelSliceGroup.length)
151 if (this.asyncSliceGroup.length)
153 if (this.samples_.length)
159 * Updates the bounds based on the
160 * current objects associated with the thread.
162 updateBounds: function() {
165 this.sliceGroup.updateBounds();
166 this.bounds.addRange(this.sliceGroup.bounds);
168 this.kernelSliceGroup.updateBounds();
169 this.bounds.addRange(this.kernelSliceGroup.bounds);
171 this.asyncSliceGroup.updateBounds();
172 this.bounds.addRange(this.asyncSliceGroup.bounds);
174 if (this.timeSlices && this.timeSlices.length) {
175 this.bounds.addValue(this.timeSlices[0].start);
176 this.bounds.addValue(
177 this.timeSlices[this.timeSlices.length - 1].end);
179 if (this.samples_ && this.samples_.length) {
180 this.bounds.addValue(this.samples_[0].start);
181 this.bounds.addValue(
182 this.samples_[this.samples_.length - 1].end);
186 addCategoriesToDict: function(categoriesDict) {
187 for (var i = 0; i < this.sliceGroup.length; i++)
188 categoriesDict[this.sliceGroup.slices[i].category] = true;
189 for (var i = 0; i < this.kernelSliceGroup.length; i++)
190 categoriesDict[this.kernelSliceGroup.slices[i].category] = true;
191 for (var i = 0; i < this.asyncSliceGroup.length; i++)
192 categoriesDict[this.asyncSliceGroup.slices[i].category] = true;
194 for (var i = 0; i < this.samples_.length; i++)
195 categoriesDict[this.samples_[i].category] = true;
199 autoCloseOpenSlices: function(opt_maxTimestamp) {
200 this.sliceGroup.autoCloseOpenSlices(opt_maxTimestamp);
201 this.kernelSliceGroup.autoCloseOpenSlices(opt_maxTimestamp);
204 mergeKernelWithUserland: function() {
205 if (this.kernelSliceGroup.length > 0) {
206 var newSlices = SliceGroup.merge(
207 this.sliceGroup, this.kernelSliceGroup);
208 this.sliceGroup.slices = newSlices.slices;
209 this.kernelSliceGroup = new SliceGroup();
214 createSubSlices: function() {
215 this.sliceGroup.createSubSlices();
216 this.samples_ = this.parent.model.samples.filter(function(sample) {
217 return sample.thread == this;
222 * @return {String} A user-friendly name for this thread.
224 get userFriendlyName() {
225 return this.name || this.tid;
229 * @return {String} User friendly details about this thread.
231 get userFriendlyDetails() {
232 return 'tid: ' + this.tid +
233 (this.name ? ', name: ' + this.name : '');
236 getSettingsKey: function() {
239 var parentKey = this.parent.getSettingsKey();
242 return parentKey + '.' + this.name;
246 * Returns the index of the slice in the timeSlices array, or undefined.
248 indexOfTimeSlice: function(timeSlice) {
249 var i = tvcm.findLowIndexInSortedArray(
251 function(slice) { return slice.start; },
253 if (this.timeSlices[i] !== timeSlice)
258 iterateAllEvents: function(callback, opt_this) {
259 this.sliceGroup.iterateAllEvents(callback, opt_this);
260 this.kernelSliceGroup.iterateAllEvents(callback, opt_this);
261 this.asyncSliceGroup.iterateAllEvents(callback, opt_this);
263 if (this.timeSlices && this.timeSlices.length)
264 this.timeSlices.forEach(callback, opt_this);
268 return this.samples_;
273 * Comparison between threads that orders first by parent.compareTo,
274 * then by names, then by tid.
276 Thread.compare = function(x, y) {
277 var tmp = x.parent.compareTo(y.parent);
281 tmp = x.sortIndex - y.sortIndex;
285 tmp = tvcm.comparePossiblyUndefinedValues(
287 function(x, y) { return x.localeCompare(y); });
291 return x.tid - y.tid;
295 ThreadSlice: ThreadSlice,