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/test_utils.html">
9 <link rel="import" href="/tracing/importer/trace_event_importer.html">
14 tvcm.unittest.testSuite(function() { // @suppress longLineCheck
15 var findSliceNamed = tracing.test_utils.findSliceNamed;
17 test('canImportEmpty', function() {
18 self.assertFalse(tracing.importer.TraceEventImporter.canImport([]));
19 self.assertFalse(tracing.importer.TraceEventImporter.canImport(''));
22 test('basicSingleThreadNonnestedParsing', function() {
24 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
25 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'},
26 {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B'},
27 {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E'}
30 var m = new tracing.TraceModel(events);
31 assertEquals(1, m.numProcesses);
32 var p = m.processes[52];
33 assertNotUndefined(p);
35 assertEquals(1, p.numThreads);
36 var t = p.threads[53];
37 assertNotUndefined(t);
38 assertEquals(2, t.sliceGroup.length);
39 assertEquals(53, t.tid);
40 var slice = t.sliceGroup.slices[0];
41 assertEquals('a', slice.title);
42 assertEquals('foo', slice.category);
43 assertEquals(0, slice.start);
44 assertAlmostEquals((560 - 520) / 1000, slice.duration);
45 assertEquals(0, slice.subSlices.length);
47 slice = t.sliceGroup.slices[1];
48 assertEquals('b', slice.title);
49 assertEquals('bar', slice.category);
50 assertAlmostEquals((629 - 520) / 1000, slice.start);
51 assertAlmostEquals((631 - 629) / 1000, slice.duration);
52 assertEquals(0, slice.subSlices.length);
55 test('basicSingleThreadNonnestedParsingWithCpuDuration', function() {
57 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B', tts: 221}, // @suppress longLineCheck
58 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E', tts: 259}, // @suppress longLineCheck
59 {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B', tts: 329}, // @suppress longLineCheck
60 {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E', tts: 331} // @suppress longLineCheck
63 var m = new tracing.TraceModel(events);
64 assertEquals(1, m.numProcesses);
65 var p = m.processes[52];
66 assertNotUndefined(p);
68 assertEquals(1, p.numThreads);
69 var t = p.threads[53];
70 assertNotUndefined(t);
71 assertEquals(2, t.sliceGroup.length);
72 assertEquals(53, t.tid);
73 var slice = t.sliceGroup.slices[0];
74 assertEquals('a', slice.title);
75 assertEquals('foo', slice.category);
76 assertEquals(0, slice.start);
77 assertAlmostEquals((560 - 520) / 1000, slice.duration);
78 assertAlmostEquals((259 - 221) / 1000, slice.cpuDuration);
79 assertEquals(0, slice.subSlices.length);
81 slice = t.sliceGroup.slices[1];
82 assertEquals('b', slice.title);
83 assertEquals('bar', slice.category);
84 assertAlmostEquals((629 - 520) / 1000, slice.start);
85 assertAlmostEquals((631 - 629) / 1000, slice.duration);
86 assertAlmostEquals((331 - 329) / 1000, slice.cpuDuration);
87 assertEquals(0, slice.subSlices.length);
90 test('argumentDupeCreatesNonFailingImportError', function() {
108 var m = new tracing.TraceModel(events);
109 var t = m.processes[1].threads[1];
110 var sA = findSliceNamed(t.sliceGroup, 'a');
112 assertEquals(2, sA.args.x);
113 assertTrue(m.hasImportWarnings);
114 assertEquals(m.importWarnings.length, 1);
117 test('importMissingArgs', function() {
119 {name: 'a', pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
120 {name: 'a', pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'},
121 {name: 'b', pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'I'}
124 // This should not throw an exception.
125 new tracing.TraceModel(events);
128 test('importDoesNotChokeOnNulls', function() {
130 {name: 'a', args: { foo: null }, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, // @suppress longLineCheck
131 {name: 'a', pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
134 // This should not throw an exception.
135 new tracing.TraceModel(events);
138 test('categoryBeginEndMismatchPrefersBegin', function() {
140 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
141 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'bar', tid: 53, ph: 'E'}
144 var m = new tracing.TraceModel(events);
145 assertEquals(1, m.numProcesses);
146 var p = m.processes[52];
147 assertNotUndefined(p);
149 assertEquals(1, p.numThreads);
150 var t = p.threads[53];
151 assertNotUndefined(t);
152 assertEquals(1, t.sliceGroup.length);
153 assertEquals(53, t.tid);
154 var slice = t.sliceGroup.slices[0];
155 assertEquals('a', slice.title);
156 assertEquals('foo', slice.category);
159 test('beginEndNameMismatch', function() {
161 {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
162 {name: 'b', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
165 var m = new tracing.TraceModel(events);
166 assertTrue(m.hasImportWarnings);
167 assertEquals(1, m.importWarnings.length);
170 test('nestedParsing', function() {
172 {name: 'a', args: {}, pid: 1, ts: 1, tts: 1, cat: 'foo', tid: 1, ph: 'B'},
173 {name: 'b', args: {}, pid: 1, ts: 2, tts: 2, cat: 'bar', tid: 1, ph: 'B'},
174 {name: 'b', args: {}, pid: 1, ts: 3, tts: 3, cat: 'bar', tid: 1, ph: 'E'},
175 {name: 'a', args: {}, pid: 1, ts: 4, tts: 3, cat: 'foo', tid: 1, ph: 'E'}
177 var m = new tracing.TraceModel(events, false);
178 var t = m.processes[1].threads[1];
180 var sA = findSliceNamed(t.sliceGroup, 'a');
181 var sB = findSliceNamed(t.sliceGroup, 'b');
183 assertEquals('a', sA.title);
184 assertEquals('foo', sA.category);
185 assertEquals(0.001, sA.start);
186 assertEquals(0.003, sA.duration);
187 assertEquals(0.002, sA.selfTime);
188 assertEquals(0.001, sA.cpuSelfTime);
190 assertEquals('b', sB.title);
191 assertEquals('bar', sB.category);
192 assertEquals(0.002, sB.start);
193 assertEquals(0.001, sB.duration);
195 assertTrue(sA.subSlices.length == 1);
196 assertTrue(sA.subSlices[0] == sB);
197 assertTrue(sB.parentSlice == sA);
200 test('nestedParsingWithTwoSubSlices', function() {
202 {name: 'a', args: {}, pid: 1, ts: 1, tts: 1, cat: 'foo', tid: 1, ph: 'B'},
203 {name: 'b', args: {}, pid: 1, ts: 2, tts: 2, cat: 'bar', tid: 1, ph: 'B'},
204 {name: 'b', args: {}, pid: 1, ts: 3, tts: 3, cat: 'bar', tid: 1, ph: 'E'},
205 {name: 'c', args: {}, pid: 1, ts: 5, tts: 5, cat: 'baz', tid: 1, ph: 'B'},
206 {name: 'c', args: {}, pid: 1, ts: 7, tts: 6, cat: 'baz', tid: 1, ph: 'E'},
207 {name: 'a', args: {}, pid: 1, ts: 8, tts: 8, cat: 'foo', tid: 1, ph: 'E'}
209 var m = new tracing.TraceModel(events, false);
210 var t = m.processes[1].threads[1];
212 var sA = findSliceNamed(t.sliceGroup, 'a');
213 var sB = findSliceNamed(t.sliceGroup, 'b');
214 var sC = findSliceNamed(t.sliceGroup, 'c');
216 assertEquals('a', sA.title);
217 assertEquals('foo', sA.category);
218 assertEquals(0.001, sA.start);
219 assertEquals(0.007, sA.duration);
220 assertEquals(0.004, sA.selfTime);
221 assertEquals(0.005, sA.cpuSelfTime);
223 assertEquals('b', sB.title);
224 assertEquals('bar', sB.category);
225 assertEquals(0.002, sB.start);
226 assertEquals(0.001, sB.duration);
228 assertEquals('c', sC.title);
229 assertEquals('baz', sC.category);
230 assertEquals(0.005, sC.start);
231 assertEquals(0.002, sC.duration);
233 assertTrue(sA.subSlices.length == 2);
234 assertTrue(sA.subSlices[0] == sB);
235 assertTrue(sA.subSlices[1] == sC);
236 assertTrue(sB.parentSlice == sA);
237 assertTrue(sC.parentSlice == sA);
240 test('nestedParsingWithDoubleNesting', function() {
242 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
243 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'B'},
244 {name: 'c', args: {}, pid: 1, ts: 3, cat: 'baz', tid: 1, ph: 'B'},
245 {name: 'c', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'E'},
246 {name: 'b', args: {}, pid: 1, ts: 7, cat: 'bar', tid: 1, ph: 'E'},
247 {name: 'a', args: {}, pid: 1, ts: 8, cat: 'foo', tid: 1, ph: 'E'}
249 var m = new tracing.TraceModel(events, false);
250 var t = m.processes[1].threads[1];
252 var sA = findSliceNamed(t.sliceGroup, 'a');
253 var sB = findSliceNamed(t.sliceGroup, 'b');
254 var sC = findSliceNamed(t.sliceGroup, 'c');
256 assertEquals('a', sA.title);
257 assertEquals('foo', sA.category);
258 assertEquals(0.001, sA.start);
259 assertEquals(0.007, sA.duration);
260 assertEquals(0.002, sA.selfTime);
262 assertEquals('b', sB.title);
263 assertEquals('bar', sB.category);
264 assertEquals(0.002, sB.start);
265 assertEquals(0.005, sB.duration);
266 assertEquals(0.002, sA.selfTime);
268 assertEquals('c', sC.title);
269 assertEquals('baz', sC.category);
270 assertEquals(0.003, sC.start);
271 assertEquals(0.002, sC.duration);
273 assertTrue(sA.subSlices.length == 1);
274 assertTrue(sA.subSlices[0] == sB);
275 assertTrue(sB.parentSlice == sA);
277 assertTrue(sB.subSlices.length == 1);
278 assertTrue(sB.subSlices[0] == sC);
279 assertTrue(sC.parentSlice == sB);
283 test('autoclosing', function() {
285 // Slice that doesn't finish.
286 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
288 // Slice that does finish to give an 'end time' to make autoclosing work.
289 {name: 'b', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'},
290 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'}
292 var m = new tracing.TraceModel(events);
293 var p = m.processes[1];
294 var t = p.threads[1];
295 var slice = t.sliceGroup.slices[0];
296 assertEquals('a', slice.title);
297 assertEquals('foo', slice.category);
298 assertTrue(slice.didNotFinish);
299 assertEquals(0, slice.start);
300 assertEquals((2 - 1) / 1000, slice.duration);
303 test('autoclosingLoneBegin', function() {
305 // Slice that doesn't finish.
306 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}
308 var m = new tracing.TraceModel(events);
309 var p = m.processes[1];
310 var t = p.threads[1];
311 var slice = t.sliceGroup.slices[0];
312 assertEquals('a', slice.title);
313 assertEquals('foo', slice.category);
314 assertTrue(slice.didNotFinish);
315 assertEquals(0, slice.start);
316 assertEquals(0, slice.duration);
319 test('autoclosingWithSubTasks', function() {
321 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
322 {name: 'b1', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'},
323 {name: 'b1', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'},
324 {name: 'b2', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'}
326 var m = new tracing.TraceModel(events, false);
327 var t = m.processes[1].threads[1];
329 var sA = findSliceNamed(t.sliceGroup, 'a');
330 var sB1 = findSliceNamed(t.sliceGroup, 'b1');
331 var sB2 = findSliceNamed(t.sliceGroup, 'b2');
333 assertEquals(0.003, sA.end);
334 assertEquals(0.003, sB1.end);
335 assertEquals(0.003, sB2.end);
338 test('autoclosingWithEventsOutsideBounds', function() {
340 // Slice that begins before min and ends after max of the other threads.
341 {name: 'a', args: {}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'B'},
342 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'},
344 // Slice that does finish to give an 'end time' to establish a basis
345 {name: 'c', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'},
346 {name: 'c', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'}
348 var m = new tracing.TraceModel(events, false);
349 var p = m.processes[1];
350 var t = p.threads[1];
351 assertEquals(2, t.sliceGroup.length);
353 var slice = findSliceNamed(t.sliceGroup, 'a');
354 assertEquals('a', slice.title);
355 assertEquals('foo', slice.category);
356 assertEquals(0, slice.start);
357 assertEquals(0.003, slice.duration);
359 var t2 = p.threads[2];
360 var slice2 = findSliceNamed(t2.sliceGroup, 'c');
361 assertEquals('c', slice2.title);
362 assertEquals('bar', slice2.category);
363 assertEquals(0.001, slice2.start);
364 assertEquals(0.001, slice2.duration);
366 assertEquals(0.000, m.bounds.min);
367 assertEquals(0.003, m.bounds.max);
370 test('nestedAutoclosing', function() {
372 // Tasks that don't finish.
373 {name: 'a1', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
374 {name: 'a2', args: {}, pid: 1, ts: 1.5, cat: 'foo', tid: 1, ph: 'B'},
376 // Slice that does finish to give an 'end time' to make autoclosing work.
377 {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'},
378 {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'}
380 var m = new tracing.TraceModel(events, false);
381 var t1 = m.processes[1].threads[1];
382 var t2 = m.processes[1].threads[2];
384 var sA1 = findSliceNamed(t1.sliceGroup, 'a1');
385 var sA2 = findSliceNamed(t1.sliceGroup, 'a2');
386 var sB = findSliceNamed(t2.sliceGroup, 'b');
388 assertEquals(0.002, sA1.end);
389 assertEquals(0.002, sA2.end);
392 test('taskColoring', function() {
393 // The test below depends on hashing of 'a' != 'b'. Fail early if that
394 // assumption is incorrect.
395 assertNotEquals(tvcm.ui.getStringHash('a'), tvcm.ui.getStringHash('b'));
398 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
399 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
400 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 1, ph: 'B'},
401 {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 1, ph: 'E'},
402 {name: 'a', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'B'},
403 {name: 'a', args: {}, pid: 1, ts: 6, cat: 'baz', tid: 1, ph: 'E'}
405 var m = new tracing.TraceModel(events);
406 var p = m.processes[1];
407 var t = p.threads[1];
408 var a1 = t.sliceGroup.slices[0];
409 assertEquals('a', a1.title);
410 assertEquals('foo', a1.category);
411 var b = t.sliceGroup.slices[1];
412 assertEquals('b', b.title);
413 assertEquals('bar', b.category);
414 assertNotEquals(a1.colorId, b.colorId);
415 var a2 = t.sliceGroup.slices[2];
416 assertEquals('a', a2.title);
417 assertEquals('baz', a2.category);
418 assertEquals(a1.colorId, a2.colorId);
421 test('multipleThreadParsing', function() {
423 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
424 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
425 {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 2, ph: 'B'},
426 {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 2, ph: 'E'}
428 var m = new tracing.TraceModel(events);
429 assertEquals(1, m.numProcesses);
430 var p = m.processes[1];
431 assertNotUndefined(p);
433 assertEquals(2, p.numThreads);
436 var t = p.threads[1];
437 assertNotUndefined(t);
438 assertEquals(1, t.sliceGroup.length);
439 assertEquals(1, t.tid);
441 var slice = t.sliceGroup.slices[0];
442 assertEquals('a', slice.title);
443 assertEquals('foo', slice.category);
444 assertEquals(0, slice.start);
445 assertEquals((2 - 1) / 1000, slice.duration);
446 assertEquals(0, slice.subSlices.length);
449 var t = p.threads[2];
450 assertNotUndefined(t);
451 assertEquals(1, t.sliceGroup.length);
452 assertEquals(2, t.tid);
454 slice = t.sliceGroup.slices[0];
455 assertEquals('b', slice.title);
456 assertEquals('bar', slice.category);
457 assertEquals((3 - 1) / 1000, slice.start);
458 assertEquals((4 - 3) / 1000, slice.duration);
459 assertEquals(0, slice.subSlices.length);
462 test('multiplePidParsing', function() {
464 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
465 {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
466 {name: 'b', args: {}, pid: 2, ts: 3, cat: 'bar', tid: 2, ph: 'B'},
467 {name: 'b', args: {}, pid: 2, ts: 4, cat: 'bar', tid: 2, ph: 'E'}
469 var m = new tracing.TraceModel(events);
470 assertEquals(2, m.numProcesses);
471 var p = m.processes[1];
472 assertNotUndefined(p);
474 assertEquals(1, p.numThreads);
476 // Check process 1 thread 1.
477 var t = p.threads[1];
478 assertNotUndefined(t);
479 assertEquals(1, t.sliceGroup.length);
480 assertEquals(1, t.tid);
482 var slice = t.sliceGroup.slices[0];
483 assertEquals('a', slice.title);
484 assertEquals('foo', slice.category);
485 assertEquals(0, slice.start);
486 assertEquals((2 - 1) / 1000, slice.duration);
487 assertEquals(0, slice.subSlices.length);
489 // Check process 2 thread 2.
490 var p = m.processes[2];
491 assertNotUndefined(p);
492 assertEquals(1, p.numThreads);
493 var t = p.threads[2];
494 assertNotUndefined(t);
495 assertEquals(1, t.sliceGroup.length);
496 assertEquals(2, t.tid);
498 slice = t.sliceGroup.slices[0];
499 assertEquals('b', slice.title);
500 assertEquals('bar', slice.category);
501 assertEquals((3 - 1) / 1000, slice.start);
502 assertEquals((4 - 3) / 1000, slice.duration);
503 assertEquals(0, slice.subSlices.length);
505 // Check getAllThreads.
506 assertArrayEquals([m.processes[1].threads[1], m.processes[2].threads[2]],
511 test('processNames', function() {
513 {name: 'process_name', args: {name: 'SomeProcessName'},
514 pid: 1, ts: 0, tid: 1, ph: 'M'},
515 {name: 'process_name', args: {name: 'SomeProcessName'},
516 pid: 2, ts: 0, tid: 1, ph: 'M'}
518 var m = new tracing.TraceModel();
519 m.importTraces([events], false, false);
520 assertEquals('SomeProcessName', m.processes[1].name);
524 test('processLabels', function() {
526 {name: 'process_labels', args: {labels: 'foo,bar,bar,foo,baz'},
527 pid: 1, ts: 0, tid: 1, ph: 'M'},
528 {name: 'process_labels', args: {labels: 'baz'},
529 pid: 2, ts: 0, tid: 1, ph: 'M'}
531 var m = new tracing.TraceModel();
532 m.importTraces([events], false, false);
533 assertArrayEquals(['foo', 'bar', 'baz'], m.processes[1].labels);
534 assertArrayEquals(['baz'], m.processes[2].labels);
537 // Process sort index.
538 test('processSortIndex', function() {
540 {name: 'process_name', args: {name: 'First'},
541 pid: 2, ts: 0, tid: 1, ph: 'M'},
542 {name: 'process_name', args: {name: 'Second'},
543 pid: 2, ts: 0, tid: 1, ph: 'M'},
544 {name: 'process_sort_index', args: {sort_index: 1},
545 pid: 1, ts: 0, tid: 1, ph: 'M'}
547 var m = new tracing.TraceModel();
548 m.importTraces([events], false, false);
550 // By name, p1 is before p2. But, its sort index overrides that.
551 assertTrue(m.processes[1].compareTo(m.processes[2]) > 0);
555 test('threadNames', 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: 2, ts: 0, tid: 2, ph: 'M'}
562 var m = new tracing.TraceModel(events);
563 m.importTraces([events], false, false);
564 assertEquals('Thread 1', m.processes[1].threads[1].name);
565 assertEquals('Thread 2', m.processes[2].threads[2].name);
568 // Thread sort index.
569 test('threadSortIndex', function() {
571 {name: 'thread_name', args: {name: 'Thread 1'},
572 pid: 1, ts: 0, tid: 1, ph: 'M'},
573 {name: 'thread_name', args: {name: 'Thread 2'},
574 pid: 1, ts: 0, tid: 2, ph: 'M'},
575 {name: 'thread_sort_index', args: {sort_index: 1},
576 pid: 1, ts: 0, tid: 1, ph: 'M'}
578 var m = new tracing.TraceModel();
579 m.importTraces([events], false, false);
581 // By name, t1 is before t2. But, its sort index overrides that.
582 var t1 = m.processes[1].threads[1];
583 var t2 = m.processes[1].threads[2];
584 assertTrue(t1.compareTo(t2) > 0);
588 test('cpuCounts', function() {
590 {name: 'num_cpus', args: {number: 4},
591 pid: 7, ts: 0, tid: 0, ph: 'M'},
592 {name: 'num_cpus', args: {number: 4},
593 pid: 14, ts: 0, tid: 0, ph: 'M'}
595 var m = new tracing.TraceModel();
596 m.importTraces([events], false, false);
597 assertEquals(4, m.kernel.softwareMeasuredCpuCount);
598 assertEquals(4, m.kernel.bestGuessAtCpuCount);
601 test('cpuCountsWithSandboxBeingConfused', function() {
603 {name: 'num_cpus', args: {number: 4},
604 pid: 7, ts: 0, tid: 0, ph: 'M'},
605 {name: 'num_cpus', args: {number: 1},
606 pid: 14, ts: 0, tid: 0, ph: 'M'}
608 var m = new tracing.TraceModel();
609 m.importTraces([events], false, false);
610 assertEquals(4, m.kernel.softwareMeasuredCpuCount);
611 assertEquals(4, m.kernel.bestGuessAtCpuCount);
614 test('parsingWhenEndComesFirst', function() {
616 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'E'},
617 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'B'},
618 {name: 'a', args: {}, pid: 1, ts: 5, cat: 'foo', tid: 1, ph: 'E'}
620 var m = new tracing.TraceModel(events, false);
621 var p = m.processes[1];
622 var t = p.threads[1];
623 assertEquals(1, t.sliceGroup.length);
624 assertEquals('a', t.sliceGroup.slices[0].title);
625 assertEquals('foo', t.sliceGroup.slices[0].category);
626 assertEquals(0.004, t.sliceGroup.slices[0].start);
627 assertEquals(0.001, t.sliceGroup.slices[0].duration);
628 assertTrue(m.hasImportWarnings);
629 assertEquals(1, m.importWarnings.length);
632 test('immediateParsing', function() {
634 // Need to include immediates inside a task so the timeline
635 // recentering/zeroing doesn't clobber their timestamp.
636 {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
637 {name: 'immediate', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'I'},
638 {name: 'slower', args: {}, pid: 1, ts: 4, cat: 'baz', tid: 1, ph: 'i'},
639 {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'}
641 var m = new tracing.TraceModel(events, false);
642 var p = m.processes[1];
643 var t = p.threads[1];
645 assertEquals(3, t.sliceGroup.length);
646 assertEquals(0.001, t.sliceGroup.slices[0].start);
647 assertEquals(0.003, t.sliceGroup.slices[0].duration);
648 assertEquals(0.002, t.sliceGroup.slices[1].start);
649 assertEquals(0, t.sliceGroup.slices[1].duration);
650 assertEquals(0.004, t.sliceGroup.slices[2].start);
652 var slice = findSliceNamed(t.sliceGroup, 'a');
653 assertEquals('a', slice.title);
654 assertEquals('foo', slice.category);
655 assertEquals(0.003, slice.duration);
657 var immed = findSliceNamed(t.sliceGroup, 'immediate');
658 assertEquals('immediate', immed.title);
659 assertEquals('bar', immed.category);
660 assertEquals(0.002, immed.start);
661 assertEquals(0, immed.duration);
663 var slower = findSliceNamed(t.sliceGroup, 'slower');
664 assertEquals('slower', slower.title);
665 assertEquals('baz', slower.category);
666 assertEquals(0.004, slower.start);
667 assertEquals(0, slower.duration);
670 test('simpleCounter', function() {
672 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
674 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
676 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 20, cat: 'foo', tid: 1,
680 var m = new tracing.TraceModel(events);
681 var p = m.processes[1];
682 var ctr = m.processes[1].counters['foo.ctr'];
684 assertEquals('ctr', ctr.name);
685 assertEquals('foo', ctr.category);
686 assertEquals(3, ctr.numSamples);
687 assertEquals(1, ctr.numSeries);
689 assertEquals('value', ctr.series[0].name);
690 assertEquals(tvcm.ui.getStringColorId('ctr.value'), ctr.series[0].color);
692 assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
695 ctr.series[0].samples.forEach(function(sample) {
696 samples.push(sample.value);
698 assertArrayEquals([0, 10, 0], samples);
700 assertArrayEquals([0, 10, 0], ctr.totals);
701 assertEquals(10, ctr.maxTotal);
704 test('instanceCounter', function() {
706 {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
708 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
710 {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
712 {name: 'ctr', args: {'value': 20}, pid: 1, ts: 15, cat: 'foo', tid: 1,
714 {name: 'ctr', args: {'value': 30}, pid: 1, ts: 18, cat: 'foo', tid: 1,
716 {name: 'ctr', args: {'value': 40}, pid: 1, ts: 20, cat: 'bar', tid: 1,
719 var m = new tracing.TraceModel(events);
720 var p = m.processes[1];
721 var ctr = m.processes[1].counters['foo.ctr[0]'];
722 assertEquals('ctr[0]', ctr.name);
723 assertEquals('foo', ctr.category);
724 assertEquals(2, ctr.numSamples);
725 assertEquals(1, ctr.numSeries);
727 assertArrayEquals([0, 0.01], ctr.timestamps);
729 ctr.series[0].samples.forEach(function(sample) {
730 samples.push(sample.value);
732 assertArrayEquals([0, 10], samples);
734 ctr = m.processes[1].counters['foo.ctr[1]'];
735 assertEquals('ctr[1]', ctr.name);
736 assertEquals('foo', ctr.category);
737 assertEquals(3, ctr.numSamples);
738 assertEquals(1, ctr.numSeries);
739 assertArrayEquals([0.01, 0.015, 0.018], ctr.timestamps);
742 ctr.series[0].samples.forEach(function(sample) {
743 samples.push(sample.value);
745 assertArrayEquals([10, 20, 30], samples);
747 ctr = m.processes[1].counters['bar.ctr[2]'];
748 assertEquals('ctr[2]', ctr.name);
749 assertEquals('bar', ctr.category);
750 assertEquals(1, ctr.numSamples);
751 assertEquals(1, ctr.numSeries);
752 assertArrayEquals([0.02], ctr.timestamps);
754 ctr.series[0].samples.forEach(function(sample) {
755 samples.push(sample.value);
757 assertArrayEquals([40], samples);
760 test('multiCounterUpdateBounds', function() {
761 var ctr = new tracing.trace_model.Counter(undefined, 'testBasicCounter',
762 '', 'testBasicCounter');
763 var value1Series = new tracing.trace_model.CounterSeries(
764 'value1', 'testBasicCounter.value1');
765 var value2Series = new tracing.trace_model.CounterSeries(
766 'value2', 'testBasicCounter.value2');
767 ctr.addSeries(value1Series);
768 ctr.addSeries(value2Series);
770 value1Series.addCounterSample(0, 0);
771 value1Series.addCounterSample(1, 1);
772 value1Series.addCounterSample(2, 1);
773 value1Series.addCounterSample(3, 2);
774 value1Series.addCounterSample(4, 3);
775 value1Series.addCounterSample(5, 1);
776 value1Series.addCounterSample(6, 3);
777 value1Series.addCounterSample(7, 3.1);
779 value2Series.addCounterSample(0, 0);
780 value2Series.addCounterSample(1, 0);
781 value2Series.addCounterSample(2, 1);
782 value2Series.addCounterSample(3, 1.1);
783 value2Series.addCounterSample(4, 0);
784 value2Series.addCounterSample(5, 7);
785 value2Series.addCounterSample(6, 0);
786 value2Series.addCounterSample(7, 0.5);
790 assertEquals(0, ctr.bounds.min);
791 assertEquals(7, ctr.bounds.max);
792 assertEquals(8, ctr.maxTotal);
793 assertArrayEquals([0, 0,
800 3.1, 3.6], ctr.totals);
803 test('multiCounter', function() {
805 {name: 'ctr', args: {'value1': 0, 'value2': 7}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'C'}, // @suppress longLineCheck
806 {name: 'ctr', args: {'value1': 10, 'value2': 4}, pid: 1, ts: 10, cat: 'foo', tid: 1, ph: 'C'}, // @suppress longLineCheck
807 {name: 'ctr', args: {'value1': 0, 'value2': 1 }, pid: 1, ts: 20, cat: 'foo', tid: 1, ph: 'C'} // @suppress longLineCheck
809 var m = new tracing.TraceModel(events);
810 var p = m.processes[1];
811 var ctr = m.processes[1].counters['foo.ctr'];
812 assertEquals('ctr', ctr.name);
814 assertEquals('ctr', ctr.name);
815 assertEquals('foo', ctr.category);
816 assertEquals(3, ctr.numSamples);
817 assertEquals(2, ctr.numSeries);
819 assertEquals('value1', ctr.series[0].name);
820 assertEquals('value2', ctr.series[1].name);
821 assertEquals(tvcm.ui.getStringColorId('ctr.value1'), ctr.series[0].color);
822 assertEquals(tvcm.ui.getStringColorId('ctr.value2'), ctr.series[1].color);
824 assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
826 ctr.series[0].samples.forEach(function(sample) {
827 samples.push(sample.value);
829 assertArrayEquals([0, 10, 0], samples);
832 ctr.series[1].samples.forEach(function(sample) {
833 samples1.push(sample.value);
835 assertArrayEquals([7, 4, 1], samples1);
836 assertArrayEquals([0, 7,
839 assertEquals(14, ctr.maxTotal);
842 test('importObjectInsteadOfArray', function() {
843 var events = { traceEvents: [
844 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
845 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
848 var m = new tracing.TraceModel(events);
849 assertEquals(1, m.numProcesses);
852 test('importString', function() {
854 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
855 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
858 var m = new tracing.TraceModel(JSON.stringify(events));
859 assertEquals(1, m.numProcesses);
862 test('importStringWithTrailingNewLine', function() {
864 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
865 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
868 var m = new tracing.TraceModel(JSON.stringify(events) + '\n');
869 assertEquals(1, m.numProcesses);
872 test('importStringWithMissingCloseSquareBracket', function() {
874 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
875 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
878 var tmp = JSON.stringify(events);
879 assertEquals(']', tmp[tmp.length - 1]);
881 // Drop off the trailing ]
882 var dropped = tmp.substring(0, tmp.length - 1);
883 var m = new tracing.TraceModel(dropped);
884 assertEquals(1, m.numProcesses);
887 test('importStringWithEndingCommaButMissingCloseSquareBracket', function() {
890 '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', // @suppress longLineCheck
891 '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' // @suppress longLineCheck
893 var text = lines.join('\n');
895 var m = new tracing.TraceModel(text);
896 assertEquals(1, m.numProcesses);
897 assertEquals(1, m.processes[52].threads[53].sliceGroup.length);
900 test('importStringWithMissingCloseSquareBracketAndNewline', function() {
902 {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
903 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
906 var tmp = JSON.stringify(events);
907 assertEquals(']', tmp[tmp.length - 1]);
909 // Drop off the trailing ] and add a newline
910 var dropped = tmp.substring(0, tmp.length - 1);
911 var m = new tracing.TraceModel(dropped + '\n');
912 assertEquals(1, m.numProcesses);
915 test('ImportStringEndingCommaButMissingCloseSquareBracketCRLF', function() {
918 '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', // @suppress longLineCheck
919 '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' // @suppress longLineCheck
921 var text = lines.join('\r\n');
923 var m = new tracing.TraceModel(text);
924 assertEquals(1, m.numProcesses);
925 assertEquals(1, m.processes[52].threads[53].sliceGroup.length);
928 test('importOldFormat', function() {
931 '{"cat":"a","pid":9,"tid":8,"ts":194,"ph":"E","name":"I","args":{}},',
932 '{"cat":"b","pid":9,"tid":8,"ts":194,"ph":"B","name":"I","args":{}}',
935 var text = lines.join('\n');
936 var m = new tracing.TraceModel(text);
937 assertEquals(1, m.numProcesses);
938 assertEquals(1, m.processes[9].threads[8].sliceGroup.length);
941 test('startFinishOneSliceOneThread', function() {
943 // Time is intentionally out of order.
944 {name: 'a', args: {}, pid: 52, ts: 560, cat: 'cat', tid: 53,
946 {name: 'a', pid: 52, ts: 524, cat: 'cat', tid: 53,
947 ph: 'S', id: 72, args: {'foo': 'bar'}}
950 var m = new tracing.TraceModel(events);
951 var t = m.processes[52].threads[53];
952 assertNotUndefined(t);
953 assertEquals(1, t.asyncSliceGroup.slices.length);
954 assertEquals('a', t.asyncSliceGroup.slices[0].title);
955 assertEquals('cat', t.asyncSliceGroup.slices[0].category);
956 assertEquals(72, t.asyncSliceGroup.slices[0].id);
957 assertEquals('bar', t.asyncSliceGroup.slices[0].args.foo);
958 assertEquals(0, t.asyncSliceGroup.slices[0].start);
959 assertAlmostEquals((60 - 24) / 1000, t.asyncSliceGroup.slices[0].duration);
960 assertEquals(t, t.asyncSliceGroup.slices[0].startThread);
961 assertEquals(t, t.asyncSliceGroup.slices[0].endThread);
964 test('endArgsAddedToSlice', function() {
966 {name: 'a', args: {x: 1}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
967 {name: 'a', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
970 var m = new tracing.TraceModel(events);
971 assertEquals(1, m.numProcesses);
972 var p = m.processes[52];
973 assertNotUndefined(p);
975 assertEquals(1, p.numThreads);
976 var t = p.threads[53];
977 assertNotUndefined(t);
978 assertEquals(1, t.sliceGroup.length);
979 assertEquals(53, t.tid);
980 var slice = t.sliceGroup.slices[0];
981 assertEquals('a', slice.title);
982 assertEquals('foo', slice.category);
983 assertEquals(0, slice.start);
984 assertEquals(0, slice.subSlices.length);
985 assertEquals(1, slice.args['x']);
986 assertEquals(2, slice.args['y']);
989 test('endArgOverrwritesOriginalArgValueIfDuplicated', function() {
991 {name: 'b', args: {z: 3}, pid: 52, ts: 629, cat: 'foo', tid: 53, ph: 'B'},
992 {name: 'b', args: {z: 4}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'}
995 var m = new tracing.TraceModel(events);
996 assertEquals(1, m.numProcesses);
997 var p = m.processes[52];
998 assertNotUndefined(p);
1000 assertEquals(1, p.numThreads);
1001 var t = p.threads[53];
1002 assertNotUndefined(t);
1003 var slice = t.sliceGroup.slices[0];
1004 assertEquals('b', slice.title);
1005 assertEquals('foo', slice.category);
1006 assertEquals(0, slice.start);
1007 assertEquals(0, slice.subSlices.length);
1008 assertEquals(4, slice.args['z']);
1011 test('asyncEndArgsAddedToSlice', function() {
1013 // Time is intentionally out of order.
1014 {name: 'c', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1016 {name: 'c', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
1020 var m = new tracing.TraceModel(events);
1021 var t = m.processes[52].threads[53];
1022 assertNotUndefined(t);
1023 assertEquals(1, t.asyncSliceGroup.slices.length);
1024 var parentSlice = t.asyncSliceGroup.slices[0];
1025 assertEquals('c', parentSlice.title);
1026 assertEquals('foo', parentSlice.category);
1028 assertNotUndefined(parentSlice.subSlices);
1029 assertEquals(1, parentSlice.subSlices.length);
1030 var subSlice = parentSlice.subSlices[0];
1031 assertEquals(1, subSlice.args['x']);
1032 assertEquals(2, subSlice.args['y']);
1035 test('asyncEndArgOverrwritesOriginalArgValueIfDuplicated', function() {
1037 // Time is intentionally out of order.
1038 {name: 'd', args: {z: 4}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1040 {name: 'd', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53,
1044 var m = new tracing.TraceModel(events);
1045 var t = m.processes[52].threads[53];
1046 assertNotUndefined(t);
1047 assertEquals(1, t.asyncSliceGroup.slices.length);
1048 var parentSlice = t.asyncSliceGroup.slices[0];
1049 assertEquals('d', parentSlice.title);
1050 assertEquals('foo', parentSlice.category);
1052 assertNotUndefined(parentSlice.subSlices);
1053 assertEquals(1, parentSlice.subSlices.length);
1054 var subSlice = parentSlice.subSlices[0];
1055 assertEquals(4, subSlice.args['z']);
1058 test('asyncStepsInOneThread', function() {
1060 // Time is intentionally out of order.
1061 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'F', id: 72}, // @suppress longLineCheck
1062 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53, ph: 'T', id: 72}, // @suppress longLineCheck
1063 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'S', id: 72} // @suppress longLineCheck
1066 var m = new tracing.TraceModel(events);
1067 var t = m.processes[52].threads[53];
1068 assertNotUndefined(t);
1069 assertEquals(1, t.asyncSliceGroup.slices.length);
1070 var parentSlice = t.asyncSliceGroup.slices[0];
1071 assertEquals('a', parentSlice.title);
1072 assertEquals('foo', parentSlice.category);
1073 assertEquals(0, parentSlice.start);
1075 assertNotUndefined(parentSlice.subSlices);
1076 assertEquals(2, parentSlice.subSlices.length);
1077 var subSlice = parentSlice.subSlices[0];
1078 assertEquals('a', subSlice.title);
1079 assertEquals('foo', subSlice.category);
1080 assertEquals(0, subSlice.start);
1081 assertAlmostEquals((548 - 524) / 1000, subSlice.duration);
1082 assertEquals(1, subSlice.args['x']);
1084 var subSlice = parentSlice.subSlices[1];
1085 assertEquals('a:s1', subSlice.title);
1086 assertEquals('foo', subSlice.category);
1087 assertAlmostEquals((548 - 524) / 1000, subSlice.start);
1088 assertAlmostEquals((560 - 548) / 1000, subSlice.duration);
1089 assertEquals(1, subSlice.args['x']);
1090 assertEquals(2, subSlice.args['y']);
1091 assertEquals(3, subSlice.args['z']);
1094 test('asyncStepsMissingStart', function() {
1096 // Time is intentionally out of order.
1097 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1099 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo',
1100 tid: 53, ph: 'T', id: 72}
1103 var m = new tracing.TraceModel(events);
1104 var t = m.processes[52].threads[53];
1108 test('asyncStepsMissingFinish', function() {
1110 // Time is intentionally out of order.
1111 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo',
1112 tid: 53, ph: 'T', id: 72},
1113 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1117 var m = new tracing.TraceModel(events);
1118 var t = m.processes[52].threads[53];
1122 test('asyncStepEndEvent', function() {
1124 // Time is intentionally out of order.
1125 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1127 {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo',
1128 tid: 53, ph: 'p', id: 72},
1129 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
1133 var m = new tracing.TraceModel(events);
1134 var t = m.processes[52].threads[53];
1135 assertNotUndefined(t);
1136 assertEquals(1, t.asyncSliceGroup.slices.length);
1137 var parentSlice = t.asyncSliceGroup.slices[0];
1138 assertEquals('a', parentSlice.title);
1139 assertEquals('foo', parentSlice.category);
1140 assertEquals(0, parentSlice.start);
1142 assertNotUndefined(parentSlice.subSlices);
1143 assertEquals(2, parentSlice.subSlices.length);
1144 var subSlice = parentSlice.subSlices[0];
1145 assertEquals('a:s1', subSlice.title);
1146 assertEquals('foo', subSlice.category);
1147 assertEquals(0, subSlice.start);
1148 assertAlmostEquals((548 - 524) / 1000, subSlice.duration);
1149 assertEquals(1, subSlice.args['x']);
1150 assertEquals(2, subSlice.args['y']);
1152 var subSlice = parentSlice.subSlices[1];
1153 assertEquals('a', subSlice.title);
1154 assertEquals('foo', subSlice.category);
1155 assertAlmostEquals((548 - 524) / 1000, subSlice.start);
1156 assertAlmostEquals((560 - 548) / 1000, subSlice.duration);
1157 assertEquals(1, subSlice.args['x']);
1158 assertEquals(3, subSlice.args['z']);
1161 test('asyncStepMismatch', function() {
1163 // Time is intentionally out of order.
1164 {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
1166 {name: 'a', args: {step: 's2'}, pid: 52, ts: 548, cat: 'foo', tid: 53,
1168 {name: 'a', args: {step: 's1'}, pid: 52, ts: 548, cat: 'foo', tid: 53,
1170 {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
1174 var m = new tracing.TraceModel(events);
1175 var t = m.processes[52].threads[53];
1177 assertTrue(m.hasImportWarnings);
1180 test('importSamples', function() {
1182 {name: 'a', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
1183 {name: 'b', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
1184 {name: 'c', args: {}, pid: 52, ts: 558, cat: 'test', tid: 53, ph: 'P'}
1186 var m = new tracing.TraceModel(events);
1187 var p = m.processes[52];
1188 assertNotUndefined(p);
1189 var t = p.threads[53];
1190 assertNotUndefined(t);
1191 assertEquals(3, t.samples_.length);
1192 assertEquals(0.0, t.samples_[0].start);
1193 assertEquals(0.0, t.samples_[1].start);
1194 assertApproxEquals(0.01, t.samples_[2].start);
1195 assertEquals('a', t.samples_[0].leafStackFrame.title);
1196 assertEquals('b', t.samples_[1].leafStackFrame.title);
1197 assertEquals('c', t.samples_[2].leafStackFrame.title);
1198 assertFalse(m.hasImportWarnings);
1201 test('importSamplesMissingArgs', function() {
1203 {name: 'a', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
1204 {name: 'b', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'},
1205 {name: 'c', pid: 52, ts: 549, cat: 'test', tid: 53, ph: 'P'}
1207 var m = new tracing.TraceModel(events);
1208 var p = m.processes[52];
1209 assertNotUndefined(p);
1210 var t = p.threads[53];
1211 assertNotUndefined(t);
1212 assertNotUndefined(t);
1213 assertEquals(3, t.samples_.length);
1214 assertFalse(m.hasImportWarnings);
1217 test('importSimpleObject', function() {
1219 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1220 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 15}}, // @suppress longLineCheck
1221 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 20}}, // @suppress longLineCheck
1222 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}} // @suppress longLineCheck
1224 var m = new tracing.TraceModel();
1225 m.importTraces([events], false);
1226 assertEquals(10, m.bounds.min);
1227 assertEquals(50, m.bounds.max);
1228 assertFalse(m.hasImportWarnings);
1230 var p = m.processes[1];
1231 assertNotUndefined(p);
1233 var i10 = p.objects.getObjectInstanceAt('0x1000', 10);
1234 assertEquals('c', i10.category);
1235 assertEquals(10, i10.creationTs);
1236 assertEquals(50, i10.deletionTs);
1237 assertEquals(2, i10.snapshots.length);
1239 var s15 = i10.snapshots[0];
1240 assertEquals(15, s15.ts);
1241 assertEquals(15, s15.args);
1243 var s20 = i10.snapshots[1];
1244 assertEquals(20, s20.ts);
1245 assertEquals(20, s20.args);
1248 test('importImplicitObjects', function() {
1250 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1251 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a',
1253 { id: 'subObject/0x1',
1257 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a',
1259 { id: 'subObject/0x1',
1262 { id: 'subObject/0x2',
1268 var m = new tracing.TraceModel();
1269 m.importTraces([events], false);
1270 var p1 = m.processes[1];
1272 var iA = p1.objects.getObjectInstanceAt('0x1000', 10);
1273 var subObjectInstances = p1.objects.getAllInstancesByTypeName()[
1276 assertEquals(2, subObjectInstances.length);
1277 var subObject1 = p1.objects.getObjectInstanceAt('0x1', 15);
1278 assertEquals('subObject', subObject1.name);
1279 assertEquals(15, subObject1.creationTs);
1281 assertEquals(2, subObject1.snapshots.length);
1282 assertEquals(15, subObject1.snapshots[0].ts);
1283 assertEquals(1, subObject1.snapshots[0].args.foo);
1284 assertEquals(20, subObject1.snapshots[1].ts);
1285 assertEquals(2, subObject1.snapshots[1].args.foo);
1287 var subObject2 = p1.objects.getObjectInstanceAt('0x2', 20);
1288 assertEquals('subObject', subObject2.name);
1289 assertEquals(20, subObject2.creationTs);
1290 assertEquals(1, subObject2.snapshots.length);
1291 assertEquals(20, subObject2.snapshots[0].ts);
1294 test('importImplicitObjectWithCategoryOverride', function() {
1296 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'cat', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1297 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'otherCat', id: '0x1000', name: 'a', // @suppress longLineCheck
1299 { id: 'subObject/0x1',
1306 var m = new tracing.TraceModel();
1307 m.importTraces([events], false);
1308 var p1 = m.processes[1];
1310 var iA = p1.objects.getObjectInstanceAt('0x1000', 10);
1311 var subObjectInstances = p1.objects.getAllInstancesByTypeName()[
1314 assertEquals(1, subObjectInstances.length);
1317 test('importImplicitObjectWithBaseTypeOverride', function() {
1319 {ts: 10000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'PictureLayerImpl', args: { // @suppress longLineCheck
1321 base_type: 'LayerImpl'
1324 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'LayerImpl', args: {}} // @suppress longLineCheck
1327 var m = new tracing.TraceModel();
1328 m.importTraces([events], false);
1329 var p1 = m.processes[1];
1330 assertEquals(0, m.importWarnings.length);
1332 var iA = p1.objects.getObjectInstanceAt('0x1000', 10);
1333 assertEquals(1, iA.snapshots.length);
1336 test('importIDRefs', function() {
1338 // An object with two snapshots.
1339 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1340 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 15}}, // @suppress longLineCheck
1341 {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 20}}, // @suppress longLineCheck
1342 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1344 // A slice that references the object.
1345 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {my_object: {id_ref: '0x1000'}}}, // @suppress longLineCheck
1346 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck
1349 var m = new tracing.TraceModel();
1350 m.importTraces([events], false);
1351 var p1 = m.processes[1];
1353 var iA = p1.objects.getObjectInstanceAt('0x1000', 10);
1354 var s15 = iA.getSnapshotAt(15);
1356 var taskSlice = p1.threads[1].sliceGroup.slices[0];
1357 assertEquals(s15, taskSlice.args.my_object);
1360 test('importIDRefsThatPointAtEachOther', function() {
1363 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1364 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck
1369 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1371 // A slice that references the object.
1372 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {my_object: {id_ref: '0x1001'}}}, // @suppress longLineCheck
1373 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck
1376 var m = new tracing.TraceModel();
1377 m.importTraces([events], false);
1378 var p1 = m.processes[1];
1380 var iA = p1.objects.getObjectInstanceAt('0x1000', 15);
1381 var iFoo = p1.objects.getObjectInstanceAt('0x1001', 15);
1382 assertNotUndefined(iA);
1383 assertNotUndefined(iFoo);
1385 var a15 = iA.getSnapshotAt(15);
1386 var foo15 = iFoo.getSnapshotAt(15);
1388 var taskSlice = p1.threads[1].sliceGroup.slices[0];
1389 assertEquals(foo15, taskSlice.args.my_object);
1392 test('importArrayWithIDs', function() {
1394 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck
1396 {id: 'foo/0x1001', value: 'bar1'},
1397 {id: 'foo/0x1002', value: 'bar2'},
1398 {id: 'foo/0x1003', value: 'bar3'}
1402 var m = new tracing.TraceModel();
1403 m.importTraces([events], false);
1404 var p1 = m.processes[1];
1406 var sA = p1.objects.getSnapshotAt('0x1000', 15);
1407 assertTrue(sA.args.x instanceof Array);
1408 assertEquals(3, sA.args.x.length);
1409 assertTrue(sA.args.x[0] instanceof tracing.trace_model.ObjectSnapshot);
1410 assertTrue(sA.args.x[1] instanceof tracing.trace_model.ObjectSnapshot);
1411 assertTrue(sA.args.x[2] instanceof tracing.trace_model.ObjectSnapshot);
1414 test('importDoesNotMutateEventList', function() {
1417 {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1418 {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck
1419 snapshot: {foo: 15}}},
1420 {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck
1422 // A slice that references the object.
1423 {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {
1424 my_object: {id_ref: '0x1000'}}
1426 {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck
1429 // The A type family exists to mutate the args list provided to
1431 function ASnapshot() {
1432 tracing.trace_model.ObjectSnapshot.apply(this, arguments);
1435 ASnapshot.prototype = {
1436 __proto__: tracing.trace_model.ObjectSnapshot.prototype
1439 // Import event while the A types are registered, causing the
1440 // arguments of the snapshots to be mutated.
1441 var m = new tracing.TraceModel();
1443 tracing.trace_model.ObjectSnapshot.register('a', ASnapshot);
1444 m.importTraces([events], false);
1446 tracing.trace_model.ObjectSnapshot.unregister('a');
1448 assertFalse(m.hasImportWarnings);
1450 // Verify that the events array wasn't modified.
1453 {snapshot: {foo: 15}});
1456 {my_object: {id_ref: '0x1000'}});
1459 test('importFlowEvent', function() {
1461 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {} }, // @suppress longLineCheck
1462 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {} }, // @suppress longLineCheck
1463 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {} } // @suppress longLineCheck
1466 var m = new tracing.TraceModel(events);
1467 var t = m.processes[52].threads[53];
1469 assertNotUndefined(t);
1470 assertEquals(3, t.sliceGroup.slices.length);
1471 assertEquals(2, m.flowEvents.length);
1473 var start = m.flowEvents[0][0];
1474 var step = m.flowEvents[0][1];
1475 var finish = m.flowEvents[1][1];
1477 assertEquals('a', start.title);
1478 assertEquals('foo', start.category);
1479 assertEquals(72, start.id);
1480 assertEquals(0, start.start);
1481 assertEquals(0, start.duration);
1483 assertEquals(start.title, step.title);
1484 assertEquals(start.category, step.category);
1485 assertEquals(start.id, step.id);
1486 assertAlmostEquals(12 / 1000, step.start);
1487 assertEquals(0, step.duration);
1489 assertEquals(start.title, finish.title);
1490 assertEquals(start.category, finish.category);
1491 assertEquals(start.id, finish.id);
1492 assertAlmostEquals((20 + 12) / 1000, finish.start);
1493 assertEquals(0, finish.duration);
1495 assertEquals(2, m.flowIntervalTree.size);
1498 test('importOutOfOrderFlowEvent', function() {
1500 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {} }, // @suppress longLineCheck
1501 { name: 'b', cat: 'foo', id: 73, pid: 52, tid: 53, ts: 148, ph: 's', args: {} }, // @suppress longLineCheck
1502 { name: 'b', cat: 'foo', id: 73, pid: 52, tid: 53, ts: 570, ph: 'f', args: {} }, // @suppress longLineCheck
1503 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {} }, // @suppress longLineCheck
1504 { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {} } // @suppress longLineCheck
1507 var expected = [0.4, 0.0, 0.412];
1508 var m = new tracing.TraceModel(events);
1509 assertEquals(3, m.flowIntervalTree.size);
1511 var order = m.flowEvents.map(function(x) { return x[0].start });
1512 for (var i = 0; i < expected.length; ++i)
1513 assertAlmostEquals(expected[i], order[i]);
1516 test('importCompleteEvent', function() {
1518 { name: 'a', args: {}, pid: 52, ts: 629, dur: 1, cat: 'baz', tid: 53, ph: 'X' }, // @suppress longLineCheck
1519 { name: 'b', args: {}, pid: 52, ts: 730, dur: 20, cat: 'foo', tid: 53, ph: 'X' }, // @suppress longLineCheck
1520 { name: 'c', args: {}, pid: 52, ts: 740, cat: 'baz', tid: 53, ph: 'X' }
1523 var m = new tracing.TraceModel(events);
1524 assertEquals(1, m.numProcesses);
1525 var p = m.processes[52];
1526 assertNotUndefined(p);
1528 assertEquals(1, p.numThreads);
1529 var t = p.threads[53];
1530 assertNotUndefined(t);
1531 assertEquals(3, t.sliceGroup.slices.length);
1532 assertEquals(53, t.tid);
1534 var slice = t.sliceGroup.slices[0];
1535 assertEquals('a', slice.title);
1536 assertEquals('baz', slice.category);
1537 assertAlmostEquals(0, slice.start);
1538 assertAlmostEquals(1 / 1000, slice.duration);
1539 assertEquals(0, slice.subSlices.length);
1541 slice = t.sliceGroup.slices[1];
1542 assertEquals('b', slice.title);
1543 assertEquals('foo', slice.category);
1544 assertAlmostEquals((730 - 629) / 1000, slice.start);
1545 assertAlmostEquals(20 / 1000, slice.duration);
1546 assertEquals(1, slice.subSlices.length);
1548 slice = t.sliceGroup.slices[2];
1549 assertEquals('c', slice.title);
1550 assertTrue(slice.didNotFinish);
1551 assertAlmostEquals(10 / 1000, slice.duration);
1554 test('importCompleteEventWithCpuDuration', function() {
1556 { name: 'a', args: {}, pid: 52, ts: 629, dur: 1, cat: 'baz', tid: 53, ph: 'X', tts: 12, tdur: 1 }, // @suppress longLineCheck
1557 { name: 'b', args: {}, pid: 52, ts: 730, dur: 20, cat: 'foo', tid: 53, ph: 'X', tts: 110, tdur: 16 }, // @suppress longLineCheck
1558 { name: 'c', args: {}, pid: 52, ts: 740, cat: 'baz', tid: 53, ph: 'X', tts: 115 } // @suppress longLineCheck
1561 var m = new tracing.TraceModel(events);
1562 assertEquals(1, m.numProcesses);
1563 var p = m.processes[52];
1564 assertNotUndefined(p);
1566 assertEquals(1, p.numThreads);
1567 var t = p.threads[53];
1568 assertNotUndefined(t);
1569 assertEquals(3, t.sliceGroup.slices.length);
1570 assertEquals(53, t.tid);
1572 var slice = t.sliceGroup.slices[0];
1573 assertEquals('a', slice.title);
1574 assertEquals('baz', slice.category);
1575 assertAlmostEquals(0, slice.start);
1576 assertAlmostEquals(1 / 1000, slice.duration);
1577 assertAlmostEquals(12 / 1000, slice.cpuStart);
1578 assertAlmostEquals(1 / 1000, slice.cpuDuration);
1579 assertEquals(0, slice.subSlices.length);
1581 slice = t.sliceGroup.slices[1];
1582 assertEquals('b', slice.title);
1583 assertEquals('foo', slice.category);
1584 assertAlmostEquals((730 - 629) / 1000, slice.start);
1585 assertAlmostEquals(20 / 1000, slice.duration);
1586 assertAlmostEquals(110 / 1000, slice.cpuStart);
1587 assertAlmostEquals(16 / 1000, slice.cpuDuration);
1588 assertEquals(1, slice.subSlices.length);
1590 slice = t.sliceGroup.slices[2];
1591 assertEquals('c', slice.title);
1592 assertTrue(slice.didNotFinish);
1593 assertAlmostEquals(10 / 1000, slice.duration);
1596 test('importNestedCompleteEventWithTightBounds', function() {
1598 { name: 'a', args: {}, pid: 52, ts: 244654227065, dur: 36075, cat: 'baz', tid: 53, ph: 'X' }, // @suppress longLineCheck
1599 { name: 'b', args: {}, pid: 52, ts: 244654227095, dur: 36045, cat: 'foo', tid: 53, ph: 'X' } // @suppress longLineCheck
1602 var m = new tracing.TraceModel(events, false);
1603 var t = m.processes[52].threads[53];
1605 var sA = findSliceNamed(t.sliceGroup, 'a');
1606 var sB = findSliceNamed(t.sliceGroup, 'b');
1608 assertEquals('a', sA.title);
1609 assertEquals('baz', sA.category);
1610 assertEquals(244654227.065, sA.start);
1611 assertEquals(36.075, sA.duration);
1612 assertAlmostEquals(0.03, sA.selfTime);
1614 assertEquals('b', sB.title);
1615 assertEquals('foo', sB.category);
1616 assertEquals(244654227.095, sB.start);
1617 assertEquals(36.045, sB.duration);
1619 assertTrue(sA.subSlices.length == 1);
1620 assertTrue(sA.subSlices[0] == sB);
1621 assertTrue(sB.parentSlice == sA);
1624 test('importAsyncEventWithSameTimestamp', function() {
1626 // Events are added with ts 0, 1, 1, 2, 2, 3, 3 ...500, 500, 1000
1627 // and use 'seq' to track the order of when the event is recorded.
1628 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 0, ph: 'S', args: {'seq': 0}}); // @suppress longLineCheck
1630 for (var i = 1; i <= 1000; i++)
1631 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: Math.round(i / 2) , ph: 'T', args: {'seq': i}}); // @suppress longLineCheck
1633 events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 1000, ph: 'F', args: {'seq': 1001}}); // @suppress longLineCheck
1635 var m = new tracing.TraceModel(events);
1636 var t = m.processes[52].threads[53];
1638 assertEquals(1, t.asyncSliceGroup.slices.length);
1639 var parentSlice = t.asyncSliceGroup.slices[0];
1640 assertEquals('a', parentSlice.title);
1641 assertEquals('foo', parentSlice.category);
1643 assertNotUndefined(parentSlice.subSlices);
1644 var subSlices = parentSlice.subSlices;
1645 assertEquals(1001, subSlices.length);
1646 // Slices should be sorted according to 'ts'. And if 'ts' is the same,
1647 // slices should keep the order that they were recorded.
1648 for (var i = 0; i < 1000; i++)
1649 assertEquals(subSlices[i].args['seq'], i);
1652 test('sampleDataSimple', function() {
1678 'cpu': 0, 'tid': 1, 'ts': 1000.0,
1679 'name': 'cycles:HG', 'sf': 3, 'weight': 1
1682 'cpu': 0, 'tid': 1, 'ts': 2000.0,
1683 'name': 'cycles:HG', 'sf': 2, 'weight': 1
1686 'cpu': 1, 'tid': 1, 'ts': 3000.0,
1687 'name': 'cycles:HG', 'sf': 3, 'weight': 1
1691 var m = new tracing.TraceModel(events, false);
1692 assertNotUndefined(m.kernel.cpus[0]);
1693 assertEquals(1, m.getAllThreads().length);
1695 assertEquals(4, tvcm.dictionaryKeys(m.stackFrames).length);
1696 assertEquals(3, m.samples.length);
1698 var t1 = m.processes[1].threads[1];
1699 assertEquals(3, t1.samples.length);
1701 var c0 = m.kernel.cpus[0];
1702 var c1 = m.kernel.cpus[1];
1703 assertEquals(2, c0.samples.length);
1704 assertEquals(1, c1.samples.length);
1706 assertEquals(c0, m.samples[0].cpu);
1707 assertEquals(t1, m.samples[0].thread);
1708 assertEquals('cycles:HG', m.samples[0].title);
1709 assertEquals(1, m.samples[0].start);
1711 ['main', 'a', 'a_sub'],
1712 m.samples[0].stackTrace.map(function(x) { return x.title; }));
1713 assertEquals(1, m.samples[0].weight);
1716 // TODO(nduca): one slice, two threads
1717 // TODO(nduca): one slice, two pids