Home | History | Annotate | Download | only in tracing
      1 <!DOCTYPE HTML>
      2 <html>
      3 <!--
      4 Copyright (c) 2012 The Chromium Authors. All rights reserved.
      5 Use of this source code is governed by a BSD-style license that can be
      6 found in the LICENSE file.
      7 -->
      8 <head i18n-values="dir:textdirection;">
      9 <title>TimelineTrack tests</title>
     10 <script
     11    src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js">
     12 </script>
     13 <script>
     14   goog.require('goog.testing.jsunit');
     15 </script>
     16 <style>
     17 * {
     18   box-sizing: border-box;
     19   -webkit-user-select: none;
     20 }
     21 
     22 .timeline-container {
     23   border: 1px solid red;
     24 }
     25 
     26 </style>
     27 <link rel="stylesheet" href="timeline.css">
     28 <script src="../shared/js/cr.js"></script>
     29 <script src="../shared/js/cr/event_target.js"></script>
     30 <script src="../shared/js/cr/ui.js"></script>
     31 <script src="../shared/js/util.js"></script>
     32 <script src="timeline_model.js"></script>
     33 <script src="sorted_array_utils.js"></script>
     34 <script src="measuring_stick.js"></script>
     35 <script src="timeline.js"></script>
     36 <script src="timeline_track.js"></script>
     37 <script src="fast_rect_renderer.js"></script>
     38 </head>
     39 <body>
     40 <script>
     41 </script>
     42 <script>
     43   'use strict';
     44 
     45   var TimelineAsyncSlice = tracing.TimelineAsyncSlice;
     46   var TimelineAsyncSliceGroup = tracing.TimelineAsyncSliceGroup;
     47   var TimelineCounter = tracing.TimelineCounter;
     48   var TimelineCounterTrack = tracing.TimelineCounterTrack;
     49   var TimelineCpu = tracing.TimelineCpu;
     50   var TimelineCpuTrack = tracing.TimelineCpuTrack;
     51   var TimelineProcess = tracing.TimelineProcess;
     52   var TimelineSelection = tracing.TimelineSelection;
     53   var TimelineSliceTrack = tracing.TimelineSliceTrack;
     54   var TimelineSlice = tracing.TimelineSlice;
     55   var TimelineThread = tracing.TimelineThread;
     56   var TimelineThreadSlice = tracing.TimelineThreadSlice;
     57   var TimelineThreadTrack = tracing.TimelineThreadTrack;
     58   var TimelineViewport = tracing.TimelineViewport;
     59   var testDivs = {};
     60 
     61   // Helper function to create a slice.
     62   function newAsyncSlice(start, duration, startThread, endThread) {
     63     var s = new TimelineAsyncSlice('a', 0, start);
     64     s.duration = duration;
     65     s.startThread = startThread;
     66     s.endThread = endThread;
     67     return s;
     68   }
     69 
     70   function getTestDiv(name) {
     71     if (!testDivs[name]) {
     72       testDivs[name] = document.createElement('div');
     73       document.body.appendChild(testDivs[name]);
     74     }
     75     testDivs[name].textContent = '';
     76     return testDivs[name];
     77   }
     78 
     79   function testBasicSlices() {
     80     var testEl = getTestDiv('testBasicSlices');
     81     var track = TimelineSliceTrack();
     82     testEl.appendChild(track);
     83     track.heading = 'testBasicSlices';
     84     track.slices = [
     85       new TimelineSlice('a', 0, 1, {}, 1),
     86       new TimelineSlice('b', 1, 2.1, {}, 4.8),
     87       new TimelineSlice('b', 1, 7, {}, 0.5),
     88       new TimelineSlice('c', 2, 7.6, {}, 0.4)
     89     ];
     90     track.viewport = new TimelineViewport(testEl);
     91     track.viewport.xSetWorldRange(0, 8.8, track.clientWidth);
     92   }
     93 
     94   function testFindAllObjectsMatchingInSliceTrack() {
     95     var track = TimelineSliceTrack();
     96     track.slices = [
     97       new TimelineSlice('a', 0, 1, {}, 1),
     98       new TimelineSlice('b', 1, 2.1, {}, 4.8),
     99       new TimelineSlice('b', 1, 7, {}, 0.5),
    100       new TimelineSlice('c', 2, 7.6, {}, 0.4)
    101     ];
    102     var selection = new TimelineSelection();
    103     track.addAllObjectsMatchingFilterToSelection(
    104         new tracing.TimelineFilter("b"), selection);
    105 
    106     assertEquals(2, selection.length);
    107     assertEquals(track.slices[1], selection[0].slice);
    108     assertEquals(track.slices[2], selection[1].slice);
    109   }
    110 
    111   function testShrinkingSliceSizes() {
    112     var testEl = getTestDiv('testShrinkingSliceSizes');
    113     var track = TimelineSliceTrack();
    114     testEl.appendChild(track);
    115     track.heading = 'testShrinkingSliceSizes';
    116     var x = 0;
    117     var widths = [10, 5, 4, 3, 2, 1, 0.5, 0.4, 0.3, 0.2, 0.1, 0.05];
    118     var slices = [];
    119     for (var i = 0; i < widths.length; i++) {
    120       var s = new TimelineSlice('a', 1, x, {}, widths[i]);
    121       x += s.duration + 0.5;
    122       slices.push(s);
    123     }
    124     track.slices = slices;
    125     track.viewport = new TimelineViewport(testEl);
    126     track.viewport.xSetWorldRange(0, 1.1 * x, track.clientWidth);
    127   }
    128 
    129   function testSelectionHitTesting() {
    130     var testEl = getTestDiv('testSelectionHitTesting');
    131     var track = new TimelineSliceTrack();
    132     testEl.appendChild(track);
    133     track.heading = 'testSelectionHitTesting';
    134     track.headingWidth = '100px';
    135     track.slices = [
    136       new TimelineSlice('a', 0, 1, {}, 1),
    137       new TimelineSlice('b', 1, 2.1, {}, 4.8)
    138     ];
    139     track.style.width = '500px';
    140     track.viewport = new TimelineViewport(testEl);
    141     track.viewport.xSetWorldRange(0, 7.6, track.clientWidth);
    142     var clientRect = track.getBoundingClientRect();
    143 
    144     var selection = new TimelineSelection();
    145     track.addIntersectingItemsToSelection(1.5, clientRect.top + 5, selection);
    146     assertEquals(track.slices[0], selection[0].slice);
    147 
    148     var selection = new TimelineSelection();
    149     track.addIntersectingItemsToSelection(2, clientRect.top + 5, selection);
    150     assertEquals(0, selection.length);
    151 
    152     var selection = new TimelineSelection();
    153     track.addIntersectingItemsToSelection(6.8, clientRect.top + 5, selection);
    154     assertEquals(track.slices[1], selection[0].slice);
    155 
    156     var selection = new TimelineSelection();
    157     track.addIntersectingItemsToSelection(6.9, clientRect.top + 5, selection);
    158     assertEquals(0, selection.length);
    159   }
    160 
    161   function testSelectionHitTestingWithTimelineThreadTrack() {
    162     var model = new tracing.TimelineModel();
    163     var p1 = model.getOrCreateProcess(1);
    164     var t1 = p1.getOrCreateThread(1);
    165     t1.subRows[0].push(new tracing.TimelineThreadSlice('a', 0, 1, {}, 5));
    166     t1.subRows[0].push(new tracing.TimelineThreadSlice('b', 0, 5.1, {}, 4));
    167 
    168     var testEl = getTestDiv('testSelectionHitTestingWithTimelineThreadTrack');
    169     var track = new tracing.TimelineThreadTrack();
    170     testEl.appendChild(track);
    171     track.heading = 'testSelectionHitTestingWithTimelineThreadTrack';
    172     track.headingWidth = '100px';
    173     track.thread = t1;
    174 
    175     track.style.width = '500px';
    176     track.viewport = new TimelineViewport(testEl);
    177     track.viewport.xSetWorldRange(0, 10, track.clientWidth);
    178     var clientRect = track.getBoundingClientRect();
    179 
    180     var selection = new TimelineSelection();
    181     track.addIntersectingItemsToSelection(1.5, clientRect.top + 5, selection);
    182     assertEquals(t1.subRows[0][0], selection[0].slice);
    183 
    184     var selection = new TimelineSelection();
    185     track.addIntersectingItemsInRangeToSelection(1.5, 1.8, clientRect.top + 5, clientRect.top + 7, selection);
    186     assertEquals(t1.subRows[0][0], selection[0].slice);
    187   }
    188 
    189   function testBasicCpu() {
    190     var testEl = getTestDiv('testBasicCpu');
    191 
    192     var cpu = new TimelineCpu(7);
    193     cpu.slices = [
    194       new TimelineSlice('a', 0, 1, {}, 1),
    195       new TimelineSlice('b', 1, 2.1, {}, 4.8)
    196     ];
    197     cpu.updateBounds();
    198 
    199     var track = TimelineCpuTrack();
    200     testEl.appendChild(track);
    201     track.heading = 'CPU ' + cpu.cpuNumber;
    202     track.cpu = cpu;
    203     track.viewport = new TimelineViewport(testEl);
    204     track.viewport.xSetWorldRange(0, 11.1, track.clientWidth);
    205   }
    206 
    207   function testViewport() {
    208     var testEl = getTestDiv('testViewport');
    209 
    210     var track = tracing.TimelineViewportTrack();
    211     testEl.appendChild(track);
    212     track.viewport = new TimelineViewport(testEl);
    213     track.viewport.setPanAndScale(0,
    214         track.clientWidth / 1000);
    215   }
    216 
    217   function testBasicCounter() {
    218     var testEl = getTestDiv('testBasicCounter');
    219 
    220     var ctr = new TimelineCounter(undefined,
    221                                   'testBasicCounter', 'testBasicCounter');
    222     ctr.seriesNames = ['value1', 'value2'];
    223     ctr.seriesColors = [tracing.getStringColorId('testBasicCounter.value1'),
    224                         tracing.getStringColorId('testBasicCounter.value2')];
    225     ctr.timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
    226     ctr.samples = [0, 5,
    227                    3, 3,
    228                    1, 1,
    229                    2, 1.1,
    230                    3, 0,
    231                    1, 7,
    232                    3, 0,
    233                    3.1, 0.5];
    234     ctr.updateBounds();
    235 
    236     var track = new TimelineCounterTrack();
    237     testEl.appendChild(track);
    238     track.heading = ctr.name;
    239     track.counter = ctr;
    240     track.viewport = new TimelineViewport(testEl);
    241     track.viewport.xSetWorldRange(0, 7.7, track.clientWidth);
    242   }
    243 
    244   function runOffscreenCounterTest(timestamps, samples, testFn) {
    245     var testEl = document.createElement('div');
    246     var ctr = new TimelineCounter(undefined,
    247                                   'foo', 'foo');
    248     var n = samples.length / timestamps.length;
    249     ctr.timestamps = timestamps;
    250     ctr.samples = samples;
    251     ctr.seriesNames = []
    252     ctr.seriesColors = []
    253     for (var i = 0; i < n; ++i) {
    254       ctr.seriesNames.push('value' + i);
    255       ctr.seriesColors.push(tracing.getStringColorId(ctr.seriesNames[i]));
    256     }
    257     ctr.updateBounds();
    258 
    259     var track = new TimelineCounterTrack();
    260     testEl.appendChild(track);
    261     document.body.appendChild(testEl);
    262 
    263     track.heading = ctr.name;
    264     track.counter = ctr;
    265     track.viewport = new TimelineViewport(testEl);
    266     track.viewport.xSetWorldRange(0, 10, track.clientWidth);
    267 
    268     try {
    269       testFn(ctr, track);
    270     } finally {
    271       document.body.removeChild(testEl);
    272     }
    273   }
    274 
    275   function testBasicCounterXPointPicking() {
    276     var timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
    277     var samples = [0, 5,
    278                    3, 3,
    279                    1, 1,
    280                    2, 1.1,
    281                    3, 0,
    282                    1, 7,
    283                    3, 0,
    284                    3.1, 0.5];
    285     runOffscreenCounterTest(timestamps, samples, function(ctr, track) {
    286       var clientRect = track.getBoundingClientRect();
    287       var y75 = clientRect.top + 0.75 * clientRect.height;
    288       var sel;
    289 
    290       // In bounds.
    291       sel = new tracing.TimelineSelection();
    292       track.addIntersectingItemsToSelection(1.5, y75, sel);
    293       assertEquals(1, sel.length);
    294       assertEquals(track, sel[0].track);
    295       assertEquals(ctr, sel[0].counter);
    296       assertEquals(1, sel[0].sampleIndex);
    297 
    298       // Outside bouds.
    299       sel = new tracing.TimelineSelection();
    300       track.addIntersectingItemsToSelection(-1, y75, sel);
    301       assertEquals(0, sel.length);
    302 
    303       sel = new tracing.TimelineSelection();
    304       track.addIntersectingItemsToSelection(8, y75, sel);
    305       assertEquals(0, sel.length);
    306     });
    307   }
    308 
    309   /* You'll need visual inspection to test eliding with this one. */
    310   function testElideVisualInspection() {
    311     var optDicts = [{ trackName: 'elideOff', elide: false },
    312                     { trackName: 'elideOn', elide: true }];
    313     for (var dictIndex in optDicts) {
    314       var dict = optDicts[dictIndex];
    315       var testEl = getTestDiv(dict.trackName);
    316       var track = new TimelineSliceTrack();
    317       if (dict.elide) {
    318         track.SHOULD_ELIDE_TEXT = true;
    319       } else {
    320         track.SHOULD_ELIDE_TEXT = false;
    321       }
    322       var tooLongTitle = 'Unless eliding this SHOULD NOT BE DISPLAYED.  ';
    323       var bigTitle = 'Very big title name that goes on longer ' +
    324                      'than you may expect';
    325       testEl.appendChild(track);
    326       track.heading = 'Visual: ' + dict.trackName;
    327       track.slices = [
    328           // title, colorId, start, args, opt_duration
    329           new TimelineSlice('a ' + tooLongTitle + bigTitle, 0, 1, {}, 1),
    330           new TimelineSlice(bigTitle, 1, 2.1, {}, 4.8),
    331           new TimelineSlice('cccc cccc cccc', 1, 7, {}, 0.5),
    332           new TimelineSlice('d', 2, 7.6, {}, 1.0)
    333       ];
    334       track.viewport = new TimelineViewport(testEl);
    335       track.viewport.xSetWorldRange(0, 9.5, track.clientWidth);
    336     }
    337   }
    338 
    339   function testElide() {
    340     var testEl = getTestDiv('testElide');
    341     var track = new TimelineSliceTrack();
    342     testEl.appendChild(track);
    343     var bigtitle = 'Super duper long long title ' +
    344       'holy moly when did you get so verbose?';
    345     var smalltitle = 'small';
    346     track.viewport = new TimelineViewport(testEl);
    347     track.heading = 'testElide';
    348     track.slices = [
    349         // title, colorId, start, args, opt_duration
    350         new TimelineSlice(bigtitle, 0, 1, {}, 1),
    351         new TimelineSlice(smalltitle, 1, 2, {}, 1)
    352     ];
    353     track.viewport = new TimelineViewport(testEl);
    354     track.viewport.xSetWorldRange(0, 3.3, track.clientWidth);
    355     var stringWidthPair = undefined;
    356     var pixWidth = track.viewport_.xViewVectorToWorld(1);
    357 
    358     // Small titles on big slices are not elided.
    359     stringWidthPair = track.elidedTitleCache.get(track, pixWidth, smalltitle,
    360       track.labelWidth(smalltitle), 1);
    361     assertEquals(smalltitle, stringWidthPair.string);
    362     // Keep shrinking the slice until eliding starts.
    363     var elidedWhenSmallEnough = false;
    364     for (var sliceLength = 1; sliceLength >= 0.00001; sliceLength /= 2.0) {
    365       stringWidthPair = track.elidedTitleCache.get(track, pixWidth, smalltitle,
    366         track.labelWidth(smalltitle), sliceLength);
    367       if (stringWidthPair.string.length < smalltitle.length) {
    368         elidedWhenSmallEnough = true;
    369         break;
    370       }
    371     }
    372     assertTrue(elidedWhenSmallEnough);
    373 
    374     // Big titles are elided immediately.
    375     var superBigTitle = '';
    376     for (var x = 0; x < 10; x++) {
    377       superBigTitle += bigtitle;
    378     }
    379     stringWidthPair = track.elidedTitleCache.get(track, pixWidth,
    380       superBigTitle, track.labelWidth(superBigTitle), 1);
    381     assertTrue(stringWidthPair.string.length < superBigTitle.length);
    382     // And elided text ends with ...
    383     var len = stringWidthPair.string.length;
    384     assertEquals('...', stringWidthPair.string.substring(len - 3, len));
    385   }
    386 
    387   function testTimelineThreadTrackWithRegularSlices() {
    388     var testEl = getTestDiv('testTimelineThreadTrackWithRegularSlices');
    389     var track = TimelineThreadTrack();
    390     testEl.appendChild(track);
    391     track.heading = 'testTimelineThreadTrackWithRegularSlices';
    392     var thread = new TimelineThread(new TimelineProcess(7), 1);
    393     thread.subRows = [
    394       [
    395         new TimelineThreadSlice('a', 0, 1, {}, 1),
    396         new TimelineThreadSlice('b', 1, 2.1, {}, 4.8),
    397         new TimelineThreadSlice('b', 1, 7, {}, 0.5),
    398         new TimelineThreadSlice('c', 2, 7.6, {}, 0.4)
    399       ],
    400       [
    401         new TimelineThreadSlice('d', 3, 1.1, {}, 0.8),
    402         new TimelineThreadSlice('e', 4, 7.1, {}, 0.3)
    403       ]
    404     ];
    405     thread.updateBounds();
    406     track.heading = 'thread regular';
    407     track.headingWidth = '150px';
    408     track.toolTip = thread.userFriendlyDetails + ':';
    409     track.thread = thread;
    410     track.viewport = new TimelineViewport(testEl);
    411     track.viewport.xSetWorldRange(0, 8.2, track.clientWidth);
    412   }
    413 
    414   function testTimelineThreadTrackWithTallSlices() {
    415     var testEl = getTestDiv('testTimelineThreadTrackWithTallSlices');
    416     var track = TimelineThreadTrack();
    417     testEl.appendChild(track);
    418     track.heading = 'testTimelineThreadTrackWithTallSlices';
    419     var thread = new TimelineThread(new TimelineProcess(7), 1);
    420     thread.subRows = [
    421       [new TimelineThreadSlice('a', 1, 0, {}, 1)],
    422       [new TimelineThreadSlice('b', 2, 0.1, {}, 0.8)],
    423       [new TimelineThreadSlice('c', 3, 0.15, {}, 0.70)],
    424       [new TimelineThreadSlice('d', 4, 0.20, {}, 0.50)],
    425       [new TimelineThreadSlice('e', 5, 0.30, {}, 0.28)],
    426       [new TimelineThreadSlice('e', 6, 0.35, {}, 0.20)],
    427       [new TimelineThreadSlice('f', 7, 0.40, {}, 0.10)]
    428     ];
    429     thread.updateBounds();
    430     track.heading = 'thread tall';
    431     track.headingWidth = '150px';
    432     track.toolTip = thread.userFriendlyDetails + ':';
    433     track.thread = thread;
    434     track.viewport = new TimelineViewport(testEl);
    435     track.viewport.xSetWorldRange(0, 1.1, track.clientWidth);
    436   }
    437 
    438   function testTimelineThreadTrackWithRegularAndAsyncSlices() {
    439     var testEl = getTestDiv('testTimelineThreadTrackWithAsyncSlices');
    440     var track = TimelineThreadTrack();
    441     testEl.appendChild(track);
    442     var thread = new TimelineThread(new TimelineProcess(7), 1);
    443     thread.subRows = [
    444       [
    445         new TimelineThreadSlice('a', 0, 1, {}, 1),
    446         new TimelineThreadSlice('b', 1, 2.1, {}, 4.8),
    447         new TimelineThreadSlice('b', 1, 7, {}, 0.5),
    448         new TimelineThreadSlice('c', 2, 7.6, {}, 0.4)
    449       ],
    450       [
    451         new TimelineThreadSlice('d', 3, 1.1, {}, 0.8),
    452         new TimelineThreadSlice('e', 4, 7.1, {}, 0.3)
    453       ]
    454     ];
    455     thread.asyncSlices.push(newAsyncSlice(1.2, 7.2 - 1.2, thread, thread));
    456     thread.asyncSlices.push(newAsyncSlice(1.3, 7.3 - 1.3, thread, thread));
    457     thread.updateBounds();
    458     track.heading = 'thread regular + async';
    459     track.headingWidth = '150px';
    460     track.toolTip = thread.userFriendlyDetails + ':';
    461     track.thread = thread;
    462     track.viewport = new TimelineViewport(testEl);
    463     track.viewport.xSetWorldRange(0, 8.15, track.clientWidth);
    464   }
    465 
    466   function testTimelineSliceTrackAddItemNearToProvidedHit() {
    467     var track = new TimelineSliceTrack();
    468     track.slices = [
    469       new TimelineSlice('a', 0, 1, {}, 1),
    470       new TimelineSlice('b', 1, 2.1, {}, 4.8),
    471       new TimelineSlice('b', 1, 7, {}, 0.5),
    472       new TimelineSlice('c', 2, 7.6, {}, 0.4)
    473     ];
    474     var sel = new tracing.TimelineSelection();
    475     track.addAllObjectsMatchingFilterToSelection(new tracing.TimelineFilter("b"), sel);
    476     var ret;
    477 
    478     // Select to the right of B.
    479     var selRight = new tracing.TimelineSelection();
    480     ret = track.addItemNearToProvidedHitToSelection(sel[0], 1, selRight);
    481     assertTrue(ret);
    482     assertEquals(track.slices[2], selRight[0].slice);
    483 
    484     // Select to the right of the 2nd b.
    485     var selRight2 = new tracing.TimelineSelection();
    486     ret = track.addItemNearToProvidedHitToSelection(sel[0], 2, selRight2);
    487     assertTrue(ret);
    488     assertEquals(track.slices[3], selRight2[0].slice);
    489 
    490     // Select to 2 to the right of the 2nd b.
    491     var selRightOfRight = new tracing.TimelineSelection();
    492     ret = track.addItemNearToProvidedHitToSelection(selRight[0], 1, selRightOfRight);
    493     assertTrue(ret);
    494     assertEquals(track.slices[3], selRightOfRight[0].slice);
    495 
    496     // Select to the right of the rightmost slice.
    497     var selNone = new tracing.TimelineSelection();
    498     ret = track.addItemNearToProvidedHitToSelection(selRightOfRight[0], 1, selNone);
    499     assertFalse(ret);
    500     assertEquals(0, selNone.length);
    501 
    502     // Select A and then select left.
    503     var sel = new tracing.TimelineSelection();
    504     track.addAllObjectsMatchingFilterToSelection(new tracing.TimelineFilter("a"), sel);
    505     var ret;
    506 
    507     selNone = new tracing.TimelineSelection();
    508     ret = track.addItemNearToProvidedHitToSelection(sel[0], -1, selNone);
    509     assertFalse(ret);
    510     assertEquals(0, selNone.length);
    511 
    512   }
    513 </script>
    514 </body>
    515 </html>
    516