| <!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="/tracing/base/time_display_modes.html"> |
| <link rel="import" href="/tracing/core/test_utils.html"> |
| <link rel="import" href="/tracing/extras/importer/trace_event_importer.html"> |
| <link rel="import" href="/tracing/importer/import.html"> |
| <link rel="import" href="/tracing/model/annotation.html"> |
| <link rel="import" href="/tracing/model/model.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.b.unittest.testSuite(function() { |
| const ThreadSlice = tr.model.ThreadSlice; |
| const TitleOrCategoryFilter = tr.c.TitleOrCategoryFilter; |
| const Frame = tr.model.Frame; |
| |
| const createModelWithOneOfEverything = function() { |
| const m = new tr.Model(); |
| const cpu = m.kernel.getOrCreateCpu(1); |
| cpu.slices.push(tr.c.TestUtils.newSliceEx({start: 1, duration: 3})); |
| |
| const p = m.getOrCreateProcess(1); |
| const t = p.getOrCreateThread(1); |
| const slice = new ThreadSlice('', 'a', 0, 1, {}, 4); |
| t.sliceGroup.pushSlice(slice); |
| t.asyncSliceGroup.push(tr.c.TestUtils.newAsyncSlice(0, 1, t, t)); |
| |
| const c = p.getOrCreateCounter('', 'ProcessCounter'); |
| let aSeries = new tr.model.CounterSeries('a', 0); |
| let 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); |
| |
| const c1 = cpu.getOrCreateCounter('', 'CpuCounter'); |
| aSeries = new tr.model.CounterSeries('a', 0); |
| 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); |
| |
| const frame1 = new Frame([slice], [{thread: t, start: 1, end: 5}]); |
| p.frames.push.apply(p.frames, frame1); |
| |
| const gd = new tr.model.GlobalMemoryDump(m, 2); |
| const 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('helper', function() { |
| function Helper(model) { |
| this.model = model; |
| } |
| Helper.guid = tr.b.GUID.allocateSimple(); |
| Helper.supportsModel = function(model) { |
| return true; |
| }; |
| |
| const m = new tr.Model(); |
| const h = m.getOrCreateHelper(Helper); |
| assert.isTrue(h instanceof Helper); |
| assert.isTrue(h === m.getOrCreateHelper(Helper)); |
| |
| function UnsupportedHelper(model) { |
| this.model = model; |
| } |
| UnsupportedHelper.guid = tr.b.GUID.allocateSimple(); |
| UnsupportedHelper.supportsModel = function(model) { |
| return false; |
| }; |
| |
| assert.isUndefined(m.getOrCreateHelper(UnsupportedHelper)); |
| // Try again to test doesHelperGUIDSupportThisModel_ . |
| assert.isUndefined(m.getOrCreateHelper(UnsupportedHelper)); |
| }); |
| |
| test('modelBounds_EmptyModel', function() { |
| const m = new tr.Model(); |
| m.updateBounds(); |
| assert.isUndefined(m.bounds.min); |
| assert.isUndefined(m.bounds.max); |
| }); |
| |
| test('modelBounds_OneEmptyThread', function() { |
| const m = new tr.Model(); |
| const t = m.getOrCreateProcess(1).getOrCreateThread(1); |
| m.updateBounds(); |
| assert.isUndefined(m.bounds.min); |
| assert.isUndefined(m.bounds.max); |
| }); |
| |
| test('modelBounds_OneThread', function() { |
| const m = new tr.Model(); |
| const t = m.getOrCreateProcess(1).getOrCreateThread(1); |
| t.sliceGroup.pushSlice(new ThreadSlice('', 'a', 0, 1, {}, 3)); |
| m.updateBounds(); |
| assert.strictEqual(m.bounds.min, 1); |
| assert.strictEqual(m.bounds.max, 4); |
| }); |
| |
| test('modelBounds_OneThreadAndOneEmptyThread', function() { |
| const m = new tr.Model(); |
| const t1 = m.getOrCreateProcess(1).getOrCreateThread(1); |
| t1.sliceGroup.pushSlice(new ThreadSlice('', 'a', 0, 1, {}, 3)); |
| const t2 = m.getOrCreateProcess(1).getOrCreateThread(1); |
| m.updateBounds(); |
| assert.strictEqual(m.bounds.min, 1); |
| assert.strictEqual(m.bounds.max, 4); |
| }); |
| |
| test('modelBounds_OneCpu', function() { |
| const m = new tr.Model(); |
| const cpu = m.kernel.getOrCreateCpu(1); |
| cpu.slices.push(tr.c.TestUtils.newSliceEx({start: 1, duration: 3})); |
| m.updateBounds(); |
| assert.strictEqual(m.bounds.min, 1); |
| assert.strictEqual(m.bounds.max, 4); |
| }); |
| |
| test('modelBounds_OneCpuOneThread', function() { |
| const m = new tr.Model(); |
| const cpu = m.kernel.getOrCreateCpu(1); |
| cpu.slices.push(tr.c.TestUtils.newSliceEx({start: 1, duration: 3})); |
| |
| const t = m.getOrCreateProcess(1).getOrCreateThread(1); |
| t.sliceGroup.pushSlice(new ThreadSlice('', 'a', 0, 1, {}, 4)); |
| |
| m.updateBounds(); |
| assert.strictEqual(m.bounds.min, 1); |
| assert.strictEqual(m.bounds.max, 5); |
| }); |
| |
| test('modelBounds_GlobalMemoryDumps', function() { |
| const 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.strictEqual(m.bounds.min, 1); |
| assert.strictEqual(m.bounds.max, 5); |
| }); |
| |
| test('modelBounds_ProcessMemoryDumps', function() { |
| const m = new tr.Model(); |
| const p = m.getOrCreateProcess(1); |
| const 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.strictEqual(m.bounds.min, 1); |
| assert.strictEqual(m.bounds.max, 5); |
| }); |
| |
| |
| test('modelConvertsTimestampToModelTime', function() { |
| const m = new tr.Model(); |
| const traceEvents = [ |
| {ts: 1000, pid: 1, tid: 1, ph: 'B', cat: 'a', name: 'taskA', args: {}}, |
| {ts: 2000, pid: 1, tid: 1, ph: 'E', cat: 'a', name: 'taskA', args: {}} |
| ]; |
| const i = new tr.importer.Import(m); |
| i.importTraces([traceEvents]); |
| assert.strictEqual( |
| m.convertTimestampToModelTime('traceEventClock', 1000), 0); |
| assert.strictEqual( |
| m.convertTimestampToModelTime('traceEventClock', 2000), 1); |
| }); |
| |
| test('TitleOrCategoryFilter', function() { |
| const s0 = tr.c.TestUtils.newSliceEx({start: 1, duration: 3}); |
| assert.isTrue(new TitleOrCategoryFilter('a').matchSlice(s0)); |
| assert.isFalse(new TitleOrCategoryFilter('x').matchSlice(s0)); |
| |
| const s1 = tr.c.TestUtils.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() { |
| const m = new tr.Model(); |
| const t = m.getOrCreateProcess(1).getOrCreateThread(1); |
| t.name = 'CrBrowserMain'; |
| |
| m.updateBounds(); |
| let f = m.findAllThreadsNamed('CrBrowserMain'); |
| assert.deepEqual([t], f); |
| f = m.findAllThreadsNamed('NoSuchThread'); |
| assert.strictEqual(f.length, 0); |
| }); |
| |
| test('model_updateCategories', function() { |
| const m = new tr.Model(); |
| const 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('getEventByStableId', function() { |
| const m = new tr.Model(); |
| const p = m.getOrCreateProcess(0); |
| const t = p.getOrCreateThread(1); |
| const slice = tr.c.TestUtils.newSliceEx({start: 0, duration: 10}); |
| t.sliceGroup.pushSlice(slice); |
| const ue = tr.c.TestUtils.newInteractionRecord(m, 0, 10); |
| m.userModel.expectations.push(ue); |
| const gie = tr.c.TestUtils.newInstantEvent({ |
| title: 'gie', |
| start: 0, |
| colorId: 0 |
| }); |
| m.instantEvents.push(gie); |
| |
| assert.strictEqual(slice, m.getEventByStableId(slice.stableId)); |
| assert.strictEqual(ue, m.getEventByStableId(ue.stableId)); |
| assert.strictEqual(gie, m.getEventByStableId(gie.stableId)); |
| }); |
| |
| test('model_annotationAddRemove', function() { |
| const m = new tr.Model(); |
| const a1 = new tr.model.Annotation(); |
| const a2 = new tr.model.Annotation(); |
| |
| assert.strictEqual(m.getAllAnnotations().length, 0); |
| m.addAnnotation(a1); |
| assert.strictEqual(m.getAllAnnotations().length, 1); |
| m.addAnnotation(a2); |
| assert.strictEqual(m.getAllAnnotations().length, 2); |
| |
| assert.strictEqual(m.getAnnotationByGUID(a1.guid), a1); |
| assert.strictEqual(m.getAnnotationByGUID(a2.guid), a2); |
| |
| m.removeAnnotation(a1); |
| assert.isUndefined(m.getAnnotationByGUID(a1.guid)); |
| assert.strictEqual(m.getAnnotationByGUID(a2.guid), a2); |
| assert.strictEqual(m.getAllAnnotations().length, 1); |
| }); |
| |
| test('model_intrinsicTimeUnit', function() { |
| const unit = tr.b.TimeDisplayModes; |
| const m = new tr.Model(); |
| |
| // by default it should be milliseconds |
| assert.strictEqual(m.intrinsicTimeUnit, unit.ms); |
| |
| m.intrinsicTimeUnit = unit.ns; |
| assert.strictEqual(m.intrinsicTimeUnit, unit.ns); |
| // should be able to set to the same |
| m.intrinsicTimeUnit = unit.ns; |
| assert.strictEqual(m.intrinsicTimeUnit, unit.ns); |
| // should not be able to change it after fixing it |
| assert.throw(function() { m.intrinsicTimeUnit = unit.ms; }); |
| assert.strictEqual(m.intrinsicTimeUnit, unit.ns); |
| }); |
| |
| test('model_getAllProcesses', function() { |
| const m = new tr.Model(); |
| const p1 = m.getOrCreateProcess(1); |
| const p2 = m.getOrCreateProcess(2); |
| const p3 = m.getOrCreateProcess(3); |
| const p4 = m.getOrCreateProcess(4); |
| const p5 = m.getOrCreateProcess(5); |
| |
| assert.sameMembers(m.getAllProcesses(), [p1, p2, p3, p4, p5]); |
| assert.sameMembers(m.getAllProcesses(p => true), [p1, p2, p3, p4, p5]); |
| assert.sameMembers(m.getAllProcesses(p => false), []); |
| assert.sameMembers(m.getAllProcesses(p => p.pid % 2 === 0), [p2, p4]); |
| }); |
| |
| test('model_joinRefs', function() { |
| function RefCountingSnapshot() { |
| tr.model.ObjectSnapshot.apply(this, arguments); |
| this.refCount = 0; |
| } |
| |
| RefCountingSnapshot.prototype = { |
| __proto__: tr.model.ObjectSnapshot.prototype, |
| |
| referencedAt() { |
| ++this.refCount; |
| } |
| }; |
| |
| const typeName = 'RefCountingSnapshot'; |
| tr.model.ObjectSnapshot.subTypes.register( |
| RefCountingSnapshot, |
| {typeName}); |
| |
| const m = new tr.Model(); |
| const p = m.getOrCreateProcess(1); |
| const s1 = p.objects.addSnapshot(new tr.model.ScopedId(typeName, '0x1'), |
| 'cat', typeName, 1000, {}); |
| const s2 = p.objects.addSnapshot(new tr.model.ScopedId(typeName, '0x2'), |
| 'cat', typeName, 2000, { |
| myRef: { |
| scope: typeName, |
| id_ref: '0x1' |
| } |
| }); |
| m.joinRefs(); |
| assert.strictEqual(s1.refCount, 1); |
| assert.strictEqual(s2.refCount, 0); |
| }); |
| }); |
| </script> |