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/counter.html">
10 <link rel="import" href="/tvcm/range.html">
16 * @fileoverview Provides the Cpu class.
18 tvcm.exportTo('tracing.trace_model', function() {
20 var Counter = tracing.trace_model.Counter;
21 var Slice = tracing.trace_model.Slice;
24 * A CpuSlice represents a slice of time on a CPU.
28 function CpuSlice(cat, title, colorId, start, args, opt_duration) {
29 Slice.apply(this, arguments);
30 this.threadThatWasRunning = undefined;
34 CpuSlice.prototype = {
35 __proto__: Slice.prototype,
37 get analysisTypeName() {
38 return 'tracing.analysis.CpuSlice';
42 var obj = new Object();
43 var keys = Object.keys(this);
44 for (var i = 0; i < keys.length; i++) {
46 if (typeof this[key] == 'function')
48 if (key == 'cpu' || key == 'threadThatWasRunning') {
50 obj[key] = this[key].guid;
58 getAssociatedTimeslice: function() {
59 if (!this.threadThatWasRunning)
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)
66 if (timeSlice.duration !== this.duration)
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.
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:
83 * Sleeping or runnable: cpuOnWhichThreadWasRunning is undefined
84 * Running: cpuOnWhichThreadWasRunning is set.
88 function ThreadTimeSlice(
89 thread, cat, title, colorId, start, args, opt_duration) {
90 Slice.call(this, cat, title, colorId, start, args, opt_duration);
92 this.cpuOnWhichThreadWasRunning = undefined;
95 ThreadTimeSlice.prototype = {
96 __proto__: Slice.prototype,
98 get analysisTypeName() {
99 return 'tracing.analysis.ThreadTimeSlice';
103 var obj = new Object();
104 var keys = Object.keys(this);
105 for (var i = 0; i < keys.length; i++) {
107 if (typeof this[key] == 'function')
109 if (key == 'thread' || key == 'cpuOnWhichThreadWasRunning') {
111 obj[key] = this[key].guid;
114 obj[key] = this[key];
119 getAssociatedCpuSlice: function() {
120 if (!this.cpuOnWhichThreadWasRunning)
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)
127 if (cpuSlice.duration !== this.duration)
134 getCpuSliceThatTookCpu: function() {
135 if (this.cpuOnWhichThreadWasRunning)
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) {
145 cpuSliceWhenLastRunning = curSlice.getAssociatedCpuSlice();
148 if (!cpuSliceWhenLastRunning)
151 var cpu = cpuSliceWhenLastRunning.cpu;
152 var indexOfSliceOnCpuWhenLastRunning =
153 cpu.indexOf(cpuSliceWhenLastRunning);
154 var nextRunningSlice = cpu.slices[indexOfSliceOnCpuWhenLastRunning + 1];
155 if (!nextRunningSlice)
157 if (Math.abs(nextRunningSlice.start - cpuSliceWhenLastRunning.end) <
159 return nextRunningSlice;
165 * The Cpu represents a Cpu from the kernel's point of view.
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;
175 this.bounds = new tvcm.Range();
176 this.samples_ = undefined; // Set during createSubSlices
178 // Start timestamp of the last active thread.
179 this.lastActiveTimestamp_ = undefined;
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;
185 // Name and arguments of the last active thread.
186 this.lastActiveName_ = undefined;
187 this.lastActiveArgs_ = undefined;
192 * @return {TimelineCounter} The counter on this process named 'name',
193 * creating it if it doesn't exist.
195 getOrCreateCounter: function(cat, name) {
198 id = cat + '.' + name;
201 if (!this.counters[id])
202 this.counters[id] = new Counter(this, id, cat, name);
203 return this.counters[id];
207 * Shifts all the timestamps inside this CPU forward by the amount
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);
218 * Updates the range based on the current slices attached to the cpu.
220 updateBounds: function() {
222 if (this.slices.length) {
223 this.bounds.addValue(this.slices[0].start);
224 this.bounds.addValue(this.slices[this.slices.length - 1].end);
226 for (var id in this.counters) {
227 this.counters[id].updateBounds();
228 this.bounds.addRange(this.counters[id].bounds);
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);
237 createSubSlices: function() {
238 this.samples_ = this.kernel.model.samples.filter(function(sample) {
239 return sample.cpu == this;
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;
252 get userFriendlyName() {
253 return 'CPU ' + this.cpuNumber;
257 var obj = new Object();
258 var keys = Object.keys(this);
259 for (var i = 0; i < keys.length; i++) {
261 if (typeof this[key] == 'function')
265 obj[key] = this[key];
271 * Returns the index of the slice in the CPU's slices, or undefined.
273 indexOf: function(cpuSlice) {
274 var i = tvcm.findLowIndexInSortedArray(
276 function(slice) { return slice.start; },
278 if (this.slices[i] !== cpuSlice)
283 iterateAllEvents: function(callback, opt_this) {
284 this.slices.forEach(callback, opt_this);
286 for (var id in this.counters)
287 this.counters[id].iterateAllEvents(callback, opt_this);
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.
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)
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.');
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];
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_,
319 this.slices.push(slice);
321 // Clear the last state.
322 this.lastActiveTimestamp_ = undefined;
323 this.lastActiveThread_ = undefined;
324 this.lastActiveName_ = undefined;
325 this.lastActiveArgs_ = undefined;
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);
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;
341 return this.samples_;
346 * Comparison between processes that orders by cpuNumber.
348 Cpu.compare = function(x, y) {
349 return x.cpuNumber - y.cpuNumber;
356 ThreadTimeSlice: ThreadTimeSlice