1 // Copyright (c) 2013 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.
7 tvcm.require('tracing.test_utils');
8 tvcm.require('tracing.importer.trace_event_importer');
10 tvcm.unittest.testSuite('tracing.importer.trace_event_importer_test', function() { // @suppress longLineCheck
11 var findSliceNamed = tracing.test_utils.findSliceNamed;
13 test('canImportEmpty', function() {
14 self.assertFalse(tracing.importer.TraceEventImporter.canImport([]));
15 self.assertFalse(tracing.importer.TraceEventImporter.canImport(''));
18 test('basicSingleThreadNonnestedParsing', function() {
20 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
21 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'},
22 {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B'},
23 {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E'}
26 var m = new tracing.TraceModel(events);
27 assertEquals(1, m.numProcesses);
28 var p = m.processes[52];
29 assertNotUndefined(p);
31 assertEquals(1, p.numThreads);
32 var t = p.threads[53];
33 assertNotUndefined(t);
34 assertEquals(2, t.sliceGroup.length);
35 assertEquals(53, t.tid);
36 var slice = t.sliceGroup.slices[0];
37 assertEquals('a', slice.title);
38 assertEquals('foo', slice.category);
39 assertEquals(0, slice.start);
40 assertAlmostEquals((560 - 520) / 1000, slice.duration);
41 assertEquals(0, slice.subSlices.length);
43 slice = t.sliceGroup.slices[1];
44 assertEquals('b', slice.title);
45 assertEquals('bar', slice.category);
46 assertAlmostEquals((629 - 520) / 1000, slice.start);
47 assertAlmostEquals((631 - 629) / 1000, slice.duration);
48 assertEquals(0, slice.subSlices.length);
51 test('basicSingleThreadNonnestedParsingWithCpuDuration', function() {
53 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B', tts: 221}, // @suppress longLineCheck
54 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E', tts: 259}, // @suppress longLineCheck
55 {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B', tts: 329}, // @suppress longLineCheck
56 {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E', tts: 331} // @suppress longLineCheck
59 var m = new tracing.TraceModel(events);
60 assertEquals(1, m.numProcesses);
61 var p = m.processes[52];
62 assertNotUndefined(p);
64 assertEquals(1, p.numThreads);
65 var t = p.threads[53];
66 assertNotUndefined(t);
67 assertEquals(2, t.sliceGroup.length);
68 assertEquals(53, t.tid);
69 var slice = t.sliceGroup.slices[0];
70 assertEquals('a', slice.title);
71 assertEquals('foo', slice.category);
72 assertEquals(0, slice.start);
73 assertAlmostEquals((560 - 520) / 1000, slice.duration);
74 assertAlmostEquals((259 - 221) / 1000, slice.cpuDuration);
75 assertEquals(0, slice.subSlices.length);
77 slice = t.sliceGroup.slices[1];
78 assertEquals('b', slice.title);
79 assertEquals('bar', slice.category);
80 assertAlmostEquals((629 - 520) / 1000, slice.start);
81 assertAlmostEquals((631 - 629) / 1000, slice.duration);
82 assertAlmostEquals((331 - 329) / 1000, slice.cpuDuration);
83 assertEquals(0, slice.subSlices.length);
86 test('argumentDupeCreatesNonFailingImportError', function() {
104 var m = new tracing.TraceModel(events);
105 var t = m.processes[1].threads[1];
106 var sA = findSliceNamed(t.sliceGroup, 'a');
108 assertEquals(2, sA.args.x);
109 assertTrue(m.hasImportWarnings);
110 assertEquals(m.importWarnings.length, 1);
113 test('importMissingArgs', function() {
115 {name: 'a', pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
116 {name: 'a', pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'},
117 {name: 'b', pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'I'}
120 // This should not throw an exception.
121 new tracing.TraceModel(events);
124 test('categoryBeginEndMismatchPrefersBegin', function() {
126 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
127 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'bar', tid: 53, ph: 'E'}
130 var m = new tracing.TraceModel(events);
131 assertEquals(1, m.numProcesses);
132 var p = m.processes[52];
133 assertNotUndefined(p);
135 assertEquals(1, p.numThreads);
136 var t = p.threads[53];
137 assertNotUndefined(t);
138 assertEquals(1, t.sliceGroup.length);
139 assertEquals(53, t.tid);
140 var slice = t.sliceGroup.slices[0];
141 assertEquals('a', slice.title);
142 assertEquals('foo', slice.category);
145 test('beginEndNameMismatch', function() {
147 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
148 {name: 'b', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
151 var m = new tracing.TraceModel(events);
152 assertTrue(m.hasImportWarnings);
153 assertEquals(1, m.importWarnings.length);
156 test('nestedParsing', function() {
158 {name: 'a', args: {}, pid: 1, ts: 1, tts: 1, cat: 'foo', tid: 1, ph: 'B'},
159 {name: 'b', args: {}, pid: 1, ts: 2, tts: 2, cat: 'bar', tid: 1, ph: 'B'},
160 {name: 'b', args: {}, pid: 1, ts: 3, tts: 3, cat: 'bar', tid: 1, ph: 'E'},
161 {name: 'a', args: {}, pid: 1, ts: 4, tts: 3, cat: 'foo', tid: 1, ph: 'E'}
163 var m = new tracing.TraceModel(events, false);
164 var t = m.processes[1].threads[1];
166 var sA = findSliceNamed(t.sliceGroup, 'a');
167 var sB = findSliceNamed(t.sliceGroup, 'b');
169 assertEquals('a', sA.title);
170 assertEquals('foo', sA.category);
171 assertEquals(0.001, sA.start);
172 assertEquals(0.003, sA.duration);
173 assertEquals(0.002, sA.selfTime);
174 assertEquals(0.001, sA.cpuSelfTime);
176 assertEquals('b', sB.title);
177 assertEquals('bar', sB.category);
178 assertEquals(0.002, sB.start);
179 assertEquals(0.001, sB.duration);
181 assertTrue(sA.subSlices.length == 1);
182 assertTrue(sA.subSlices[0] == sB);
183 assertTrue(sB.parentSlice == sA);
186 test('nestedParsingWithTwoSubSlices', function() {
188 {name: 'a', args: {}, pid: 1, ts: 1, tts: 1, cat: 'foo', tid: 1, ph: 'B'},
189 {name: 'b', args: {}, pid: 1, ts: 2, tts: 2, cat: 'bar', tid: 1, ph: 'B'},
190 {name: 'b', args: {}, pid: 1, ts: 3, tts: 3, cat: 'bar', tid: 1, ph: 'E'},
191 {name: 'c', args: {}, pid: 1, ts: 5, tts: 5, cat: 'baz', tid: 1, ph: 'B'},
192 {name: 'c', args: {}, pid: 1, ts: 7, tts: 6, cat: 'baz', tid: 1, ph: 'E'},
193 {name: 'a', args: {}, pid: 1, ts: 8, tts: 8, cat: 'foo', tid: 1, ph: 'E'}
195 var m = new tracing.TraceModel(events, false);
196 var t = m.processes[1].threads[1];
198 var sA = findSliceNamed(t.sliceGroup, 'a');
199 var sB = findSliceNamed(t.sliceGroup, 'b');
200 var sC = findSliceNamed(t.sliceGroup, 'c');
202 assertEquals('a', sA.title);
203 assertEquals('foo', sA.category);
204 assertEquals(0.001, sA.start);
205 assertEquals(0.007, sA.duration);
206 assertEquals(0.004, sA.selfTime);
207 assertEquals(0.005, sA.cpuSelfTime);
209 assertEquals('b', sB.title);
210 assertEquals('bar', sB.category);
211 assertEquals(0.002, sB.start);
212 assertEquals(0.001, sB.duration);
214 assertEquals('c', sC.title);
215 assertEquals('baz', sC.category);
216 assertEquals(0.005, sC.start);
217 assertEquals(0.002, sC.duration);
219 assertTrue(sA.subSlices.length == 2);
220 assertTrue(sA.subSlices[0] == sB);
221 assertTrue(sA.subSlices[1] == sC);
222 assertTrue(sB.parentSlice == sA);
223 assertTrue(sC.parentSlice == sA);
226 test('nestedParsingWithDoubleNesting', function() {
228 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
229 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'B'},
230 {name: 'c', args: {}, pid: 1, ts: 3, cat: 'baz', tid: 1, ph: 'B'},
231 {name: 'c', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'E'},
232 {name: 'b', args: {}, pid: 1, ts: 7, cat: 'bar', tid: 1, ph: 'E'},
233 {name: 'a', args: {}, pid: 1, ts: 8, cat: 'foo', tid: 1, ph: 'E'}
235 var m = new tracing.TraceModel(events, false);
236 var t = m.processes[1].threads[1];
238 var sA = findSliceNamed(t.sliceGroup, 'a');
239 var sB = findSliceNamed(t.sliceGroup, 'b');
240 var sC = findSliceNamed(t.sliceGroup, 'c');
242 assertEquals('a', sA.title);
243 assertEquals('foo', sA.category);
244 assertEquals(0.001, sA.start);
245 assertEquals(0.007, sA.duration);
246 assertEquals(0.002, sA.selfTime);
248 assertEquals('b', sB.title);
249 assertEquals('bar', sB.category);
250 assertEquals(0.002, sB.start);
251 assertEquals(0.005, sB.duration);
252 assertEquals(0.002, sA.selfTime);
254 assertEquals('c', sC.title);
255 assertEquals('baz', sC.category);
256 assertEquals(0.003, sC.start);
257 assertEquals(0.002, sC.duration);
259 assertTrue(sA.subSlices.length == 1);
260 assertTrue(sA.subSlices[0] == sB);
261 assertTrue(sB.parentSlice == sA);
263 assertTrue(sB.subSlices.length == 1);
264 assertTrue(sB.subSlices[0] == sC);
265 assertTrue(sC.parentSlice == sB);
269 test('autoclosing', function() {
271 // Slice that doesn't finish.
272 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
274 // Slice that does finish to give an 'end time' to make autoclosing work.
275 {name: 'b', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'},
276 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'}
278 var m = new tracing.TraceModel(events);
279 var p = m.processes[1];
280 var t = p.threads[1];
281 var slice = t.sliceGroup.slices[0];
282 assertEquals('a', slice.title);
283 assertEquals('foo', slice.category);
284 assertTrue(slice.didNotFinish);
285 assertEquals(0, slice.start);
286 assertEquals((2 - 1) / 1000, slice.duration);
289 test('autoclosingLoneBegin', function() {
291 // Slice that doesn't finish.
292 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}
294 var m = new tracing.TraceModel(events);
295 var p = m.processes[1];
296 var t = p.threads[1];
297 var slice = t.sliceGroup.slices[0];
298 assertEquals('a', slice.title);
299 assertEquals('foo', slice.category);
300 assertTrue(slice.didNotFinish);
301 assertEquals(0, slice.start);
302 assertEquals(0, slice.duration);
305 test('autoclosingWithSubTasks', function() {
307 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
308 {name: 'b1', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'},
309 {name: 'b1', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'},
310 {name: 'b2', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'}
312 var m = new tracing.TraceModel(events, false);
313 var t = m.processes[1].threads[1];
315 var sA = findSliceNamed(t.sliceGroup, 'a');
316 var sB1 = findSliceNamed(t.sliceGroup, 'b1');
317 var sB2 = findSliceNamed(t.sliceGroup, 'b2');
319 assertEquals(0.003, sA.end);
320 assertEquals(0.003, sB1.end);
321 assertEquals(0.003, sB2.end);
324 test('autoclosingWithEventsOutsideBounds', function() {
326 // Slice that begins before min and ends after max of the other threads.
327 {name: 'a', args: {}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'B'},
328 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'},
330 // Slice that does finish to give an 'end time' to establish a basis
331 {name: 'c', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'},
332 {name: 'c', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'}
334 var m = new tracing.TraceModel(events, false);
335 var p = m.processes[1];
336 var t = p.threads[1];
337 assertEquals(2, t.sliceGroup.length);
339 var slice = findSliceNamed(t.sliceGroup, 'a');
340 assertEquals('a', slice.title);
341 assertEquals('foo', slice.category);
342 assertEquals(0, slice.start);
343 assertEquals(0.003, slice.duration);
345 var t2 = p.threads[2];
346 var slice2 = findSliceNamed(t2.sliceGroup, 'c');
347 assertEquals('c', slice2.title);
348 assertEquals('bar', slice2.category);
349 assertEquals(0.001, slice2.start);
350 assertEquals(0.001, slice2.duration);
352 assertEquals(0.000, m.bounds.min);
353 assertEquals(0.003, m.bounds.max);
356 test('nestedAutoclosing', function() {
358 // Tasks that don't finish.
359 {name: 'a1', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
360 {name: 'a2', args: {}, pid: 1, ts: 1.5, cat: 'foo', tid: 1, ph: 'B'},
362 // Slice that does finish to give an 'end time' to make autoclosing work.
363 {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'},
364 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'}
366 var m = new tracing.TraceModel(events, false);
367 var t1 = m.processes[1].threads[1];
368 var t2 = m.processes[1].threads[2];
370 var sA1 = findSliceNamed(t1.sliceGroup, 'a1');
371 var sA2 = findSliceNamed(t1.sliceGroup, 'a2');
372 var sB = findSliceNamed(t2.sliceGroup, 'b');
374 assertEquals(0.002, sA1.end);
375 assertEquals(0.002, sA2.end);
378 test('taskColoring', function() {
379 // The test below depends on hashing of 'a' != 'b'. Fail early if that
380 // assumption is incorrect.
381 assertNotEquals(tvcm.ui.getStringHash('a'), tvcm.ui.getStringHash('b'));
384 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
385 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
386 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 1, ph: 'B'},
387 {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 1, ph: 'E'},
388 {name: 'a', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'B'},
389 {name: 'a', args: {}, pid: 1, ts: 6, cat: 'baz', tid: 1, ph: 'E'}
391 var m = new tracing.TraceModel(events);
392 var p = m.processes[1];
393 var t = p.threads[1];
394 var a1 = t.sliceGroup.slices[0];
395 assertEquals('a', a1.title);
396 assertEquals('foo', a1.category);
397 var b = t.sliceGroup.slices[1];
398 assertEquals('b', b.title);
399 assertEquals('bar', b.category);
400 assertNotEquals(a1.colorId, b.colorId);
401 var a2 = t.sliceGroup.slices[2];
402 assertEquals('a', a2.title);
403 assertEquals('baz', a2.category);
404 assertEquals(a1.colorId, a2.colorId);
407 test('multipleThreadParsing', function() {
409 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
410 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
411 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 2, ph: 'B'},
412 {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 2, ph: 'E'}
414 var m = new tracing.TraceModel(events);
415 assertEquals(1, m.numProcesses);
416 var p = m.processes[1];
417 assertNotUndefined(p);
419 assertEquals(2, p.numThreads);
422 var t = p.threads[1];
423 assertNotUndefined(t);
424 assertEquals(1, t.sliceGroup.length);
425 assertEquals(1, t.tid);
427 var slice = t.sliceGroup.slices[0];
428 assertEquals('a', slice.title);
429 assertEquals('foo', slice.category);
430 assertEquals(0, slice.start);
431 assertEquals((2 - 1) / 1000, slice.duration);
432 assertEquals(0, slice.subSlices.length);
435 var t = p.threads[2];
436 assertNotUndefined(t);
437 assertEquals(1, t.sliceGroup.length);
438 assertEquals(2, t.tid);
440 slice = t.sliceGroup.slices[0];
441 assertEquals('b', slice.title);
442 assertEquals('bar', slice.category);
443 assertEquals((3 - 1) / 1000, slice.start);
444 assertEquals((4 - 3) / 1000, slice.duration);
445 assertEquals(0, slice.subSlices.length);
448 test('multiplePidParsing', function() {
450 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
451 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
452 {name: 'b', args: {}, pid: 2, ts: 3, cat: 'bar', tid: 2, ph: 'B'},
453 {name: 'b', args: {}, pid: 2, ts: 4, cat: 'bar', tid: 2, ph: 'E'}
455 var m = new tracing.TraceModel(events);
456 assertEquals(2, m.numProcesses);
457 var p = m.processes[1];
458 assertNotUndefined(p);
460 assertEquals(1, p.numThreads);
462 // Check process 1 thread 1.
463 var t = p.threads[1];
464 assertNotUndefined(t);
465 assertEquals(1, t.sliceGroup.length);
466 assertEquals(1, t.tid);
468 var slice = t.sliceGroup.slices[0];
469 assertEquals('a', slice.title);
470 assertEquals('foo', slice.category);
471 assertEquals(0, slice.start);
472 assertEquals((2 - 1) / 1000, slice.duration);
473 assertEquals(0, slice.subSlices.length);
475 // Check process 2 thread 2.
476 var p = m.processes[2];
477 assertNotUndefined(p);
478 assertEquals(1, p.numThreads);
479 var t = p.threads[2];
480 assertNotUndefined(t);
481 assertEquals(1, t.sliceGroup.length);
482 assertEquals(2, t.tid);
484 slice = t.sliceGroup.slices[0];
485 assertEquals('b', slice.title);
486 assertEquals('bar', slice.category);
487 assertEquals((3 - 1) / 1000, slice.start);
488 assertEquals((4 - 3) / 1000, slice.duration);
489 assertEquals(0, slice.subSlices.length);
491 // Check getAllThreads.
492 assertArrayEquals([m.processes[1].threads[1], m.processes[2].threads[2]],
497 test('processNames', function() {
499 {name: 'process_name', args: {name: 'SomeProcessName'},
500 pid: 1, ts: 0, tid: 1, ph: 'M'},
501 {name: 'process_name', args: {name: 'SomeProcessName'},
502 pid: 2, ts: 0, tid: 1, ph: 'M'}
504 var m = new tracing.TraceModel();
505 m.importTraces([events], false, false);
506 assertEquals('SomeProcessName', m.processes[1].name);
510 test('processLabels', function() {
512 {name: 'process_labels', args: {labels: 'foo,bar,bar,foo,baz'},
513 pid: 1, ts: 0, tid: 1, ph: 'M'},
514 {name: 'process_labels', args: {labels: 'baz'},
515 pid: 2, ts: 0, tid: 1, ph: 'M'}
517 var m = new tracing.TraceModel();
518 m.importTraces([events], false, false);
519 assertArrayEquals(['foo', 'bar', 'baz'], m.processes[1].labels);
520 assertArrayEquals(['baz'], m.processes[2].labels);
523 // Process sort index.
524 test('processSortIndex', function() {
526 {name: 'process_name', args: {name: 'First'},
527 pid: 2, ts: 0, tid: 1, ph: 'M'},
528 {name: 'process_name', args: {name: 'Second'},
529 pid: 2, ts: 0, tid: 1, ph: 'M'},
530 {name: 'process_sort_index', args: {sort_index: 1},
531 pid: 1, ts: 0, tid: 1, ph: 'M'}
533 var m = new tracing.TraceModel();
534 m.importTraces([events], false, false);
536 // By name, p1 is before p2. But, its sort index overrides that.
537 assertTrue(m.processes[1].compareTo(m.processes[2]) > 0);
541 test('threadNames', function() {
543 {name: 'thread_name', args: {name: 'Thread 1'},
544 pid: 1, ts: 0, tid: 1, ph: 'M'},
545 {name: 'thread_name', args: {name: 'Thread 2'},
546 pid: 2, ts: 0, tid: 2, ph: 'M'}
548 var m = new tracing.TraceModel(events);
549 m.importTraces([events], false, false);
550 assertEquals('Thread 1', m.processes[1].threads[1].name);
551 assertEquals('Thread 2', m.processes[2].threads[2].name);
554 // Thread sort index.
555 test('threadSortIndex', function() {
557 {name: 'thread_name', args: {name: 'Thread 1'},
558 pid: 1, ts: 0, tid: 1, ph: 'M'},
559 {name: 'thread_name', args: {name: 'Thread 2'},
560 pid: 1, ts: 0, tid: 2, ph: 'M'},
561 {name: 'thread_sort_index', args: {sort_index: 1},
562 pid: 1, ts: 0, tid: 1, ph: 'M'}
564 var m = new tracing.TraceModel();
565 m.importTraces([events], false, false);
567 // By name, t1 is before t2. But, its sort index overrides that.
568 var t1 = m.processes[1].threads[1];
569 var t2 = m.processes[1].threads[2];
570 assertTrue(t1.compareTo(t2) > 0);
574 test('cpuCounts', function() {
576 {name: 'num_cpus', args: {number: 4},
577 pid: 7, ts: 0, tid: 0, ph: 'M'},
578 {name: 'num_cpus', args: {number: 4},
579 pid: 14, ts: 0, tid: 0, ph: 'M'}
581 var m = new tracing.TraceModel();
582 m.importTraces([events], false, false);
583 assertEquals(4, m.kernel.softwareMeasuredCpuCount);
584 assertEquals(4, m.kernel.bestGuessAtCpuCount);
587 test('cpuCountsWithSandboxBeingConfused', function() {
589 {name: 'num_cpus', args: {number: 4},
590 pid: 7, ts: 0, tid: 0, ph: 'M'},
591 {name: 'num_cpus', args: {number: 1},
592 pid: 14, ts: 0, tid: 0, ph: 'M'}
594 var m = new tracing.TraceModel();
595 m.importTraces([events], false, false);
596 assertEquals(4, m.kernel.softwareMeasuredCpuCount);
597 assertEquals(4, m.kernel.bestGuessAtCpuCount);
600 test('parsingWhenEndComesFirst', function() {
602 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'E'},
603 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'B'},
604 {name: 'a', args: {}, pid: 1, ts: 5, cat: 'foo', tid: 1, ph: 'E'}
606 var m = new tracing.TraceModel(events, false);
607 var p = m.processes[1];
608 var t = p.threads[1];
609 assertEquals(1, t.sliceGroup.length);
610 assertEquals('a', t.sliceGroup.slices[0].title);
611 assertEquals('foo', t.sliceGroup.slices[0].category);
612 assertEquals(0.004, t.sliceGroup.slices[0].start);
613 assertEquals(0.001, t.sliceGroup.slices[0].duration);
614 assertTrue(m.hasImportWarnings);
615 assertEquals(1, m.importWarnings.length);
618 test('immediateParsing', function() {
620 // Need to include immediates inside a task so the timeline
621 // recentering/zeroing doesn't clobber their timestamp.
622 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
623 {name: 'immediate', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'I'},
624 {name: 'slower', args: {}, pid: 1, ts: 4, cat: 'baz', tid: 1, ph: 'i'},
625 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'}
627 var m = new tracing.TraceModel(events, false);
628 var p = m.processes[1];
629 var t = p.threads[1];
631 assertEquals(3, t.sliceGroup.length);
632 assertEquals(0.001, t.sliceGroup.slices[0].start);
633 assertEquals(0.003, t.sliceGroup.slices[0].duration);
634 assertEquals(0.002, t.sliceGroup.slices[1].start);
635 assertEquals(0, t.sliceGroup.slices[1].duration);
636 assertEquals(0.004, t.sliceGroup.slices[2].start);
638 var slice = findSliceNamed(t.sliceGroup, 'a');
639 assertEquals('a', slice.title);
640 assertEquals('foo', slice.category);
641 assertEquals(0.003, slice.duration);
643 var immed = findSliceNamed(t.sliceGroup, 'immediate');
644 assertEquals('immediate', immed.title);
645 assertEquals('bar', immed.category);
646 assertEquals(0.002, immed.start);
647 assertEquals(0, immed.duration);
649 var slower = findSliceNamed(t.sliceGroup, 'slower');
650 assertEquals('slower', slower.title);
651 assertEquals('baz', slower.category);
652 assertEquals(0.004, slower.start);
653 assertEquals(0, slower.duration);
656 test('simpleCounter', function() {
658 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
660 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
662 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 20, cat: 'foo', tid: 1,
666 var m = new tracing.TraceModel(events);
667 var p = m.processes[1];
668 var ctr = m.processes[1].counters['foo.ctr'];
670 assertEquals('ctr', ctr.name);
671 assertEquals('foo', ctr.category);
672 assertEquals(3, ctr.numSamples);
673 assertEquals(1, ctr.numSeries);
675 assertEquals('value', ctr.series[0].name);
676 assertEquals(tvcm.ui.getStringColorId('ctr.value'), ctr.series[0].color);
678 assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
681 ctr.series[0].samples.forEach(function(sample) {
682 samples.push(sample.value);
684 assertArrayEquals([0, 10, 0], samples);
686 assertArrayEquals([0, 10, 0], ctr.totals);
687 assertEquals(10, ctr.maxTotal);
690 test('instanceCounter', function() {
692 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
694 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
696 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
698 {name: 'ctr', args: {'value': 20}, pid: 1, ts: 15, cat: 'foo', tid: 1,
700 {name: 'ctr', args: {'value': 30}, pid: 1, ts: 18, cat: 'foo', tid: 1,
702 {name: 'ctr', args: {'value': 40}, pid: 1, ts: 20, cat: 'bar', tid: 1,
705 var m = new tracing.TraceModel(events);
706 var p = m.processes[1];
707 var ctr = m.processes[1].counters['foo.ctr[0]'];
708 assertEquals('ctr[0]', ctr.name);
709 assertEquals('foo', ctr.category);
710 assertEquals(2, ctr.numSamples);
711 assertEquals(1, ctr.numSeries);
713 assertArrayEquals([0, 0.01], ctr.timestamps);
715 ctr.series[0].samples.forEach(function(sample) {
716 samples.push(sample.value);
718 assertArrayEquals([0, 10], samples);
720 ctr = m.processes[1].counters['foo.ctr[1]'];
721 assertEquals('ctr[1]', ctr.name);
722 assertEquals('foo', ctr.category);
723 assertEquals(3, ctr.numSamples);
724 assertEquals(1, ctr.numSeries);
725 assertArrayEquals([0.01, 0.015, 0.018], ctr.timestamps);
728 ctr.series[0].samples.forEach(function(sample) {
729 samples.push(sample.value);
731 assertArrayEquals([10, 20, 30], samples);
733 ctr = m.processes[1].counters['bar.ctr[2]'];
734 assertEquals('ctr[2]', ctr.name);
735 assertEquals('bar', ctr.category);
736 assertEquals(1, ctr.numSamples);
737 assertEquals(1, ctr.numSeries);
738 assertArrayEquals([0.02], ctr.timestamps);
740 ctr.series[0].samples.forEach(function(sample) {
741 samples.push(sample.value);
743 assertArrayEquals([40], samples);
746 test('multiCounterUpdateBounds', function() {
747 var ctr = new tracing.trace_model.Counter(undefined, 'testBasicCounter',
748 '', 'testBasicCounter');
749 var value1Series = new tracing.trace_model.CounterSeries(
750 'value1', 'testBasicCounter.value1');
751 var value2Series = new tracing.trace_model.CounterSeries(
752 'value2', 'testBasicCounter.value2');
753 ctr.addSeries(value1Series);
754 ctr.addSeries(value2Series);
756 value1Series.addCounterSample(0, 0);
757 value1Series.addCounterSample(1, 1);
758 value1Series.addCounterSample(2, 1);
759 value1Series.addCounterSample(3, 2);
760 value1Series.addCounterSample(4, 3);
761 value1Series.addCounterSample(5, 1);
762 value1Series.addCounterSample(6, 3);
763 value1Series.addCounterSample(7, 3.1);
765 value2Series.addCounterSample(0, 0);
766 value2Series.addCounterSample(1, 0);
767 value2Series.addCounterSample(2, 1);
768 value2Series.addCounterSample(3, 1.1);
769 value2Series.addCounterSample(4, 0);
770 value2Series.addCounterSample(5, 7);
771 value2Series.addCounterSample(6, 0);
772 value2Series.addCounterSample(7, 0.5);
776 assertEquals(0, ctr.bounds.min);
777 assertEquals(7, ctr.bounds.max);
778 assertEquals(8, ctr.maxTotal);
779 assertArrayEquals([0, 0,
786 3.1, 3.6], ctr.totals);
789 test('multiCounter', function() {
791 {name: 'ctr', args: {'value1': 0, 'value2': 7}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'C'}, // @suppress longLineCheck
792 {name: 'ctr', args: {'value1': 10, 'value2': 4}, pid: 1, ts: 10, cat: 'foo', tid: 1, ph: 'C'}, // @suppress longLineCheck
793 {name: 'ctr', args: {'value1': 0, 'value2': 1 }, pid: 1, ts: 20, cat: 'foo', tid: 1, ph: 'C'} // @suppress longLineCheck
795 var m = new tracing.TraceModel(events);
796 var p = m.processes[1];
797 var ctr = m.processes[1].counters['foo.ctr'];
798 assertEquals('ctr', ctr.name);
800 assertEquals('ctr', ctr.name);
801 assertEquals('foo', ctr.category);
802 assertEquals(3, ctr.numSamples);
803 assertEquals(2, ctr.numSeries);
805 assertEquals('value1', ctr.series[0].name);
806 assertEquals('value2', ctr.series[1].name);
807 assertEquals(tvcm.ui.getStringColorId('ctr.value1'), ctr.series[0].color);
808 assertEquals(tvcm.ui.getStringColorId('ctr.value2'), ctr.series[1].color);
810 assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
812 ctr.series[0].samples.forEach(function(sample) {
813 samples.push(sample.value);
815 assertArrayEquals([0, 10, 0], samples);
818 ctr.series[1].samples.forEach(function(sample) {
819 samples1.push(sample.value);
821 assertArrayEquals([7, 4, 1], samples1);
822 assertArrayEquals([0, 7,
825 assertEquals(14, ctr.maxTotal);
828 test('importObjectInsteadOfArray', function() {
829 var events = { traceEvents: [
830 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
831 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
834 var m = new tracing.TraceModel(events);
835 assertEquals(1, m.numProcesses);
838 test('importString', function() {
840 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
841 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
844 var m = new tracing.TraceModel(JSON.stringify(events));
845 assertEquals(1, m.numProcesses);
848 test('importStringWithTrailingNewLine', function() {
850 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
851 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
854 var m = new tracing.TraceModel(JSON.stringify(events) + '\n');
855 assertEquals(1, m.numProcesses);
858 test('importStringWithMissingCloseSquareBracket', function() {
860 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
861 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
864 var tmp = JSON.stringify(events);
865 assertEquals(']', tmp[tmp.length - 1]);
867 // Drop off the trailing ]
868 var dropped = tmp.substring(0, tmp.length - 1);
869 var m = new tracing.TraceModel(dropped);
870 assertEquals(1, m.numProcesses);
873 test('importStringWithEndingCommaButMissingCloseSquareBracket', function() {
876 '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', // @suppress longLineCheck
877 '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' // @suppress longLineCheck
879 var text = lines.join('\n');
881 var m = new tracing.TraceModel(text);
882 assertEquals(1, m.numProcesses);
883 assertEquals(1, m.processes[52].threads[53].sliceGroup.length);
886 test('importStringWithMissingCloseSquareBracketAndNewline', function() {
888 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
889 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
892 var tmp = JSON.stringify(events);
893 assertEquals(']', tmp[tmp.length - 1]);
895 // Drop off the trailing ] and add a newline
896 var dropped = tmp.substring(0, tmp.length - 1);
897 var m = new tracing.TraceModel(dropped + '\n');
898 assertEquals(1, m.numProcesses);
901 test('ImportStringEndingCommaButMissingCloseSquareBracketCRLF', function() {
904 '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', // @suppress longLineCheck
905 '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' // @suppress longLineCheck
907 var text = lines.join('\r\n');
909 var m = new tracing.TraceModel(text);
910 assertEquals(1, m.numProcesses);
911 assertEquals(1, m.processes[52].threads[53].sliceGroup.length);
914 test('importOldFormat', function() {
917 '{"cat":"a","pid":9,"tid":8,"ts":194,"ph":"E","name":"I","args":{}},',
918 '{"cat":"b","pid":9,"tid":8,"ts":194,"ph":"B","name":"I","args":{}}',
921 var text = lines.join('\n');
922 var m = new tracing.TraceModel(text);
923 assertEquals(1, m.numProcesses);
924 assertEquals(1, m.processes[9].threads[8].sliceGroup.length);
927 test('startFinishOneSliceOneThread', function() {
929 // Time is intentionally out of order.
930 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'cat', tid: 53,
932 {name: 'a', pid: 52, ts: 524, cat: 'cat', tid: 53,
933 ph: 'S', id: 72, args: {'foo': 'bar'}}
936 var m = new tracing.TraceModel(events);
937 var t = m.processes[52].threads[53];
938 assertNotUndefined(t);
939 assertEquals(1, t.asyncSliceGroup.slices.length);
940 assertEquals('a', t.asyncSliceGroup.slices[0].title);
941 assertEquals('cat', t.asyncSliceGroup.slices[0].category);
942 assertEquals(72, t.asyncSliceGroup.slices[0].id);
943 assertEquals('bar', t.asyncSliceGroup.slices[0].args.foo);
944 assertEquals(0, t.asyncSliceGroup.slices[0].start);
945 assertAlmostEquals((60 - 24) / 1000, t.asyncSliceGroup.slices[0].duration);
946 assertEquals(t, t.asyncSliceGroup.slices[0].startThread);
947 assertEquals(t, t.asyncSliceGroup.slices[0].endThread);
950 test('endArgsAddedToSlice', function() {
952 {name: 'a', args: {x: 1}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
953 {name: 'a', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
956 var m = new tracing.TraceModel(events);
957 assertEquals(1, m.numProcesses);
958 var p = m.processes[52];
959 assertNotUndefined(p);
961 assertEquals(1, p.numThreads);
962 var t = p.threads[53];
963 assertNotUndefined(t);
964 assertEquals(1, t.sliceGroup.length);
965 assertEquals(53, t.tid);
966 var slice = t.sliceGroup.slices[0];
967 assertEquals('a', slice.title);
968 assertEquals('foo', slice.category);
969 assertEquals(0, slice.start);
970 assertEquals(0, slice.subSlices.length);
971 assertEquals(1, slice.args['x']);
972 assertEquals(2, slice.args['y']);
975 test('endArgOverrwritesOriginalArgValueIfDuplicated', function() {
977 {name: 'b', args: {z: 3}, pid: 52, ts: 629, cat: 'foo', tid: 53, ph: 'B'},
978 {name: 'b', args: {z: 4}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'}
981 var m = new tracing.TraceModel(events);
982 assertEquals(1, m.numProcesses);
983 var p = m.processes[52];
984 assertNotUndefined(p);
986 assertEquals(1, p.numThreads);
987 var t = p.threads[53];
988 assertNotUndefined(t);
989 var slice = t.sliceGroup.slices[0];
990 assertEquals('b', slice.title);
991 assertEquals('foo', slice.category);
992 assertEquals(0, slice.start);
993 assertEquals(0, slice.subSlices.length);
994 assertEquals(4, slice.args['z']);
997 test('asyncEndArgsAddedToSlice', function() {
999 // Time is intentionally out of order.
1000 {name: 'c', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1002 {name: 'c', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
1006 var m = new tracing.TraceModel(events);
1007 var t = m.processes[52].threads[53];
1008 assertNotUndefined(t);
1009 assertEquals(1, t.asyncSliceGroup.slices.length);
1010 var parentSlice = t.asyncSliceGroup.slices[0];
1011 assertEquals('c', parentSlice.title);
1012 assertEquals('foo', parentSlice.category);
1014 assertNotUndefined(parentSlice.subSlices);
1015 assertEquals(1, parentSlice.subSlices.length);
1016 var subSlice = parentSlice.subSlices[0];
1017 assertEquals(1, subSlice.args['x']);
1018 assertEquals(2, subSlice.args['y']);
1021 test('asyncEndArgOverrwritesOriginalArgValueIfDuplicated', function() {
1023 // Time is intentionally out of order.
1024 {name: 'd', args: {z: 4}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1026 {name: 'd', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53,
1030 var m = new tracing.TraceModel(events);
1031 var t = m.processes[52].threads[53];
1032 assertNotUndefined(t);
1033 assertEquals(1, t.asyncSliceGroup.slices.length);
1034 var parentSlice = t.asyncSliceGroup.slices[0];
1035 assertEquals('d', parentSlice.title);
1036 assertEquals('foo', parentSlice.category);
1038 assertNotUndefined(parentSlice.subSlices);
1039 assertEquals(1, parentSlice.subSlices.length);
1040 var subSlice = parentSlice.subSlices[0];
1041 assertEquals(4, subSlice.args['z']);
1044 test('asyncStepsInOneThread', function() {
1046 // Time is intentionally out of order.
1047 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'F', id: 72}, // @suppress longLineCheck
1048 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53, ph: 'T', id: 72}, // @suppress longLineCheck
1049 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'S', id: 72} // @suppress longLineCheck
1052 var m = new tracing.TraceModel(events);
1053 var t = m.processes[52].threads[53];
1054 assertNotUndefined(t);
1055 assertEquals(1, t.asyncSliceGroup.slices.length);
1056 var parentSlice = t.asyncSliceGroup.slices[0];
1057 assertEquals('a', parentSlice.title);
1058 assertEquals('foo', parentSlice.category);
1059 assertEquals(0, parentSlice.start);
1061 assertNotUndefined(parentSlice.subSlices);
1062 assertEquals(2, parentSlice.subSlices.length);
1063 var subSlice = parentSlice.subSlices[0];
1064 assertEquals('a', subSlice.title);
1065 assertEquals('foo', subSlice.category);
1066 assertEquals(0, subSlice.start);
1067 assertAlmostEquals((548 - 524) / 1000, subSlice.duration);
1068 assertEquals(1, subSlice.args['x']);
1070 var subSlice = parentSlice.subSlices[1];
1071 assertEquals('a:s1', subSlice.title);
1072 assertEquals('foo', subSlice.category);
1073 assertAlmostEquals((548 - 524) / 1000, subSlice.start);
1074 assertAlmostEquals((560 - 548) / 1000, subSlice.duration);
1075 assertEquals(1, subSlice.args['x']);
1076 assertEquals(2, subSlice.args['y']);
1077 assertEquals(3, subSlice.args['z']);
1080 test('asyncStepsMissingStart', function() {
1082 // Time is intentionally out of order.
1083 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1085 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo',
1086 tid: 53, ph: 'T', id: 72}
1089 var m = new tracing.TraceModel(events);
1090 var t = m.processes[52].threads[53];
1094 test('asyncStepsMissingFinish', function() {
1096 // Time is intentionally out of order.
1097 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo',
1098 tid: 53, ph: 'T', id: 72},
1099 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1103 var m = new tracing.TraceModel(events);
1104 var t = m.processes[52].threads[53];
1108 test('asyncStepEndEvent', function() {
1110 // Time is intentionally out of order.
1111 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1113 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo',
1114 tid: 53, ph: 'p', id: 72},
1115 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
1119 var m = new tracing.TraceModel(events);
1120 var t = m.processes[52].threads[53];
1121 assertNotUndefined(t);
1122 assertEquals(1, t.asyncSliceGroup.slices.length);
1123 var parentSlice = t.asyncSliceGroup.slices[0];
1124 assertEquals('a', parentSlice.title);
1125 assertEquals('foo', parentSlice.category);
1126 assertEquals(0, parentSlice.start);
1128 assertNotUndefined(parentSlice.subSlices);
1129 assertEquals(2, parentSlice.subSlices.length);
1130 var subSlice = parentSlice.subSlices[0];
1131 assertEquals('a:s1', subSlice.title);
1132 assertEquals('foo', subSlice.category);
1133 assertEquals(0, subSlice.start);
1134 assertAlmostEquals((548 - 524) / 1000, subSlice.duration);
1135 assertEquals(1, subSlice.args['x']);
1136 assertEquals(2, subSlice.args['y']);
1138 var subSlice = parentSlice.subSlices[1];
1139 assertEquals('a', subSlice.title);
1140 assertEquals('foo', subSlice.category);
1141 assertAlmostEquals((548 - 524) / 1000, subSlice.start);
1142 assertAlmostEquals((560 - 548) / 1000, subSlice.duration);
1143 assertEquals(1, subSlice.args['x']);
1144 assertEquals(3, subSlice.args['z']);
1147 test('asyncStepMismatch', function() {
1149 // Time is intentionally out of order.
1150 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1152 {name: 'a', args: {step: 's2'}, pid: 52, ts: 548, cat: 'foo', tid: 53,
1154 {name: 'a', args: {step: 's1'}, pid: 52, ts: 548, cat: 'foo', tid: 53,
1156 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
1160 var m = new tracing.TraceModel(events);
1161 var t = m.processes[52].threads[53];
1163 assertTrue(m.hasImportWarnings);
1166 test('importSamples', function() {
1168 {name: 'a', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
1169 {name: 'b', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
1170 {name: 'c', args: {}, pid: 52, ts: 558, cat: 'test', tid: 53, ph: 'P'}
1172 var m = new tracing.TraceModel(events);
1173 var p = m.processes[52];
1174 assertNotUndefined(p);
1175 var t = p.threads[53];
1176 assertNotUndefined(t);
1177 assertEquals(3, t.samples_.length);
1178 assertEquals(0.0, t.samples_[0].start);
1179 assertEquals(0.0, t.samples_[1].start);
1180 assertApproxEquals(0.01, t.samples_[2].start);
1181 assertEquals('a', t.samples_[0].leafStackFrame.title);
1182 assertEquals('b', t.samples_[1].leafStackFrame.title);
1183 assertEquals('c', t.samples_[2].leafStackFrame.title);
1184 assertFalse(m.hasImportWarnings);
1187 test('importSamplesMissingArgs', function() {
1189 {name: 'a', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
1190 {name: 'b', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
1191 {name: 'c', pid: 52, ts: 549, cat: 'test', tid: 53, ph: 'P'}
1193 var m = new tracing.TraceModel(events);
1194 var p = m.processes[52];
1195 assertNotUndefined(p);
1196 var t = p.threads[53];
1197 assertNotUndefined(t);
1198 assertNotUndefined(t);
1199 assertEquals(3, t.samples_.length);
1200 assertFalse(m.hasImportWarnings);
1203 test('importSimpleObject', function() {
1205 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1206 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 15}}, // @suppress longLineCheck
1207 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 20}}, // @suppress longLineCheck
1208 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}} // @suppress longLineCheck
1210 var m = new tracing.TraceModel();
1211 m.importTraces([events], false);
1212 assertEquals(10, m.bounds.min);
1213 assertEquals(50, m.bounds.max);
1214 assertFalse(m.hasImportWarnings);
1216 var p = m.processes[1];
1217 assertNotUndefined(p);
1219 var i10 = p.objects.getObjectInstanceAt('0x1000', 10);
1220 assertEquals('c', i10.category);
1221 assertEquals(10, i10.creationTs);
1222 assertEquals(50, i10.deletionTs);
1223 assertEquals(2, i10.snapshots.length);
1225 var s15 = i10.snapshots[0];
1226 assertEquals(15, s15.ts);
1227 assertEquals(15, s15.args);
1229 var s20 = i10.snapshots[1];
1230 assertEquals(20, s20.ts);
1231 assertEquals(20, s20.args);
1234 test('importImplicitObjects', function() {
1236 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1237 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a',
1239 { id: 'subObject/0x1',
1243 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a',
1245 { id: 'subObject/0x1',
1248 { id: 'subObject/0x2',
1254 var m = new tracing.TraceModel();
1255 m.importTraces([events], false);
1256 var p1 = m.processes[1];
1258 var iA = p1.objects.getObjectInstanceAt('0x1000', 10);
1259 var subObjectInstances = p1.objects.getAllInstancesByTypeName()[
1262 assertEquals(2, subObjectInstances.length);
1263 var subObject1 = p1.objects.getObjectInstanceAt('0x1', 15);
1264 assertEquals('subObject', subObject1.name);
1265 assertEquals(15, subObject1.creationTs);
1267 assertEquals(2, subObject1.snapshots.length);
1268 assertEquals(15, subObject1.snapshots[0].ts);
1269 assertEquals(1, subObject1.snapshots[0].args.foo);
1270 assertEquals(20, subObject1.snapshots[1].ts);
1271 assertEquals(2, subObject1.snapshots[1].args.foo);
1273 var subObject2 = p1.objects.getObjectInstanceAt('0x2', 20);
1274 assertEquals('subObject', subObject2.name);
1275 assertEquals(20, subObject2.creationTs);
1276 assertEquals(1, subObject2.snapshots.length);
1277 assertEquals(20, subObject2.snapshots[0].ts);
1280 test('importImplicitObjectWithCategoryOverride', function() {
1282 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'cat', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1283 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'otherCat', id: '0x1000', name: 'a', // @suppress longLineCheck
1285 { id: 'subObject/0x1',
1292 var m = new tracing.TraceModel();
1293 m.importTraces([events], false);
1294 var p1 = m.processes[1];
1296 var iA = p1.objects.getObjectInstanceAt('0x1000', 10);
1297 var subObjectInstances = p1.objects.getAllInstancesByTypeName()[
1300 assertEquals(1, subObjectInstances.length);
1303 test('importImplicitObjectWithBaseTypeOverride', function() {
1305 {ts: 10000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'PictureLayerImpl', args: { // @suppress longLineCheck
1307 base_type: 'LayerImpl'
1310 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'LayerImpl', args: {}} // @suppress longLineCheck
1313 var m = new tracing.TraceModel();
1314 m.importTraces([events], false);
1315 var p1 = m.processes[1];
1316 assertEquals(0, m.importWarnings.length);
1318 var iA = p1.objects.getObjectInstanceAt('0x1000', 10);
1319 assertEquals(1, iA.snapshots.length);
1322 test('importIDRefs', function() {
1324 // An object with two snapshots.
1325 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1326 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 15}}, // @suppress longLineCheck
1327 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 20}}, // @suppress longLineCheck
1328 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1330 // A slice that references the object.
1331 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {my_object: {id_ref: '0x1000'}}}, // @suppress longLineCheck
1332 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck
1335 var m = new tracing.TraceModel();
1336 m.importTraces([events], false);
1337 var p1 = m.processes[1];
1339 var iA = p1.objects.getObjectInstanceAt('0x1000', 10);
1340 var s15 = iA.getSnapshotAt(15);
1342 var taskSlice = p1.threads[1].sliceGroup.slices[0];
1343 assertEquals(s15, taskSlice.args.my_object);
1346 test('importIDRefsThatPointAtEachOther', function() {
1349 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1350 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck
1355 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1357 // A slice that references the object.
1358 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {my_object: {id_ref: '0x1001'}}}, // @suppress longLineCheck
1359 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck
1362 var m = new tracing.TraceModel();
1363 m.importTraces([events], false);
1364 var p1 = m.processes[1];
1366 var iA = p1.objects.getObjectInstanceAt('0x1000', 15);
1367 var iFoo = p1.objects.getObjectInstanceAt('0x1001', 15);
1368 assertNotUndefined(iA);
1369 assertNotUndefined(iFoo);
1371 var a15 = iA.getSnapshotAt(15);
1372 var foo15 = iFoo.getSnapshotAt(15);
1374 var taskSlice = p1.threads[1].sliceGroup.slices[0];
1375 assertEquals(foo15, taskSlice.args.my_object);
1378 test('importArrayWithIDs', function() {
1380 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck
1382 {id: 'foo/0x1001', value: 'bar1'},
1383 {id: 'foo/0x1002', value: 'bar2'},
1384 {id: 'foo/0x1003', value: 'bar3'}
1388 var m = new tracing.TraceModel();
1389 m.importTraces([events], false);
1390 var p1 = m.processes[1];
1392 var sA = p1.objects.getSnapshotAt('0x1000', 15);
1393 assertTrue(sA.args.x instanceof Array);
1394 assertEquals(3, sA.args.x.length);
1395 assertTrue(sA.args.x[0] instanceof tracing.trace_model.ObjectSnapshot);
1396 assertTrue(sA.args.x[1] instanceof tracing.trace_model.ObjectSnapshot);
1397 assertTrue(sA.args.x[2] instanceof tracing.trace_model.ObjectSnapshot);
1400 test('importDoesNotMutateEventList', function() {
1403 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1404 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck
1405 snapshot: {foo: 15}}},
1406 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1408 // A slice that references the object.
1409 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {
1410 my_object: {id_ref: '0x1000'}}
1412 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck
1415 // The A type family exists to mutate the args list provided to
1417 function ASnapshot() {
1418 tracing.trace_model.ObjectSnapshot.apply(this, arguments);
1421 ASnapshot.prototype = {
1422 __proto__: tracing.trace_model.ObjectSnapshot.prototype
1425 // Import event while the A types are registered, causing the
1426 // arguments of the snapshots to be mutated.
1427 var m = new tracing.TraceModel();
1429 tracing.trace_model.ObjectSnapshot.register('a', ASnapshot);
1430 m.importTraces([events], false);
1432 tracing.trace_model.ObjectSnapshot.unregister('a');
1434 assertFalse(m.hasImportWarnings);
1436 // Verify that the events array wasn't modified.
1439 {snapshot: {foo: 15}});
1442 {my_object: {id_ref: '0x1000'}});
1445 test('importFlowEvent', function() {
1447 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {} }, // @suppress longLineCheck
1448 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {} }, // @suppress longLineCheck
1449 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {} } // @suppress longLineCheck
1452 var m = new tracing.TraceModel(events);
1453 var t = m.processes[52].threads[53];
1455 assertNotUndefined(t);
1456 assertEquals(3, t.sliceGroup.slices.length);
1457 assertEquals(2, m.flowEvents.length);
1459 var start = m.flowEvents[0][0];
1460 var step = m.flowEvents[0][1];
1461 var finish = m.flowEvents[1][1];
1463 assertEquals('a', start.title);
1464 assertEquals('foo', start.category);
1465 assertEquals(72, start.id);
1466 assertEquals(0, start.start);
1467 assertEquals(0, start.duration);
1469 assertEquals(start.title, step.title);
1470 assertEquals(start.category, step.category);
1471 assertEquals(start.id, step.id);
1472 assertAlmostEquals(12 / 1000, step.start);
1473 assertEquals(0, step.duration);
1475 assertEquals(start.title, finish.title);
1476 assertEquals(start.category, finish.category);
1477 assertEquals(start.id, finish.id);
1478 assertAlmostEquals((20 + 12) / 1000, finish.start);
1479 assertEquals(0, finish.duration);
1481 assertEquals(2, m.flowIntervalTree.size);
1484 test('importOutOfOrderFlowEvent', function() {
1486 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {} }, // @suppress longLineCheck
1487 { name: 'b', cat: 'foo', id: 73, pid: 52, tid: 53, ts: 148, ph: 's', args: {} }, // @suppress longLineCheck
1488 { name: 'b', cat: 'foo', id: 73, pid: 52, tid: 53, ts: 570, ph: 'f', args: {} }, // @suppress longLineCheck
1489 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {} }, // @suppress longLineCheck
1490 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {} } // @suppress longLineCheck
1493 var expected = [0.4, 0.0, 0.412];
1494 var m = new tracing.TraceModel(events);
1495 assertEquals(3, m.flowIntervalTree.size);
1497 var order = m.flowEvents.map(function(x) { return x[0].start });
1498 for (var i = 0; i < expected.length; ++i)
1499 assertAlmostEquals(expected[i], order[i]);
1502 test('importCompleteEvent', function() {
1504 { name: 'a', args: {}, pid: 52, ts: 629, dur: 1, cat: 'baz', tid: 53, ph: 'X' }, // @suppress longLineCheck
1505 { name: 'b', args: {}, pid: 52, ts: 730, dur: 20, cat: 'foo', tid: 53, ph: 'X' }, // @suppress longLineCheck
1506 { name: 'c', args: {}, pid: 52, ts: 740, cat: 'baz', tid: 53, ph: 'X' }
1509 var m = new tracing.TraceModel(events);
1510 assertEquals(1, m.numProcesses);
1511 var p = m.processes[52];
1512 assertNotUndefined(p);
1514 assertEquals(1, p.numThreads);
1515 var t = p.threads[53];
1516 assertNotUndefined(t);
1517 assertEquals(3, t.sliceGroup.slices.length);
1518 assertEquals(53, t.tid);
1520 var slice = t.sliceGroup.slices[0];
1521 assertEquals('a', slice.title);
1522 assertEquals('baz', slice.category);
1523 assertAlmostEquals(0, slice.start);
1524 assertAlmostEquals(1 / 1000, slice.duration);
1525 assertEquals(0, slice.subSlices.length);
1527 slice = t.sliceGroup.slices[1];
1528 assertEquals('b', slice.title);
1529 assertEquals('foo', slice.category);
1530 assertAlmostEquals((730 - 629) / 1000, slice.start);
1531 assertAlmostEquals(20 / 1000, slice.duration);
1532 assertEquals(1, slice.subSlices.length);
1534 slice = t.sliceGroup.slices[2];
1535 assertEquals('c', slice.title);
1536 assertTrue(slice.didNotFinish);
1537 assertAlmostEquals(10 / 1000, slice.duration);
1540 test('importCompleteEventWithCpuDuration', function() {
1542 { name: 'a', args: {}, pid: 52, ts: 629, dur: 1, cat: 'baz', tid: 53, ph: 'X', tts: 12, tdur: 1 }, // @suppress longLineCheck
1543 { name: 'b', args: {}, pid: 52, ts: 730, dur: 20, cat: 'foo', tid: 53, ph: 'X', tts: 110, tdur: 16 }, // @suppress longLineCheck
1544 { name: 'c', args: {}, pid: 52, ts: 740, cat: 'baz', tid: 53, ph: 'X', tts: 115 } // @suppress longLineCheck
1547 var m = new tracing.TraceModel(events);
1548 assertEquals(1, m.numProcesses);
1549 var p = m.processes[52];
1550 assertNotUndefined(p);
1552 assertEquals(1, p.numThreads);
1553 var t = p.threads[53];
1554 assertNotUndefined(t);
1555 assertEquals(3, t.sliceGroup.slices.length);
1556 assertEquals(53, t.tid);
1558 var slice = t.sliceGroup.slices[0];
1559 assertEquals('a', slice.title);
1560 assertEquals('baz', slice.category);
1561 assertAlmostEquals(0, slice.start);
1562 assertAlmostEquals(1 / 1000, slice.duration);
1563 assertAlmostEquals(12 / 1000, slice.cpuStart);
1564 assertAlmostEquals(1 / 1000, slice.cpuDuration);
1565 assertEquals(0, slice.subSlices.length);
1567 slice = t.sliceGroup.slices[1];
1568 assertEquals('b', slice.title);
1569 assertEquals('foo', slice.category);
1570 assertAlmostEquals((730 - 629) / 1000, slice.start);
1571 assertAlmostEquals(20 / 1000, slice.duration);
1572 assertAlmostEquals(110 / 1000, slice.cpuStart);
1573 assertAlmostEquals(16 / 1000, slice.cpuDuration);
1574 assertEquals(1, slice.subSlices.length);
1576 slice = t.sliceGroup.slices[2];
1577 assertEquals('c', slice.title);
1578 assertTrue(slice.didNotFinish);
1579 assertAlmostEquals(10 / 1000, slice.duration);
1582 test('importNestedCompleteEventWithTightBounds', function() {
1584 { name: 'a', args: {}, pid: 52, ts: 244654227065, dur: 36075, cat: 'baz', tid: 53, ph: 'X' }, // @suppress longLineCheck
1585 { name: 'b', args: {}, pid: 52, ts: 244654227095, dur: 36045, cat: 'foo', tid: 53, ph: 'X' } // @suppress longLineCheck
1588 var m = new tracing.TraceModel(events, false);
1589 var t = m.processes[52].threads[53];
1591 var sA = findSliceNamed(t.sliceGroup, 'a');
1592 var sB = findSliceNamed(t.sliceGroup, 'b');
1594 assertEquals('a', sA.title);
1595 assertEquals('baz', sA.category);
1596 assertEquals(244654227.065, sA.start);
1597 assertEquals(36.075, sA.duration);
1598 assertAlmostEquals(0.03, sA.selfTime);
1600 assertEquals('b', sB.title);
1601 assertEquals('foo', sB.category);
1602 assertEquals(244654227.095, sB.start);
1603 assertEquals(36.045, sB.duration);
1605 assertTrue(sA.subSlices.length == 1);
1606 assertTrue(sA.subSlices[0] == sB);
1607 assertTrue(sB.parentSlice == sA);
1610 test('importAsyncEventWithSameTimestamp', function() {
1612 // Events are added with ts 0, 1, 1, 2, 2, 3, 3 ...500, 500, 1000
1613 // and use 'seq' to track the order of when the event is recorded.
1614 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 0, ph: 'S', args: {'seq': 0}}); // @suppress longLineCheck
1616 for (var i = 1; i <= 1000; i++)
1617 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: Math.round(i / 2) , ph: 'T', args: {'seq': i}}); // @suppress longLineCheck
1619 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 1000, ph: 'F', args: {'seq': 1001}}); // @suppress longLineCheck
1621 var m = new tracing.TraceModel(events);
1622 var t = m.processes[52].threads[53];
1624 assertEquals(1, t.asyncSliceGroup.slices.length);
1625 var parentSlice = t.asyncSliceGroup.slices[0];
1626 assertEquals('a', parentSlice.title);
1627 assertEquals('foo', parentSlice.category);
1629 assertNotUndefined(parentSlice.subSlices);
1630 var subSlices = parentSlice.subSlices;
1631 assertEquals(1001, subSlices.length);
1632 // Slices should be sorted according to 'ts'. And if 'ts' is the same,
1633 // slices should keep the order that they were recorded.
1634 for (var i = 0; i < 1000; i++)
1635 assertEquals(subSlices[i].args['seq'], i);
1638 test('sampleDataSimple', function() {
1664 'cpu': 0, 'tid': 1, 'ts': 1000.0,
1665 'name': 'cycles:HG', 'sf': 3, 'weight': 1
1668 'cpu': 0, 'tid': 1, 'ts': 2000.0,
1669 'name': 'cycles:HG', 'sf': 2, 'weight': 1
1672 'cpu': 1, 'tid': 1, 'ts': 3000.0,
1673 'name': 'cycles:HG', 'sf': 3, 'weight': 1
1677 var m = new tracing.TraceModel(events, false);
1678 assertNotUndefined(m.kernel.cpus[0]);
1679 assertEquals(1, m.getAllThreads().length);
1681 assertEquals(4, tvcm.dictionaryKeys(m.stackFrames).length);
1682 assertEquals(3, m.samples.length);
1684 var t1 = m.processes[1].threads[1];
1685 assertEquals(3, t1.samples.length);
1687 var c0 = m.kernel.cpus[0];
1688 var c1 = m.kernel.cpus[1];
1689 assertEquals(2, c0.samples.length);
1690 assertEquals(1, c1.samples.length);
1692 assertEquals(c0, m.samples[0].cpu);
1693 assertEquals(t1, m.samples[0].thread);
1694 assertEquals('cycles:HG', m.samples[0].title);
1695 assertEquals(1, m.samples[0].start);
1697 ['main', 'a', 'a_sub'],
1698 m.samples[0].stackTrace.map(function(x) { return x.title; }));
1699 assertEquals(1, m.samples[0].weight);
1702 // TODO(nduca): one slice, two threads
1703 // TODO(nduca): one slice, two pids