Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / trace-viewer / trace_viewer / tracing / trace_model / cpu.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/counter.html">
10 <link rel="import" href="/tvcm/range.html">
11
12 <script>
13 'use strict';
14
15 /**
16  * @fileoverview Provides the Cpu class.
17  */
18 tvcm.exportTo('tracing.trace_model', function() {
19
20   var Counter = tracing.trace_model.Counter;
21   var Slice = tracing.trace_model.Slice;
22
23   /**
24    * A CpuSlice represents a slice of time on a CPU.
25    *
26    * @constructor
27    */
28   function CpuSlice(cat, title, colorId, start, args, opt_duration) {
29     Slice.apply(this, arguments);
30     this.threadThatWasRunning = undefined;
31     this.cpu = undefined;
32   }
33
34   CpuSlice.prototype = {
35     __proto__: Slice.prototype,
36
37     get analysisTypeName() {
38       return 'tracing.analysis.CpuSlice';
39     },
40
41     toJSON: function() {
42       var obj = new Object();
43       var keys = Object.keys(this);
44       for (var i = 0; i < keys.length; i++) {
45         var key = keys[i];
46         if (typeof this[key] == 'function')
47           continue;
48         if (key == 'cpu' || key == 'threadThatWasRunning') {
49           if (this[key])
50             obj[key] = this[key].guid;
51           continue;
52         }
53         obj[key] = this[key];
54       }
55       return obj;
56     },
57
58     getAssociatedTimeslice: function() {
59       if (!this.threadThatWasRunning)
60         return undefined;
61       var timeSlices = this.threadThatWasRunning.timeSlices;
62       for (var i = 0; i < timeSlices.length; i++) {
63         var timeSlice = timeSlices[i];
64         if (timeSlice.start !== this.start)
65           continue;
66         if (timeSlice.duration !== this.duration)
67           continue;
68         return timeSlice;
69       }
70       return undefined;
71     }
72   };
73
74   /**
75    * A ThreadTimeSlice is a slice of time on a specific thread where that thread
76    * was running on a specific CPU, or in a specific sleep state.
77    *
78    * As a thread switches moves through its life, it sometimes goes to sleep and
79    * can't run. Other times, its runnable but isn't actually assigned to a CPU.
80    * Finally, sometimes it gets put on a CPU to actually execute. Each of these
81    * states is represented by a ThreadTimeSlice:
82    *
83    *   Sleeping or runnable: cpuOnWhichThreadWasRunning is undefined
84    *   Running:  cpuOnWhichThreadWasRunning is set.
85    *
86    * @constructor
87    */
88   function ThreadTimeSlice(
89       thread, cat, title, colorId, start, args, opt_duration) {
90     Slice.call(this, cat, title, colorId, start, args, opt_duration);
91     this.thread = thread;
92     this.cpuOnWhichThreadWasRunning = undefined;
93   }
94
95   ThreadTimeSlice.prototype = {
96     __proto__: Slice.prototype,
97
98     get analysisTypeName() {
99       return 'tracing.analysis.ThreadTimeSlice';
100     },
101
102     toJSON: function() {
103       var obj = new Object();
104       var keys = Object.keys(this);
105       for (var i = 0; i < keys.length; i++) {
106         var key = keys[i];
107         if (typeof this[key] == 'function')
108           continue;
109         if (key == 'thread' || key == 'cpuOnWhichThreadWasRunning') {
110           if (this[key])
111             obj[key] = this[key].guid;
112           continue;
113         }
114         obj[key] = this[key];
115       }
116       return obj;
117     },
118
119     getAssociatedCpuSlice: function() {
120       if (!this.cpuOnWhichThreadWasRunning)
121         return undefined;
122       var cpuSlices = this.cpuOnWhichThreadWasRunning.slices;
123       for (var i = 0; i < cpuSlices.length; i++) {
124         var cpuSlice = cpuSlices[i];
125         if (cpuSlice.start !== this.start)
126           continue;
127         if (cpuSlice.duration !== this.duration)
128           continue;
129         return cpuSlice;
130       }
131       return undefined;
132     },
133
134     getCpuSliceThatTookCpu: function() {
135       if (this.cpuOnWhichThreadWasRunning)
136         return undefined;
137       var curIndex = this.thread.indexOfTimeSlice(this);
138       var cpuSliceWhenLastRunning;
139       while (curIndex >= 0) {
140         var curSlice = this.thread.timeSlices[curIndex];
141         if (!curSlice.cpuOnWhichThreadWasRunning) {
142           curIndex--;
143           continue;
144         }
145         cpuSliceWhenLastRunning = curSlice.getAssociatedCpuSlice();
146         break;
147       }
148       if (!cpuSliceWhenLastRunning)
149         return undefined;
150
151       var cpu = cpuSliceWhenLastRunning.cpu;
152       var indexOfSliceOnCpuWhenLastRunning =
153           cpu.indexOf(cpuSliceWhenLastRunning);
154       var nextRunningSlice = cpu.slices[indexOfSliceOnCpuWhenLastRunning + 1];
155       if (!nextRunningSlice)
156         return undefined;
157       if (Math.abs(nextRunningSlice.start - cpuSliceWhenLastRunning.end) <
158           0.00001)
159         return nextRunningSlice;
160       return undefined;
161     }
162   };
163
164   /**
165    * The Cpu represents a Cpu from the kernel's point of view.
166    * @constructor
167    */
168   function Cpu(kernel, number) {
169     if (kernel === undefined || number === undefined)
170       throw new Error('Missing arguments');
171     this.kernel = kernel;
172     this.cpuNumber = number;
173     this.slices = [];
174     this.counters = {};
175     this.bounds = new tvcm.Range();
176     this.samples_ = undefined; // Set during createSubSlices
177
178     // Start timestamp of the last active thread.
179     this.lastActiveTimestamp_ = undefined;
180
181     // Identifier of the last active thread. On Linux, it's a pid while on
182     // Windows it's a thread id.
183     this.lastActiveThread_ = undefined;
184
185     // Name and arguments of the last active thread.
186     this.lastActiveName_ = undefined;
187     this.lastActiveArgs_ = undefined;
188   };
189
190   Cpu.prototype = {
191     /**
192      * @return {TimelineCounter} The counter on this process named 'name',
193      * creating it if it doesn't exist.
194      */
195     getOrCreateCounter: function(cat, name) {
196       var id;
197       if (cat.length)
198         id = cat + '.' + name;
199       else
200         id = name;
201       if (!this.counters[id])
202         this.counters[id] = new Counter(this, id, cat, name);
203       return this.counters[id];
204     },
205
206     /**
207      * Shifts all the timestamps inside this CPU forward by the amount
208      * specified.
209      */
210     shiftTimestampsForward: function(amount) {
211       for (var sI = 0; sI < this.slices.length; sI++)
212         this.slices[sI].start = (this.slices[sI].start + amount);
213       for (var id in this.counters)
214         this.counters[id].shiftTimestampsForward(amount);
215     },
216
217     /**
218      * Updates the range based on the current slices attached to the cpu.
219      */
220     updateBounds: function() {
221       this.bounds.reset();
222       if (this.slices.length) {
223         this.bounds.addValue(this.slices[0].start);
224         this.bounds.addValue(this.slices[this.slices.length - 1].end);
225       }
226       for (var id in this.counters) {
227         this.counters[id].updateBounds();
228         this.bounds.addRange(this.counters[id].bounds);
229       }
230       if (this.samples_ && this.samples_.length) {
231         this.bounds.addValue(this.samples_[0].start);
232         this.bounds.addValue(
233             this.samples_[this.samples_.length - 1].end);
234       }
235     },
236
237     createSubSlices: function() {
238       this.samples_ = this.kernel.model.samples.filter(function(sample) {
239         return sample.cpu == this;
240       }, this);
241     },
242
243     addCategoriesToDict: function(categoriesDict) {
244       for (var i = 0; i < this.slices.length; i++)
245         categoriesDict[this.slices[i].category] = true;
246       for (var id in this.counters)
247         categoriesDict[this.counters[id].category] = true;
248       for (var i = 0; i < this.samples_.length; i++)
249         categoriesDict[this.samples_[i].category] = true;
250     },
251
252     get userFriendlyName() {
253       return 'CPU ' + this.cpuNumber;
254     },
255
256     toJSON: function() {
257       var obj = new Object();
258       var keys = Object.keys(this);
259       for (var i = 0; i < keys.length; i++) {
260         var key = keys[i];
261         if (typeof this[key] == 'function')
262           continue;
263         if (key == 'kernel')
264           continue;
265         obj[key] = this[key];
266       }
267       return obj;
268     },
269
270     /*
271      * Returns the index of the slice in the CPU's slices, or undefined.
272      */
273     indexOf: function(cpuSlice) {
274       var i = tvcm.findLowIndexInSortedArray(
275           this.slices,
276           function(slice) { return slice.start; },
277           cpuSlice.start);
278       if (this.slices[i] !== cpuSlice)
279         return undefined;
280       return i;
281     },
282
283     iterateAllEvents: function(callback, opt_this) {
284       this.slices.forEach(callback, opt_this);
285
286       for (var id in this.counters)
287         this.counters[id].iterateAllEvents(callback, opt_this);
288     },
289
290     /**
291      * Closes the thread running on the CPU. |end_timestamp| is the timestamp
292      * at which the thread was unscheduled. |args| is merged with the arguments
293      * specified when the thread was initially scheduled.
294      */
295     closeActiveThread: function(end_timestamp, args) {
296       // Don't generate a slice if the last active thread is the idle task.
297       if (this.lastActiveThread_ == undefined || this.lastActiveThread_ == 0)
298         return;
299
300       if (end_timestamp < this.lastActiveTimestamp_) {
301         throw new Error('The end timestamp of a thread running on CPU ' +
302                         this.cpuNumber + ' is before its start timestamp.');
303       }
304
305       // Merge |args| with |this.lastActiveArgs_|. If a key is in both
306       // dictionaries, the value from |args| is used.
307       for (var key in args) {
308         this.lastActiveArgs_[key] = args[key];
309       }
310
311       var duration = end_timestamp - this.lastActiveTimestamp_;
312       var slice = new tracing.trace_model.CpuSlice(
313           '', this.lastActiveName_,
314           tvcm.ui.getStringColorId(this.lastActiveName_),
315           this.lastActiveTimestamp_,
316           this.lastActiveArgs_,
317           duration);
318       slice.cpu = this;
319       this.slices.push(slice);
320
321       // Clear the last state.
322       this.lastActiveTimestamp_ = undefined;
323       this.lastActiveThread_ = undefined;
324       this.lastActiveName_ = undefined;
325       this.lastActiveArgs_ = undefined;
326     },
327
328     switchActiveThread: function(timestamp, old_thread_args, new_thread_id,
329                                  new_thread_name, new_thread_args) {
330       // Close the previous active thread and generate a slice.
331       this.closeActiveThread(timestamp, old_thread_args);
332
333       // Keep track of the new thread.
334       this.lastActiveTimestamp_ = timestamp;
335       this.lastActiveThread_ = new_thread_id;
336       this.lastActiveName_ = new_thread_name;
337       this.lastActiveArgs_ = new_thread_args;
338     },
339
340     get samples() {
341       return this.samples_;
342     }
343   };
344
345   /**
346    * Comparison between processes that orders by cpuNumber.
347    */
348   Cpu.compare = function(x, y) {
349     return x.cpuNumber - y.cpuNumber;
350   };
351
352
353   return {
354     Cpu: Cpu,
355     CpuSlice: CpuSlice,
356     ThreadTimeSlice: ThreadTimeSlice
357   };
358 });
359 </script>