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