3 Copyright (c) 2013 The Chromium Authors. All rights reserved.
4 Use of this source code is governed by a BSD-style license that can be
5 found in the LICENSE file.
8 <link rel="import" href="/tracing/trace_model/slice.html">
9 <link rel="import" href="/tracing/trace_model/slice_group.html">
10 <link rel="import" href="/tracing/trace_model/async_slice_group.html">
11 <link rel="import" href="/base/guid.html">
12 <link rel="import" href="/base/range.html">
18 * @fileoverview Provides the Thread class.
20 tv.exportTo('tracing.trace_model', function() {
21 var Slice = tracing.trace_model.Slice;
22 var SliceGroup = tracing.trace_model.SliceGroup;
23 var AsyncSlice = tracing.trace_model.AsyncSlice;
24 var AsyncSliceGroup = tracing.trace_model.AsyncSliceGroup;
27 * A ThreadSlice represents an interval of time on a thread resource
28 * with associated nestinged slice information.
30 * ThreadSlices are typically associated with a specific trace event pair on a
33 * TRACE_EVENT_BEGIN1("x","myArg", 7) at time=0.1ms
34 * TRACE_EVENT_END0() at time=0.3ms
35 * This results in a single slice from 0.1 with duration 0.2 on a
40 function ThreadSlice(cat, title, colorId, start, args, opt_duration,
41 opt_cpuStart, opt_cpuDuration) {
42 Slice.call(this, cat, title, colorId, start, args, opt_duration,
43 opt_cpuStart, opt_cpuDuration);
44 // Do not modify this directly.
45 // subSlices is configured by SliceGroup.rebuildSubRows_.
49 ThreadSlice.prototype = {
50 __proto__: Slice.prototype
54 * A Thread stores all the trace events collected for a particular
55 * thread. We organize the synchronous slices on a thread by "subrows," where
56 * subrow 0 has all the root slices, subrow 1 those nested 1 deep, and so on.
57 * The asynchronous slices are stored in an AsyncSliceGroup object.
59 * The slices stored on a Thread should be instances of
64 function Thread(parent, tid) {
65 this.guid_ = tv.GUID.allocate();
67 throw new Error('Parent must be provided.');
71 this.name = undefined;
72 this.samples_ = undefined; // Set during createSubSlices
75 function ThreadSliceForThisThread(
76 cat, title, colorId, start, args, opt_duration,
77 opt_cpuStart, opt_cpuDuration) {
78 ThreadSlice.call(this, cat, title, colorId, start, args, opt_duration,
79 opt_cpuStart, opt_cpuDuration);
80 this.parentThread = that;
82 ThreadSliceForThisThread.prototype = {
83 __proto__: ThreadSlice.prototype
86 this.sliceGroup = new SliceGroup(this, ThreadSliceForThisThread, 'slices');
87 this.timeSlices = undefined;
88 this.kernelSliceGroup = new SliceGroup(this, undefined, 'kernel-slices');
89 this.asyncSliceGroup = new AsyncSliceGroup(this, 'async-slices');
90 this.bounds = new tv.Range();
96 * @return {Number} A globally unique identifier for this counter.
102 compareTo: function(that) {
103 return Thread.compare(this, that);
107 var obj = new Object();
108 var keys = Object.keys(this);
109 for (var i = 0; i < keys.length; i++) {
111 if (typeof this[key] == 'function')
113 if (key == 'parent') {
114 obj[key] = this[key].guid;
117 obj[key] = this[key];
123 * Shifts all the timestamps inside this thread forward by the amount
126 shiftTimestampsForward: function(amount) {
127 this.sliceGroup.shiftTimestampsForward(amount);
129 if (this.timeSlices) {
130 for (var i = 0; i < this.timeSlices.length; i++) {
131 var slice = this.timeSlices[i];
132 slice.start += amount;
136 this.kernelSliceGroup.shiftTimestampsForward(amount);
137 this.asyncSliceGroup.shiftTimestampsForward(amount);
141 * Determines whether this thread is empty. If true, it usually implies
142 * that it should be pruned from the model.
145 if (this.sliceGroup.length)
147 if (this.sliceGroup.openSliceCount)
149 if (this.timeSlices && this.timeSlices.length)
151 if (this.kernelSliceGroup.length)
153 if (this.asyncSliceGroup.length)
155 if (this.samples_.length)
161 * Updates the bounds based on the
162 * current objects associated with the thread.
164 updateBounds: function() {
167 this.sliceGroup.updateBounds();
168 this.bounds.addRange(this.sliceGroup.bounds);
170 this.kernelSliceGroup.updateBounds();
171 this.bounds.addRange(this.kernelSliceGroup.bounds);
173 this.asyncSliceGroup.updateBounds();
174 this.bounds.addRange(this.asyncSliceGroup.bounds);
176 if (this.timeSlices && this.timeSlices.length) {
177 this.bounds.addValue(this.timeSlices[0].start);
178 this.bounds.addValue(
179 this.timeSlices[this.timeSlices.length - 1].end);
182 if (this.samples_ && this.samples_.length) {
183 this.bounds.addValue(this.samples_[0].start);
184 this.bounds.addValue(
185 this.samples_[this.samples_.length - 1].end);
189 addCategoriesToDict: function(categoriesDict) {
190 for (var i = 0; i < this.sliceGroup.length; i++)
191 categoriesDict[this.sliceGroup.slices[i].category] = true;
192 for (var i = 0; i < this.kernelSliceGroup.length; i++)
193 categoriesDict[this.kernelSliceGroup.slices[i].category] = true;
194 for (var i = 0; i < this.asyncSliceGroup.length; i++)
195 categoriesDict[this.asyncSliceGroup.slices[i].category] = true;
197 for (var i = 0; i < this.samples_.length; i++)
198 categoriesDict[this.samples_[i].category] = true;
202 autoCloseOpenSlices: function(opt_maxTimestamp) {
203 this.sliceGroup.autoCloseOpenSlices(opt_maxTimestamp);
204 this.kernelSliceGroup.autoCloseOpenSlices(opt_maxTimestamp);
207 mergeKernelWithUserland: function() {
208 if (this.kernelSliceGroup.length > 0) {
209 var newSlices = SliceGroup.merge(
210 this.sliceGroup, this.kernelSliceGroup);
211 this.sliceGroup.slices = newSlices.slices;
212 this.kernelSliceGroup = new SliceGroup(this);
217 createSubSlices: function() {
218 this.sliceGroup.createSubSlices();
219 this.samples_ = this.parent.model.samples.filter(function(sample) {
220 return sample.thread == this;
225 * @return {String} A user-friendly name for this thread.
227 get userFriendlyName() {
228 return this.name || this.tid;
232 * @return {String} User friendly details about this thread.
234 get userFriendlyDetails() {
235 return 'tid: ' + this.tid +
236 (this.name ? ', name: ' + this.name : '');
239 getSettingsKey: function() {
242 var parentKey = this.parent.getSettingsKey();
245 return parentKey + '.' + this.name;
249 * Returns the index of the slice in the timeSlices array, or undefined.
251 indexOfTimeSlice: function(timeSlice) {
252 var i = tv.findLowIndexInSortedArray(
254 function(slice) { return slice.start; },
256 if (this.timeSlices[i] !== timeSlice)
261 iterateAllEvents: function(callback, opt_this) {
262 this.sliceGroup.iterateAllEvents(callback, opt_this);
263 this.kernelSliceGroup.iterateAllEvents(callback, opt_this);
264 this.asyncSliceGroup.iterateAllEvents(callback, opt_this);
266 if (this.timeSlices && this.timeSlices.length)
267 this.timeSlices.forEach(callback, opt_this);
270 iterateAllPersistableObjects: function(cb) {
272 if (this.sliceGroup.length)
274 this.asyncSliceGroup.viewSubGroups.forEach(cb);
278 return this.samples_;
283 * Comparison between threads that orders first by parent.compareTo,
284 * then by names, then by tid.
286 Thread.compare = function(x, y) {
287 var tmp = x.parent.compareTo(y.parent);
291 tmp = x.sortIndex - y.sortIndex;
295 tmp = tv.comparePossiblyUndefinedValues(
297 function(x, y) { return x.localeCompare(y); });
301 return x.tid - y.tid;
305 ThreadSlice: ThreadSlice,