| <!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/core/test_utils.html"> |
| <link rel="import" href="/tracing/model/model.html"> |
| <link rel="import" href="/tracing/ui/timeline_track_view.html"> |
| |
| <script> |
| 'use strict'; |
| |
| tr.b.unittest.testSuite(function() { |
| const AsyncSliceGroup = tr.model.AsyncSliceGroup; |
| const AsyncSliceGroupTrack = tr.ui.tracks.AsyncSliceGroupTrack; |
| const Process = tr.model.Process; |
| const ProcessTrack = tr.ui.tracks.ProcessTrack; |
| const Thread = tr.model.Thread; |
| const ThreadTrack = tr.ui.tracks.ThreadTrack; |
| const newAsyncSlice = tr.c.TestUtils.newAsyncSlice; |
| const newAsyncSliceNamed = tr.c.TestUtils.newAsyncSliceNamed; |
| const groupAsyncSlicesIntoSubRows = tr.ui.tracks.groupAsyncSlicesIntoSubRows; |
| |
| test('filterSubRows', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| const g = new AsyncSliceGroup(t1); |
| g.push(newAsyncSlice(0, 1, t1, t1)); |
| const track = new AsyncSliceGroupTrack(new tr.ui.TimelineViewport()); |
| track.group = g; |
| |
| assert.strictEqual(track.children.length, 1); |
| assert.isTrue(track.hasVisibleContent); |
| }); |
| |
| test('groupAsyncSlicesIntoSubRows_empty', function() { |
| const rows = groupAsyncSlicesIntoSubRows([]); |
| assert.strictEqual(rows.length, 0); |
| }); |
| |
| test('groupAsyncSlicesIntoSubRows_trivial', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| |
| const s1 = newAsyncSlice(10, 200, t1, t1); |
| const s2 = newAsyncSlice(300, 30, t1, t1); |
| |
| const slices = [s2, s1]; |
| const rows = groupAsyncSlicesIntoSubRows(slices); |
| |
| assert.strictEqual(rows.length, 1); |
| assert.sameMembers(rows[0], [s1, s2]); |
| }); |
| |
| test('groupAsyncSlicesIntoSubRows_nonTrivial', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| |
| const s1 = newAsyncSlice(10, 200, t1, t1); // Should be stripped. |
| const s1s1 = newAsyncSlice(10, 200, t1, t1); |
| s1.subSlices = [s1s1]; |
| |
| const s2 = newAsyncSlice(300, 30, t1, t1); |
| const s2s1 = newAsyncSlice(300, 10, t1, t1); |
| const s2s2 = newAsyncSlice(310, 20, t1, t1); // Should not be stripped. |
| const s2s2s1 = newAsyncSlice(310, 20, t1, t1); |
| s2s2.subSlices = [s2s2s1]; |
| s2.subSlices = [s2s2, s2s1]; |
| |
| const s3 = newAsyncSlice(200, 50, t1, t1); // Overlaps with s1. |
| const s3s1 = newAsyncSlice(220, 5, t1, t1); |
| s3.subSlices = [s3s1]; |
| |
| const slices = [s2, s3, s1]; |
| const rows = groupAsyncSlicesIntoSubRows(slices); |
| |
| assert.strictEqual(rows.length, 5); |
| assert.sameMembers(rows[0], [s1s1, s2]); |
| assert.sameMembers(rows[1], [s2s1, s2s2]); |
| assert.sameMembers(rows[2], [s2s2s1]); |
| assert.sameMembers(rows[3], [s3]); |
| assert.sameMembers(rows[4], [s3s1]); |
| }); |
| |
| test('rebuildSubRows_twoNonOverlappingSlices', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| const g = new AsyncSliceGroup(t1); |
| const s1 = newAsyncSlice(0, 1, t1, t1); |
| const subs1 = newAsyncSliceNamed('b', 0, 1, t1, t1); |
| s1.subSlices = [subs1]; |
| g.push(s1); |
| g.push(newAsyncSlice(1, 1, t1, t1)); |
| const track = new AsyncSliceGroupTrack(new tr.ui.TimelineViewport()); |
| track.group = g; |
| const subRows = track.subRows; |
| assert.strictEqual(subRows.length, 1); |
| assert.strictEqual(subRows[0].length, 2); |
| assert.sameMembers(g.slices[1].subSlices, []); |
| }); |
| |
| test('rebuildSubRows_twoOverlappingSlices', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| const g = new AsyncSliceGroup(t1); |
| |
| const s1 = newAsyncSlice(0, 1, t1, t1); |
| const subs1 = newAsyncSliceNamed('b', 0, 1, t1, t1); |
| s1.subSlices = [subs1]; |
| const s2 = newAsyncSlice(0, 1.5, t1, t1); |
| const subs2 = newAsyncSliceNamed('b', 0, 1, t1, t1); |
| s2.subSlices = [subs2]; |
| g.push(s1); |
| g.push(s2); |
| |
| g.updateBounds(); |
| |
| const track = new AsyncSliceGroupTrack(new tr.ui.TimelineViewport()); |
| track.group = g; |
| |
| const subRows = track.subRows; |
| |
| assert.strictEqual(subRows.length, 2); |
| assert.strictEqual(subRows[0].length, 1); |
| assert.strictEqual(subRows[1].length, 1); |
| assert.strictEqual(subRows[1][0], g.slices[1].subSlices[0]); |
| }); |
| |
| test('rebuildSubRows_threePartlyOverlappingSlices', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| const g = new AsyncSliceGroup(t1); |
| g.push(newAsyncSlice(0, 1, t1, t1)); |
| g.push(newAsyncSlice(0, 1.5, t1, t1)); |
| g.push(newAsyncSlice(1, 1.5, t1, t1)); |
| g.updateBounds(); |
| const track = new AsyncSliceGroupTrack(new tr.ui.TimelineViewport()); |
| track.group = g; |
| const subRows = track.subRows; |
| |
| assert.strictEqual(subRows.length, 2); |
| assert.strictEqual(subRows[0].length, 2); |
| assert.strictEqual(subRows[0][0], g.slices[0]); |
| assert.strictEqual(subRows[0][1], g.slices[2]); |
| assert.strictEqual(subRows[1][0], g.slices[1]); |
| assert.strictEqual(subRows[1].length, 1); |
| assert.sameMembers(g.slices[0].subSlices, []); |
| assert.sameMembers(g.slices[1].subSlices, []); |
| assert.sameMembers(g.slices[2].subSlices, []); |
| }); |
| |
| test('rebuildSubRows_threeOverlappingSlices', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| const g = new AsyncSliceGroup(t1); |
| |
| g.push(newAsyncSlice(0, 1, t1, t1)); |
| g.push(newAsyncSlice(0, 1.5, t1, t1)); |
| g.push(newAsyncSlice(2, 1, t1, t1)); |
| g.updateBounds(); |
| |
| const track = new AsyncSliceGroupTrack(new tr.ui.TimelineViewport()); |
| track.group = g; |
| |
| const subRows = track.subRows; |
| assert.strictEqual(subRows.length, 2); |
| assert.strictEqual(subRows[0].length, 2); |
| assert.strictEqual(subRows[1].length, 1); |
| assert.strictEqual(subRows[0][0], g.slices[0]); |
| assert.strictEqual(subRows[1][0], g.slices[1]); |
| assert.strictEqual(subRows[0][1], g.slices[2]); |
| }); |
| |
| test('rebuildSubRows_twoViewSubGroups', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| const g = new AsyncSliceGroup(t1); |
| g.push(newAsyncSliceNamed('foo', 0, 1, t1, t1)); |
| g.push(newAsyncSliceNamed('foo', 2, 1, t1, t1)); |
| g.push(newAsyncSliceNamed('bar', 1, 2, t1, t1)); |
| g.push(newAsyncSliceNamed('bar', 3, 2, t1, t1)); |
| g.updateBounds(); |
| |
| const track = new AsyncSliceGroupTrack(new tr.ui.TimelineViewport()); |
| track.group = g; |
| track.heading = 'sup'; |
| |
| assert.strictEqual(track.subRows.length, 2); |
| const subTracks = Polymer.dom(track).children; |
| assert.strictEqual(subTracks.length, 3); |
| assert.strictEqual(subTracks[0].slices.length, 0); |
| assert.strictEqual(subTracks[1].slices.length, 2); |
| assert.strictEqual(subTracks[2].slices.length, 2); |
| const headings = |
| [subTracks[0].heading, subTracks[1].heading, subTracks[2].heading]; |
| assert.sameMembers(headings, ['foo', 'bar', 'sup']); |
| }); |
| |
| // Tests that no slices and their sub slices overlap. |
| test('rebuildSubRows_NonOverlappingSubSlices', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| const g = new AsyncSliceGroup(t1); |
| |
| const slice1 = newAsyncSlice(0, 5, t1, t1); |
| const slice1Child = newAsyncSlice(1, 2, t1, t1); |
| slice1.subSlices = [slice1Child]; |
| const slice2 = newAsyncSlice(3, 5, t1, t1); |
| const slice3 = newAsyncSlice(5, 4, t1, t1); |
| const slice3Child = newAsyncSlice(6, 2, t1, t1); |
| slice3.subSlices = [slice3Child]; |
| g.push(slice1); |
| g.push(slice2); |
| g.push(slice3); |
| g.updateBounds(); |
| |
| const track = new AsyncSliceGroupTrack(new tr.ui.TimelineViewport()); |
| track.group = g; |
| |
| const subRows = track.subRows; |
| // Checks each sub row to see that we don't have any overlapping slices. |
| for (let i = 0; i < subRows.length; i++) { |
| const row = subRows[i]; |
| for (let j = 0; j < row.length; j++) { |
| for (let k = j + 1; k < row.length; k++) { |
| assert.isTrue(row[j].end <= row[k].start); |
| } |
| } |
| } |
| }); |
| |
| test('rebuildSubRows_NonOverlappingSubSlicesThreeNestedLevels', function() { |
| const model = new tr.Model(); |
| const p1 = new Process(model, 1); |
| const t1 = new Thread(p1, 1); |
| const g = new AsyncSliceGroup(t1); |
| |
| const slice1 = newAsyncSlice(0, 4, t1, t1); |
| const slice1Child = newAsyncSlice(1, 2, t1, t1); |
| slice1.subSlices = [slice1Child]; |
| const slice2 = newAsyncSlice(2, 7, t1, t1); |
| const slice3 = newAsyncSlice(5, 5, t1, t1); |
| const slice3Child = newAsyncSlice(6, 3, t1, t1); |
| const slice3Child2 = newAsyncSlice(7, 1, t1, t1); |
| slice3.subSlices = [slice3Child]; |
| slice3Child.subSlices = [slice3Child2]; |
| g.push(slice1); |
| g.push(slice2); |
| g.push(slice3); |
| g.updateBounds(); |
| |
| const track = new AsyncSliceGroupTrack(new tr.ui.TimelineViewport()); |
| track.group = g; |
| |
| const subRows = track.subRows; |
| // Checks each sub row to see that we don't have any overlapping slices. |
| for (let i = 0; i < subRows.length; i++) { |
| const row = subRows[i]; |
| for (let j = 0; j < row.length; j++) { |
| for (let k = j + 1; k < row.length; k++) { |
| assert.isTrue(row[j].end <= row[k].start); |
| } |
| } |
| } |
| }); |
| |
| test('asyncSliceGroupContainerMap', function() { |
| const vp = new tr.ui.TimelineViewport(); |
| const containerToTrack = vp.containerToTrackMap; |
| const model = new tr.Model(); |
| const process = model.getOrCreateProcess(123); |
| const thread = process.getOrCreateThread(456); |
| const group = new AsyncSliceGroup(thread); |
| |
| const processTrack = new ProcessTrack(vp); |
| const threadTrack = new ThreadTrack(vp); |
| const groupTrack = new AsyncSliceGroupTrack(vp); |
| processTrack.process = process; |
| threadTrack.thread = thread; |
| groupTrack.group = group; |
| Polymer.dom(processTrack).appendChild(threadTrack); |
| Polymer.dom(threadTrack).appendChild(groupTrack); |
| |
| assert.strictEqual(processTrack.eventContainer, process); |
| assert.strictEqual(threadTrack.eventContainer, thread); |
| assert.strictEqual(groupTrack.eventContainer, group); |
| |
| assert.isUndefined(containerToTrack.getTrackByStableId('123')); |
| assert.isUndefined(containerToTrack.getTrackByStableId('123.456')); |
| assert.isUndefined( |
| containerToTrack.getTrackByStableId('123.456.AsyncSliceGroup')); |
| |
| vp.modelTrackContainer = { |
| addContainersToTrackMap(containerToTrackMap) { |
| processTrack.addContainersToTrackMap(containerToTrackMap); |
| }, |
| addEventListener() {} |
| }; |
| vp.rebuildContainerToTrackMap(); |
| |
| // Check that all tracks call childs' addContainersToTrackMap() |
| // by checking the resulting map. |
| assert.strictEqual( |
| containerToTrack.getTrackByStableId('123'), processTrack); |
| assert.strictEqual( |
| containerToTrack.getTrackByStableId('123.456'), threadTrack); |
| assert.strictEqual( |
| containerToTrack.getTrackByStableId('123.456.AsyncSliceGroup'), |
| groupTrack); |
| |
| // Check the track's eventContainer getter. |
| assert.strictEqual(processTrack.eventContainer, process); |
| assert.strictEqual(threadTrack.eventContainer, thread); |
| assert.strictEqual(groupTrack.eventContainer, group); |
| }); |
| }); |
| </script> |