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>
      9 <title>TraceEventImporter tests</title>
     10 <script src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js"></script>
     11 <script src="../shared/js/cr.js"></script>
     12 <script src="../shared/js/cr/event_target.js"></script>
     13 <script src="test_utils.js"></script>
     14 <script src="timeline_model.js"></script>
     15 <script src="trace_event_importer.js"></script>
     16 <script>
     17   goog.require('goog.testing.jsunit');
     18 </script>
     19 
     20 </head>
     21 <body>
     22 <script>
     23 
     24 function testCanImportEmpty() {
     25   self.assertFalse(tracing.TraceEventImporter.canImport([]));
     26   self.assertFalse(tracing.TraceEventImporter.canImport(''));
     27 }
     28 
     29 function testBasicSingleThreadNonnestedParsing() {
     30   var events = [
     31     {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
     32     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'},
     33     {name: 'b', args: {}, pid: 52, ts: 629, cat: 'foo', tid: 53, ph: 'B'},
     34     {name: 'b', args: {}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'}
     35   ];
     36 
     37   var m = new tracing.TimelineModel(events);
     38   assertEquals(1, m.numProcesses);
     39   var p = m.processes[52];
     40   assertNotUndefined(p);
     41 
     42   assertEquals(1, p.numThreads);
     43   var t = p.threads[53];
     44   assertNotUndefined(t);
     45   assertEquals(1, t.subRows.length);
     46   assertEquals(53, t.tid);
     47   var subRow = t.subRows[0];
     48   assertEquals(2, subRow.length);
     49   var slice = subRow[0];
     50   assertEquals('a', slice.title);
     51   assertEquals(0, slice.start);
     52   assertAlmostEquals((560 - 520) / 1000, slice.duration);
     53   assertEquals(0, slice.subSlices.length);
     54 
     55   slice = subRow[1];
     56   assertEquals('b', slice.title);
     57   assertAlmostEquals((629 - 520) / 1000, slice.start);
     58   assertAlmostEquals((631 - 629) / 1000, slice.duration);
     59   assertEquals(0, slice.subSlices.length);
     60 }
     61 
     62 function testNestedParsing() {
     63   var events = [
     64     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
     65     {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'},
     66     {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'},
     67     {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'}
     68   ];
     69   var m = new tracing.TimelineModel(events);
     70 
     71   var p = m.processes[1];
     72   var t = p.threads[1];
     73   assertEquals(2, t.subRows.length);
     74   var subRow = t.subRows[0];
     75   assertEquals(1, subRow.length);
     76   var slice = subRow[0];
     77   assertEquals('a', slice.title);
     78   assertEquals((4 - 1) / 1000, slice.duration);
     79   assertEquals(1, slice.subSlices.length);
     80 
     81   slice = slice.subSlices[0];
     82   assertEquals('b', slice.title);
     83   assertEquals((2 - 1) / 1000, slice.start);
     84   assertEquals((3 - 2) / 1000, slice.duration);
     85   assertEquals(0, slice.subSlices.length);
     86 
     87   subRow = t.subRows[1];
     88   slice = subRow[0];
     89   assertEquals(t.subRows[0][0].subSlices[0], slice);
     90 }
     91 
     92 function testAutoclosing() {
     93   var events = [
     94     // Slice that doesn't finish.
     95     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
     96 
     97     // Slice that does finish to give an 'end time' to make autoclosing work.
     98     {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'},
     99     {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'}
    100   ];
    101   var m = new tracing.TimelineModel(events);
    102   var p = m.processes[1];
    103   var t = p.threads[1];
    104   var subRow = t.subRows[0];
    105   var slice = subRow[0];
    106   assertEquals('a', slice.title);
    107   assertTrue(slice.didNotFinish);
    108   assertEquals(0, slice.start);
    109   assertEquals((2 - 1) / 1000, slice.duration);
    110 }
    111 
    112 function testAutoclosingLoneBegin() {
    113   var events = [
    114     // Slice that doesn't finish.
    115     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'}
    116   ];
    117   var m = new tracing.TimelineModel(events);
    118   var p = m.processes[1];
    119   var t = p.threads[1];
    120   var subRow = t.subRows[0];
    121   var slice = subRow[0];
    122   assertEquals('a', slice.title);
    123   assertTrue(slice.didNotFinish);
    124   assertEquals(0, slice.start);
    125   assertEquals(0, slice.duration);
    126 }
    127 
    128 function testAutoclosingWithSubTasks() {
    129   var events = [
    130     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    131     {name: 'b1', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'B'},
    132     {name: 'b1', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'E'},
    133     {name: 'b2', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'}
    134   ];
    135   var m = new tracing.TimelineModel(events);
    136   var p = m.processes[1];
    137   var t = p.threads[1];
    138   assertEquals(2, t.subRows.length);
    139   assertEquals(1, t.subRows[0].length);
    140   assertEquals(2, t.subRows[1].length);
    141 }
    142 
    143 function testAutoclosingWithEventsOutsideRange() {
    144   var events = [
    145     // Slice that begins before min and ends after max of the other threads.
    146     {name: 'a', args: {}, pid: 1, ts: 0, cat: 'foo', tid: 1, ph: 'B'},
    147     {name: 'a', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'},
    148 
    149     // Slice that does finish to give an 'end time' to establish a basis
    150     {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'},
    151     {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'}
    152   ];
    153   var m = new tracing.TimelineModel(events);
    154   var p = m.processes[1];
    155   var t = p.threads[1];
    156   var subRow = t.subRows[0];
    157   assertEquals('a', subRow[0].title);
    158   assertEquals(0, subRow[0].start);
    159   assertEquals(0.003, subRow[0].duration);
    160 
    161   var t = p.threads[2];
    162   var subRow = t.subRows[0];
    163   assertEquals('b', subRow[0].title);
    164   assertEquals(0.001, subRow[0].start);
    165   assertEquals(0.001, subRow[0].duration);
    166 
    167   // 0.00345 instead of 0.003 because TimelineModel bloats the world range by
    168   // 15%.
    169   assertEquals(-0.00045, m.minTimestamp);
    170   assertEquals(0.00345, m.maxTimestamp);
    171 
    172 }
    173 
    174 function testNestedAutoclosing() {
    175   var events = [
    176     // Tasks that dont finish.
    177     {name: 'a1', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    178     {name: 'a2', args: {}, pid: 1, ts: 1.5, cat: 'foo', tid: 1, ph: 'B'},
    179 
    180     // Slice that does finish to give an 'end time' to make autoclosing work.
    181     {name: 'b', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 2, ph: 'B'},
    182     {name: 'b', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 2, ph: 'E'}
    183   ];
    184   var m = new tracing.TimelineModel(events);
    185   var p = m.processes[1];
    186   var t = p.threads[1];
    187   var subRow = t.subRows[0];
    188   var slice = subRow[0];
    189   assertEquals('a1', slice.title);
    190   assertTrue(slice.didNotFinish);
    191   assertEquals(0, slice.start);
    192   assertEquals((2 - 1) / 1000, slice.duration);
    193 
    194   var slice = slice.subSlices[0];
    195   assertEquals('a2', slice.title);
    196   assertTrue(slice.didNotFinish);
    197   assertEquals((1.5 - 1) / 1000, slice.start);
    198   assertEquals((2 - 1.5) / 1000, slice.duration);
    199 }
    200 
    201 function testTaskColoring() {
    202   // The test below depends on hashing of 'a' != 'b'. Fail early if that
    203   // assumption is incorrect.
    204   assertNotEquals(tracing.getStringHash('a'), tracing.getStringHash('b'));
    205 
    206   var events = [
    207     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    208     {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
    209     {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 1, ph: 'B'},
    210     {name: 'b', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'},
    211     {name: 'a', args: {}, pid: 1, ts: 5, cat: 'foo', tid: 1, ph: 'B'},
    212     {name: 'a', args: {}, pid: 1, ts: 6, cat: 'foo', tid: 1, ph: 'E'}
    213   ];
    214   var m = new tracing.TimelineModel(events);
    215   var p = m.processes[1];
    216   var t = p.threads[1];
    217   var subRow = t.subRows[0];
    218   var a1 = subRow[0];
    219   assertEquals('a', a1.title);
    220   var b = subRow[1];
    221   assertEquals('b', b.title);
    222   assertNotEquals(a1.colorId, b.colorId);
    223   var a2 = subRow[0];
    224   assertEquals('a', a2.title);
    225   assertEquals(a1.colorId, a2.colorId);
    226 }
    227 
    228 function testMultipleThreadParsing() {
    229   var events = [
    230     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    231     {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
    232     {name: 'b', args: {}, pid: 1, ts: 3, cat: 'foo', tid: 2, ph: 'B'},
    233     {name: 'b', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 2, ph: 'E'}
    234   ];
    235   var m = new tracing.TimelineModel(events);
    236   assertEquals(1, m.numProcesses);
    237   var p = m.processes[1];
    238   assertNotUndefined(p);
    239 
    240   assertEquals(2, p.numThreads);
    241 
    242   // Check thread 1.
    243   var t = p.threads[1];
    244   assertNotUndefined(t);
    245   assertEquals(1, t.subRows.length);
    246   assertEquals(1, t.tid);
    247 
    248   var subRow = t.subRows[0];
    249   assertEquals(1, subRow.length);
    250   var slice = subRow[0];
    251   assertEquals('a', slice.title);
    252   assertEquals(0, slice.start);
    253   assertEquals((2 - 1) / 1000, slice.duration);
    254   assertEquals(0, slice.subSlices.length);
    255 
    256   // Check thread 2.
    257   var t = p.threads[2];
    258   assertNotUndefined(t);
    259   assertEquals(1, t.subRows.length);
    260   assertEquals(2, t.tid);
    261 
    262   subRow = t.subRows[0];
    263   assertEquals(1, subRow.length);
    264   slice = subRow[0];
    265   assertEquals('b', slice.title);
    266   assertEquals((3 - 1) / 1000, slice.start);
    267   assertEquals((4 - 3) / 1000, slice.duration);
    268   assertEquals(0, slice.subSlices.length);
    269 }
    270 
    271 function testMultiplePidParsing() {
    272   var events = [
    273     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    274     {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
    275     {name: 'b', args: {}, pid: 2, ts: 3, cat: 'foo', tid: 2, ph: 'B'},
    276     {name: 'b', args: {}, pid: 2, ts: 4, cat: 'foo', tid: 2, ph: 'E'}
    277   ];
    278   var m = new tracing.TimelineModel(events);
    279   assertEquals(2, m.numProcesses);
    280   var p = m.processes[1];
    281   assertNotUndefined(p);
    282 
    283   assertEquals(1, p.numThreads);
    284 
    285   // Check process 1 thread 1.
    286   var t = p.threads[1];
    287   assertNotUndefined(t);
    288   assertEquals(1, t.subRows.length);
    289   assertEquals(1, t.tid);
    290 
    291   var subRow = t.subRows[0];
    292   assertEquals(1, subRow.length);
    293   var slice = subRow[0];
    294   assertEquals('a', slice.title);
    295   assertEquals(0, slice.start);
    296   assertEquals((2 - 1) / 1000, slice.duration);
    297   assertEquals(0, slice.subSlices.length);
    298 
    299   // Check process 2 thread 2.
    300   var p = m.processes[2];
    301   assertNotUndefined(p);
    302   assertEquals(1, p.numThreads);
    303   var t = p.threads[2];
    304   assertNotUndefined(t);
    305   assertEquals(1, t.subRows.length);
    306   assertEquals(2, t.tid);
    307 
    308   subRow = t.subRows[0];
    309   assertEquals(1, subRow.length);
    310   slice = subRow[0];
    311   assertEquals('b', slice.title);
    312   assertEquals((3 - 1) / 1000, slice.start);
    313   assertEquals((4 - 3) / 1000, slice.duration);
    314   assertEquals(0, slice.subSlices.length);
    315 
    316   // Check getAllThreads.
    317   assertArrayEquals([m.processes[1].threads[1], m.processes[2].threads[2]],
    318                     m.getAllThreads());
    319 }
    320 
    321 // Thread names.
    322 function testThreadNames() {
    323   var events = [
    324     {name: 'thread_name', args: {name: 'Thread 1'},
    325       pid: 1, ts: 0, tid: 1, ph: 'M'},
    326     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    327     {name: 'a', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'E'},
    328     {name: 'b', args: {}, pid: 2, ts: 3, cat: 'foo', tid: 2, ph: 'B'},
    329     {name: 'b', args: {}, pid: 2, ts: 4, cat: 'foo', tid: 2, ph: 'E'},
    330     {name: 'thread_name', args: {name: 'Thread 2'},
    331       pid: 2, ts: 0, tid: 2, ph: 'M'}
    332   ];
    333   var m = new tracing.TimelineModel(events);
    334   assertEquals('Thread 1', m.processes[1].threads[1].name);
    335   assertEquals('Thread 2', m.processes[2].threads[2].name);
    336 }
    337 
    338 // User time.
    339 function testUserTime() {
    340   var events = [
    341     {name: 'thread_name', args: {name: 'Thread 1'},
    342       pid: 1, ts: 0, tid: 1, ph: 'M'},
    343     {name: 'a', args: {}, pid: 1, ts: 1, uts: 10, cat: 'foo', tid: 1, ph: 'B'},
    344     {name: 'a', args: {}, pid: 1, ts: 2, uts: 20, cat: 'foo', tid: 1, ph: 'E'},
    345     {name: 'a', args: {}, pid: 1, ts: 2 , uts: 60, cat: 'foo', tid: 1, ph: 'I'}
    346   ];
    347   var m = new tracing.TimelineModel(events);
    348   var subRow = m.processes[1].threads[1].subRows[0];
    349   assertEquals(0.01, subRow[0].startInUserTime);
    350   assertEquals(0.01, subRow[0].durationInUserTime);
    351   assertEquals(0.06, subRow[1].startInUserTime);
    352   assertEquals(0, subRow[1].durationInUserTime);
    353 }
    354 
    355 
    356 function testImmediateParsing() {
    357   var events = [
    358     // Need to include immediates inside a task so the timeline
    359     // recentering/zeroing doesn't clobber their timestamp.
    360     {name: 'a', args: {}, pid: 1, ts: 1, cat: 'foo', tid: 1, ph: 'B'},
    361     {name: 'immediate', args: {}, pid: 1, ts: 2, cat: 'foo', tid: 1, ph: 'I'},
    362     {name: 'a', args: {}, pid: 1, ts: 4, cat: 'foo', tid: 1, ph: 'E'}
    363   ];
    364   var m = new tracing.TimelineModel(events);
    365   var p = m.processes[1];
    366   var t = p.threads[1];
    367   assertEquals(2, t.subRows.length);
    368   var subRow = t.subRows[0];
    369   assertEquals(1, subRow.length);
    370   var slice = subRow[0];
    371   assertEquals('a', slice.title);
    372   assertEquals((4 - 1) / 1000, slice.duration);
    373   assertEquals(1, slice.subSlices.length);
    374 
    375   var immed = slice.subSlices[0];
    376   assertEquals('immediate', immed.title);
    377   assertEquals((2 - 1) / 1000, immed.start);
    378   assertEquals(0, immed.duration);
    379   assertEquals(0, immed.subSlices.length);
    380 
    381   subRow = t.subRows[1];
    382   assertEquals(immed, subRow[0]);
    383 }
    384 
    385 function testSimpleCounter() {
    386   var events = [
    387     {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
    388      ph: 'C'},
    389     {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
    390      ph: 'C'},
    391     {name: 'ctr', args: {'value': 0}, pid: 1, ts: 20, cat: 'foo', tid: 1,
    392      ph: 'C'}
    393 
    394   ];
    395   var m = new tracing.TimelineModel(events);
    396   var p = m.processes[1];
    397   var ctr = m.processes[1].counters['foo.ctr'];
    398 
    399   assertEquals('ctr', ctr.name);
    400   assertEquals(3, ctr.numSamples);
    401   assertEquals(1, ctr.numSeries);
    402 
    403   assertArrayEquals(['value'], ctr.seriesNames);
    404   assertArrayEquals([tracing.getStringColorId('ctr.value')], ctr.seriesColors);
    405   assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
    406   assertArrayEquals([0, 10, 0], ctr.samples);
    407   assertArrayEquals([0, 10, 0], ctr.totals);
    408   assertEquals(10, ctr.maxTotal);
    409 }
    410 
    411 function testInstanceCounter() {
    412   var events = [
    413     {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
    414      ph: 'C', id: 0},
    415     {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
    416      ph: 'C', id: 0},
    417     {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
    418      ph: 'C', id: 1},
    419     {name: 'ctr', args: {'value': 20}, pid: 1, ts: 15, cat: 'foo', tid: 1,
    420      ph: 'C', id: 1},
    421     {name: 'ctr', args: {'value': 30}, pid: 1, ts: 18, cat: 'foo', tid: 1,
    422      ph: 'C', id: 1}
    423   ];
    424   var m = new tracing.TimelineModel(events);
    425   var p = m.processes[1];
    426   var ctr = m.processes[1].counters['foo.ctr[0]'];
    427   assertEquals('ctr[0]', ctr.name);
    428   assertEquals(2, ctr.numSamples);
    429   assertEquals(1, ctr.numSeries);
    430   assertArrayEquals([0, 0.01], ctr.timestamps);
    431   assertArrayEquals([0, 10], ctr.samples);
    432 
    433   var ctr = m.processes[1].counters['foo.ctr[1]'];
    434   assertEquals('ctr[1]', ctr.name);
    435   assertEquals(3, ctr.numSamples);
    436   assertEquals(1, ctr.numSeries);
    437   assertArrayEquals([0.01, 0.015, 0.018], ctr.timestamps);
    438   assertArrayEquals([10, 20, 30], ctr.samples);
    439 }
    440 
    441 function testMultiCounterUpdateBounds() {
    442   var ctr = new tracing.TimelineCounter(undefined, 'testBasicCounter',
    443 'testBasicCounter');
    444   ctr.numSeries = 1;
    445   ctr.seriesNames = ['value1', 'value2'];
    446   ctr.seriesColors = ['testBasicCounter.value1', 'testBasicCounter.value2'];
    447   ctr.timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
    448   ctr.samples = [0, 0,
    449                  1, 0,
    450                  1, 1,
    451                  2, 1.1,
    452                  3, 0,
    453                  1, 7,
    454                  3, 0,
    455                  3.1, 0.5];
    456   ctr.updateBounds();
    457   assertEquals(0, ctr.minTimestamp);
    458   assertEquals(7, ctr.maxTimestamp);
    459   assertEquals(8, ctr.maxTotal);
    460   assertArrayEquals([0, 0,
    461                      1, 1,
    462                      1, 2,
    463                      2, 3.1,
    464                      3, 3,
    465                      1, 8,
    466                      3, 3,
    467                      3.1, 3.6], ctr.totals);
    468 }
    469 
    470 function testMultiCounter() {
    471   var events = [
    472     {name: 'ctr', args: {'value1': 0, 'value2': 7}, pid: 1, ts: 0, cat: 'foo',
    473      tid: 1, ph: 'C'},
    474     {name: 'ctr', args: {'value1': 10, 'value2': 4}, pid: 1, ts: 10, cat: 'foo',
    475      tid: 1, ph: 'C'},
    476     {name: 'ctr', args: {'value1': 0, 'value2': 1 }, pid: 1, ts: 20, cat: 'foo',
    477      tid: 1, ph: 'C'}
    478   ];
    479   var m = new tracing.TimelineModel(events);
    480   var p = m.processes[1];
    481   var ctr = m.processes[1].counters['foo.ctr'];
    482   assertEquals('ctr', ctr.name);
    483 
    484   assertEquals('ctr', ctr.name);
    485   assertEquals(3, ctr.numSamples);
    486   assertEquals(2, ctr.numSeries);
    487 
    488   assertArrayEquals(['value1', 'value2'], ctr.seriesNames);
    489   assertArrayEquals([tracing.getStringColorId('ctr.value1'),
    490                      tracing.getStringColorId('ctr.value2')],
    491                     ctr.seriesColors);
    492   assertArrayEquals([0, 0.01, 0.02], ctr.timestamps);
    493   assertArrayEquals([0, 7,
    494                      10, 4,
    495                      0, 1], ctr.samples);
    496   assertArrayEquals([0, 7,
    497                      10, 14,
    498                      0, 1], ctr.totals);
    499   assertEquals(14, ctr.maxTotal);
    500 }
    501 
    502 function testImportObjectInsteadOfArray() {
    503   var events = { traceEvents: [
    504     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    505     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    506   ] };
    507 
    508   var m = new tracing.TimelineModel(events);
    509   assertEquals(1, m.numProcesses);
    510 }
    511 
    512 function testImportString() {
    513   var events = [
    514     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    515     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    516   ];
    517 
    518   var m = new tracing.TimelineModel(JSON.stringify(events));
    519   assertEquals(1, m.numProcesses);
    520 }
    521 
    522 function testImportStringWithTrailingNewLine() {
    523   var events = [
    524     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    525     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    526   ];
    527 
    528   var m = new tracing.TimelineModel(JSON.stringify(events) + '\n');
    529   assertEquals(1, m.numProcesses);
    530 }
    531 
    532 function testImportStringWithMissingCloseSquareBracket() {
    533   var events = [
    534     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    535     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    536   ];
    537 
    538   var tmp = JSON.stringify(events);
    539   assertEquals(']', tmp[tmp.length - 1]);
    540 
    541   // Drop off the trailing ]
    542   var dropped = tmp.substring(0, tmp.length - 1);
    543   var m = new tracing.TimelineModel(dropped);
    544   assertEquals(1, m.numProcesses);
    545 }
    546 
    547 function testImportStringWithMissingCloseSquareBracketAndNewline() {
    548   var events = [
    549     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53, ph: 'B'},
    550     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'}
    551   ];
    552 
    553   var tmp = JSON.stringify(events);
    554   assertEquals(']', tmp[tmp.length - 1]);
    555 
    556   // Drop off the trailing ] and add a newline
    557   var dropped = tmp.substring(0, tmp.length - 1);
    558   var m = new tracing.TimelineModel(dropped + '\n');
    559   assertEquals(1, m.numProcesses);
    560 }
    561 
    562 function testStartFinishOneSliceOneThread() {
    563   var events = [
    564     // Time is intentionally out of order.
    565     {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    566        ph: 'F', id: 72},
    567     {name: 'a', args: {}, pid: 52, ts: 524, cat: 'foo', tid: 53,
    568        ph: 'S', id: 72, args: {foo: 'bar'}}
    569   ];
    570 
    571   var m = new tracing.TimelineModel(events);
    572   var t = m.processes[52].threads[53];
    573   assertNotUndefined(t);
    574   assertEquals(1, t.asyncSlices.slices.length);
    575   assertEquals('a', t.asyncSlices.slices[0].title);
    576   assertEquals(72, t.asyncSlices.slices[0].id);
    577   assertEquals('bar', t.asyncSlices.slices[0].args.foo);
    578   assertEquals(0, t.asyncSlices.slices[0].start);
    579   assertAlmostEquals((60 - 24) / 1000, t.asyncSlices.slices[0].duration);
    580   assertEquals(t, t.asyncSlices.slices[0].startThread);
    581   assertEquals(t, t.asyncSlices.slices[0].endThread);
    582 }
    583 
    584 function testEndArgsAddedToSlice() {
    585   var events = [
    586     {name: 'a', args: {x: 1}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
    587     {name: 'a', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'},
    588   ];
    589 
    590   var m = new tracing.TimelineModel(events);
    591   assertEquals(1, m.numProcesses);
    592   var p = m.processes[52];
    593   assertNotUndefined(p);
    594 
    595   assertEquals(1, p.numThreads);
    596   var t = p.threads[53];
    597   assertNotUndefined(t);
    598   assertEquals(1, t.subRows.length);
    599   assertEquals(53, t.tid);
    600   var subRow = t.subRows[0];
    601   assertEquals(1, subRow.length);
    602   var slice = subRow[0];
    603   assertEquals('a', slice.title);
    604   assertEquals(0, slice.start);
    605   assertEquals(0, slice.subSlices.length);
    606   assertEquals(1, slice.args['x']);
    607   assertEquals(2, slice.args['y']);
    608 }
    609 
    610 function testEndArgOverrwritesOriginalArgValueIfDuplicated() {
    611   var events = [
    612     {name: 'b', args: {z: 3}, pid: 52, ts: 629, cat: 'foo', tid: 53, ph: 'B'},
    613     {name: 'b', args: {z: 4}, pid: 52, ts: 631, cat: 'foo', tid: 53, ph: 'E'}
    614   ];
    615 
    616   var m = new tracing.TimelineModel(events);
    617   assertEquals(1, m.numProcesses);
    618   var p = m.processes[52];
    619   assertNotUndefined(p);
    620 
    621   assertEquals(1, p.numThreads);
    622   var t = p.threads[53];
    623   assertNotUndefined(t);
    624   assertEquals(1, t.subRows.length);
    625   assertEquals(53, t.tid);
    626   var subRow = t.subRows[0];
    627   assertEquals(1, subRow.length);
    628   var slice = subRow[0];
    629   assertEquals('b', slice.title);
    630   assertEquals(0, slice.start);
    631   assertEquals(0, slice.subSlices.length);
    632   assertEquals(4, slice.args['z']);
    633 }
    634 
    635 function testAsyncEndArgsAddedToSlice() {
    636   var events = [
    637     // Time is intentionally out of order.
    638     {name: 'c', args: {y: 2}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    639        ph: 'F', id: 72},
    640     {name: 'c', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
    641        ph: 'S', id: 72}
    642   ];
    643 
    644   var m = new tracing.TimelineModel(events);
    645   var t = m.processes[52].threads[53];
    646   assertNotUndefined(t);
    647   assertEquals(1, t.asyncSlices.slices.length);
    648   var parentSlice = t.asyncSlices.slices[0];
    649   assertEquals('c', parentSlice.title);
    650 
    651   assertNotUndefined(parentSlice.subSlices);
    652   assertEquals(1, parentSlice.subSlices.length);
    653   var subSlice = parentSlice.subSlices[0];
    654   assertEquals(1, subSlice.args['x']);
    655   assertEquals(2, subSlice.args['y']);
    656 }
    657 
    658 function testAsyncEndArgOverrwritesOriginalArgValueIfDuplicated() {
    659   var events = [
    660     // Time is intentionally out of order.
    661     {name: 'd', args: {z: 4}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    662        ph: 'F', id: 72},
    663     {name: 'd', args: {z: 3}, pid: 52, ts: 524, cat: 'foo', tid: 53,
    664        ph: 'S', id: 72}
    665   ];
    666 
    667   var m = new tracing.TimelineModel(events);
    668   var t = m.processes[52].threads[53];
    669   assertNotUndefined(t);
    670   assertEquals(1, t.asyncSlices.slices.length);
    671   var parentSlice = t.asyncSlices.slices[0];
    672   assertEquals('d', parentSlice.title);
    673 
    674   assertNotUndefined(parentSlice.subSlices);
    675   assertEquals(1, parentSlice.subSlices.length);
    676   var subSlice = parentSlice.subSlices[0];
    677   assertEquals(4, subSlice.args['z']);
    678 }
    679 
    680 function testAsyncStepsInOneThread() {
    681   var events = [
    682     // Time is intentionally out of order.
    683     {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    684        ph: 'F', id: 72},
    685     {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53,
    686        ph: 'T', id: 72, },
    687     {name: 'a', args: {x: 1}, pid: 52, ts: 524, cat: 'foo', tid: 53,
    688        ph: 'S', id: 72}
    689   ];
    690 
    691   var m = new tracing.TimelineModel(events);
    692   var t = m.processes[52].threads[53];
    693   assertNotUndefined(t);
    694   assertEquals(1, t.asyncSlices.slices.length);
    695   var parentSlice = t.asyncSlices.slices[0];
    696   assertEquals('a', parentSlice.title);
    697   assertEquals(0, parentSlice.start);
    698 
    699   assertNotUndefined(parentSlice.subSlices);
    700   assertEquals(2, parentSlice.subSlices.length);
    701   var subSlice = parentSlice.subSlices[0];
    702   assertEquals('a', subSlice.title);
    703   assertEquals(0, subSlice.start);
    704   assertAlmostEquals((548 - 524) / 1000, subSlice.duration);
    705   assertEquals(1, subSlice.args['x']);
    706 
    707   var subSlice = parentSlice.subSlices[1];
    708   assertEquals('a:s1', subSlice.title);
    709   assertAlmostEquals((548 - 524) / 1000, subSlice.start);
    710   assertAlmostEquals((560 - 548) / 1000, subSlice.duration);
    711   assertEquals(2, subSlice.args['y']);
    712   assertEquals(3, subSlice.args['z']);
    713 }
    714 
    715 function testAsyncStepsMissingStart() {
    716   var events = [
    717     // Time is intentionally out of order.
    718     {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    719        ph: 'F', id: 72},
    720     {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53,
    721        ph: 'T', id: 72, },
    722   ];
    723 
    724   var m = new tracing.TimelineModel(events);
    725   var t = m.processes[52].threads[53];
    726   assertUndefined(t);
    727 }
    728 
    729 function testAsyncStepsMissingFinish() {
    730   var events = [
    731     // Time is intentionally out of order.
    732     {name: 'a', args: {step: 's1', y: 2}, pid: 52, ts: 548, cat: 'foo', tid: 53,
    733        ph: 'T', id: 72, },
    734     {name: 'a', args: {z: 3}, pid: 52, ts: 560, cat: 'foo', tid: 53,
    735        ph: 'S', id: 72},
    736   ];
    737 
    738   var m = new tracing.TimelineModel(events);
    739   var t = m.processes[52].threads[53];
    740   assertUndefined(t);
    741 }
    742 
    743 // TODO(nduca): one slice, two threads
    744 // TODO(nduca): one slice, two pids
    745 
    746 </script>
    747 </body>
    748 </html>
    749