blob: d73b8331504d983fa5d59e08f14ead41ac4c2f17 [file] [log] [blame]
<!DOCTYPE html>
<html>
<!--
Copyright (c) 2010 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.
-->
<head>
<title>TraceEventImporter tests</title>
<script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
<script src="../shared/js/cr.js"></script>
<script src="../shared/js/cr/event_target.js"></script>
<script src="test_utils.js"></script>
<script src="timeline_model.js"></script>
<script src="trace_event_importer.js"></script>
<script>
goog.require('goog.testing.jsunit');
</script>
</head>
<body>
<script>
function testBasicSingleThreadNonnestedParsing() {
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: 'foo', tid: 53, ph: 'B'},
{name: 'b', args: {}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'}
];
var m = new tracing.TimelineModel(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.subRows.length);
assertEquals(53, t.tid);
var subRow = t.subRows[0];
assertEquals(2, subRow.length);
var slice = subRow[0];
assertEquals('a', slice.title);
assertEquals(0, slice.start);
assertAlmostEquals((560 - 520) / 1000, slice.duration);
assertEquals(0, slice.subSlices.length);
slice = subRow[1];
assertEquals('b', slice.title);
assertAlmostEquals((629 - 520) / 1000, slice.start);
assertAlmostEquals((631 - 629) / 1000, slice.duration);
assertEquals(0, slice.subSlices.length);
}
function testNestedParsing() {
var events = [
{name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
{name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'},
{name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'},
{name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'}
];
var m = new tracing.TimelineModel(events);
var p = m.processes[1];
var t = p.threads[1];
assertEquals(2, t.subRows.length);
var subRow = t.subRows[0];
assertEquals(1, subRow.length);
var slice = subRow[0];
assertEquals('a', slice.title);
assertEquals((4 - 1) / 1000, slice.duration);
assertEquals(1, slice.subSlices.length);
slice = slice.subSlices[0];
assertEquals('b', slice.title);
assertEquals((2 - 1) / 1000, slice.start);
assertEquals((3 - 2) / 1000, slice.duration);
assertEquals(0, slice.subSlices.length);
subRow = t.subRows[1];
slice = subRow[0];
assertEquals(t.subRows[0][0].subSlices[0], slice);
}
function testAutoclosing() {
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: 'foo', tid: 2, ph: 'B'},
{name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'}
];
var m = new tracing.TimelineModel(events);
var p = m.processes[1];
var t = p.threads[1];
var subRow = t.subRows[0];
var slice = subRow[0];
assertEquals('a', slice.title);
assertTrue(slice.didNotFinish);
assertEquals(0, slice.start);
assertEquals((2 - 1) / 1000, slice.duration);
}
function testAutoclosingLoneBegin() {
var events = [
// Slice that doesn't finish.
{name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}
];
var m = new tracing.TimelineModel(events);
var p = m.processes[1];
var t = p.threads[1];
var subRow = t.subRows[0];
var slice = subRow[0];
assertEquals('a', slice.title);
assertTrue(slice.didNotFinish);
assertEquals(0, slice.start);
assertEquals(0, slice.duration);
}
function testAutoclosingWithSubTasks() {
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 tracing.TimelineModel(events);
var p = m.processes[1];
var t = p.threads[1];
assertEquals(2, t.subRows.length);
assertEquals(1, t.subRows[0].length);
assertEquals(2, t.subRows[1].length);
}
function testAutoclosingWithEventsOutsideRange() {
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: 'a', 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: '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 tracing.TimelineModel(events);
var p = m.processes[1];
var t = p.threads[1];
var subRow = t.subRows[0];
assertEquals('a', subRow[0].title);
assertEquals(0, subRow[0].start);
assertEquals(0.003, subRow[0].duration);
var t = p.threads[2];
var subRow = t.subRows[0];
assertEquals('b', subRow[0].title);
assertEquals(0.001, subRow[0].start);
assertEquals(0.001, subRow[0].duration);
// 0.00345 instead of 0.003 because TimelineModel bloats the world range by
// 15%.
assertEquals(-0.00045, m.minTimestamp);
assertEquals(0.00345, m.maxTimestamp);
}
function testNestedAutoclosing() {
var events = [
// Tasks that dont 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 tracing.TimelineModel(events);
var p = m.processes[1];
var t = p.threads[1];
var subRow = t.subRows[0];
var slice = subRow[0];
assertEquals('a1', slice.title);
assertTrue(slice.didNotFinish);
assertEquals(0, slice.start);
assertEquals((2 - 1) / 1000, slice.duration);
var slice = slice.subSlices[0];
assertEquals('a2', slice.title);
assertTrue(slice.didNotFinish);
assertEquals((1.5 - 1) / 1000, slice.start);
assertEquals((2 - 1.5) / 1000, slice.duration);
}
function testTaskColoring() {
// The test below depends on hashing of 'a' != 'b'. Fail early if that
// assumption is incorrect.
assertNotEquals(tracing.getStringHash('a'), tracing.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: 'foo', tid: 1, ph: 'B'},
{name: 'b', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'},
{name: 'a', args: {}, pid: 1, ts: 5, cat: 'foo', tid: 1, ph: 'B'},
{name: 'a', args: {}, pid: 1, ts: 6, cat: 'foo', tid: 1, ph: 'E'}
];
var m = new tracing.TimelineModel(events);
var p = m.processes[1];
var t = p.threads[1];
var subRow = t.subRows[0];
var a1 = subRow[0];
assertEquals('a', a1.title);
var b = subRow[1];
assertEquals('b', b.title);
assertNotEquals(a1.colorId, b.colorId);
var a2 = subRow[0];
assertEquals('a', a2.title);
assertEquals(a1.colorId, a2.colorId);
}
function testMultipleThreadParsing() {
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: 'foo', tid: 2, ph: 'B'},
{name: 'b', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 2, ph: 'E'}
];
var m = new tracing.TimelineModel(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.subRows.length);
assertEquals(1, t.tid);
var subRow = t.subRows[0];
assertEquals(1, subRow.length);
var slice = subRow[0];
assertEquals('a', slice.title);
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.subRows.length);
assertEquals(2, t.tid);
subRow = t.subRows[0];
assertEquals(1, subRow.length);
slice = subRow[0];
assertEquals('b', slice.title);
assertEquals((3 - 1) / 1000, slice.start);
assertEquals((4 - 3) / 1000, slice.duration);
assertEquals(0, slice.subSlices.length);
}
function testMultiplePidParsing() {
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: 'foo', tid: 2, ph: 'B'},
{name: 'b', args: {}, pid: 2, ts: 4, cat: 'foo', tid: 2, ph: 'E'}
];
var m = new tracing.TimelineModel(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.subRows.length);
assertEquals(1, t.tid);
var subRow = t.subRows[0];
assertEquals(1, subRow.length);
var slice = subRow[0];
assertEquals('a', slice.title);
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.subRows.length);
assertEquals(2, t.tid);
subRow = t.subRows[0];
assertEquals(1, subRow.length);
slice = subRow[0];
assertEquals('b', slice.title);
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());
}
// Thread names.
function testThreadNames() {
var events = [
{name: 'thread_name', args: {name: 'Thread 1'},
pid: 1, ts: 0, tid: 1, ph: 'M'},
{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: 'foo', tid: 2, ph: 'B'},
{name: 'b', args: {}, pid: 2, ts: 4, cat: 'foo', tid: 2, ph: 'E'},
{name: 'thread_name', args: {name: 'Thread 2'},
pid: 2, ts: 0, tid: 2, ph: 'M'}
];
var m = new tracing.TimelineModel(events);
assertEquals('Thread 1', m.processes[1].threads[1].name);
assertEquals('Thread 2', m.processes[2].threads[2].name);
}
// User time.
function testUserTime() {
var events = [
{name: 'thread_name', args: {name: 'Thread 1'},
pid: 1, ts: 0, tid: 1, ph: 'M'},
{name: 'a', args: {}, pid: 1, ts: 1, uts: 10, cat: 'foo', tid: 1, ph: 'B'},
{name: 'a', args: {}, pid: 1, ts: 2, uts: 20, cat: 'foo', tid: 1, ph: 'E'},
{name: 'a', args: {}, pid: 1, ts: 2 , uts: 60, cat: 'foo', tid: 1, ph: 'I'}
];
var m = new tracing.TimelineModel(events);
var subRow = m.processes[1].threads[1].subRows[0];
assertEquals(0.01, subRow[0].startInUserTime);
assertEquals(0.01, subRow[0].durationInUserTime);
assertEquals(0.06, subRow[1].startInUserTime);
assertEquals(0, subRow[1].durationInUserTime);
}
function testImmediateParsing() {
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: 'foo', tid: 1, ph: 'I'},
{name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'}
];
var m = new tracing.TimelineModel(events);
var p = m.processes[1];
var t = p.threads[1];
assertEquals(2, t.subRows.length);
var subRow = t.subRows[0];
assertEquals(1, subRow.length);
var slice = subRow[0];
assertEquals('a', slice.title);
assertEquals((4 - 1) / 1000, slice.duration);
assertEquals(1, slice.subSlices.length);
var immed = slice.subSlices[0];
assertEquals('immediate', immed.title);
assertEquals((2 - 1) / 1000, immed.start);
assertEquals(0, immed.duration);
assertEquals(0, immed.subSlices.length);
subRow = t.subRows[1];
assertEquals(immed, subRow[0]);
}
function testSimpleCounter() {
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 tracing.TimelineModel(events);
var p = m.processes[1];
var ctr = m.processes[1].counters['foo.ctr'];
assertEquals('ctr', ctr.name);
assertEquals(3, ctr.numSamples);
assertEquals(1, ctr.numSeries);
assertArrayEquals(['value'], ctr.seriesNames);
assertArrayEquals([tracing.getStringColorId('ctr.value')], ctr.seriesColors);
assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
assertArrayEquals([0, 10, 0], ctr.samples);
assertArrayEquals([0, 10, 0], ctr.totals);
assertEquals(10, ctr.maxTotal);
}
function testInstanceCounter() {
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}
];
var m = new tracing.TimelineModel(events);
var p = m.processes[1];
var ctr = m.processes[1].counters['foo.ctr[0]'];
assertEquals('ctr[0]', ctr.name);
assertEquals(2, ctr.numSamples);
assertEquals(1, ctr.numSeries);
assertArrayEquals([0, 0.01], ctr.timestamps);
assertArrayEquals([0, 10], ctr.samples);
var ctr = m.processes[1].counters['foo.ctr[1]'];
assertEquals('ctr[1]', ctr.name);
assertEquals(3, ctr.numSamples);
assertEquals(1, ctr.numSeries);
assertArrayEquals([0.01, 0.015, 0.018], ctr.timestamps);
assertArrayEquals([10, 20, 30], ctr.samples);
}
function testMultiCounterUpdateBounds() {
var ctr = new tracing.TimelineCounter(undefined, 'testBasicCounter',
'testBasicCounter');
ctr.numSeries = 1;
ctr.seriesNames = ['value1', 'value2'];
ctr.seriesColors = ['testBasicCounter.value1', 'testBasicCounter.value2'];
ctr.timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
ctr.samples = [0, 0,
1, 0,
1, 1,
2, 1.1,
3, 0,
1, 7,
3, 0,
3.1, 0.5];
ctr.updateBounds();
assertEquals(0, ctr.minTimestamp);
assertEquals(7, ctr.maxTimestamp);
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);
}
function testMultiCounter() {
var events = [
{name: 'ctr', args: {'value1': 0, 'value2': 7}, pid: 1, ts: 0, cat: 'foo',
tid: 1, ph: 'C'},
{name: 'ctr', args: {'value1': 10, 'value2': 4}, pid: 1, ts: 10, cat: 'foo',
tid: 1, ph: 'C'},
{name: 'ctr', args: {'value1': 0, 'value2': 1 }, pid: 1, ts: 20, cat: 'foo',
tid: 1, ph: 'C'}
];
var m = new tracing.TimelineModel(events);
var p = m.processes[1];
var ctr = m.processes[1].counters['foo.ctr'];
assertEquals('ctr', ctr.name);
assertEquals('ctr', ctr.name);
assertEquals(3, ctr.numSamples);
assertEquals(2, ctr.numSeries);
assertArrayEquals(['value1', 'value2'], ctr.seriesNames);
assertArrayEquals([tracing.getStringColorId('ctr.value1'),
tracing.getStringColorId('ctr.value2')],
ctr.seriesColors);
assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
assertArrayEquals([0, 7,
10, 4,
0, 1], ctr.samples);
assertArrayEquals([0, 7,
10, 14,
0, 1], ctr.totals);
assertEquals(14, ctr.maxTotal);
}
function testImportObjectInsteadOfArray() {
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 tracing.TimelineModel(events);
assertEquals(1, m.numProcesses);
}
function testImportString() {
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 tracing.TimelineModel(JSON.stringify(events));
assertEquals(1, m.numProcesses);
}
function testImportStringWithTrailingNewLine() {
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 tracing.TimelineModel(JSON.stringify(events) + '\n');
assertEquals(1, m.numProcesses);
}
function testImportStringWithMissingCloseSquareBracket() {
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 tracing.TimelineModel(dropped);
assertEquals(1, m.numProcesses);
}
function testImportStringWithMissingCloseSquareBracketAndNewline() {
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 tracing.TimelineModel(dropped + '\n');
assertEquals(1, m.numProcesses);
}
</script>
</body>
</html>