| <!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="/core/trace_model/annotation.html"> |
| <link rel="import" href="/core/trace_model/trace_model.html"> |
| <link rel="import" href="/extras/full_config.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tv.b.unittest.testSuite(function() { |
| var ThreadSlice = tv.c.trace_model.ThreadSlice; |
| var TraceModel = tv.c.TraceModel; |
| var TitleOrCategoryFilter = tv.c.TitleOrCategoryFilter; |
| var Frame = tv.c.trace_model.Frame; |
| |
| var createTraceModelWithOneOfEverything = function() { |
| var m = new TraceModel(); |
| var cpu = m.kernel.getOrCreateCpu(1); |
| cpu.slices.push(tv.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(tv.c.test_utils.newAsyncSlice(0, 1, t, t)); |
| |
| var c = p.getOrCreateCounter('', 'ProcessCounter'); |
| var aSeries = new tv.c.trace_model.CounterSeries('a', 0); |
| var bSeries = new tv.c.trace_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 tv.c.trace_model.CounterSeries('a', 0); |
| var bSeries = new tv.c.trace_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 tv.c.trace_model.GlobalMemoryDump(m, 2); |
| var pd = new tv.c.trace_model.ProcessMemoryDump(gd, p, 2); |
| gd.processMemoryDumps[1] = pd; |
| m.globalMemoryDumps.push(gd); |
| p.memoryDumps.push(pd); |
| |
| m.updateBounds(); |
| |
| return m; |
| }; |
| |
| test('traceModelBounds_EmptyTraceModel', function() { |
| var m = new TraceModel(); |
| m.updateBounds(); |
| assert.isUndefined(m.bounds.min); |
| assert.isUndefined(m.bounds.max); |
| }); |
| |
| test('traceModelBounds_OneEmptyThread', function() { |
| var m = new TraceModel(); |
| var t = m.getOrCreateProcess(1).getOrCreateThread(1); |
| m.updateBounds(); |
| assert.isUndefined(m.bounds.min); |
| assert.isUndefined(m.bounds.max); |
| }); |
| |
| test('traceModelBounds_OneThread', function() { |
| var m = new TraceModel(); |
| 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('traceModelBounds_OneThreadAndOneEmptyThread', function() { |
| var m = new TraceModel(); |
| 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('traceModelBounds_OneCpu', function() { |
| var m = new TraceModel(); |
| var cpu = m.kernel.getOrCreateCpu(1); |
| cpu.slices.push(tv.c.test_utils.newSlice(1, 3)); |
| m.updateBounds(); |
| assert.equal(m.bounds.min, 1); |
| assert.equal(m.bounds.max, 4); |
| }); |
| |
| test('traceModelBounds_OneCpuOneThread', function() { |
| var m = new TraceModel(); |
| var cpu = m.kernel.getOrCreateCpu(1); |
| cpu.slices.push(tv.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('traceModelBounds_GlobalMemoryDumps', function() { |
| var m = new TraceModel(); |
| m.globalMemoryDumps.push(new tv.c.trace_model.GlobalMemoryDump(m, 1)); |
| m.globalMemoryDumps.push(new tv.c.trace_model.GlobalMemoryDump(m, 3)); |
| m.globalMemoryDumps.push(new tv.c.trace_model.GlobalMemoryDump(m, 5)); |
| |
| m.updateBounds(); |
| assert.equal(m.bounds.min, 1); |
| assert.equal(m.bounds.max, 5); |
| }); |
| |
| test('traceModelBounds_ProcessMemoryDumps', function() { |
| var m = new TraceModel(); |
| var p = m.getOrCreateProcess(1); |
| var gd = new tv.c.trace_model.GlobalMemoryDump(m, -1); |
| p.memoryDumps.push(new tv.c.trace_model.ProcessMemoryDump(gd, m, 1)); |
| p.memoryDumps.push(new tv.c.trace_model.ProcessMemoryDump(gd, m, 3)); |
| p.memoryDumps.push(new tv.c.trace_model.ProcessMemoryDump(gd, m, 5)); |
| |
| m.updateBounds(); |
| assert.equal(m.bounds.min, 1); |
| assert.equal(m.bounds.max, 5); |
| }); |
| |
| test('traceModelCanImportEmpty', function() { |
| var m; |
| m = new TraceModel([]); |
| m = new TraceModel(''); |
| }); |
| |
| test('traceModelCanImportSubtraces', 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 TraceModel(); |
| m.importTraces([combined]); |
| assert.equal(tv.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('traceModelCanImportCompressedSingleSubtrace', function() { |
| var compressedTrace = atob('H4sIACKfFVUC/wsuLUpLTE51y8nMS08t0jVSUIg2MDCMV' + |
| 'dDT0zNUMDQwMNAzsFIAIqcaw5qSxOJsR65gfDqMEDpcATiC61ZbAAAA'); |
| var m = new TraceModel(); |
| m.importTraces([compressedTrace]); |
| assert.equal(1, tv.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('traceModelCanImportSubtracesRecursively', 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 TraceModel(); |
| m.importTraces([outerTrace]); |
| assert.equal(tv.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('traceModelWithImportFailure', function() { |
| var malformed = '{traceEvents: [{garbage'; |
| var m = new TraceModel(); |
| assert.throw(function() { |
| m.importTraces([malformed]); |
| }); |
| }); |
| |
| test('TitleOrCategoryFilter', function() { |
| var s0 = tv.c.test_utils.newSlice(1, 3); |
| assert.isTrue(new TitleOrCategoryFilter('a').matchSlice(s0)); |
| assert.isFalse(new TitleOrCategoryFilter('x').matchSlice(s0)); |
| |
| var s1 = tv.c.test_utils.newSliceNamed('ba', 1, 3); |
| assert.isTrue(new TitleOrCategoryFilter('a').matchSlice(s1)); |
| assert.isTrue(new TitleOrCategoryFilter('ba').matchSlice(s1)); |
| assert.isFalse(new TitleOrCategoryFilter('x').matchSlice(s1)); |
| }); |
| |
| test('traceModel_findAllThreadsNamed', function() { |
| var m = new TraceModel(); |
| 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('traceModel_updateCategories', function() { |
| var m = new TraceModel(); |
| 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('traceModel_iterateAllEvents', function() { |
| var m = createTraceModelWithOneOfEverything(); |
| var wasCalled = false; |
| m.iterateAllEvents(function(event) { |
| assert.isTrue(event instanceof tv.c.trace_model.Event); |
| wasCalled = true; |
| }); |
| assert.isTrue(wasCalled); |
| }); |
| |
| test('customizeCallback', function() { |
| var m = new tv.c.TraceModel(); |
| 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('traceModel_sortsSamples', function() { |
| var m = new tv.c.TraceModel(); |
| // 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('traceModel_sortsGlobalMemoryDumps', function() { |
| var m = new tv.c.TraceModel(); |
| m.importTraces([], true /* shiftWorldToZero */, false, function() { |
| m.globalMemoryDumps.push(new tv.c.trace_model.GlobalMemoryDump(m, 1)); |
| m.globalMemoryDumps.push(new tv.c.trace_model.GlobalMemoryDump(m, 5)); |
| m.globalMemoryDumps.push(new tv.c.trace_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('traceModel_finalizesProcessMemoryDumps', function() { |
| var m = new tv.c.TraceModel(); |
| var p = m.getOrCreateProcess(1); |
| m.importTraces([], true /* shiftWorldToZero */, false, function() { |
| var g = new tv.c.trace_model.GlobalMemoryDump(m, -1); |
| |
| var pmd1 = new tv.c.trace_model.ProcessMemoryDump(g, p, 1); |
| p.memoryDumps.push(pmd1); |
| |
| var pmd2 = new tv.c.trace_model.ProcessMemoryDump(g, p, 5); |
| p.memoryDumps.push(pmd2); |
| |
| var pmd3 = new tv.c.trace_model.ProcessMemoryDump(g, p, 3); |
| p.memoryDumps.push(pmd3); |
| pmd3.vmRegions = []; |
| }); |
| |
| // Check the sort order. |
| assert.equal(p.memoryDumps[0].start, 0); |
| assert.equal(p.memoryDumps[1].start, 2); |
| assert.equal(p.memoryDumps[2].start, 4); |
| |
| // 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('traceModel_annotationAddRemove', function() { |
| var m = new tv.c.TraceModel(); |
| var a1 = new tv.c.trace_model.Annotation(); |
| var a2 = new tv.c.trace_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); |
| }); |
| }); |
| </script> |