blob: a622fd47c8fda9a239f0112724bd6759c373f292 [file] [log] [blame]
<!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="/base/units/time.html">
<link rel="import" href="/core/test_utils.html">
<link rel="import" href="/extras/importer/linux_perf/ftrace_importer.html">
<link rel="import" href="/extras/importer/trace_event_importer.html">
<link rel="import" href="/extras/importer/zip_importer.html">
<link rel="import" href="/extras/importer/v8/v8_log_importer.html">
<link rel="import" href="/model/annotation.html">
<link rel="import" href="/model/model.html">
<script>
'use strict';
tr.b.unittest.testSuite(function() {
var ThreadSlice = tr.model.ThreadSlice;
var TitleOrCategoryFilter = tr.c.TitleOrCategoryFilter;
var Frame = tr.model.Frame;
var createModelWithOneOfEverything = function() {
var m = new tr.Model();
var cpu = m.kernel.getOrCreateCpu(1);
cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
var p = m.getOrCreateProcess(1);
var t = p.getOrCreateThread(1);
var slice = new ThreadSlice('', 'a', 0, 1, {}, 4);
t.sliceGroup.pushSlice(slice);
t.asyncSliceGroup.push(tr.c.test_utils.newAsyncSlice(0, 1, t, t));
var c = p.getOrCreateCounter('', 'ProcessCounter');
var aSeries = new tr.model.CounterSeries('a', 0);
var bSeries = new tr.model.CounterSeries('b', 0);
c.addSeries(aSeries);
c.addSeries(bSeries);
aSeries.addCounterSample(0, 5);
aSeries.addCounterSample(1, 6);
aSeries.addCounterSample(2, 5);
aSeries.addCounterSample(3, 7);
bSeries.addCounterSample(0, 10);
bSeries.addCounterSample(1, 15);
bSeries.addCounterSample(2, 12);
bSeries.addCounterSample(3, 16);
var c1 = cpu.getOrCreateCounter('', 'CpuCounter');
var aSeries = new tr.model.CounterSeries('a', 0);
var bSeries = new tr.model.CounterSeries('b', 0);
c1.addSeries(aSeries);
c1.addSeries(bSeries);
aSeries.addCounterSample(0, 5);
aSeries.addCounterSample(1, 6);
aSeries.addCounterSample(2, 5);
aSeries.addCounterSample(3, 7);
bSeries.addCounterSample(0, 10);
bSeries.addCounterSample(1, 15);
bSeries.addCounterSample(2, 12);
bSeries.addCounterSample(3, 16);
var frame1 = new Frame([slice], [{thread: t, start: 1, end: 5}]);
p.frames.push.apply(p.frames, frame1);
var gd = new tr.model.GlobalMemoryDump(m, 2);
var pd = new tr.model.ProcessMemoryDump(gd, p, 2);
gd.processMemoryDumps[1] = pd;
m.globalMemoryDumps.push(gd);
p.memoryDumps.push(pd);
m.updateBounds();
return m;
};
test('modelBounds_EmptyModel', function() {
var m = new tr.Model();
m.updateBounds();
assert.isUndefined(m.bounds.min);
assert.isUndefined(m.bounds.max);
});
test('modelBounds_OneEmptyThread', function() {
var m = new tr.Model();
var t = m.getOrCreateProcess(1).getOrCreateThread(1);
m.updateBounds();
assert.isUndefined(m.bounds.min);
assert.isUndefined(m.bounds.max);
});
test('modelBounds_OneThread', function() {
var m = new tr.Model();
var t = m.getOrCreateProcess(1).getOrCreateThread(1);
t.sliceGroup.pushSlice(new ThreadSlice('', 'a', 0, 1, {}, 3));
m.updateBounds();
assert.equal(m.bounds.min, 1);
assert.equal(m.bounds.max, 4);
});
test('modelBounds_OneThreadAndOneEmptyThread', function() {
var m = new tr.Model();
var t1 = m.getOrCreateProcess(1).getOrCreateThread(1);
t1.sliceGroup.pushSlice(new ThreadSlice('', 'a', 0, 1, {}, 3));
var t2 = m.getOrCreateProcess(1).getOrCreateThread(1);
m.updateBounds();
assert.equal(m.bounds.min, 1);
assert.equal(m.bounds.max, 4);
});
test('modelBounds_OneCpu', function() {
var m = new tr.Model();
var cpu = m.kernel.getOrCreateCpu(1);
cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
m.updateBounds();
assert.equal(m.bounds.min, 1);
assert.equal(m.bounds.max, 4);
});
test('modelBounds_OneCpuOneThread', function() {
var m = new tr.Model();
var cpu = m.kernel.getOrCreateCpu(1);
cpu.slices.push(tr.c.test_utils.newSlice(1, 3));
var t = m.getOrCreateProcess(1).getOrCreateThread(1);
t.sliceGroup.pushSlice(new ThreadSlice('', 'a', 0, 1, {}, 4));
m.updateBounds();
assert.equal(m.bounds.min, 1);
assert.equal(m.bounds.max, 5);
});
test('modelBounds_GlobalMemoryDumps', function() {
var m = new tr.Model();
m.globalMemoryDumps.push(new tr.model.GlobalMemoryDump(m, 1));
m.globalMemoryDumps.push(new tr.model.GlobalMemoryDump(m, 3));
m.globalMemoryDumps.push(new tr.model.GlobalMemoryDump(m, 5));
m.updateBounds();
assert.equal(m.bounds.min, 1);
assert.equal(m.bounds.max, 5);
});
test('modelBounds_ProcessMemoryDumps', function() {
var m = new tr.Model();
var p = m.getOrCreateProcess(1);
var gd = new tr.model.GlobalMemoryDump(m, -1);
p.memoryDumps.push(new tr.model.ProcessMemoryDump(gd, m, 1));
p.memoryDumps.push(new tr.model.ProcessMemoryDump(gd, m, 3));
p.memoryDumps.push(new tr.model.ProcessMemoryDump(gd, m, 5));
m.updateBounds();
assert.equal(m.bounds.min, 1);
assert.equal(m.bounds.max, 5);
});
test('modelCanImportEmpty', function() {
var m;
m = new tr.Model([]);
assert.isDefined(m.modelIndices);
m = new tr.Model('');
});
test('modelCanImportSubtraces', function() {
var systraceLines = [
'SurfaceFlinger-2 [001] ...1 1000.0: 0: B|1|taskA',
'SurfaceFlinger-2 [001] ...1 2000.0: 0: E',
' chrome-3 [001] ...1 2000.0: 0: trace_event_clock_sync: ' +
'parent_ts=0'
];
var traceEvents = [
{ts: 1000, pid: 1, tid: 3, ph: 'B', cat: 'c', name: 'taskB', args: {
my_object: {id_ref: '0x1000'}
}},
{ts: 2000, pid: 1, tid: 3, ph: 'E', cat: 'c', name: 'taskB', args: {}}
];
var combined = JSON.stringify({
traceEvents: traceEvents,
systemTraceEvents: systraceLines.join('\n')
});
var m = new tr.Model();
m.importTraces([combined]);
assert.equal(tr.b.dictionaryValues(m.processes).length, 1);
var p1 = m.processes[1];
assert.isDefined(p1);
var t2 = p1.threads[2];
var t3 = p1.threads[3];
assert.isDefined(t2);
assert.isDefined(t3);
assert.equal(1, 1, t2.sliceGroup.length);
assert.equal(t2.sliceGroup.slices[0].title, 'taskA');
assert.equal(t3.sliceGroup.length, 1);
assert.equal(t3.sliceGroup.slices[0].title, 'taskB');
});
test('modelCanImportCompressedSingleSubtrace', function() {
var compressedTrace = atob('H4sIACKfFVUC/wsuLUpLTE51y8nMS08t0jVSUIg2MDCMV' +
'dDT0zNUMDQwMNAzsFIAIqcaw5qSxOJsR65gfDqMEDpcATiC61ZbAAAA');
var m = new tr.Model();
m.importTraces([compressedTrace]);
assert.equal(1, tr.b.dictionaryValues(m.processes).length);
var p1 = m.processes[1];
assert.isDefined(p1);
var t2 = p1.threads[2];
assert.isDefined(t2);
assert.equal(1, t2.sliceGroup.length, 1);
assert.equal('taskA', t2.sliceGroup.slices[0].title);
});
test('modelCanImportSubtracesRecursively', function() {
var systraceLines = [
'SurfaceFlinger-2 [001] ...1 1000.0: 0: B|1|taskA',
'SurfaceFlinger-2 [001] ...1 2000.0: 0: E',
' chrome-3 [001] ...1 2000.0: 0: trace_event_clock_sync: ' +
'parent_ts=0'
];
var outerTraceEvents = [
{ts: 1000, pid: 1, tid: 3, ph: 'B', cat: 'c', name: 'taskB', args: {
my_object: {id_ref: '0x1000'}
}}
];
var innerTraceEvents = [
{ts: 2000, pid: 1, tid: 3, ph: 'E', cat: 'c', name: 'taskB', args: {}}
];
var innerTrace = JSON.stringify({
traceEvents: innerTraceEvents,
systemTraceEvents: systraceLines.join('\n')
});
var outerTrace = JSON.stringify({
traceEvents: outerTraceEvents,
systemTraceEvents: innerTrace
});
var m = new tr.Model();
m.importTraces([outerTrace]);
assert.equal(tr.b.dictionaryValues(m.processes).length, 1);
var p1 = m.processes[1];
assert.isDefined(p1);
var t2 = p1.threads[2];
var t3 = p1.threads[3];
assert.isDefined(t2);
assert.isDefined(t3);
assert.equal(1, 1, t2.sliceGroup.length);
assert.equal(t2.sliceGroup.slices[0].title, 'taskA');
assert.equal(t3.sliceGroup.length, 1);
assert.equal(t3.sliceGroup.slices[0].title, 'taskB');
});
test('modelWithImportFailure', function() {
var malformed = '{traceEvents: [{garbage';
var m = new tr.Model();
assert.throw(function() {
m.importTraces([malformed]);
});
});
test('TitleOrCategoryFilter', function() {
var s0 = tr.c.test_utils.newSlice(1, 3);
assert.isTrue(new TitleOrCategoryFilter('a').matchSlice(s0));
assert.isFalse(new TitleOrCategoryFilter('x').matchSlice(s0));
var s1 = tr.c.test_utils.newSliceEx({title: 'ba', start: 1, duration: 3});
assert.isTrue(new TitleOrCategoryFilter('a').matchSlice(s1));
assert.isTrue(new TitleOrCategoryFilter('ba').matchSlice(s1));
assert.isFalse(new TitleOrCategoryFilter('x').matchSlice(s1));
});
test('model_findAllThreadsNamed', function() {
var m = new tr.Model();
var t = m.getOrCreateProcess(1).getOrCreateThread(1);
t.name = 'CrBrowserMain';
m.updateBounds();
var f = m.findAllThreadsNamed('CrBrowserMain');
assert.deepEqual([t], f);
f = m.findAllThreadsNamed('NoSuchThread');
assert.equal(f.length, 0);
});
test('model_updateCategories', function() {
var m = new tr.Model();
var t = m.getOrCreateProcess(1).getOrCreateThread(1);
t.sliceGroup.pushSlice(new ThreadSlice('categoryA', 'a', 0, 1, {}, 3));
t.sliceGroup.pushSlice(new ThreadSlice('categoryA', 'a', 0, 1, {}, 3));
t.sliceGroup.pushSlice(new ThreadSlice('categoryB', 'a', 0, 1, {}, 3));
t.sliceGroup.pushSlice(new ThreadSlice('categoryA', 'a', 0, 1, {}, 3));
t.sliceGroup.pushSlice(new ThreadSlice('', 'a', 0, 1, {}, 3));
m.updateCategories_();
assert.deepEqual(['categoryA', 'categoryB'], m.categories);
});
test('model_iterateAllEvents', function() {
var m = createModelWithOneOfEverything();
var wasCalled = false;
m.iterateAllEvents(function(event) {
assert.isTrue(event instanceof tr.model.Event);
wasCalled = true;
});
assert.isTrue(wasCalled);
});
test('customizeCallback', function() {
var m = new tr.Model();
m.importTraces([], false, false, function() {
var browserProcess = m.getOrCreateProcess(1);
var browserMain = browserProcess.getOrCreateThread(2);
browserMain.sliceGroup.beginSlice('cat', 'Task', 0);
browserMain.sliceGroup.beginSlice('cat', 'SubTask', 1);
browserMain.sliceGroup.endSlice(9);
browserMain.sliceGroup.endSlice(10);
browserMain.sliceGroup.beginSlice('cat', 'Task', 20);
browserMain.sliceGroup.endSlice(30);
});
var t2 = m.processes[1].threads[2];
assert.equal(t2.sliceGroup.length, 3);
assert.equal(t2.sliceGroup.topLevelSlices.length, 2);
});
test('model_sortsSamples', function() {
var m = new tr.Model();
// The 184, 0 and 185 are the tick-times
// and irrespective of the order
// in which the lines appear in the trace,
// the samples should always be sorted by sampling time.
m.importTraces(['tick,0x9a,184,0,0x0,5',
'tick,0x9b,0,0,0x0,5',
'tick,0x9c,185,0,0x0,5']);
assert.equal(m.samples[0].start, 0);
assert.equal(m.samples[1].start, 0.184);
assert.equal(m.samples[2].start, 0.185);
});
test('model_sortsGlobalMemoryDumps', function() {
var m = new tr.Model();
m.importTraces([], true /* shiftWorldToZero */, false, function() {
m.globalMemoryDumps.push(new tr.model.GlobalMemoryDump(m, 1));
m.globalMemoryDumps.push(new tr.model.GlobalMemoryDump(m, 5));
m.globalMemoryDumps.push(new tr.model.GlobalMemoryDump(m, 3));
});
assert.equal(m.globalMemoryDumps[0].start, 0);
assert.equal(m.globalMemoryDumps[1].start, 2);
assert.equal(m.globalMemoryDumps[2].start, 4);
});
test('model_finalizesProcessMemoryDumps', function() {
var m = new tr.Model();
var p = m.getOrCreateProcess(1);
m.importTraces([], true /* shiftWorldToZero */, false, function() {
var g = new tr.model.GlobalMemoryDump(m, -1);
m.globalMemoryDumps.push(g);
var pmd1 = new tr.model.ProcessMemoryDump(g, p, 1);
p.memoryDumps.push(pmd1);
var pmd2 = new tr.model.ProcessMemoryDump(g, p, 5);
p.memoryDumps.push(pmd2);
var pmd3 = new tr.model.ProcessMemoryDump(g, p, 3);
p.memoryDumps.push(pmd3);
pmd3.vmRegions = [];
});
// Check the sort order.
assert.equal(p.memoryDumps[0].start, 2);
assert.equal(p.memoryDumps[1].start, 4);
assert.equal(p.memoryDumps[2].start, 6);
// Check that the most recent VM regions are linked correctly.
assert.isUndefined(p.memoryDumps[0].mostRecentVmRegions);
assert.lengthOf(p.memoryDumps[1].mostRecentVmRegions, 0);
assert.strictEqual(
p.memoryDumps[1].mostRecentVmRegions,
p.memoryDumps[2].mostRecentVmRegions);
});
test('model_annotationAddRemove', function() {
var m = new tr.Model();
var a1 = new tr.model.Annotation();
var a2 = new tr.model.Annotation();
assert.equal(m.getAllAnnotations().length, 0);
m.addAnnotation(a1);
assert.equal(m.getAllAnnotations().length, 1);
m.addAnnotation(a2);
assert.equal(m.getAllAnnotations().length, 2);
assert.equal(m.getAnnotationByGUID(a1.guid), a1);
assert.equal(m.getAnnotationByGUID(a2.guid), a2);
m.removeAnnotation(a1);
assert.isUndefined(m.getAnnotationByGUID(a1.guid));
assert.equal(m.getAnnotationByGUID(a2.guid), a2);
assert.equal(m.getAllAnnotations().length, 1);
});
test('model_intrinsicTimeUnit', function() {
var unit = tr.b.units.Time.supportedUnits;
var m = new tr.Model();
// by default it should be milliseconds
assert.equal(m.intrinsicTimeUnit, unit.ms);
m.intrinsicTimeUnit = unit.ns;
assert.equal(m.intrinsicTimeUnit, unit.ns);
// should be able to set to the same
m.intrinsicTimeUnit = unit.ns;
assert.equal(m.intrinsicTimeUnit, unit.ns);
// should not be able to change it after fixing it
assert.throw(function() { m.intrinsicTimeUnit = unit.ms; });
assert.equal(m.intrinsicTimeUnit, unit.ns);
});
});
</script>