3f313d05bc964ec99d72b4c2ebf6e1ad83c39dda
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / trace_model / thread.html
1 <!DOCTYPE html>
2 <!--
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.
6 -->
7
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="/tvcm/guid.html">
12 <link rel="import" href="/tvcm/range.html">
13
14 <script>
15 'use strict';
16
17 /**
18  * @fileoverview Provides the Thread class.
19  */
20 tvcm.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;
25
26   /**
27    * A ThreadSlice represents an interval of time on a thread resource
28    * with associated nestinged slice information.
29    *
30    * ThreadSlices are typically associated with a specific trace event pair on a
31    * specific thread.
32    * For example,
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
36    * specific thread.
37    *
38    * @constructor
39    */
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_.
46     this.subSlices = [];
47   }
48
49   ThreadSlice.prototype = {
50     __proto__: Slice.prototype
51   };
52
53   /**
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.
58    *
59    * The slices stored on a Thread should be instances of
60    * ThreadSlice.
61    *
62    * @constructor
63    */
64   function Thread(parent, tid) {
65     this.guid_ = tvcm.GUID.allocate();
66     if (!parent)
67       throw new Error('Parent must be provided.');
68     this.parent = parent;
69     this.sortIndex = 0;
70     this.tid = tid;
71     this.name = undefined;
72     this.samples_ = undefined; // Set during createSubSlices
73
74     var that = this;
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;
81     }
82     ThreadSliceForThisThread.prototype = {
83       __proto__: ThreadSlice.prototype
84     };
85
86     this.sliceGroup = new SliceGroup(ThreadSliceForThisThread);
87     this.timeSlices = undefined;
88     this.kernelSliceGroup = new SliceGroup();
89     this.asyncSliceGroup = new AsyncSliceGroup();
90     this.bounds = new tvcm.Range();
91     this.ephemeralSettings = {};
92   }
93
94   Thread.prototype = {
95
96     /*
97      * @return {Number} A globally unique identifier for this counter.
98      */
99     get guid() {
100       return this.guid_;
101     },
102
103     compareTo: function(that) {
104       return Thread.compare(this, that);
105     },
106
107     toJSON: function() {
108       var obj = new Object();
109       var keys = Object.keys(this);
110       for (var i = 0; i < keys.length; i++) {
111         var key = keys[i];
112         if (typeof this[key] == 'function')
113           continue;
114         if (key == 'parent') {
115           obj[key] = this[key].guid;
116           continue;
117         }
118         obj[key] = this[key];
119       }
120       return obj;
121     },
122
123     /**
124      * Shifts all the timestamps inside this thread forward by the amount
125      * specified.
126      */
127     shiftTimestampsForward: function(amount) {
128       this.sliceGroup.shiftTimestampsForward(amount);
129
130       if (this.timeSlices) {
131         for (var i = 0; i < this.timeSlices.length; i++) {
132           var slice = this.timeSlices[i];
133           slice.start += amount;
134         }
135       }
136
137       this.kernelSliceGroup.shiftTimestampsForward(amount);
138       this.asyncSliceGroup.shiftTimestampsForward(amount);
139     },
140
141     /**
142      * Determines whether this thread is empty. If true, it usually implies
143      * that it should be pruned from the model.
144      */
145     get isEmpty() {
146       if (this.sliceGroup.length)
147         return false;
148       if (this.sliceGroup.openSliceCount)
149         return false;
150       if (this.timeSlices && this.timeSlices.length)
151         return false;
152       if (this.kernelSliceGroup.length)
153         return false;
154       if (this.asyncSliceGroup.length)
155         return false;
156       if (this.samples_.length)
157         return false;
158       return true;
159     },
160
161     /**
162      * Updates the bounds based on the
163      * current objects associated with the thread.
164      */
165     updateBounds: function() {
166       this.bounds.reset();
167
168       this.sliceGroup.updateBounds();
169       this.bounds.addRange(this.sliceGroup.bounds);
170
171       this.kernelSliceGroup.updateBounds();
172       this.bounds.addRange(this.kernelSliceGroup.bounds);
173
174       this.asyncSliceGroup.updateBounds();
175       this.bounds.addRange(this.asyncSliceGroup.bounds);
176
177       if (this.timeSlices && this.timeSlices.length) {
178         this.bounds.addValue(this.timeSlices[0].start);
179         this.bounds.addValue(
180             this.timeSlices[this.timeSlices.length - 1].end);
181       }
182
183       if (this.samples_ && this.samples_.length) {
184         this.bounds.addValue(this.samples_[0].start);
185         this.bounds.addValue(
186             this.samples_[this.samples_.length - 1].end);
187       }
188     },
189
190     addCategoriesToDict: function(categoriesDict) {
191       for (var i = 0; i < this.sliceGroup.length; i++)
192         categoriesDict[this.sliceGroup.slices[i].category] = true;
193       for (var i = 0; i < this.kernelSliceGroup.length; i++)
194         categoriesDict[this.kernelSliceGroup.slices[i].category] = true;
195       for (var i = 0; i < this.asyncSliceGroup.length; i++)
196         categoriesDict[this.asyncSliceGroup.slices[i].category] = true;
197       if (this.samples_) {
198         for (var i = 0; i < this.samples_.length; i++)
199           categoriesDict[this.samples_[i].category] = true;
200       }
201     },
202
203     autoCloseOpenSlices: function(opt_maxTimestamp) {
204       this.sliceGroup.autoCloseOpenSlices(opt_maxTimestamp);
205       this.kernelSliceGroup.autoCloseOpenSlices(opt_maxTimestamp);
206     },
207
208     mergeKernelWithUserland: function() {
209       if (this.kernelSliceGroup.length > 0) {
210         var newSlices = SliceGroup.merge(
211             this.sliceGroup, this.kernelSliceGroup);
212         this.sliceGroup.slices = newSlices.slices;
213         this.kernelSliceGroup = new SliceGroup();
214         this.updateBounds();
215       }
216     },
217
218     createSubSlices: function() {
219       this.sliceGroup.createSubSlices();
220       this.samples_ = this.parent.model.samples.filter(function(sample) {
221         return sample.thread == this;
222       }, this);
223     },
224
225     /**
226      * @return {String} A user-friendly name for this thread.
227      */
228     get userFriendlyName() {
229       return this.name || this.tid;
230     },
231
232     /**
233      * @return {String} User friendly details about this thread.
234      */
235     get userFriendlyDetails() {
236       return 'tid: ' + this.tid +
237           (this.name ? ', name: ' + this.name : '');
238     },
239
240     getSettingsKey: function() {
241       if (!this.name)
242         return undefined;
243       var parentKey = this.parent.getSettingsKey();
244       if (!parentKey)
245         return undefined;
246       return parentKey + '.' + this.name;
247     },
248
249     /*
250      * Returns the index of the slice in the timeSlices array, or undefined.
251      */
252     indexOfTimeSlice: function(timeSlice) {
253       var i = tvcm.findLowIndexInSortedArray(
254           this.timeSlices,
255           function(slice) { return slice.start; },
256           timeSlice.start);
257       if (this.timeSlices[i] !== timeSlice)
258         return undefined;
259       return i;
260     },
261
262     iterateAllEvents: function(callback, opt_this) {
263       this.sliceGroup.iterateAllEvents(callback, opt_this);
264       this.kernelSliceGroup.iterateAllEvents(callback, opt_this);
265       this.asyncSliceGroup.iterateAllEvents(callback, opt_this);
266
267       if (this.timeSlices && this.timeSlices.length)
268         this.timeSlices.forEach(callback, opt_this);
269     },
270
271     get samples() {
272       return this.samples_;
273     }
274   };
275
276   /**
277    * Comparison between threads that orders first by parent.compareTo,
278    * then by names, then by tid.
279    */
280   Thread.compare = function(x, y) {
281     var tmp = x.parent.compareTo(y.parent);
282     if (tmp)
283       return tmp;
284
285     tmp = x.sortIndex - y.sortIndex;
286     if (tmp)
287       return tmp;
288
289     tmp = tvcm.comparePossiblyUndefinedValues(
290         x.name, y.name,
291         function(x, y) { return x.localeCompare(y); });
292     if (tmp)
293       return tmp;
294
295     return x.tid - y.tid;
296   };
297
298   return {
299     ThreadSlice: ThreadSlice,
300     Thread: Thread
301   };
302 });
303 </script>