| <!DOCTYPE html> |
| <!-- |
| Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| |
| <link rel="import" href="/core/test_utils.html"> |
| <link rel="import" href="/extras/importer/trace_event_importer.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tv.b.unittest.testSuite(function() { // @suppress longLineCheck |
| var findSliceNamed = tv.c.test_utils.findSliceNamed; |
| |
| test('canImportEmpty', function() { |
| self.assertFalse(tv.e.importer.TraceEventImporter.canImport([])); |
| self.assertFalse(tv.e.importer.TraceEventImporter.canImport('')); |
| }); |
| |
| test('basicSingleThreadNonnestedParsing', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}, |
| {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B'}, |
| {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| |
| assertEquals(1, p.numThreads); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| assertEquals(2, t.sliceGroup.length); |
| assertEquals(53, t.tid); |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertEquals(0, slice.start); |
| assertAlmostEquals((560 - 520) / 1000, slice.duration); |
| assertEquals(0, slice.subSlices.length); |
| |
| slice = t.sliceGroup.slices[1]; |
| assertEquals('b', slice.title); |
| assertEquals('bar', slice.category); |
| assertAlmostEquals((629 - 520) / 1000, slice.start); |
| assertAlmostEquals((631 - 629) / 1000, slice.duration); |
| assertEquals(0, slice.subSlices.length); |
| }); |
| |
| test('basicSingleThreadNonnestedParsingWithCpuDuration', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B', tts: 221}, // @suppress longLineCheck |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E', tts: 259}, // @suppress longLineCheck |
| {name: 'b', args: {}, pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'B', tts: 329}, // @suppress longLineCheck |
| {name: 'b', args: {}, pid: 52, ts: 631, cat: 'bar', tid: 53, ph: 'E', tts: 331} // @suppress longLineCheck |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| |
| assertEquals(1, p.numThreads); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| assertEquals(2, t.sliceGroup.length); |
| assertEquals(53, t.tid); |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertEquals(0, slice.start); |
| assertAlmostEquals((560 - 520) / 1000, slice.duration); |
| assertAlmostEquals((259 - 221) / 1000, slice.cpuDuration); |
| assertEquals(0, slice.subSlices.length); |
| |
| slice = t.sliceGroup.slices[1]; |
| assertEquals('b', slice.title); |
| assertEquals('bar', slice.category); |
| assertAlmostEquals((629 - 520) / 1000, slice.start); |
| assertAlmostEquals((631 - 629) / 1000, slice.duration); |
| assertAlmostEquals((331 - 329) / 1000, slice.cpuDuration); |
| assertEquals(0, slice.subSlices.length); |
| }); |
| |
| test('argumentDupeCreatesNonFailingImportError', function() { |
| var events = [ |
| {name: 'a', |
| args: {'x': 1}, |
| pid: 1, |
| ts: 520, |
| cat: 'foo', |
| tid: 1, |
| ph: 'B'}, |
| {name: 'a', |
| args: {'x': 2}, |
| pid: 1, |
| ts: 560, |
| cat: 'foo', |
| tid: 1, |
| ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[1].threads[1]; |
| var sA = findSliceNamed(t.sliceGroup, 'a'); |
| |
| assertEquals(2, sA.args.x); |
| assertTrue(m.hasImportWarnings); |
| assertEquals(m.importWarnings.length, 1); |
| }); |
| |
| test('importMissingArgs', function() { |
| var events = [ |
| {name: 'a', pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}, |
| {name: 'b', pid: 52, ts: 629, cat: 'bar', tid: 53, ph: 'I'} |
| ]; |
| |
| // This should not throw an exception. |
| new tv.c.TraceModel(events); |
| }); |
| |
| test('importDoesNotChokeOnNulls', function() { |
| var events = [ |
| {name: 'a', args: { foo: null }, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, // @suppress longLineCheck |
| {name: 'a', pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| // This should not throw an exception. |
| new tv.c.TraceModel(events); |
| }); |
| |
| test('categoryBeginEndMismatchPrefersBegin', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'bar', tid: 53, ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| |
| assertEquals(1, p.numThreads); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| assertEquals(1, t.sliceGroup.length); |
| assertEquals(53, t.tid); |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| }); |
| |
| test('beginEndNameMismatch', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'b', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| assertTrue(m.hasImportWarnings); |
| assertEquals(1, m.importWarnings.length); |
| }); |
| |
| test('nestedParsing', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 1, ts: 1, tts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 2, tts: 2, cat: 'bar', tid: 1, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 3, tts: 3, cat: 'bar', tid: 1, ph: 'E'}, |
| {name: 'a', args: {}, pid: 1, ts: 4, tts: 3, cat: 'foo', tid: 1, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var t = m.processes[1].threads[1]; |
| |
| var sA = findSliceNamed(t.sliceGroup, 'a'); |
| var sB = findSliceNamed(t.sliceGroup, 'b'); |
| |
| assertEquals('a', sA.title); |
| assertEquals('foo', sA.category); |
| assertEquals(0.001, sA.start); |
| assertEquals(0.003, sA.duration); |
| assertEquals(0.002, sA.selfTime); |
| assertEquals(0.001, sA.cpuSelfTime); |
| |
| assertEquals('b', sB.title); |
| assertEquals('bar', sB.category); |
| assertEquals(0.002, sB.start); |
| assertEquals(0.001, sB.duration); |
| |
| assertTrue(sA.subSlices.length == 1); |
| assertTrue(sA.subSlices[0] == sB); |
| assertTrue(sB.parentSlice == sA); |
| }); |
| |
| test('nestedParsingWithTwoSubSlices', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 1, ts: 1, tts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 2, tts: 2, cat: 'bar', tid: 1, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 3, tts: 3, cat: 'bar', tid: 1, ph: 'E'}, |
| {name: 'c', args: {}, pid: 1, ts: 5, tts: 5, cat: 'baz', tid: 1, ph: 'B'}, |
| {name: 'c', args: {}, pid: 1, ts: 7, tts: 6, cat: 'baz', tid: 1, ph: 'E'}, |
| {name: 'a', args: {}, pid: 1, ts: 8, tts: 8, cat: 'foo', tid: 1, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var t = m.processes[1].threads[1]; |
| |
| var sA = findSliceNamed(t.sliceGroup, 'a'); |
| var sB = findSliceNamed(t.sliceGroup, 'b'); |
| var sC = findSliceNamed(t.sliceGroup, 'c'); |
| |
| assertEquals('a', sA.title); |
| assertEquals('foo', sA.category); |
| assertEquals(0.001, sA.start); |
| assertEquals(0.007, sA.duration); |
| assertEquals(0.004, sA.selfTime); |
| assertEquals(0.005, sA.cpuSelfTime); |
| |
| assertEquals('b', sB.title); |
| assertEquals('bar', sB.category); |
| assertEquals(0.002, sB.start); |
| assertEquals(0.001, sB.duration); |
| |
| assertEquals('c', sC.title); |
| assertEquals('baz', sC.category); |
| assertEquals(0.005, sC.start); |
| assertEquals(0.002, sC.duration); |
| |
| assertTrue(sA.subSlices.length == 2); |
| assertTrue(sA.subSlices[0] == sB); |
| assertTrue(sA.subSlices[1] == sC); |
| assertTrue(sB.parentSlice == sA); |
| assertTrue(sC.parentSlice == sA); |
| }); |
| |
| test('nestedParsingWithDoubleNesting', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'B'}, |
| {name: 'c', args: {}, pid: 1, ts: 3, cat: 'baz', tid: 1, ph: 'B'}, |
| {name: 'c', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'E'}, |
| {name: 'b', args: {}, pid: 1, ts: 7, cat: 'bar', tid: 1, ph: 'E'}, |
| {name: 'a', args: {}, pid: 1, ts: 8, cat: 'foo', tid: 1, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var t = m.processes[1].threads[1]; |
| |
| var sA = findSliceNamed(t.sliceGroup, 'a'); |
| var sB = findSliceNamed(t.sliceGroup, 'b'); |
| var sC = findSliceNamed(t.sliceGroup, 'c'); |
| |
| assertEquals('a', sA.title); |
| assertEquals('foo', sA.category); |
| assertEquals(0.001, sA.start); |
| assertEquals(0.007, sA.duration); |
| assertEquals(0.002, sA.selfTime); |
| |
| assertEquals('b', sB.title); |
| assertEquals('bar', sB.category); |
| assertEquals(0.002, sB.start); |
| assertEquals(0.005, sB.duration); |
| assertEquals(0.002, sA.selfTime); |
| |
| assertEquals('c', sC.title); |
| assertEquals('baz', sC.category); |
| assertEquals(0.003, sC.start); |
| assertEquals(0.002, sC.duration); |
| |
| assertTrue(sA.subSlices.length == 1); |
| assertTrue(sA.subSlices[0] == sB); |
| assertTrue(sB.parentSlice == sA); |
| |
| assertTrue(sB.subSlices.length == 1); |
| assertTrue(sB.subSlices[0] == sC); |
| assertTrue(sC.parentSlice == sB); |
| }); |
| |
| |
| test('autoclosing', function() { |
| var events = [ |
| // Slice that doesn't finish. |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| |
| // Slice that does finish to give an 'end time' to make autoclosing work. |
| {name: 'b', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| var p = m.processes[1]; |
| var t = p.threads[1]; |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertTrue(slice.didNotFinish); |
| assertEquals(0, slice.start); |
| assertEquals((2 - 1) / 1000, slice.duration); |
| }); |
| |
| test('autoclosingLoneBegin', function() { |
| var events = [ |
| // Slice that doesn't finish. |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| var p = m.processes[1]; |
| var t = p.threads[1]; |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertTrue(slice.didNotFinish); |
| assertEquals(0, slice.start); |
| assertEquals(0, slice.duration); |
| }); |
| |
| test('autoclosingWithSubTasks', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'b1', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'b1', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'}, |
| {name: 'b2', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'} |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var t = m.processes[1].threads[1]; |
| |
| var sA = findSliceNamed(t.sliceGroup, 'a'); |
| var sB1 = findSliceNamed(t.sliceGroup, 'b1'); |
| var sB2 = findSliceNamed(t.sliceGroup, 'b2'); |
| |
| assertEquals(0.003, sA.end); |
| assertEquals(0.003, sB1.end); |
| assertEquals(0.003, sB2.end); |
| }); |
| |
| test('autoclosingWithEventsOutsideBounds', function() { |
| var events = [ |
| // Slice that begins before min and ends after max of the other threads. |
| {name: 'a', args: {}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'}, |
| |
| // Slice that does finish to give an 'end time' to establish a basis |
| {name: 'c', args: {}, pid: 1, ts: 1, cat: 'bar', tid: 2, ph: 'B'}, |
| {name: 'c', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 2, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var p = m.processes[1]; |
| var t = p.threads[1]; |
| assertEquals(2, t.sliceGroup.length); |
| |
| var slice = findSliceNamed(t.sliceGroup, 'a'); |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertEquals(0, slice.start); |
| assertEquals(0.003, slice.duration); |
| |
| var t2 = p.threads[2]; |
| var slice2 = findSliceNamed(t2.sliceGroup, 'c'); |
| assertEquals('c', slice2.title); |
| assertEquals('bar', slice2.category); |
| assertEquals(0.001, slice2.start); |
| assertEquals(0.001, slice2.duration); |
| |
| assertEquals(0.000, m.bounds.min); |
| assertEquals(0.003, m.bounds.max); |
| }); |
| |
| test('nestedAutoclosing', function() { |
| var events = [ |
| // Tasks that don't finish. |
| {name: 'a1', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'a2', args: {}, pid: 1, ts: 1.5, cat: 'foo', tid: 1, ph: 'B'}, |
| |
| // Slice that does finish to give an 'end time' to make autoclosing work. |
| {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var t1 = m.processes[1].threads[1]; |
| var t2 = m.processes[1].threads[2]; |
| |
| var sA1 = findSliceNamed(t1.sliceGroup, 'a1'); |
| var sA2 = findSliceNamed(t1.sliceGroup, 'a2'); |
| var sB = findSliceNamed(t2.sliceGroup, 'b'); |
| |
| assertEquals(0.002, sA1.end); |
| assertEquals(0.002, sA2.end); |
| }); |
| |
| test('taskColoring', function() { |
| // The test below depends on hashing of 'a' != 'b'. Fail early if that |
| // assumption is incorrect. |
| assertNotEquals(tv.b.ui.getStringHash('a'), tv.b.ui.getStringHash('b')); |
| |
| var events = [ |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, |
| {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 1, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 1, ph: 'E'}, |
| {name: 'a', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 1, ph: 'B'}, |
| {name: 'a', args: {}, pid: 1, ts: 6, cat: 'baz', tid: 1, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| var p = m.processes[1]; |
| var t = p.threads[1]; |
| var a1 = t.sliceGroup.slices[0]; |
| assertEquals('a', a1.title); |
| assertEquals('foo', a1.category); |
| var b = t.sliceGroup.slices[1]; |
| assertEquals('b', b.title); |
| assertEquals('bar', b.category); |
| assertNotEquals(a1.colorId, b.colorId); |
| var a2 = t.sliceGroup.slices[2]; |
| assertEquals('a', a2.title); |
| assertEquals('baz', a2.category); |
| assertEquals(a1.colorId, a2.colorId); |
| }); |
| |
| test('multipleThreadParsing', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, |
| {name: 'b', args: {}, pid: 1, ts: 3, cat: 'bar', tid: 2, ph: 'B'}, |
| {name: 'b', args: {}, pid: 1, ts: 4, cat: 'bar', tid: 2, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| var p = m.processes[1]; |
| assertNotUndefined(p); |
| |
| assertEquals(2, p.numThreads); |
| |
| // Check thread 1. |
| var t = p.threads[1]; |
| assertNotUndefined(t); |
| assertEquals(1, t.sliceGroup.length); |
| assertEquals(1, t.tid); |
| |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertEquals(0, slice.start); |
| assertEquals((2 - 1) / 1000, slice.duration); |
| assertEquals(0, slice.subSlices.length); |
| |
| // Check thread 2. |
| var t = p.threads[2]; |
| assertNotUndefined(t); |
| assertEquals(1, t.sliceGroup.length); |
| assertEquals(2, t.tid); |
| |
| slice = t.sliceGroup.slices[0]; |
| assertEquals('b', slice.title); |
| assertEquals('bar', slice.category); |
| assertEquals((3 - 1) / 1000, slice.start); |
| assertEquals((4 - 3) / 1000, slice.duration); |
| assertEquals(0, slice.subSlices.length); |
| }); |
| |
| test('multiplePidParsing', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'}, |
| {name: 'b', args: {}, pid: 2, ts: 3, cat: 'bar', tid: 2, ph: 'B'}, |
| {name: 'b', args: {}, pid: 2, ts: 4, cat: 'bar', tid: 2, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| assertEquals(2, m.numProcesses); |
| var p = m.processes[1]; |
| assertNotUndefined(p); |
| |
| assertEquals(1, p.numThreads); |
| |
| // Check process 1 thread 1. |
| var t = p.threads[1]; |
| assertNotUndefined(t); |
| assertEquals(1, t.sliceGroup.length); |
| assertEquals(1, t.tid); |
| |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertEquals(0, slice.start); |
| assertEquals((2 - 1) / 1000, slice.duration); |
| assertEquals(0, slice.subSlices.length); |
| |
| // Check process 2 thread 2. |
| var p = m.processes[2]; |
| assertNotUndefined(p); |
| assertEquals(1, p.numThreads); |
| var t = p.threads[2]; |
| assertNotUndefined(t); |
| assertEquals(1, t.sliceGroup.length); |
| assertEquals(2, t.tid); |
| |
| slice = t.sliceGroup.slices[0]; |
| assertEquals('b', slice.title); |
| assertEquals('bar', slice.category); |
| assertEquals((3 - 1) / 1000, slice.start); |
| assertEquals((4 - 3) / 1000, slice.duration); |
| assertEquals(0, slice.subSlices.length); |
| |
| // Check getAllThreads. |
| assertArrayEquals([m.processes[1].threads[1], m.processes[2].threads[2]], |
| m.getAllThreads()); |
| }); |
| |
| // Process names. |
| test('processNames', function() { |
| var events = [ |
| {name: 'process_name', args: {name: 'SomeProcessName'}, |
| pid: 1, ts: 0, tid: 1, ph: 'M'}, |
| {name: 'process_name', args: {name: 'SomeProcessName'}, |
| pid: 2, ts: 0, tid: 1, ph: 'M'} |
| ]; |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false, false); |
| assertEquals('SomeProcessName', m.processes[1].name); |
| }); |
| |
| // Process labels. |
| test('processLabels', function() { |
| var events = [ |
| {name: 'process_labels', args: {labels: 'foo,bar,bar,foo,baz'}, |
| pid: 1, ts: 0, tid: 1, ph: 'M'}, |
| {name: 'process_labels', args: {labels: 'baz'}, |
| pid: 2, ts: 0, tid: 1, ph: 'M'} |
| ]; |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false, false); |
| assertArrayEquals(['foo', 'bar', 'baz'], m.processes[1].labels); |
| assertArrayEquals(['baz'], m.processes[2].labels); |
| }); |
| |
| // Process sort index. |
| test('processSortIndex', function() { |
| var events = [ |
| {name: 'process_name', args: {name: 'First'}, |
| pid: 2, ts: 0, tid: 1, ph: 'M'}, |
| {name: 'process_name', args: {name: 'Second'}, |
| pid: 2, ts: 0, tid: 1, ph: 'M'}, |
| {name: 'process_sort_index', args: {sort_index: 1}, |
| pid: 1, ts: 0, tid: 1, ph: 'M'} |
| ]; |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false, false); |
| |
| // By name, p1 is before p2. But, its sort index overrides that. |
| assertTrue(m.processes[1].compareTo(m.processes[2]) > 0); |
| }); |
| |
| // Thread names. |
| test('threadNames', function() { |
| var events = [ |
| {name: 'thread_name', args: {name: 'Thread 1'}, |
| pid: 1, ts: 0, tid: 1, ph: 'M'}, |
| {name: 'thread_name', args: {name: 'Thread 2'}, |
| pid: 2, ts: 0, tid: 2, ph: 'M'} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| m.importTraces([events], false, false); |
| assertEquals('Thread 1', m.processes[1].threads[1].name); |
| assertEquals('Thread 2', m.processes[2].threads[2].name); |
| }); |
| |
| // Thread sort index. |
| test('threadSortIndex', function() { |
| var events = [ |
| {name: 'thread_name', args: {name: 'Thread 1'}, |
| pid: 1, ts: 0, tid: 1, ph: 'M'}, |
| {name: 'thread_name', args: {name: 'Thread 2'}, |
| pid: 1, ts: 0, tid: 2, ph: 'M'}, |
| {name: 'thread_sort_index', args: {sort_index: 1}, |
| pid: 1, ts: 0, tid: 1, ph: 'M'} |
| ]; |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false, false); |
| |
| // By name, t1 is before t2. But, its sort index overrides that. |
| var t1 = m.processes[1].threads[1]; |
| var t2 = m.processes[1].threads[2]; |
| assertTrue(t1.compareTo(t2) > 0); |
| }); |
| |
| // CPU counts. |
| test('cpuCounts', function() { |
| var events = [ |
| {name: 'num_cpus', args: {number: 4}, |
| pid: 7, ts: 0, tid: 0, ph: 'M'}, |
| {name: 'num_cpus', args: {number: 4}, |
| pid: 14, ts: 0, tid: 0, ph: 'M'} |
| ]; |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false, false); |
| assertEquals(4, m.kernel.softwareMeasuredCpuCount); |
| assertEquals(4, m.kernel.bestGuessAtCpuCount); |
| }); |
| |
| test('cpuCountsWithSandboxBeingConfused', function() { |
| var events = [ |
| {name: 'num_cpus', args: {number: 4}, |
| pid: 7, ts: 0, tid: 0, ph: 'M'}, |
| {name: 'num_cpus', args: {number: 1}, |
| pid: 14, ts: 0, tid: 0, ph: 'M'} |
| ]; |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false, false); |
| assertEquals(4, m.kernel.softwareMeasuredCpuCount); |
| assertEquals(4, m.kernel.bestGuessAtCpuCount); |
| }); |
| |
| test('parsingWhenEndComesFirst', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'E'}, |
| {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'a', args: {}, pid: 1, ts: 5, cat: 'foo', tid: 1, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var p = m.processes[1]; |
| var t = p.threads[1]; |
| assertEquals(1, t.sliceGroup.length); |
| assertEquals('a', t.sliceGroup.slices[0].title); |
| assertEquals('foo', t.sliceGroup.slices[0].category); |
| assertEquals(0.004, t.sliceGroup.slices[0].start); |
| assertEquals(0.001, t.sliceGroup.slices[0].duration); |
| assertTrue(m.hasImportWarnings); |
| assertEquals(1, m.importWarnings.length); |
| }); |
| |
| test('immediateParsing', function() { |
| var events = [ |
| // Need to include immediates inside a task so the timeline |
| // recentering/zeroing doesn't clobber their timestamp. |
| {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}, |
| {name: 'immediate', args: {}, pid: 1, ts: 2, cat: 'bar', tid: 1, ph: 'I'}, |
| {name: 'slower', args: {}, pid: 1, ts: 4, cat: 'baz', tid: 1, ph: 'i'}, |
| {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'} |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var p = m.processes[1]; |
| var t = p.threads[1]; |
| |
| assertEquals(3, t.sliceGroup.length); |
| assertEquals(0.001, t.sliceGroup.slices[0].start); |
| assertEquals(0.003, t.sliceGroup.slices[0].duration); |
| assertEquals(0.002, t.sliceGroup.slices[1].start); |
| assertEquals(0, t.sliceGroup.slices[1].duration); |
| assertEquals(0.004, t.sliceGroup.slices[2].start); |
| |
| var slice = findSliceNamed(t.sliceGroup, 'a'); |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertEquals(0.003, slice.duration); |
| |
| var immed = findSliceNamed(t.sliceGroup, 'immediate'); |
| assertEquals('immediate', immed.title); |
| assertEquals('bar', immed.category); |
| assertEquals(0.002, immed.start); |
| assertEquals(0, immed.duration); |
| |
| var slower = findSliceNamed(t.sliceGroup, 'slower'); |
| assertEquals('slower', slower.title); |
| assertEquals('baz', slower.category); |
| assertEquals(0.004, slower.start); |
| assertEquals(0, slower.duration); |
| }); |
| |
| test('simpleCounter', function() { |
| var events = [ |
| {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1, |
| ph: 'C'}, |
| {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, |
| ph: 'C'}, |
| {name: 'ctr', args: {'value': 0}, pid: 1, ts: 20, cat: 'foo', tid: 1, |
| ph: 'C'} |
| |
| ]; |
| var m = new tv.c.TraceModel(events); |
| var p = m.processes[1]; |
| var ctr = m.processes[1].counters['foo.ctr']; |
| |
| assertEquals('ctr', ctr.name); |
| assertEquals('foo', ctr.category); |
| assertEquals(3, ctr.numSamples); |
| assertEquals(1, ctr.numSeries); |
| |
| assertEquals('value', ctr.series[0].name); |
| assertEquals(tv.b.ui.getColorIdForGeneralPurposeString('ctr.value'), |
| ctr.series[0].color); |
| |
| assertArrayEquals([0, 0.01, 0.02], ctr.timestamps); |
| |
| var samples = []; |
| ctr.series[0].samples.forEach(function(sample) { |
| samples.push(sample.value); |
| }); |
| assertArrayEquals([0, 10, 0], samples); |
| |
| assertArrayEquals([0, 10, 0], ctr.totals); |
| assertEquals(10, ctr.maxTotal); |
| }); |
| |
| test('instanceCounter', function() { |
| var events = [ |
| {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1, |
| ph: 'C', id: 0}, |
| {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, |
| ph: 'C', id: 0}, |
| {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1, |
| ph: 'C', id: 1}, |
| {name: 'ctr', args: {'value': 20}, pid: 1, ts: 15, cat: 'foo', tid: 1, |
| ph: 'C', id: 1}, |
| {name: 'ctr', args: {'value': 30}, pid: 1, ts: 18, cat: 'foo', tid: 1, |
| ph: 'C', id: 1}, |
| {name: 'ctr', args: {'value': 40}, pid: 1, ts: 20, cat: 'bar', tid: 1, |
| ph: 'C', id: 2} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| var p = m.processes[1]; |
| var ctr = m.processes[1].counters['foo.ctr[0]']; |
| assertEquals('ctr[0]', ctr.name); |
| assertEquals('foo', ctr.category); |
| assertEquals(2, ctr.numSamples); |
| assertEquals(1, ctr.numSeries); |
| |
| assertArrayEquals([0, 0.01], ctr.timestamps); |
| var samples = []; |
| ctr.series[0].samples.forEach(function(sample) { |
| samples.push(sample.value); |
| }); |
| assertArrayEquals([0, 10], samples); |
| |
| ctr = m.processes[1].counters['foo.ctr[1]']; |
| assertEquals('ctr[1]', ctr.name); |
| assertEquals('foo', ctr.category); |
| assertEquals(3, ctr.numSamples); |
| assertEquals(1, ctr.numSeries); |
| assertArrayEquals([0.01, 0.015, 0.018], ctr.timestamps); |
| |
| samples = []; |
| ctr.series[0].samples.forEach(function(sample) { |
| samples.push(sample.value); |
| }); |
| assertArrayEquals([10, 20, 30], samples); |
| |
| ctr = m.processes[1].counters['bar.ctr[2]']; |
| assertEquals('ctr[2]', ctr.name); |
| assertEquals('bar', ctr.category); |
| assertEquals(1, ctr.numSamples); |
| assertEquals(1, ctr.numSeries); |
| assertArrayEquals([0.02], ctr.timestamps); |
| var samples = []; |
| ctr.series[0].samples.forEach(function(sample) { |
| samples.push(sample.value); |
| }); |
| assertArrayEquals([40], samples); |
| }); |
| |
| test('multiCounterUpdateBounds', function() { |
| var ctr = new tv.c.trace_model.Counter(undefined, 'testBasicCounter', |
| '', 'testBasicCounter'); |
| var value1Series = new tv.c.trace_model.CounterSeries( |
| 'value1', 'testBasicCounter.value1'); |
| var value2Series = new tv.c.trace_model.CounterSeries( |
| 'value2', 'testBasicCounter.value2'); |
| ctr.addSeries(value1Series); |
| ctr.addSeries(value2Series); |
| |
| value1Series.addCounterSample(0, 0); |
| value1Series.addCounterSample(1, 1); |
| value1Series.addCounterSample(2, 1); |
| value1Series.addCounterSample(3, 2); |
| value1Series.addCounterSample(4, 3); |
| value1Series.addCounterSample(5, 1); |
| value1Series.addCounterSample(6, 3); |
| value1Series.addCounterSample(7, 3.1); |
| |
| value2Series.addCounterSample(0, 0); |
| value2Series.addCounterSample(1, 0); |
| value2Series.addCounterSample(2, 1); |
| value2Series.addCounterSample(3, 1.1); |
| value2Series.addCounterSample(4, 0); |
| value2Series.addCounterSample(5, 7); |
| value2Series.addCounterSample(6, 0); |
| value2Series.addCounterSample(7, 0.5); |
| |
| ctr.updateBounds(); |
| |
| assertEquals(0, ctr.bounds.min); |
| assertEquals(7, ctr.bounds.max); |
| assertEquals(8, ctr.maxTotal); |
| assertArrayEquals([0, 0, |
| 1, 1, |
| 1, 2, |
| 2, 3.1, |
| 3, 3, |
| 1, 8, |
| 3, 3, |
| 3.1, 3.6], ctr.totals); |
| }); |
| |
| test('multiCounter', function() { |
| var events = [ |
| {name: 'ctr', args: {'value1': 0, 'value2': 7}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'C'}, // @suppress longLineCheck |
| {name: 'ctr', args: {'value1': 10, 'value2': 4}, pid: 1, ts: 10, cat: 'foo', tid: 1, ph: 'C'}, // @suppress longLineCheck |
| {name: 'ctr', args: {'value1': 0, 'value2': 1 }, pid: 1, ts: 20, cat: 'foo', tid: 1, ph: 'C'} // @suppress longLineCheck |
| ]; |
| var m = new tv.c.TraceModel(events); |
| var p = m.processes[1]; |
| var ctr = m.processes[1].counters['foo.ctr']; |
| assertEquals('ctr', ctr.name); |
| |
| assertEquals('ctr', ctr.name); |
| assertEquals('foo', ctr.category); |
| assertEquals(3, ctr.numSamples); |
| assertEquals(2, ctr.numSeries); |
| |
| assertEquals('value1', ctr.series[0].name); |
| assertEquals('value2', ctr.series[1].name); |
| assertEquals(tv.b.ui.getColorIdForGeneralPurposeString('ctr.value1'), |
| ctr.series[0].color); |
| assertEquals(tv.b.ui.getColorIdForGeneralPurposeString('ctr.value2'), |
| ctr.series[1].color); |
| |
| assertArrayEquals([0, 0.01, 0.02], ctr.timestamps); |
| var samples = []; |
| ctr.series[0].samples.forEach(function(sample) { |
| samples.push(sample.value); |
| }); |
| assertArrayEquals([0, 10, 0], samples); |
| |
| var samples1 = []; |
| ctr.series[1].samples.forEach(function(sample) { |
| samples1.push(sample.value); |
| }); |
| assertArrayEquals([7, 4, 1], samples1); |
| assertArrayEquals([0, 7, |
| 10, 14, |
| 0, 1], ctr.totals); |
| assertEquals(14, ctr.maxTotal); |
| }); |
| |
| test('importObjectInsteadOfArray', function() { |
| var events = { traceEvents: [ |
| {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ] }; |
| |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| }); |
| |
| test('importString', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(JSON.stringify(events)); |
| assertEquals(1, m.numProcesses); |
| }); |
| |
| test('importStringWithLeadingSpaces', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(' ' + JSON.stringify(events)); |
| assertEquals(1, m.numProcesses); |
| }); |
| |
| test('importStringWithTrailingNewLine', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(JSON.stringify(events) + '\n'); |
| assertEquals(1, m.numProcesses); |
| }); |
| |
| test('importStringWithMissingCloseSquareBracket', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| var tmp = JSON.stringify(events); |
| assertEquals(']', tmp[tmp.length - 1]); |
| |
| // Drop off the trailing ] |
| var dropped = tmp.substring(0, tmp.length - 1); |
| var m = new tv.c.TraceModel(dropped); |
| assertEquals(1, m.numProcesses); |
| }); |
| |
| test('importStringWithEndingCommaButMissingCloseSquareBracket', function() { |
| var lines = [ |
| '[', |
| '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', // @suppress longLineCheck |
| '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' // @suppress longLineCheck |
| ]; |
| var text = lines.join('\n'); |
| |
| var m = new tv.c.TraceModel(text); |
| assertEquals(1, m.numProcesses); |
| assertEquals(1, m.processes[52].threads[53].sliceGroup.length); |
| }); |
| |
| test('importStringWithMissingCloseSquareBracketAndNewline', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| var tmp = JSON.stringify(events); |
| assertEquals(']', tmp[tmp.length - 1]); |
| |
| // Drop off the trailing ] and add a newline |
| var dropped = tmp.substring(0, tmp.length - 1); |
| var m = new tv.c.TraceModel(dropped + '\n'); |
| assertEquals(1, m.numProcesses); |
| }); |
| |
| test('ImportStringEndingCommaButMissingCloseSquareBracketCRLF', function() { |
| var lines = [ |
| '[', |
| '{"name": "a", "args": {}, "pid": 52, "ts": 524, "cat": "foo", "tid": 53, "ph": "B"},', // @suppress longLineCheck |
| '{"name": "a", "args": {}, "pid": 52, "ts": 560, "cat": "foo", "tid": 53, "ph": "E"},' // @suppress longLineCheck |
| ]; |
| var text = lines.join('\r\n'); |
| |
| var m = new tv.c.TraceModel(text); |
| assertEquals(1, m.numProcesses); |
| assertEquals(1, m.processes[52].threads[53].sliceGroup.length); |
| }); |
| |
| test('importOldFormat', function() { |
| var lines = [ |
| '[', |
| '{"cat":"a","pid":9,"tid":8,"ts":194,"ph":"E","name":"I","args":{}},', |
| '{"cat":"b","pid":9,"tid":8,"ts":194,"ph":"B","name":"I","args":{}}', |
| ']' |
| ]; |
| var text = lines.join('\n'); |
| var m = new tv.c.TraceModel(text); |
| assertEquals(1, m.numProcesses); |
| assertEquals(1, m.processes[9].threads[8].sliceGroup.length); |
| }); |
| |
| test('startFinishOneSliceOneThread', function() { |
| var events = [ |
| // Time is intentionally out of order. |
| {name: 'a', args: {}, pid: 52, ts: 560, cat: 'cat', tid: 53, |
| ph: 'F', id: 72}, |
| {name: 'a', pid: 52, ts: 524, cat: 'cat', tid: 53, |
| ph: 'S', id: 72, args: {'foo': 'bar'}} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| assertEquals('a', t.asyncSliceGroup.slices[0].title); |
| assertEquals('cat', t.asyncSliceGroup.slices[0].category); |
| assertEquals(72, t.asyncSliceGroup.slices[0].id); |
| assertEquals('bar', t.asyncSliceGroup.slices[0].args.foo); |
| assertEquals(0, t.asyncSliceGroup.slices[0].start); |
| assertAlmostEquals((60 - 24) / 1000, t.asyncSliceGroup.slices[0].duration); |
| assertEquals(t, t.asyncSliceGroup.slices[0].startThread); |
| assertEquals(t, t.asyncSliceGroup.slices[0].endThread); |
| }); |
| |
| test('endArgsAddedToSlice', function() { |
| var events = [ |
| {name: 'a', args: {x: 1}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'a', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| |
| assertEquals(1, p.numThreads); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| assertEquals(1, t.sliceGroup.length); |
| assertEquals(53, t.tid); |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('foo', slice.category); |
| assertEquals(0, slice.start); |
| assertEquals(0, slice.subSlices.length); |
| assertEquals(1, slice.args['x']); |
| assertEquals(2, slice.args['y']); |
| }); |
| |
| test('endArgOverrwritesOriginalArgValueIfDuplicated', function() { |
| var events = [ |
| {name: 'b', args: {z: 3}, pid: 52, ts: 629, cat: 'foo', tid: 53, ph: 'B'}, |
| {name: 'b', args: {z: 4}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| |
| assertEquals(1, p.numThreads); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('b', slice.title); |
| assertEquals('foo', slice.category); |
| assertEquals(0, slice.start); |
| assertEquals(0, slice.subSlices.length); |
| assertEquals(4, slice.args['z']); |
| }); |
| |
| test('asyncEndArgsAddedToSlice', function() { |
| var events = [ |
| // Time is intentionally out of order. |
| {name: 'c', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'F', id: 72}, |
| {name: 'c', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'S', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('c', parentSlice.title); |
| assertEquals('foo', parentSlice.category); |
| assertEquals(1, parentSlice.args['x']); |
| assertEquals(2, parentSlice.args['y']); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| assertEquals(0, parentSlice.subSlices.length); |
| }); |
| |
| test('asyncEndArgOverwritesOriginalArgValueIfDuplicated', function() { |
| var events = [ |
| // Time is intentionally out of order. |
| {name: 'd', args: {z: 4}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'F', id: 72}, |
| {name: 'd', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'S', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('d', parentSlice.title); |
| assertEquals('foo', parentSlice.category); |
| assertEquals(4, parentSlice.args['z']); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| assertEquals(0, parentSlice.subSlices.length); |
| }); |
| |
| test('asyncStepsInOneThread', function() { |
| var events = [ |
| // Time is intentionally out of order. |
| {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'F', id: 72}, // @suppress longLineCheck |
| {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53, ph: 'T', id: 72}, // @suppress longLineCheck |
| {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'S', id: 72} // @suppress longLineCheck |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('a', parentSlice.title); |
| assertEquals('foo', parentSlice.category); |
| assertEquals(0, parentSlice.start); |
| assertEquals(1, parentSlice.args['x']); |
| assertUndefined(parentSlice.args['y']); |
| assertEquals(3, parentSlice.args['z']); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| assertEquals(1, parentSlice.subSlices.length); |
| |
| var subSlice = parentSlice.subSlices[0]; |
| assertEquals('a:s1', subSlice.title); |
| assertEquals('foo', subSlice.category); |
| assertAlmostEquals((548 - 524) / 1000, subSlice.start); |
| assertAlmostEquals((560 - 548) / 1000, subSlice.duration); |
| assertUndefined(subSlice.args['x']); |
| assertEquals(2, subSlice.args['y']); |
| assertUndefined(subSlice.args['z']); |
| }); |
| |
| test('asyncStepsMissingStart', function() { |
| var events = [ |
| // Time is intentionally out of order. |
| {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'F', id: 72}, |
| {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', |
| tid: 53, ph: 'T', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertUndefined(t); |
| }); |
| |
| test('asyncStepsMissingFinish', function() { |
| var events = [ |
| // Time is intentionally out of order. |
| {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', |
| tid: 53, ph: 'T', id: 72}, |
| {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'S', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertUndefined(t); |
| }); |
| |
| test('asyncStepEndEvent', function() { |
| var events = [ |
| // Time is intentionally out of order. |
| {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'F', id: 72}, |
| {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', |
| tid: 53, ph: 'p', id: 72}, |
| {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'S', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('a', parentSlice.title); |
| assertEquals('foo', parentSlice.category); |
| assertEquals(0, parentSlice.start); |
| assertEquals(1, parentSlice.args['x']); |
| assertUndefined(parentSlice.args['y']); |
| assertEquals(3, parentSlice.args['z']); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| assertEquals(1, parentSlice.subSlices.length); |
| var subSlice = parentSlice.subSlices[0]; |
| assertEquals('a:s1', subSlice.title); |
| assertEquals('foo', subSlice.category); |
| assertEquals(0, subSlice.start); |
| assertAlmostEquals((548 - 524) / 1000, subSlice.duration); |
| assertUndefined(subSlice.args['x']); |
| assertEquals(2, subSlice.args['y']); |
| assertUndefined(subSlice.args['z']); |
| }); |
| |
| test('asyncStepMismatch', function() { |
| var events = [ |
| // Time is intentionally out of order. |
| {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'F', id: 72}, |
| {name: 'a', args: {step: 's2'}, pid: 52, ts: 548, cat: 'foo', tid: 53, |
| ph: 'T', id: 72}, |
| {name: 'a', args: {step: 's1'}, pid: 52, ts: 548, cat: 'foo', tid: 53, |
| ph: 'p', id: 72}, |
| {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'S', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertUndefined(t); |
| assertTrue(m.hasImportWarnings); |
| }); |
| |
| test('nestableAsyncBasic', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'b', args: {x: 1}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'b', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'e', id: 72}, |
| {name: 'a', args: {}, pid: 52, ts: 565, cat: 'foo', tid: 53, |
| ph: 'e', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('a', parentSlice.title); |
| assertEquals('foo', parentSlice.category); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| assertEquals(1, parentSlice.subSlices.length); |
| var subSlice = parentSlice.subSlices[0]; |
| // Arguments should include both BEGIN and END event. |
| assertEquals(1, subSlice.args['x']); |
| assertEquals(2, subSlice.args['y']); |
| assertUndefined(subSlice.subSlices); |
| }); |
| |
| test('nestableAsyncCombinedParams', function() { |
| var events = [ |
| {name: 'a', args: {x: 1, params: {p1: 'hello', p2: 123}}, |
| pid: 52, ts: 525, cat: 'foo', tid: 53, ph: 'b', id: 72}, |
| {name: 'a', args: {y: 2, params: {p3: 'hi'}}, pid: 52, ts: 560, |
| cat: 'foo', tid: 53, ph: 'e', id: 72}, |
| {name: 'b', args: {params: {p4: 'foo'}}, |
| pid: 52, ts: 525, cat: 'foo', tid: 53, ph: 'b', id: 73}, |
| {name: 'b', args: {params: ''}, pid: 52, ts: 560, |
| cat: 'foo', tid: 53, ph: 'e', id: 73}, |
| {name: 'c', args: {params: {p5: 'bar'}}, |
| pid: 52, ts: 525, cat: 'foo', tid: 53, ph: 'b', id: 74}, |
| {name: 'c', args: {}, pid: 52, ts: 560, |
| cat: 'foo', tid: 53, ph: 'e', id: 74} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(3, t.asyncSliceGroup.slices.length); |
| |
| var sliceA = t.asyncSliceGroup.slices[0]; |
| // Arguments should include both BEGIN and END event. |
| assertEquals(1, sliceA.args['x']); |
| assertEquals(2, sliceA.args['y']); |
| var paramsA = sliceA.args['params']; |
| assertNotUndefined(paramsA); |
| assertEquals('hello', paramsA.p1); |
| assertEquals(123, paramsA.p2); |
| assertEquals('hi', paramsA.p3); |
| |
| var sliceB = t.asyncSliceGroup.slices[1]; |
| // Arguments should include both BEGIN and END event. |
| var paramsB = sliceB.args['params']; |
| assertNotUndefined(paramsB); |
| assertEquals('foo', paramsB.p4); |
| |
| var sliceC = t.asyncSliceGroup.slices[2]; |
| // Arguments should include both BEGIN and END event. |
| var paramsC = sliceC.args['params']; |
| assertNotUndefined(paramsC); |
| assertEquals('bar', paramsC.p5); |
| }); |
| |
| test('nestableAsyncManyLevels', function() { |
| // There are 5 nested levels. |
| var events = [ |
| {name: 'l1', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'l2', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'l3', args: {}, pid: 52, ts: 526, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'l4', args: {}, pid: 52, ts: 527, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'l5', args: {}, pid: 52, ts: 528, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'l5', args: {}, pid: 52, ts: 529, cat: 'foo', tid: 53, |
| ph: 'e', id: 72}, |
| {name: 'l4', args: {}, pid: 52, ts: 530, cat: 'foo', tid: 53, |
| ph: 'e', id: 72}, |
| {name: 'l3', args: {}, pid: 52, ts: 531, cat: 'foo', tid: 53, |
| ph: 'e', id: 72}, |
| {name: 'l2', args: {}, pid: 52, ts: 532, cat: 'foo', tid: 53, |
| ph: 'e', id: 72}, |
| {name: 'l1', args: {}, pid: 52, ts: 533, cat: 'foo', tid: 53, |
| ph: 'e', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| // Perfectly matched events should not produce a warning. |
| assertFalse(m.hasImportWarnings); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| |
| var l1Slice = t.asyncSliceGroup.slices[0]; |
| assertEquals('l1', l1Slice.title); |
| assertAlmostEquals(0, l1Slice.start); |
| assertAlmostEquals(9 / 1000, l1Slice.duration); |
| |
| assertNotUndefined(l1Slice.subSlices); |
| assertEquals(1, l1Slice.subSlices.length); |
| var l2Slice = l1Slice.subSlices[0]; |
| assertEquals('l2', l2Slice.title); |
| assertAlmostEquals(1 / 1000, l2Slice.start); |
| assertAlmostEquals(7 / 1000, l2Slice.duration); |
| |
| assertNotUndefined(l2Slice.subSlices); |
| assertEquals(1, l2Slice.subSlices.length); |
| var l3Slice = l2Slice.subSlices[0]; |
| assertEquals('l3', l3Slice.title); |
| assertAlmostEquals(2 / 1000, l3Slice.start); |
| assertAlmostEquals(5 / 1000, l3Slice.duration); |
| |
| assertNotUndefined(l3Slice.subSlices); |
| assertEquals(1, l3Slice.subSlices.length); |
| var l4Slice = l3Slice.subSlices[0]; |
| assertEquals('l4', l4Slice.title); |
| assertAlmostEquals(3 / 1000, l4Slice.start); |
| assertAlmostEquals(3 / 1000, l4Slice.duration); |
| |
| assertNotUndefined(l4Slice.subSlices); |
| assertEquals(1, l4Slice.subSlices.length); |
| var l5Slice = l4Slice.subSlices[0]; |
| assertEquals('l5', l5Slice.title); |
| assertAlmostEquals(4 / 1000, l5Slice.start); |
| assertAlmostEquals(1 / 1000, l5Slice.duration); |
| }); |
| |
| test('nestableAsyncInstantEvent', function() { |
| var events = [ |
| {name: 'c', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'n', id: 71}, |
| {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'd', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'n', id: 72}, |
| {name: 'a', args: {}, pid: 52, ts: 565, cat: 'foo', tid: 53, |
| ph: 'e', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(2, t.asyncSliceGroup.slices.length); |
| var instantSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('c', instantSlice.title); |
| assertAlmostEquals(0, instantSlice.start); |
| assertAlmostEquals(0, instantSlice.duration); |
| assertUndefined(instantSlice.subSlices); |
| |
| var nestedSlice = t.asyncSliceGroup.slices[1]; |
| assertEquals('a', nestedSlice.title); |
| assertAlmostEquals(0, nestedSlice.start); |
| assertAlmostEquals((565 - 524) / 1000, nestedSlice.duration); |
| assertNotUndefined(nestedSlice.subSlices); |
| assertEquals(1, nestedSlice.subSlices.length); |
| var nestedInstantSlice = nestedSlice.subSlices[0]; |
| assertUndefined(nestedInstantSlice.subSlices); |
| assertEquals('d', nestedInstantSlice.title); |
| }); |
| |
| test('nestableAsyncUnmatchedOuterBeginEvent', function() { |
| var events = [ |
| {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'b', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'b', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'e', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| // Unmatched BEGIN should produce a warning. |
| assertTrue(m.hasImportWarnings); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('a', parentSlice.title); |
| assertEquals('foo', parentSlice.category); |
| assertAlmostEquals(0, parentSlice.start); |
| // Unmatched BEGIN event ends at the last event of that ID. |
| assertAlmostEquals(36 / 1000, parentSlice.duration); |
| // Arguments should include only include its arguments. |
| assertUndefined(parentSlice.args['y']); |
| assertEquals(1, parentSlice.args['x']); |
| assertNotUndefined(parentSlice.error); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| assertEquals(1, parentSlice.subSlices.length); |
| var subSlice = parentSlice.subSlices[0]; |
| assertAlmostEquals(1 / 1000, subSlice.start); |
| assertAlmostEquals(35 / 1000, subSlice.duration); |
| assertUndefined(subSlice.subSlices); |
| // Arguments should include those of the END event. |
| assertEquals(2, subSlice.args['y']); |
| assertUndefined(subSlice.subSlices); |
| }); |
| |
| test('nestableAsyncUnmatchedInnerBeginEvent', function() { |
| var events = [ |
| {name: 'a', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'c', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'n', id: 72}, |
| {name: 'b', args: {x: 1}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'a', args: {y: 2}, pid: 52, ts: 565, cat: 'foo', tid: 53, |
| ph: 'e', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| // Unmatched BEGIN should produce a warning. |
| assertTrue(m.hasImportWarnings); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('a', parentSlice.title); |
| assertEquals('foo', parentSlice.category); |
| assertAlmostEquals(0, parentSlice.start); |
| assertAlmostEquals(41 / 1000, parentSlice.duration); |
| // Arguments should include both BEGIN and END event. |
| assertEquals(2, parentSlice.args['y']); |
| assertEquals(3, parentSlice.args['z']); |
| assertUndefined(parentSlice.args['x']); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| assertEquals(2, parentSlice.subSlices.length); |
| var subSliceInstant = parentSlice.subSlices[0]; |
| var subSliceUnmatched = parentSlice.subSlices[1]; |
| assertEquals('c', subSliceInstant.title); |
| assertEquals('b', subSliceUnmatched.title); |
| // Unmatched BEGIN ends at the last event of that ID. |
| assertAlmostEquals(1 / 1000, subSliceUnmatched.start); |
| assertAlmostEquals(40 / 1000, subSliceUnmatched.duration); |
| assertUndefined(subSliceUnmatched.subSlices); |
| assertEquals(1, subSliceUnmatched.args['x']); |
| assertUndefined(subSliceUnmatched['y']); |
| assertNotUndefined(subSliceUnmatched.error); |
| assertAlmostEquals(1 / 1000, subSliceInstant.start); |
| assertAlmostEquals(0, subSliceInstant.duration); |
| assertUndefined(subSliceInstant.subSlices); |
| }); |
| |
| test('nestableAsyncUnmatchedOuterEndEvent', function() { |
| // Events are intentionally out-of-order. |
| var events = [ |
| {name: 'b', args: {x: 1}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'b', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, |
| ph: 'e', id: 72}, |
| {name: 'a', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'e', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| // Unmatched END should produce a warning. |
| assertTrue(m.hasImportWarnings); |
| assertEquals(2, t.asyncSliceGroup.slices.length); |
| var unmatchedSlice = t.asyncSliceGroup.slices[0]; |
| var slice = t.asyncSliceGroup.slices[1]; |
| assertEquals('a', unmatchedSlice.title); |
| assertAlmostEquals(0, unmatchedSlice.start); |
| // Unmatched END event begins at the first event of that ID. In this |
| // case, the first event happens to be the same unmatched event. |
| assertAlmostEquals(0 / 1000, unmatchedSlice.duration); |
| assertUndefined(unmatchedSlice.args['x']); |
| assertUndefined(unmatchedSlice.args['y']); |
| assertEquals(3, unmatchedSlice.args['z']); |
| assertNotUndefined(unmatchedSlice.error); |
| assertUndefined(unmatchedSlice.subSlices); |
| |
| assertEquals('b', slice.title); |
| assertAlmostEquals(1 / 1000, slice.start); |
| assertAlmostEquals(35 / 1000, slice.duration); |
| // Arguments should include both BEGIN and END event. |
| assertEquals(1, slice.args['x']); |
| assertEquals(2, slice.args['y']); |
| assertUndefined(slice.subSlices); |
| }); |
| |
| test('nestableAsyncUnmatchedInnerEndEvent', function() { |
| var events = [ |
| {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'c', args: {}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'n', id: 72}, |
| {name: 'b', args: {z: 3}, pid: 52, ts: 525, cat: 'foo', tid: 53, |
| ph: 'e', id: 72}, |
| {name: 'a', args: {y: 2}, pid: 52, ts: 565, cat: 'foo', tid: 53, |
| ph: 'e', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| // Unmatched END should produce a warning. |
| assertTrue(m.hasImportWarnings); |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('a', parentSlice.title); |
| assertAlmostEquals(0, parentSlice.start); |
| assertAlmostEquals(41 / 1000, parentSlice.duration); |
| // Arguments should include both BEGIN and END event. |
| assertEquals(1, parentSlice.args['x']); |
| assertEquals(2, parentSlice.args['y']); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| assertEquals(2, parentSlice.subSlices.length); |
| var subSliceInstant = parentSlice.subSlices[0]; |
| var subSliceUnmatched = parentSlice.subSlices[1]; |
| assertEquals('c', subSliceInstant.title); |
| assertEquals('b', subSliceUnmatched.title); |
| // Unmatched END begins at the first event of that ID. |
| assertAlmostEquals(0 / 1000, subSliceUnmatched.start); |
| assertAlmostEquals(1 / 1000, subSliceUnmatched.duration); |
| // Arguments should include both BEGIN and END event. |
| assertUndefined(subSliceUnmatched.args['x']); |
| assertUndefined(subSliceUnmatched.args['y']); |
| assertEquals(3, subSliceUnmatched.args['z']); |
| assertNotUndefined(subSliceUnmatched.error); |
| |
| assertUndefined(subSliceUnmatched.subSlices); |
| assertAlmostEquals(1 / 1000, subSliceInstant.start); |
| assertAlmostEquals(0, subSliceInstant.duration); |
| assertUndefined(subSliceInstant.subSlices); |
| }); |
| |
| test('nestableAsyncSameIDDifferentCategory', function() { |
| // Events with the same ID, but different categories should not be |
| // considered as nested. |
| var events = [ |
| {name: 'EVENT_A', args: {}, pid: 52, ts: 500, cat: 'foo', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'EVENT_B', args: {y: 2}, pid: 52, ts: 550, cat: 'bar', tid: 53, |
| ph: 'b', id: 72}, |
| {name: 'EVENT_B', args: {}, pid: 52, ts: 600, cat: 'bar', tid: 53, |
| ph: 'e', id: 72}, |
| {name: 'EVENT_A', args: {x: 1}, pid: 52, ts: 650, cat: 'foo', tid: 53, |
| ph: 'e', id: 72} |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| assertNotUndefined(t); |
| assertEquals(2, t.asyncSliceGroup.slices.length); |
| var eventASlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('EVENT_A', eventASlice.title); |
| assertEquals('foo', eventASlice.category); |
| assertEquals('foo:72', eventASlice.id); |
| assertEquals(1, eventASlice.args['x']); |
| assertUndefined(eventASlice.subSlices); |
| |
| var eventBSlice = t.asyncSliceGroup.slices[1]; |
| assertEquals('EVENT_B', eventBSlice.title); |
| assertEquals('bar', eventBSlice.category); |
| assertEquals('bar:72', eventBSlice.id); |
| assertEquals(2, eventBSlice.args['y']); |
| assertUndefined(eventBSlice.subSlices); |
| }); |
| |
| test('importSamples', function() { |
| var events = [ |
| {name: 'a', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'}, |
| {name: 'b', args: {}, pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'}, |
| {name: 'c', args: {}, pid: 52, ts: 558, cat: 'test', tid: 53, ph: 'P'} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| assertEquals(3, t.samples_.length); |
| assertEquals(0.0, t.samples_[0].start); |
| assertEquals(0.0, t.samples_[1].start); |
| assertApproxEquals(0.01, t.samples_[2].start); |
| assertEquals('a', t.samples_[0].leafStackFrame.title); |
| assertEquals('b', t.samples_[1].leafStackFrame.title); |
| assertEquals('c', t.samples_[2].leafStackFrame.title); |
| assertFalse(m.hasImportWarnings); |
| }); |
| |
| test('importSamplesWithStackFrames', function() { |
| var eventData = { |
| traceEvents: [ |
| { name: 'a', args: {}, pid: 1, ts: 0, cat: 'test', tid: 2, ph: 'P', sf: 7 } // @suppress longLineCheck |
| ], |
| stackFrames: { |
| '1': { |
| category: 'm1', |
| name: 'main' |
| }, |
| '7': { |
| category: 'm2', |
| name: 'frame7', |
| parent: '1' |
| } |
| } |
| }; |
| |
| var options = new tv.c.ImportOptions(); |
| options.shiftWorldToZero = false; |
| var m = new tv.c.TraceModel(eventData, options); |
| |
| var p = m.processes[1]; |
| var t = p.threads[2]; |
| |
| assertEquals(1, t.samples.length); |
| assertEquals(0.0, t.samples_[0].start); |
| assertEquals('frame7', t.samples_[0].leafStackFrame.title); |
| assertFalse(m.hasImportWarnings); |
| }); |
| |
| test('importSamplesMissingArgs', function() { |
| var events = [ |
| {name: 'a', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'}, |
| {name: 'b', pid: 52, ts: 548, cat: 'test', tid: 53, ph: 'P'}, |
| {name: 'c', pid: 52, ts: 549, cat: 'test', tid: 53, ph: 'P'} |
| ]; |
| var m = new tv.c.TraceModel(events); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| assertNotUndefined(t); |
| assertEquals(3, t.samples_.length); |
| assertFalse(m.hasImportWarnings); |
| }); |
| |
| test('importSimpleObject', function() { |
| var events = [ |
| {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 15}}, // @suppress longLineCheck |
| {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 20}}, // @suppress longLineCheck |
| {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}} // @suppress longLineCheck |
| ]; |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false); |
| assertEquals(10, m.bounds.min); |
| assertEquals(50, m.bounds.max); |
| assertFalse(m.hasImportWarnings); |
| |
| var p = m.processes[1]; |
| assertNotUndefined(p); |
| |
| var i10 = p.objects.getObjectInstanceAt('0x1000', 10); |
| assertEquals('c', i10.category); |
| assertEquals(10, i10.creationTs); |
| assertEquals(50, i10.deletionTs); |
| assertEquals(2, i10.snapshots.length); |
| |
| var s15 = i10.snapshots[0]; |
| assertEquals(15, s15.ts); |
| assertEquals(15, s15.args); |
| |
| var s20 = i10.snapshots[1]; |
| assertEquals(20, s20.ts); |
| assertEquals(20, s20.args); |
| }); |
| |
| test('importImplicitObjects', function() { |
| var events = [ |
| {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', |
| args: { snapshot: [ |
| { id: 'subObject/0x1', |
| foo: 1 |
| } |
| ]}}, |
| {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', |
| args: { snapshot: [ |
| { id: 'subObject/0x1', |
| foo: 2 |
| }, |
| { id: 'subObject/0x2', |
| foo: 1 |
| } |
| ]}} |
| ]; |
| |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false); |
| var p1 = m.processes[1]; |
| |
| var iA = p1.objects.getObjectInstanceAt('0x1000', 10); |
| var subObjectInstances = p1.objects.getAllInstancesByTypeName()[ |
| 'subObject']; |
| |
| assertEquals(2, subObjectInstances.length); |
| var subObject1 = p1.objects.getObjectInstanceAt('0x1', 15); |
| assertEquals('subObject', subObject1.name); |
| assertEquals(15, subObject1.creationTs); |
| |
| assertEquals(2, subObject1.snapshots.length); |
| assertEquals(15, subObject1.snapshots[0].ts); |
| assertEquals(1, subObject1.snapshots[0].args.foo); |
| assertEquals(20, subObject1.snapshots[1].ts); |
| assertEquals(2, subObject1.snapshots[1].args.foo); |
| |
| var subObject2 = p1.objects.getObjectInstanceAt('0x2', 20); |
| assertEquals('subObject', subObject2.name); |
| assertEquals(20, subObject2.creationTs); |
| assertEquals(1, subObject2.snapshots.length); |
| assertEquals(20, subObject2.snapshots[0].ts); |
| }); |
| |
| test('importImplicitObjectWithCategoryOverride', function() { |
| var events = [ |
| {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'cat', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'otherCat', id: '0x1000', name: 'a', // @suppress longLineCheck |
| args: { snapshot: [ |
| { id: 'subObject/0x1', |
| cat: 'cat', |
| foo: 1 |
| } |
| ]}} |
| ]; |
| |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false); |
| var p1 = m.processes[1]; |
| |
| var iA = p1.objects.getObjectInstanceAt('0x1000', 10); |
| var subObjectInstances = p1.objects.getAllInstancesByTypeName()[ |
| 'subObject']; |
| |
| assertEquals(1, subObjectInstances.length); |
| }); |
| |
| test('importImplicitObjectWithBaseTypeOverride', function() { |
| var events = [ |
| {ts: 10000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'PictureLayerImpl', args: { // @suppress longLineCheck |
| snapshot: { |
| base_type: 'LayerImpl' |
| } |
| }}, |
| {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'LayerImpl', args: {}} // @suppress longLineCheck |
| ]; |
| |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false); |
| var p1 = m.processes[1]; |
| assertEquals(0, m.importWarnings.length); |
| |
| var iA = p1.objects.getObjectInstanceAt('0x1000', 10); |
| assertEquals(1, iA.snapshots.length); |
| }); |
| |
| test('importIDRefs', function() { |
| var events = [ |
| // An object with two snapshots. |
| {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 15}}, // @suppress longLineCheck |
| {ts: 20000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: {snapshot: 20}}, // @suppress longLineCheck |
| {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| |
| // A slice that references the object. |
| {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {my_object: {id_ref: '0x1000'}}}, // @suppress longLineCheck |
| {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck |
| ]; |
| |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false); |
| var p1 = m.processes[1]; |
| |
| var iA = p1.objects.getObjectInstanceAt('0x1000', 10); |
| var s15 = iA.getSnapshotAt(15); |
| |
| var taskSlice = p1.threads[1].sliceGroup.slices[0]; |
| assertEquals(s15, taskSlice.args.my_object); |
| }); |
| |
| test('importIDRefsThatPointAtEachOther', function() { |
| var events = [ |
| // An object. |
| {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck |
| snapshot: { x: { |
| id: 'foo/0x1001', |
| value: 'bar' |
| }}}}, |
| {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| |
| // A slice that references the object. |
| {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: {my_object: {id_ref: '0x1001'}}}, // @suppress longLineCheck |
| {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck |
| ]; |
| |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false); |
| var p1 = m.processes[1]; |
| |
| var iA = p1.objects.getObjectInstanceAt('0x1000', 15); |
| var iFoo = p1.objects.getObjectInstanceAt('0x1001', 15); |
| assertNotUndefined(iA); |
| assertNotUndefined(iFoo); |
| |
| var a15 = iA.getSnapshotAt(15); |
| var foo15 = iFoo.getSnapshotAt(15); |
| |
| var taskSlice = p1.threads[1].sliceGroup.slices[0]; |
| assertEquals(foo15, taskSlice.args.my_object); |
| }); |
| |
| test('importArrayWithIDs', function() { |
| var events = [ |
| {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck |
| snapshot: { x: [ |
| {id: 'foo/0x1001', value: 'bar1'}, |
| {id: 'foo/0x1002', value: 'bar2'}, |
| {id: 'foo/0x1003', value: 'bar3'} |
| ]}}} |
| ]; |
| |
| var m = new tv.c.TraceModel(); |
| m.importTraces([events], false); |
| var p1 = m.processes[1]; |
| |
| var sA = p1.objects.getSnapshotAt('0x1000', 15); |
| assertTrue(sA.args.x instanceof Array); |
| assertEquals(3, sA.args.x.length); |
| assertTrue(sA.args.x[0] instanceof tv.c.trace_model.ObjectSnapshot); |
| assertTrue(sA.args.x[1] instanceof tv.c.trace_model.ObjectSnapshot); |
| assertTrue(sA.args.x[2] instanceof tv.c.trace_model.ObjectSnapshot); |
| }); |
| |
| test('importDoesNotMutateEventList', function() { |
| var events = [ |
| // An object. |
| {ts: 10000, pid: 1, tid: 1, ph: 'N', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| {ts: 15000, pid: 1, tid: 1, ph: 'O', cat: 'c', id: '0x1000', name: 'a', args: { // @suppress longLineCheck |
| snapshot: {foo: 15}}}, |
| {ts: 50000, pid: 1, tid: 1, ph: 'D', cat: 'c', id: '0x1000', name: 'a', args: {}}, // @suppress longLineCheck |
| |
| // A slice that references the object. |
| {ts: 17000, pid: 1, tid: 1, ph: 'B', cat: 'c', name: 'taskSlice', args: { |
| my_object: {id_ref: '0x1000'}} |
| }, |
| {ts: 17500, pid: 1, tid: 1, ph: 'E', cat: 'c', name: 'taskSlice', args: {}} // @suppress longLineCheck |
| ]; |
| |
| // The A type family exists to mutate the args list provided to |
| // snapshots. |
| function ASnapshot() { |
| tv.c.trace_model.ObjectSnapshot.apply(this, arguments); |
| this.args.foo = 7; |
| } |
| ASnapshot.prototype = { |
| __proto__: tv.c.trace_model.ObjectSnapshot.prototype |
| }; |
| |
| // Import event while the A types are registered, causing the |
| // arguments of the snapshots to be mutated. |
| var m = new tv.c.TraceModel(); |
| try { |
| tv.c.trace_model.ObjectSnapshot.register(ASnapshot, {typeName: 'a'}); |
| m.importTraces([events], false); |
| } finally { |
| tv.c.trace_model.ObjectSnapshot.unregister(ASnapshot); |
| } |
| assertFalse(m.hasImportWarnings); |
| |
| // Verify that the events array wasn't modified. |
| assertObjectEquals( |
| events[1].args, |
| {snapshot: {foo: 15}}); |
| assertObjectEquals( |
| events[3].args, |
| {my_object: {id_ref: '0x1000'}}); |
| }); |
| |
| test('importFlowEvent', function() { |
| var events = [ |
| { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {} }, // @suppress longLineCheck |
| { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {} }, // @suppress longLineCheck |
| { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {} } // @suppress longLineCheck |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| |
| assertNotUndefined(t); |
| assertEquals(3, t.sliceGroup.slices.length); |
| assertEquals(2, m.flowEvents.length); |
| |
| var start = m.flowEvents[0][0]; |
| var step = m.flowEvents[0][1]; |
| var finish = m.flowEvents[1][1]; |
| |
| assertEquals('a', start.title); |
| assertEquals('foo', start.category); |
| assertEquals(72, start.id); |
| assertEquals(0, start.start); |
| assertEquals(0, start.duration); |
| |
| assertEquals(start.title, step.title); |
| assertEquals(start.category, step.category); |
| assertEquals(start.id, step.id); |
| assertAlmostEquals(12 / 1000, step.start); |
| assertEquals(0, step.duration); |
| |
| assertEquals(start.title, finish.title); |
| assertEquals(start.category, finish.category); |
| assertEquals(start.id, finish.id); |
| assertAlmostEquals((20 + 12) / 1000, finish.start); |
| assertEquals(0, finish.duration); |
| |
| assertEquals(2, m.flowIntervalTree.size); |
| }); |
| |
| test('importOutOfOrderFlowEvent', function() { |
| var events = [ |
| { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 548, ph: 's', args: {} }, // @suppress longLineCheck |
| { name: 'b', cat: 'foo', id: 73, pid: 52, tid: 53, ts: 148, ph: 's', args: {} }, // @suppress longLineCheck |
| { name: 'b', cat: 'foo', id: 73, pid: 52, tid: 53, ts: 570, ph: 'f', args: {} }, // @suppress longLineCheck |
| { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 560, ph: 't', args: {} }, // @suppress longLineCheck |
| { name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 580, ph: 'f', args: {} } // @suppress longLineCheck |
| ]; |
| |
| var expected = [0.4, 0.0, 0.412]; |
| var m = new tv.c.TraceModel(events); |
| assertEquals(3, m.flowIntervalTree.size); |
| |
| var order = m.flowEvents.map(function(x) { return x[0].start }); |
| for (var i = 0; i < expected.length; ++i) |
| assertAlmostEquals(expected[i], order[i]); |
| }); |
| |
| test('importCompleteEvent', function() { |
| var events = [ |
| { name: 'a', args: {}, pid: 52, ts: 629, dur: 1, cat: 'baz', tid: 53, ph: 'X' }, // @suppress longLineCheck |
| { name: 'b', args: {}, pid: 52, ts: 730, dur: 20, cat: 'foo', tid: 53, ph: 'X' }, // @suppress longLineCheck |
| { name: 'c', args: {}, pid: 52, ts: 740, cat: 'baz', tid: 53, ph: 'X' } |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| |
| assertEquals(1, p.numThreads); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| assertEquals(3, t.sliceGroup.slices.length); |
| assertEquals(53, t.tid); |
| |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('baz', slice.category); |
| assertAlmostEquals(0, slice.start); |
| assertAlmostEquals(1 / 1000, slice.duration); |
| assertEquals(0, slice.subSlices.length); |
| |
| slice = t.sliceGroup.slices[1]; |
| assertEquals('b', slice.title); |
| assertEquals('foo', slice.category); |
| assertAlmostEquals((730 - 629) / 1000, slice.start); |
| assertAlmostEquals(20 / 1000, slice.duration); |
| assertEquals(1, slice.subSlices.length); |
| |
| slice = t.sliceGroup.slices[2]; |
| assertEquals('c', slice.title); |
| assertTrue(slice.didNotFinish); |
| assertAlmostEquals(10 / 1000, slice.duration); |
| }); |
| |
| test('importCompleteEventWithCpuDuration', function() { |
| var events = [ |
| { name: 'a', args: {}, pid: 52, ts: 629, dur: 1, cat: 'baz', tid: 53, ph: 'X', tts: 12, tdur: 1 }, // @suppress longLineCheck |
| { name: 'b', args: {}, pid: 52, ts: 730, dur: 20, cat: 'foo', tid: 53, ph: 'X', tts: 110, tdur: 16 }, // @suppress longLineCheck |
| { name: 'c', args: {}, pid: 52, ts: 740, cat: 'baz', tid: 53, ph: 'X', tts: 115 } // @suppress longLineCheck |
| ]; |
| |
| var m = new tv.c.TraceModel(events); |
| assertEquals(1, m.numProcesses); |
| var p = m.processes[52]; |
| assertNotUndefined(p); |
| |
| assertEquals(1, p.numThreads); |
| var t = p.threads[53]; |
| assertNotUndefined(t); |
| assertEquals(3, t.sliceGroup.slices.length); |
| assertEquals(53, t.tid); |
| |
| var slice = t.sliceGroup.slices[0]; |
| assertEquals('a', slice.title); |
| assertEquals('baz', slice.category); |
| assertAlmostEquals(0, slice.start); |
| assertAlmostEquals(1 / 1000, slice.duration); |
| assertAlmostEquals(12 / 1000, slice.cpuStart); |
| assertAlmostEquals(1 / 1000, slice.cpuDuration); |
| assertEquals(0, slice.subSlices.length); |
| |
| slice = t.sliceGroup.slices[1]; |
| assertEquals('b', slice.title); |
| assertEquals('foo', slice.category); |
| assertAlmostEquals((730 - 629) / 1000, slice.start); |
| assertAlmostEquals(20 / 1000, slice.duration); |
| assertAlmostEquals(110 / 1000, slice.cpuStart); |
| assertAlmostEquals(16 / 1000, slice.cpuDuration); |
| assertEquals(1, slice.subSlices.length); |
| |
| slice = t.sliceGroup.slices[2]; |
| assertEquals('c', slice.title); |
| assertTrue(slice.didNotFinish); |
| assertAlmostEquals(10 / 1000, slice.duration); |
| }); |
| |
| test('importNestedCompleteEventWithTightBounds', function() { |
| var events = [ |
| { name: 'a', args: {}, pid: 52, ts: 244654227065, dur: 36075, cat: 'baz', tid: 53, ph: 'X' }, // @suppress longLineCheck |
| { name: 'b', args: {}, pid: 52, ts: 244654227095, dur: 36045, cat: 'foo', tid: 53, ph: 'X' } // @suppress longLineCheck |
| ]; |
| |
| var m = new tv.c.TraceModel(events, false); |
| var t = m.processes[52].threads[53]; |
| |
| var sA = findSliceNamed(t.sliceGroup, 'a'); |
| var sB = findSliceNamed(t.sliceGroup, 'b'); |
| |
| assertEquals('a', sA.title); |
| assertEquals('baz', sA.category); |
| assertEquals(244654227.065, sA.start); |
| assertEquals(36.075, sA.duration); |
| assertAlmostEquals(0.03, sA.selfTime); |
| |
| assertEquals('b', sB.title); |
| assertEquals('foo', sB.category); |
| assertEquals(244654227.095, sB.start); |
| assertEquals(36.045, sB.duration); |
| |
| assertTrue(sA.subSlices.length == 1); |
| assertTrue(sA.subSlices[0] == sB); |
| assertTrue(sB.parentSlice == sA); |
| }); |
| |
| |
| test('importCompleteEventWithStackFrame', function() { |
| var eventData = { |
| traceEvents: [ |
| { name: 'a', args: {}, pid: 1, ts: 0, dur: 1, cat: 'baz', tid: 2, ph: 'X', sf: 7 }, // @suppress longLineCheck |
| { name: 'b', args: {}, pid: 1, ts: 5, dur: 1, cat: 'baz', tid: 2, ph: 'X', sf: 8, esf: 9 } // @suppress longLineCheck |
| ], |
| stackFrames: { |
| '1': { |
| category: 'm1', |
| name: 'main' |
| }, |
| '7': { |
| category: 'm2', |
| name: 'frame7', |
| parent: '1' |
| }, |
| '8': { |
| category: 'm2', |
| name: 'frame8', |
| parent: '1' |
| }, |
| '9': { |
| category: 'm2', |
| name: 'frame9', |
| parent: '1' |
| } |
| } |
| }; |
| |
| var options = new tv.c.ImportOptions(); |
| options.shiftWorldToZero = false; |
| var m = new tv.c.TraceModel(eventData, options); |
| |
| var p = m.processes[1]; |
| var t = p.threads[2]; |
| assertNotUndefined(t); |
| assertEquals(2, t.sliceGroup.slices.length); |
| |
| var s0 = t.sliceGroup.slices[0]; |
| assertEquals('frame7', s0.startStackFrame.title); |
| assertUndefined(s0.endStackFrame); |
| |
| var s1 = t.sliceGroup.slices[1]; |
| assertEquals('frame8', s1.startStackFrame.title); |
| assertEquals('frame9', s1.endStackFrame.title); |
| }); |
| |
| test('importAsyncEventWithSameTimestamp', function() { |
| var events = []; |
| // Events are added with ts 0, 1, 1, 2, 2, 3, 3 ...500, 500, 1000 |
| // and use 'seq' to track the order of when the event is recorded. |
| events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 0, ph: 'S', args: {'seq': 0}}); // @suppress longLineCheck |
| |
| for (var i = 1; i <= 1000; i++) |
| events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: Math.round(i / 2) , ph: 'T', args: {'seq': i}}); // @suppress longLineCheck |
| |
| events.push({name: 'a', cat: 'foo', id: 72, pid: 52, tid: 53, ts: 1000, ph: 'F', args: {'seq': 1001}}); // @suppress longLineCheck |
| |
| var m = new tv.c.TraceModel(events); |
| var t = m.processes[52].threads[53]; |
| |
| assertEquals(1, t.asyncSliceGroup.slices.length); |
| var parentSlice = t.asyncSliceGroup.slices[0]; |
| assertEquals('a', parentSlice.title); |
| assertEquals('foo', parentSlice.category); |
| |
| assertNotUndefined(parentSlice.subSlices); |
| var subSlices = parentSlice.subSlices; |
| assertEquals(1000, subSlices.length); |
| // Slices should be sorted according to 'ts'. And if 'ts' is the same, |
| // slices should keep the order that they were recorded. |
| for (var i = 0; i < 1000; i++) |
| assertEquals(subSlices[i].args['seq'], i + 1); |
| }); |
| |
| test('sampleDataSimple', function() { |
| var events = { |
| 'traceEvents': [], |
| 'stackFrames': { |
| '1': { |
| 'category': 'mod', |
| 'name': 'main' |
| }, |
| '2': { |
| 'category': 'mod', |
| 'name': 'a', |
| 'parent': 1 |
| }, |
| '3': { |
| 'category': 'mod', |
| 'name': 'a_sub', |
| 'parent': 2 |
| }, |
| '4': { |
| 'category': 'mod', |
| 'name': 'b', |
| 'parent': 1 |
| } |
| }, |
| 'samples': [ |
| { |
| 'cpu': 0, 'tid': 1, 'ts': 1000.0, |
| 'name': 'cycles:HG', 'sf': 3, 'weight': 1 |
| }, |
| { |
| 'cpu': 0, 'tid': 1, 'ts': 2000.0, |
| 'name': 'cycles:HG', 'sf': 2, 'weight': 1 |
| }, |
| { |
| 'cpu': 1, 'tid': 1, 'ts': 3000.0, |
| 'name': 'cycles:HG', 'sf': 3, 'weight': 1 |
| } |
| ] |
| }; |
| var m = new tv.c.TraceModel(events, false); |
| assertNotUndefined(m.kernel.cpus[0]); |
| assertEquals(1, m.getAllThreads().length); |
| |
| assertEquals(4, tv.b.dictionaryKeys(m.stackFrames).length); |
| assertEquals(3, m.samples.length); |
| |
| var t1 = m.processes[1].threads[1]; |
| assertEquals(3, t1.samples.length); |
| |
| var c0 = m.kernel.cpus[0]; |
| var c1 = m.kernel.cpus[1]; |
| assertEquals(2, c0.samples.length); |
| assertEquals(1, c1.samples.length); |
| |
| assertEquals(c0, m.samples[0].cpu); |
| assertEquals(t1, m.samples[0].thread); |
| assertEquals('cycles:HG', m.samples[0].title); |
| assertEquals(1, m.samples[0].start); |
| assertArrayEquals( |
| ['main', 'a', 'a_sub'], |
| m.samples[0].stackTrace.map(function(x) { return x.title; })); |
| assertEquals(1, m.samples[0].weight); |
| }); |
| |
| test('importMemoryDumps', function() { |
| var events = [ |
| // 2 process memory dump events without a global memory dump event. |
| {name: 'a', pid: 42, ts: 10, cat: 'test', tid: 53, ph: 'v', 'id': 'dump1', args: {}}, // @suppress longLineCheck |
| {name: 'b', pid: 43, ts: 11, cat: 'test', tid: 54, ph: 'v', 'id': 'dump1', args: {}}, // @suppress longLineCheck |
| // 1 global memory dump event and 1 process memory dump event. |
| {name: 'c', pid: 44, ts: 12, cat: 'test', tid: 55, ph: 'V', 'id': 'dump2', args: {}}, // @suppress longLineCheck |
| {name: 'd', pid: 42, ts: 13, cat: 'test', tid: 56, ph: 'v', 'id': 'dump2', args: {}} // @suppress longLineCheck |
| ]; |
| var m = new tv.c.TraceModel(events, false); |
| var p1 = m.getProcess(42); |
| var p2 = m.getProcess(43); |
| assertNotUndefined(p1); |
| assertNotUndefined(p2); |
| |
| // Check that TraceModel and Process objects contain the right dumps. |
| assertEquals(2, m.globalMemoryDumps.length); |
| assertEquals(2, p1.memoryDumps.length); |
| assertEquals(1, p2.memoryDumps.length); |
| |
| assertEquals(10, m.globalMemoryDumps[0].start); |
| assertEquals(10, p1.memoryDumps[0].start); |
| assertEquals(11, p2.memoryDumps[0].start); |
| assertEquals(1, m.globalMemoryDumps[0].duration); |
| assertEquals(0, p1.memoryDumps[0].duration); |
| assertEquals(0, p2.memoryDumps[0].duration); |
| |
| assertEquals(12, m.globalMemoryDumps[1].start); |
| assertEquals(13, p1.memoryDumps[1].start); |
| assertEquals(1, m.globalMemoryDumps[1].duration); |
| assertEquals(0, p1.memoryDumps[1].duration); |
| |
| // Check that GlobalMemoryDump and ProcessMemoryDump objects are |
| // interconnected correctly. |
| assertEquals(m.globalMemoryDumps[0].processMemoryDumps[42], |
| p1.memoryDumps[0]); |
| assertEquals(m.globalMemoryDumps[0].processMemoryDumps[43], |
| p2.memoryDumps[0]); |
| assertEquals(m.globalMemoryDumps[0], p1.memoryDumps[0].globalMemoryDump); |
| assertEquals(m.globalMemoryDumps[0], p2.memoryDumps[0].globalMemoryDump); |
| |
| assertEquals(m.globalMemoryDumps[1].processMemoryDumps[42], |
| p1.memoryDumps[1]); |
| assertEquals(m.globalMemoryDumps[1], p1.memoryDumps[1].globalMemoryDump); |
| }); |
| |
| test('importThreadInstantSliceWithStackFrame', function() { |
| var eventData = { |
| traceEvents: [ |
| { name: 'a', args: {}, pid: 1, ts: 0, cat: 'baz', tid: 2, ph: 'I', s: 't', sf: 7 } // @suppress longLineCheck |
| ], |
| stackFrames: { |
| '1': { |
| category: 'm1', |
| name: 'main' |
| }, |
| '7': { |
| category: 'm2', |
| name: 'frame7', |
| parent: '1' |
| } |
| } |
| }; |
| |
| var options = new tv.c.ImportOptions(); |
| options.shiftWorldToZero = false; |
| var m = new tv.c.TraceModel(eventData, options); |
| |
| var p = m.processes[1]; |
| var t = p.threads[2]; |
| assertNotUndefined(t); |
| assertEquals(1, t.sliceGroup.slices.length); |
| |
| var s0 = t.sliceGroup.slices[0]; |
| assertEquals('frame7', s0.startStackFrame.title); |
| assertUndefined(s0.endStackFrame); |
| }); |
| |
| test('importDurationEventsWithStackFrames', function() { |
| var eventData = { |
| traceEvents: [ |
| { name: 'a', args: {}, pid: 1, ts: 0, cat: 'baz', tid: 2, ph: 'B', sf: 7 }, // @suppress longLineCheck |
| { name: 'b', args: {}, pid: 1, ts: 5, cat: 'baz', tid: 2, ph: 'E', sf: 8 } // @suppress longLineCheck |
| ], |
| stackFrames: { |
| '1': { |
| category: 'm1', |
| name: 'main' |
| }, |
| '7': { |
| category: 'm2', |
| name: 'frame7', |
| parent: '1' |
| }, |
| '8': { |
| category: 'm2', |
| name: 'frame8', |
| parent: '1' |
| } |
| } |
| }; |
| |
| var options = new tv.c.ImportOptions(); |
| options.shiftWorldToZero = false; |
| var m = new tv.c.TraceModel(eventData, options); |
| |
| var p = m.processes[1]; |
| var t = p.threads[2]; |
| assertNotUndefined(t); |
| assertEquals(1, t.sliceGroup.slices.length); |
| |
| var s0 = t.sliceGroup.slices[0]; |
| assertEquals('frame7', s0.startStackFrame.title); |
| assertEquals('frame8', s0.endStackFrame.title); |
| }); |
| |
| // TODO(nduca): one slice, two threads |
| // TODO(nduca): one slice, two pids |
| |
| }); |
| </script> |