Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(678)

Side by Side Diff: chrome/browser/resources/tracing/timeline_model.js

Issue 9706010: about:tracing support for TRACE_ASYNC_START/FINISH events. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 5
6 /** 6 /**
7 * @fileoverview TimelineModel is a parsed representation of the 7 * @fileoverview TimelineModel is a parsed representation of the
8 * TraceEvents obtained from base/trace_event in which the begin-end 8 * TraceEvents obtained from base/trace_event in which the begin-end
9 * tokens are converted into a hierarchy of processes, threads, 9 * tokens are converted into a hierarchy of processes, threads,
10 * subrows, and slices. 10 * subrows, and slices.
11 * 11 *
12 * The building block of the model is a slice. A slice is roughly 12 * The building block of the model is a slice. A slice is roughly
13 * equivalent to function call executing on a specific thread. As a 13 * equivalent to function call executing on a specific thread. As a
14 * result, slices may have one or more subslices. 14 * result, slices may have one or more subslices.
15 * 15 *
16 * A thread contains one or more subrows of slices. Row 0 corresponds to 16 * A thread contains one or more subrows of slices. Row 0 corresponds to
17 * the "root" slices, e.g. the topmost slices. Row 1 contains slices that 17 * the "root" slices, e.g. the topmost slices. Row 1 contains slices that
18 * are nested 1 deep in the stack, and so on. We use these subrows to draw 18 * are nested 1 deep in the stack, and so on. We use these subrows to draw
19 * nesting tasks. 19 * nesting tasks.
20 * 20 *
21 */ 21 */
22 cr.define('tracing', function() { 22 cr.define('tracing', function() {
23 /** 23 /**
24 * A TimelineSlice represents an interval of time on a given resource plus 24 * A TimelineSlice represents an interval of time plus parameters associated
25 * parameters associated with that interval. 25 * with that interval.
26 *
27 * A slice is 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_END() at time=0.3ms
32 * This results in a single timeline slice from 0.1 with duration 0.2 on a
33 * specific thread.
34 *
35 * A slice can also be an interval of time on a Cpu on a TimelineCpu.
36 * 26 *
37 * All time units are stored in milliseconds. 27 * All time units are stored in milliseconds.
38 * @constructor 28 * @constructor
39 */ 29 */
40 function TimelineSlice(title, colorId, start, args, opt_duration) { 30 function TimelineSlice(title, colorId, start, args, opt_duration) {
41 this.title = title; 31 this.title = title;
42 this.start = start; 32 this.start = start;
43 this.colorId = colorId; 33 this.colorId = colorId;
44 this.args = args; 34 this.args = args;
45 this.didNotFinish = false; 35 this.didNotFinish = false;
46 this.subSlices = [];
47 if (opt_duration !== undefined) 36 if (opt_duration !== undefined)
48 this.duration = opt_duration; 37 this.duration = opt_duration;
49 } 38 }
50 39
51 TimelineSlice.prototype = { 40 TimelineSlice.prototype = {
52 selected: false, 41 selected: false,
53 42
54 duration: undefined, 43 duration: undefined,
55 44
56 get end() { 45 get end() {
57 return this.start + this.duration; 46 return this.start + this.duration;
58 } 47 }
59 }; 48 };
60 49
61 /** 50 /**
51 * A TimelineThreadSlice represents an interval of time on a thread resource
52 * with associated nestinged slice information.
53 *
54 * ThreadSlices are typically associated with a specific trace event pair on a
55 * specific thread.
56 * For example,
57 * TRACE_EVENT_BEGIN1("x","myArg", 7) at time=0.1ms
58 * TRACE_EVENT_END() at time=0.3ms
jbates 2012/03/15 00:17:15 nit: TRACE_EVENT_END0("x") so noobs aren't confuse
59 * This results in a single timeline slice from 0.1 with duration 0.2 on a
60 * specific thread.
61 *
62 * @constructor
63 */
64 function TimelineThreadSlice(title, colorId, start, args, opt_duration) {
65 TimelineSlice.call(this, title, colorId, start, args, opt_duration);
66 this.subSlices = [];
67 }
68
69 TimelineThreadSlice.prototype = {
70 __proto__: TimelineSlice.prototype
71 }
72
73
74 /**
75 * A TimelineAsyncSlice represents an interval of time during which an
76 * asynchronous operation is in progress. An AsyncSlice consumes no CPU time
77 * itself and so is only associated with Threads at its start and end point.
78 *
79 * @constructor
80 */
81 function TimelineAsyncSlice(title, colorId, start, args) {
82 TimelineSlice.call(this, title, colorId, start, args);
83 };
84
85 TimelineAsyncSlice.prototype = {
86 __proto__: TimelineSlice.prototype,
87
88 id: undefined,
89
90 startThread: undefined,
91
92 endThread: undefined
93 };
94
95 /**
62 * A TimelineThread stores all the trace events collected for a particular 96 * A TimelineThread stores all the trace events collected for a particular
63 * thread. We organize the slices on a thread by "subrows," where subrow 0 97 * thread. We organize the synchronous slices on a thread by "subrows," where
64 * has all the root slices, subrow 1 those nested 1 deep, and so on. There 98 * subrow 0 has all the root slices, subrow 1 those nested 1 deep, and so on.
65 * is also a set of non-nested subrows. 99 * The asynchronous slices ar stored in an TimelineAsyncSliceGroup object.
jbates 2012/03/15 00:17:15 ar->are
100 *
101 * The slices stored on a TimelineThread should be instances of
102 * TimelineThreadSlice.
66 * 103 *
67 * @constructor 104 * @constructor
68 */ 105 */
69 function TimelineThread(parent, tid) { 106 function TimelineThread(parent, tid) {
107 if (!parent)
108 throw "parent must be provided.";
70 this.parent = parent; 109 this.parent = parent;
71 this.tid = tid; 110 this.tid = tid;
72 this.subRows = [[]]; 111 this.subRows = [[]];
73 this.nonNestedSubRows = []; 112 this.asyncSlices = new TimelineAsyncSliceGroup(
113 "AsyncSliceGroup for " + this.ptid);
jbates 2012/03/15 00:17:15 Is "AsyncSliceGroup for ptid" the title presented
114 }
115
116 var ptidMap = {};
117
118 /**
119 * @return {String} A string that can be used as a unique key for a specific
120 * thread within a process.
121 */
122 TimelineThread.getPTIDFromPidAndTid = function(pid, tid) {
123 if (!ptidMap[pid])
124 ptidMap[pid] = {};
125 if (!ptidMap[pid][tid])
126 ptidMap[pid][tid] = pid + ':' + tid;;
127 return ptidMap[pid][tid];
74 } 128 }
75 129
76 TimelineThread.prototype = { 130 TimelineThread.prototype = {
77 /** 131 /**
78 * Name of the thread, if present. 132 * Name of the thread, if present.
79 */ 133 */
80 name: undefined, 134 name: undefined,
81 135
136 /**
137 * @return {string} A concatenation of the parent id and the thread's
138 * tid. Can be used to uniquely identify a thread.
139 */
140 get ptid() {
141 return TimelineThread.getPTIDFromPidAndTid(this.tid, this.parent.pid);
142 },
143
82 getSubrow: function(i) { 144 getSubrow: function(i) {
83 while (i >= this.subRows.length) 145 while (i >= this.subRows.length)
84 this.subRows.push([]); 146 this.subRows.push([]);
85 return this.subRows[i]; 147 return this.subRows[i];
86 }, 148 },
87 149
88 addNonNestedSlice: function(slice) { 150
89 for (var i = 0; i < this.nonNestedSubRows.length; i++) { 151 shiftSubRow_: function(subRow, amount) {
90 var currSubRow = this.nonNestedSubRows[i]; 152 for (var tS = 0; tS < subRow.length; tS++) {
91 var lastSlice = currSubRow[currSubRow.length - 1]; 153 var slice = subRow[tS];
92 if (slice.start >= lastSlice.start + lastSlice.duration) { 154 slice.start = (slice.start + amount);
93 currSubRow.push(slice);
94 return;
95 }
96 } 155 }
97 this.nonNestedSubRows.push([slice]); 156 },
157
158 /**
159 * Shifts all the timestamps inside this thread forward by the amount
160 * specified.
161 */
162 shiftTimestampsForward: function(amount) {
163 if (this.cpuSlices)
164 this.shiftSubRow_(this.cpuSlices, amount);
165
166 for (var tSR = 0; tSR < this.subRows.length; tSR++) {
167 this.shiftSubRow_(this.subRows[tSR], amount);
168 }
169
170 this.asyncSlices.shiftTimestampsForward(amount);
98 }, 171 },
99 172
100 /** 173 /**
101 * Updates the minTimestamp and maxTimestamp fields based on the 174 * Updates the minTimestamp and maxTimestamp fields based on the
102 * current slices and nonNestedSubRows attached to the thread. 175 * current objects associated with the thread.
103 */ 176 */
104 updateBounds: function() { 177 updateBounds: function() {
105 var values = []; 178 var values = [];
106 var slices; 179 var slices;
107 if (this.subRows[0].length != 0) { 180 if (this.subRows[0].length != 0) {
108 slices = this.subRows[0]; 181 slices = this.subRows[0];
109 values.push(slices[0].start); 182 values.push(slices[0].start);
110 values.push(slices[slices.length - 1].end); 183 values.push(slices[slices.length - 1].end);
111 } 184 }
112 for (var i = 0; i < this.nonNestedSubRows.length; ++i) { 185 if (this.asyncSlices.slices.length) {
113 slices = this.nonNestedSubRows[i]; 186 this.asyncSlices.updateBounds();
114 values.push(slices[0].start); 187 values.push(this.asyncSlices.minTimestamp);
115 values.push(slices[slices.length - 1].end); 188 values.push(this.asyncSlices.maxTimestamp);
116 } 189 }
117 if (values.length) { 190 if (values.length) {
118 this.minTimestamp = Math.min.apply(Math, values); 191 this.minTimestamp = Math.min.apply(Math, values);
119 this.maxTimestamp = Math.max.apply(Math, values); 192 this.maxTimestamp = Math.max.apply(Math, values);
120 } else { 193 } else {
121 this.minTimestamp = undefined; 194 this.minTimestamp = undefined;
122 this.maxTimestamp = undefined; 195 this.maxTimestamp = undefined;
123 } 196 }
124 }, 197 },
125 198
126 /** 199 /**
127 * @return {String} A user-friendly name for this thread. 200 * @return {String} A user-friendly name for this thread.
128 */ 201 */
129 get userFriendlyName() { 202 get userFriendlyName() {
130 var tname = this.name || this.tid; 203 var tname = this.name || this.tid;
131 return this.parent.pid + ': ' + tname; 204 return this.parent.pid + ': ' + tname;
132 }, 205 },
133 206
134 /** 207 /**
135 * @return {String} User friendly details about this thread. 208 * @return {String} User friendly details about this thread.
136 */ 209 */
137 get userFriendlyDetials() { 210 get userFriendlyDetails() {
138 return 'pid: ' + this.parent.pid + 211 return 'pid: ' + this.parent.pid +
139 ', tid: ' + this.tid + 212 ', tid: ' + this.tid +
140 (this.name ? ', name: ' + this.name : ''); 213 (this.name ? ', name: ' + this.name : '');
141 } 214 }
142 215
143 }; 216 };
144 217
145 /** 218 /**
146 * Comparison between threads that orders first by pid, 219 * Comparison between threads that orders first by pid,
147 * then by names, then by tid. 220 * then by names, then by tid.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
184 257
185 get numSeries() { 258 get numSeries() {
186 return this.seriesNames.length; 259 return this.seriesNames.length;
187 }, 260 },
188 261
189 get numSamples() { 262 get numSamples() {
190 return this.timestamps.length; 263 return this.timestamps.length;
191 }, 264 },
192 265
193 /** 266 /**
267 * Shifts all the timestamps inside this counter forward by the amount
268 * specified.
269 */
270 shiftTimestampsForward: function(amount) {
271 for (var sI = 0; sI < this.timestamps.length; sI++)
272 this.timestamps[sI] = (this.timestamps[sI] + amount);
273 },
274
275 /**
194 * Updates the bounds for this counter based on the samples it contains. 276 * Updates the bounds for this counter based on the samples it contains.
195 */ 277 */
196 updateBounds: function() { 278 updateBounds: function() {
197 if (this.seriesNames.length != this.seriesColors.length) 279 if (this.seriesNames.length != this.seriesColors.length)
198 throw 'seriesNames.length must match seriesColors.length'; 280 throw 'seriesNames.length must match seriesColors.length';
199 if (this.numSeries * this.numSamples != this.samples.length) 281 if (this.numSeries * this.numSamples != this.samples.length)
200 throw 'samples.length must be a multiple of numSamples.'; 282 throw 'samples.length must be a multiple of numSamples.';
201 283
202 this.totals = []; 284 this.totals = [];
203 if (this.samples.length == 0) { 285 if (this.samples.length == 0) {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 TimelineProcess.prototype = { 335 TimelineProcess.prototype = {
254 get numThreads() { 336 get numThreads() {
255 var n = 0; 337 var n = 0;
256 for (var p in this.threads) { 338 for (var p in this.threads) {
257 n++; 339 n++;
258 } 340 }
259 return n; 341 return n;
260 }, 342 },
261 343
262 /** 344 /**
345 * Shifts all the timestamps inside this process forward by the amount
346 * specified.
347 */
348 shiftTimestampsForward: function(amount) {
349 for (var tid in this.threads)
350 this.threads[tid].shiftTimestampsForward(amount);
351 for (var id in this.counters)
352 this.counters[id].shiftTimestampsForward(amount);
353 },
354
355 /**
263 * @return {TimlineThread} The thread identified by tid on this process, 356 * @return {TimlineThread} The thread identified by tid on this process,
264 * creating it if it doesn't exist. 357 * creating it if it doesn't exist.
265 */ 358 */
266 getOrCreateThread: function(tid) { 359 getOrCreateThread: function(tid) {
267 if (!this.threads[tid]) 360 if (!this.threads[tid])
268 this.threads[tid] = new TimelineThread(this, tid); 361 this.threads[tid] = new TimelineThread(this, tid);
269 return this.threads[tid]; 362 return this.threads[tid];
270 }, 363 },
271 364
272 /** 365 /**
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
308 if (cat.length) 401 if (cat.length)
309 id = cat + '.' + name; 402 id = cat + '.' + name;
310 else 403 else
311 id = name; 404 id = name;
312 if (!this.counters[id]) 405 if (!this.counters[id])
313 this.counters[id] = new TimelineCounter(this, id, name); 406 this.counters[id] = new TimelineCounter(this, id, name);
314 return this.counters[id]; 407 return this.counters[id];
315 }, 408 },
316 409
317 /** 410 /**
411 * Shifts all the timestamps inside this CPU forward by the amount
412 * specified.
413 */
414 shiftTimestampsForward: function(amount) {
415 for (var sI = 0; sI < this.slices.length; sI++)
416 this.slices[sI].start = (this.slices[sI].start + amount);
417 for (var id in this.counters)
418 this.counters[id].shiftTimestampsForward(amount);
419 },
420
421 /**
318 * Updates the minTimestamp and maxTimestamp fields based on the 422 * Updates the minTimestamp and maxTimestamp fields based on the
319 * current slices attached to the cpu. 423 * current slices attached to the cpu.
320 */ 424 */
321 updateBounds: function() { 425 updateBounds: function() {
322 var values = []; 426 var values = [];
323 if (this.slices.length) { 427 if (this.slices.length) {
324 this.minTimestamp = this.slices[0].start; 428 this.minTimestamp = this.slices[0].start;
325 this.maxTimestamp = this.slices[this.slices.length - 1].end; 429 this.maxTimestamp = this.slices[this.slices.length - 1].end;
326 } else { 430 } else {
327 this.minTimestamp = undefined; 431 this.minTimestamp = undefined;
328 this.maxTimestamp = undefined; 432 this.maxTimestamp = undefined;
329 } 433 }
330 } 434 }
331 }; 435 };
332 436
333 /** 437 /**
334 * Comparison between processes that orders by cpuNumber. 438 * Comparison between processes that orders by cpuNumber.
335 */ 439 */
336 TimelineCpu.compare = function(x, y) { 440 TimelineCpu.compare = function(x, y) {
337 return x.cpuNumber - y.cpuNumber; 441 return x.cpuNumber - y.cpuNumber;
338 }; 442 };
339 443
444 /**
445 * A group of AsyncSlices.
446 * @constructor
447 */
448 function TimelineAsyncSliceGroup(name) {
449 this.name = name;
450 this.slices = [];
451 }
452
453 TimelineAsyncSliceGroup.prototype = {
454 __proto__: Object.prototype,
455
456 /**
457 * Helper function that pushes the provided slice onto the slices array.
458 */
459 push: function(slice) {
460 this.slices.push(slice);
461 },
462
463 /**
464 * @return {Number} The number of slices in this group.
465 */
466 get length() {
467 return this.slices.length;
468 },
469
470 /**
471 * Built automatically rebuildSubRows()
jbates 2012/03/15 00:17:15 Built automatically by rebuildSubRows
472 */
473 subRows_: undefined,
474
475 /**
476 * Updates the bounds for this group based on the slices it contains.
477 */
478 sortSlices_: function() {
479 this.slices.sort(function(x,y) {
480 return x.start - y.start;
481 });
482 },
483
484 /**
485 * Shifts all the timestamps inside this group forward by the amount
486 * specified.
487 */
488 shiftTimestampsForward: function(amount) {
489 for (var sI = 0; sI < this.slices.length; sI++)
490 this.slices[sI].start = (this.slices[sI].start + amount);
491 },
492
493 /**
494 * Updates the bounds for this group based on the slices it contains.
495 */
496 updateBounds: function() {
497 this.sortSlices_();
498 if (this.slices.length) {
499 this.minTimestamp = this.slices[0].start;
500 this.maxTimestamp = this.slices[this.slices.length - 1].end;
501 } else {
502 this.minTimestamp = undefined;
503 this.maxTimestamp = undefined;
504 }
505 this.subRows_ = undefined;
506 },
507
508 get subRows() {
509 if (!this.subRows_)
510 this.rebuildSubRows_();
511 return this.subRows_;
512 },
513
514 /**
515 * Breaks up the list of slices into N rows, each of which is a list of
516 * slices that are non overlapping.
517 *
518 * It uses a very simple approach: walk through the slices in sorted order
519 * by start time. For each slice, try to fit it in an existing subRow. If it
520 * doesn't fit in any subrow, make another subRow.
521 */
522 rebuildSubRows_: function() {
523 this.sortSlices_();
524 var subRows = [];
525 for (var i = 0; i < this.slices.length; i++) {
526 var slice = this.slices[i];
527
528 var found = false;
529 for (var j = 0; j < subRows.length; j++) {
530 var subRow = subRows[j];
531 var lastSliceInSubRow = subRow[subRow.length - 1];
532 if (slice.start >= lastSliceInSubRow.end) {
533 found = true;
534 subRow.push(slice);
535 }
536 }
537 if (!found) {
538 subRows.push([slice]);
539 }
540 }
541 this.subRows_ = subRows;
542 },
543
544 /**
545 * Breaks up this group into slices based on start thread.
546 *
547 * @return {Array} An array of TimelineAsyncSliceGroups where each group has
548 * slices that started on the same thread.
549 **/
550 computeSubGroups: function() {
551 var subGroupsByPTID = {};
552 for (var i = 0; i < this.slices.length; ++i) {
553 var slice = this.slices[i];
554 var slicePTID = slice.startThread.ptid;
555 if (!subGroupsByPTID[slicePTID])
556 subGroupsByPTID[slicePTID] = new TimelineAsyncSliceGroup(this.name)
557 subGroupsByPTID[slicePTID].slices.push(slice);
558 }
559 var groups = []
560 for (var ptid in subGroupsByPTID) {
561 var group = subGroupsByPTID[ptid];
562 group.updateBounds()
563 groups.push(group);
564 }
565 return groups;
566 }
567
568 };
569
570 /**
571 * Comparison between counters that orders by pid, then name.
572 */
573 TimelineCounter.compare = function(x, y) {
574 if (x.parent.pid != y.parent.pid) {
575 return TimelineProcess.compare(x.parent, y.parent.pid);
576 }
577 var tmp = x.name.localeCompare(y.name);
578 if (tmp == 0)
579 return x.tid - y.tid;
580 return tmp;
581 };
582
340 // The color pallette is split in half, with the upper 583 // The color pallette is split in half, with the upper
341 // half of the pallette being the "highlighted" verison 584 // half of the pallette being the "highlighted" verison
342 // of the base color. So, color 7's highlighted form is 585 // of the base color. So, color 7's highlighted form is
343 // 7 + (pallette.length / 2). 586 // 7 + (pallette.length / 2).
344 // 587 //
345 // These bright versions of colors are automatically generated 588 // These bright versions of colors are automatically generated
346 // from the base colors. 589 // from the base colors.
347 // 590 //
348 // Within the color pallette, there are "regular" colors, 591 // Within the color pallette, there are "regular" colors,
349 // which can be used for random color selection, and 592 // which can be used for random color selection, and
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 * See TimelineModel.importEvents for details and more advanced ways to 723 * See TimelineModel.importEvents for details and more advanced ways to
481 * import data. 724 * import data.
482 * @param {bool=} opt_zeroAndBoost Whether to align to zero and boost the 725 * @param {bool=} opt_zeroAndBoost Whether to align to zero and boost the
483 * by 15%. Defaults to true. 726 * by 15%. Defaults to true.
484 * @constructor 727 * @constructor
485 */ 728 */
486 function TimelineModel(opt_eventData, opt_zeroAndBoost) { 729 function TimelineModel(opt_eventData, opt_zeroAndBoost) {
487 this.cpus = {}; 730 this.cpus = {};
488 this.processes = {}; 731 this.processes = {};
489 this.importErrors = []; 732 this.importErrors = [];
733 this.asyncSliceGroups = {};
490 734
491 if (opt_eventData) 735 if (opt_eventData)
492 this.importEvents(opt_eventData, opt_zeroAndBoost); 736 this.importEvents(opt_eventData, opt_zeroAndBoost);
493 } 737 }
494 738
495 var importerConstructors = []; 739 var importerConstructors = [];
496 740
497 /** 741 /**
498 * Registers an importer. All registered importers are considered 742 * Registers an importer. All registered importers are considered
499 * when processing an import request. 743 * when processing an import request.
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
572 816
573 // Begin-events without matching end events leave a thread in a state 817 // Begin-events without matching end events leave a thread in a state
574 // where the toplevel subrows are empty but child subrows have 818 // where the toplevel subrows are empty but child subrows have
575 // entries. The autocloser will fix this up later. But, for the 819 // entries. The autocloser will fix this up later. But, for the
576 // purposes of pruning, such threads need to be treated as having 820 // purposes of pruning, such threads need to be treated as having
577 // content. 821 // content.
578 var hasNonEmptySubrow = false; 822 var hasNonEmptySubrow = false;
579 for (var s = 0; s < thread.subRows.length; s++) 823 for (var s = 0; s < thread.subRows.length; s++)
580 hasNonEmptySubrow |= thread.subRows[s].length > 0; 824 hasNonEmptySubrow |= thread.subRows[s].length > 0;
581 825
582 if (hasNonEmptySubrow || thread.nonNestedSubRows.legnth) 826 if (hasNonEmptySubrow || thread.asyncSlices.length > 0)
583 prunedThreads[tid] = thread; 827 prunedThreads[tid] = thread;
584 } 828 }
585 process.threads = prunedThreads; 829 process.threads = prunedThreads;
586 } 830 }
587 }, 831 },
588 832
589 updateBounds: function() { 833 updateBounds: function() {
590 var wmin = Infinity; 834 var wmin = Infinity;
591 var wmax = -wmin; 835 var wmax = -wmin;
592 var hasData = false; 836 var hasData = false;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 } else { 875 } else {
632 this.maxTimestamp = undefined; 876 this.maxTimestamp = undefined;
633 this.minTimestamp = undefined; 877 this.minTimestamp = undefined;
634 } 878 }
635 }, 879 },
636 880
637 shiftWorldToZero: function() { 881 shiftWorldToZero: function() {
638 if (this.minTimestamp === undefined) 882 if (this.minTimestamp === undefined)
639 return; 883 return;
640 var timeBase = this.minTimestamp; 884 var timeBase = this.minTimestamp;
641 var threads = this.getAllThreads(); 885 for (var pid in this.processes)
642 for (var tI = 0; tI < threads.length; tI++) { 886 this.processes[pid].shiftTimestampsForward(-timeBase);
643 var thread = threads[tI]; 887 for (var cpuNumber in this.cpus)
644 var shiftSubRow = function(subRow) { 888 this.cpus[cpuNumber].shiftTimestampsForward(-timeBase);
645 for (var tS = 0; tS < subRow.length; tS++) {
646 var slice = subRow[tS];
647 slice.start = (slice.start - timeBase);
648 }
649 };
650
651 if (thread.cpuSlices)
652 shiftSubRow(thread.cpuSlices);
653
654 for (var tSR = 0; tSR < thread.subRows.length; tSR++) {
655 shiftSubRow(thread.subRows[tSR]);
656 }
657 for (var tSR = 0; tSR < thread.nonNestedSubRows.length; tSR++) {
658 shiftSubRow(thread.nonNestedSubRows[tSR]);
659 }
660 }
661 var counters = this.getAllCounters();
662 for (var tI = 0; tI < counters.length; tI++) {
663 var counter = counters[tI];
664 for (var sI = 0; sI < counter.timestamps.length; sI++)
665 counter.timestamps[sI] = (counter.timestamps[sI] - timeBase);
666 }
667 var cpus = this.getAllCpus();
668 for (var tI = 0; tI < cpus.length; tI++) {
669 var cpu = cpus[tI];
670 for (var sI = 0; sI < cpu.slices.length; sI++)
671 cpu.slices[sI].start = (cpu.slices[sI].start - timeBase);
672 }
673 this.updateBounds(); 889 this.updateBounds();
674 }, 890 },
675 891
676 getAllThreads: function() { 892 getAllThreads: function() {
677 var threads = []; 893 var threads = [];
678 for (var pid in this.processes) { 894 for (var pid in this.processes) {
679 var process = this.processes[pid]; 895 var process = this.processes[pid];
680 for (var tid in process.threads) { 896 for (var tid in process.threads) {
681 threads.push(process.threads[tid]); 897 threads.push(process.threads[tid]);
682 } 898 }
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
725 941
726 /** 942 /**
727 * Imports the provided events into the model. The eventData type 943 * Imports the provided events into the model. The eventData type
728 * is undefined and will be passed to all the timeline importers registered 944 * is undefined and will be passed to all the timeline importers registered
729 * via TimelineModel.registerImporter. The first importer that returns true 945 * via TimelineModel.registerImporter. The first importer that returns true
730 * for canImport(events) will be used to import the events. 946 * for canImport(events) will be used to import the events.
731 * 947 *
732 * @param {Object} events Events to import. 948 * @param {Object} events Events to import.
733 * @param {boolean} isChildImport True the eventData being imported is an 949 * @param {boolean} isChildImport True the eventData being imported is an
734 * additional trace after the primary eventData. 950 * additional trace after the primary eventData.
951 * @returns {TimelineModelImporter} The importer used for the eventData.
735 */ 952 */
736 importOneTrace_: function(eventData, isAdditionalImport) { 953 importOneTrace_: function(eventData, isAdditionalImport) {
737 var importerConstructor; 954 var importerConstructor;
738 for (var i = 0; i < importerConstructors.length; ++i) { 955 for (var i = 0; i < importerConstructors.length; ++i) {
739 if (importerConstructors[i].canImport(eventData)) { 956 if (importerConstructors[i].canImport(eventData)) {
740 importerConstructor = importerConstructors[i]; 957 importerConstructor = importerConstructors[i];
741 break; 958 break;
742 } 959 }
743 } 960 }
744 if (!importerConstructor) 961 if (!importerConstructor)
745 throw 'Could not find an importer for the provided eventData.'; 962 throw 'Could not find an importer for the provided eventData.';
746 963
747 var importer = new importerConstructor( 964 var importer = new importerConstructor(
748 this, eventData, isAdditionalImport); 965 this, eventData, isAdditionalImport);
749 importer.importEvents(); 966 importer.importEvents();
750 this.pruneEmptyThreads(); 967 return importer;
751 }, 968 },
752 969
753 /** 970 /**
754 * Imports the provided traces into the model. The eventData type 971 * Imports the provided traces into the model. The eventData type
755 * is undefined and will be passed to all the timeline importers registered 972 * is undefined and will be passed to all the timeline importers registered
756 * via TimelineModel.registerImporter. The first importer that returns true 973 * via TimelineModel.registerImporter. The first importer that returns true
757 * for canImport(events) will be used to import the events. 974 * for canImport(events) will be used to import the events.
758 * 975 *
759 * The primary trace is provided via the eventData variable. If multiple 976 * The primary trace is provided via the eventData variable. If multiple
760 * traces are to be imported, specify the first one as events, and the 977 * traces are to be imported, specify the first one as events, and the
761 * remainder in the opt_additionalEventData array. 978 * remainder in the opt_additionalEventData array.
762 * 979 *
763 * @param {Object} eventData Events to import. 980 * @param {Object} eventData Events to import.
764 * @param {bool=} opt_zeroAndBoost Whether to align to zero and boost the 981 * @param {bool=} opt_zeroAndBoost Whether to align to zero and boost the
765 * by 15%. Defaults to true. 982 * by 15%. Defaults to true.
766 * @param {Array=} opt_additionalEventData An array of eventData objects 983 * @param {Array=} opt_additionalEventData An array of eventData objects
767 * (e.g. array of arrays) to 984 * (e.g. array of arrays) to
768 * import after importing the primary events. 985 * import after importing the primary events.
769 */ 986 */
770 importEvents: function(eventData, 987 importEvents: function(eventData,
771 opt_zeroAndBoost, opt_additionalEventData) { 988 opt_zeroAndBoost, opt_additionalEventData) {
772 if (opt_zeroAndBoost === undefined) 989 if (opt_zeroAndBoost === undefined)
773 opt_zeroAndBoost = true; 990 opt_zeroAndBoost = true;
774 991
775 this.importOneTrace_(eventData, false); 992 activeImporters = [];
993 var importer = this.importOneTrace_(eventData, false);
994 activeImporters.push(importer);
776 if (opt_additionalEventData) { 995 if (opt_additionalEventData) {
777 for (var i = 0; i < opt_additionalEventData.length; ++i) { 996 for (var i = 0; i < opt_additionalEventData.length; ++i) {
778 this.importOneTrace_(opt_additionalEventData[i], true); 997 importer = this.importOneTrace_(opt_additionalEventData[i], true);
998 activeImporters.push(importer);
779 } 999 }
780 } 1000 }
1001 for(var i = 0; i < activeImporters.length; ++i)
1002 activeImporters[i].finalizeImport();
1003
1004 for(var i = 0; i < activeImporters.length; ++i)
1005 this.pruneEmptyThreads();
781 1006
782 this.updateBounds(); 1007 this.updateBounds();
783 1008
784 if (opt_zeroAndBoost) 1009 if (opt_zeroAndBoost)
785 this.shiftWorldToZero(); 1010 this.shiftWorldToZero();
786 1011
787 if (opt_zeroAndBoost && 1012 if (opt_zeroAndBoost &&
788 this.minTimestamp !== undefined && 1013 this.minTimestamp !== undefined &&
789 this.maxTimestamp !== undefined) { 1014 this.maxTimestamp !== undefined) {
790 var boost = (this.maxTimestamp - this.minTimestamp) * 0.15; 1015 var boost = (this.maxTimestamp - this.minTimestamp) * 0.15;
791 this.minTimestamp = this.minTimestamp - boost; 1016 this.minTimestamp = this.minTimestamp - boost;
792 this.maxTimestamp = this.maxTimestamp + boost; 1017 this.maxTimestamp = this.maxTimestamp + boost;
793 } 1018 }
794 } 1019 }
795 }; 1020 };
796 1021
797 return { 1022 return {
798 getPallette: getPallette, 1023 getPallette: getPallette,
799 getPalletteHighlightIdBoost: getPalletteHighlightIdBoost, 1024 getPalletteHighlightIdBoost: getPalletteHighlightIdBoost,
800 getColorIdByName: getColorIdByName, 1025 getColorIdByName: getColorIdByName,
801 getStringHash: getStringHash, 1026 getStringHash: getStringHash,
802 getStringColorId: getStringColorId, 1027 getStringColorId: getStringColorId,
803 1028
804 TimelineSlice: TimelineSlice, 1029 TimelineSlice: TimelineSlice,
1030 TimelineThreadSlice: TimelineThreadSlice,
1031 TimelineAsyncSlice: TimelineAsyncSlice,
805 TimelineThread: TimelineThread, 1032 TimelineThread: TimelineThread,
806 TimelineCounter: TimelineCounter, 1033 TimelineCounter: TimelineCounter,
807 TimelineProcess: TimelineProcess, 1034 TimelineProcess: TimelineProcess,
808 TimelineCpu: TimelineCpu, 1035 TimelineCpu: TimelineCpu,
1036 TimelineAsyncSliceGroup: TimelineAsyncSliceGroup,
809 TimelineModel: TimelineModel 1037 TimelineModel: TimelineModel
810 }; 1038 };
811 1039
812 }); 1040 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698