• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE HTML>
2<html>
3<!--
4Copyright (c) 2012 The Chromium Authors. All rights reserved.
5Use of this source code is governed by a BSD-style license that can be
6found in the LICENSE file.
7-->
8<head i18n-values="dir:textdirection;">
9<title>TimelineAnalysis tests</title>
10<script src="base.js"></script>
11<style>
12  .timeline-view {
13    border: 1px solid black;
14    margin: 10px;
15  }
16  .timeline-find-dialog {
17    border: 1px solid black;
18    margin: 10px;
19  }
20</style>
21</head>
22<body>
23  <script>
24    base.require('unittest');
25    base.require('tracing_controller');
26    base.require('test_utils');
27    base.require('timeline_model');
28    base.require('trace_event_importer');
29    base.require('timeline_analysis');
30    base.require('timeline_filter');
31    base.require('tracks.timeline_counter_track');
32    base.require('tracks.timeline_slice_track');
33    base.require('tracks.timeline_thread_track');
34    base.require('timeline'); /* TODO(nduca): reduce dependency */
35  </script>
36  <script>
37    'use strict';
38
39    var TimelineCounter = tracing.TimelineCounter;
40    var TimelineThread = tracing.TimelineThread;
41    var TimelineAnalysisView = tracing.TimelineAnalysisView;
42    var TimelineModel = tracing.TimelineModel;
43    var TimelineThreadTrack = tracks.TimelineThreadTrack;
44    var TimelineSelection = tracing.TimelineSelection;
45    var TimelineTitleFilter = tracing.TimelineTitleFilter;
46    var TimelineCounterTrack = tracks.TimelineCounterTrack;
47    var TimelineSliceTrack = tracks.TimelineSliceTrack;
48    var newSliceNamed = test_utils.newSliceNamed;
49    var newSliceCategory = test_utils.newSliceCategory;
50
51    function createSelectionWithSingleSlice(withCategory) {
52      var model = new TimelineModel();
53      var t53 = model.getOrCreateProcess(52).getOrCreateThread(53);
54      if (withCategory)
55        t53.pushSlice(newSliceCategory('foo', 'b', 0, 0.002));
56      else
57        t53.pushSlice(newSliceNamed('b', 0, 0.002));
58
59      var t53track = new TimelineThreadTrack();
60      t53track.thread = t53;
61
62      var selection = new TimelineSelection();
63      t53track.addAllObjectsMatchingFilterToSelection(
64        new TimelineTitleFilter('b'), selection);
65      assertEquals(1, selection.length);
66
67      return selection;
68    }
69
70    function createSelectionWithTwoSlices() {
71      var events = [
72        {name: 'a', args: {}, pid: 52, ts: 520, cat: 'foo', tid: 53, ph: 'B'},
73        {name: 'a', args: {}, pid: 52, ts: 560, cat: 'foo', tid: 53, ph: 'E'},
74        {name: 'aa', args: {}, pid: 52, ts: 640, cat: 'foo', tid: 53, ph: 'B'},
75        {name: 'aa', args: {}, pid: 52, ts: 700, cat: 'foo', tid: 53, ph: 'E'}
76      ];
77      var model = new TimelineModel(events);
78
79      var t53track = new TimelineThreadTrack();
80      t53track.thread = model.processes[52].threads[53];
81
82      var selection = new TimelineSelection();
83      t53track.addAllObjectsMatchingFilterToSelection(
84        new TimelineTitleFilter('a'), selection);
85      assertEquals(2, selection.length);
86
87      return selection;
88    }
89
90    function createSelectionWithTwoSlicesSameTitle() {
91      var events = [
92        {name: 'c', args: {}, pid: 52, ts: 620, cat: 'foo', tid: 53, ph: 'B'},
93        {name: 'c', args: {}, pid: 52, ts: 660, cat: 'foo', tid: 53, ph: 'E'},
94        {name: 'c', args: {}, pid: 52, ts: 740, cat: 'foo', tid: 53, ph: 'B'},
95        {name: 'c', args: {}, pid: 52, ts: 800, cat: 'foo', tid: 53, ph: 'E'}
96      ];
97      var model = new TimelineModel(events);
98
99      var t53track = new TimelineThreadTrack();
100      t53track.thread = model.processes[52].threads[53];
101
102      var selection = new TimelineSelection();
103      t53track.addAllObjectsMatchingFilterToSelection(
104        new TimelineTitleFilter('c'), selection);
105      assertEquals(2, selection.length);
106
107      return selection;
108    }
109
110    function createSelectionWithCounters(numSamples) {
111      if (numSamples > 2 || numSamples < 1)
112        throw new Error('This function only supports 1 or 2 samples');
113      var events = [
114        {name: 'ctr', args: {'value': 0}, pid: 1, ts: 0, cat: 'foo', tid: 1,
115         ph: 'C', id: 0},
116        {name: 'ctr', args: {'value': 10}, pid: 1, ts: 10, cat: 'foo', tid: 1,
117         ph: 'C', id: 0}
118      ];
119      var model = new TimelineModel(events);
120      var p = model.processes[1];
121      var ctr = model.processes[1].counters['foo.ctr[0]'];
122      assertEquals('ctr[0]', ctr.name);
123      assertEquals(2, ctr.numSamples);
124      assertEquals(1, ctr.numSeries);
125      assertArrayEquals([0, 0.01], ctr.timestamps);
126      assertArrayEquals([0, 10], ctr.samples);
127
128      var selection = new TimelineSelection();
129      var t1track = new TimelineThreadTrack();
130      selection.addCounterSample(t1track, ctr, 1);
131
132      if (numSamples == 1)
133        return selection;
134
135      selection.addCounterSample(t1track, ctr, 0);
136      return selection;
137    }
138
139    function createSelectionWithTwoSeriesSingleCounter() {
140      var events = [
141        {name: 'ctr', args: {'bytesallocated': 0, 'bytesfree': 25}, pid: 1,
142         ts: 0, cat: 'foo', tid: 1, ph: 'C', id: 0},
143        {name: 'ctr', args: {'bytesallocated': 10, 'bytesfree': 15}, pid: 1,
144         ts: 10, cat: 'foo', tid: 1, ph: 'C', id: 0},
145        {name: 'ctr', args: {'bytesallocated': 20, 'bytesfree': 5}, pid: 1,
146         ts: 20, cat: 'foo', tid: 1, ph: 'C', id: 0}
147      ];
148      var model = new TimelineModel(events);
149      var p = model.processes[1];
150      var ctr = model.processes[1].counters['foo.ctr[0]'];
151      assertEquals('ctr[0]', ctr.name);
152      assertEquals(3, ctr.numSamples);
153      assertEquals(2, ctr.numSeries);
154
155      var selection = new TimelineSelection();
156      var t1track = new TimelineThreadTrack();
157      selection.addCounterSample(t1track, ctr, 1);
158
159      return selection;
160    }
161
162    function createSelectionWithTwoSeriesTwoCounters() {
163      var ctr1 = new TimelineCounter(null, 0, '', 'ctr1');
164      ctr1.seriesNames.push('bytesallocated', 'bytesfree');
165      ctr1.seriesColors.push(0, 1);
166      ctr1.timestamps.push(0, 10, 20);
167      ctr1.samples.push(0, 25, 10, 15, 20, 5);
168
169      var ctr2 = new TimelineCounter(null, 0, '', 'ctr2');
170      ctr2.seriesNames.push('bytesallocated', 'bytesfree');
171      ctr2.seriesColors.push(0, 1);
172      ctr2.timestamps.push(0, 10, 20);
173      ctr2.samples.push(0, 25, 10, 15, 20, 5);
174
175      var selection = new TimelineSelection();
176      var t1track = new TimelineThreadTrack();
177      selection.addCounterSample(t1track, ctr1, 1);
178      selection.addCounterSample(t1track, ctr2, 2);
179
180      return selection;
181    }
182
183    function createSelectionWithTwoCountersDiffSeriesDiffHits() {
184      var ctr1 = new TimelineCounter(null, 0, '', 'a');
185      ctr1.seriesNames.push('bytesallocated');
186      ctr1.seriesColors.push(0);
187      ctr1.timestamps.push(0, 10, 20);
188      ctr1.samples.push(0, 25, 10);
189      assertEquals('a', ctr1.name);
190      assertEquals(3, ctr1.numSamples);
191      assertEquals(1, ctr1.numSeries);
192
193      var ctr2 = new TimelineCounter(null, 0, '', 'b');
194      ctr2.seriesNames.push('bytesallocated', 'bytesfree');
195      ctr2.seriesColors.push(0, 1);
196      ctr2.timestamps.push(0, 10, 20, 30);
197      ctr2.samples.push(0, 25, 10, 15, 20, 5, 25, 0);
198      assertEquals('b', ctr2.name);
199      assertEquals(4, ctr2.numSamples);
200      assertEquals(2, ctr2.numSeries);
201
202      var selection = new TimelineSelection();
203      var t1track = new TimelineThreadTrack();
204      selection.addCounterSample(t1track, ctr1, 1);
205      selection.addCounterSample(t1track, ctr2, 2);
206
207      return selection;
208    }
209
210    function createSelectionWithSingleSliceSingleCounter() {
211      var model = new TimelineModel();
212      var thread = model.getOrCreateProcess(1).getOrCreateThread(1);
213      thread.pushSlice(newSliceNamed('b', 1, 5));
214
215      var ctr1 = model.getOrCreateProcess(1).getOrCreateCounter('cat', 'ctr1');
216      ctr1.seriesNames.push('bytesallocated', 'bytesfree');
217      ctr1.seriesColors.push(0, 1);
218      ctr1.timestamps.push(0, 10, 20);
219      ctr1.samples.push(0, 25, 10, 15, 20, 5);
220      assertEquals('ctr1', ctr1.name);
221      assertEquals(3, ctr1.numSamples);
222      assertEquals(2, ctr1.numSeries);
223
224      var ctr1track = new TimelineCounterTrack();
225      ctr1track.counter = ctr1;
226
227      var threadTrack = new TimelineSliceTrack();
228      threadTrack.slices = thread.slices;
229
230      var selection = new TimelineSelection();
231      selection.addCounterSample(ctr1track, ctr1, 1);
232      threadTrack.addAllObjectsMatchingFilterToSelection(
233        new TimelineTitleFilter('b'), selection);
234      assertEquals(2, selection.length);
235      return selection;
236    }
237
238    function createSelectionWithNormallyDistributedSamples(numSlices) {
239      // Distance between start times is normally distributed, with mu = 16ms
240      // and sigma = 3ms.
241      var startTimes = [
242        0, 18.4362262859, 32.5378088645, 44.8978868054,
243        63.4772725504, 77.438888345, 92.0102867913, 99.6208686689,
244        119.150576393, 137.54545468, 153.991587743, 175.456095568,
245        193.395772651, 205.691644582, 218.740054982, 239.308480724,
246        250.880949151, 268.528689601, 281.950478133, 296.791635722,
247        315.862427391, 333.954888221, 342.392899581, 362.364373939,
248        377.593380892, 392.296896748, 415.779941407, 435.517713864,
249        454.581222491, 470.329018858, 488.37029095, 502.283017166,
250        521.15141113, 534.36224697, 554.425018316, 574.89913248,
251        589.60294439, 604.780562233, 615.481610668, 630.055628965,
252        645.908449096, 661.776084055, 673.276049017, 689.776401428,
253        704.440135004, 716.33262401, 732.380086528, 743.970715322,
254        756.506690025, 772.391485532, 794.636984401, 803.801415494,
255        819.006502926, 837.610127549, 854.551103283, 875.170613672,
256        891.508235124, 905.263299017, 929.309555683, 943.417968804,
257        957.289319239, 972.302910569, 986.669355637, 1002.71558868,
258        1013.83359637, 1030.16840733, 1040.39503139, 1057.61583325,
259        1075.64709686, 1086.67671319, 1100.4617455, 1118.4871842,
260        1129.98143488, 1144.52318588, 1160.36966285, 1179.50049042,
261        1195.03088169, 1215.98199401, 1226.66591838, 1245.83650314,
262        1268.18058265, 1285.11047342, 1301.71570575, 1316.40723345,
263        1329.94342488, 1343.7569577, 1358.28267513, 1371.17560308,
264        1386.42247119, 1401.51767749, 1417.52489051, 1440.98712348,
265        1457.80113781, 1475.66079406, 1494.64137536, 1509.52941903,
266        1524.54762552, 1545.42960714, 1565.19444597, 1580.56308936,
267        1596.72211651];
268
269      var events = [];
270
271      var model = new TimelineModel();
272      var thread = model.getOrCreateProcess(52).getOrCreateThread(53);
273      var duration = 1; // 1ms
274
275      for (var i = 0; i < startTimes.length; ++i) {
276        for (var j = 0; j < numSlices; ++j) {
277          var name = 'slice' + String(numSlices - 1 - j);
278          thread.slices.push(newSliceNamed(name, startTimes[i], duration));
279        }
280      }
281
282      var t53track = new TimelineThreadTrack();
283      t53track.thread = model.processes[52].threads[53];
284
285      var selection = new TimelineSelection();
286      t53track.addAllObjectsMatchingFilterToSelection(
287        new TimelineTitleFilter('slice'), selection);
288      assertEquals(101 * numSlices, selection.length);
289
290      return selection;
291    }
292
293    function testAnalysisViewWithSingleSlice() {
294      var selection = createSelectionWithSingleSlice();
295
296      var analysisEl = new TimelineAnalysisView();
297      analysisEl.selection = selection;
298      this.addHTMLOutput(undefined, analysisEl);
299    }
300
301    function testAnalysisViewWithSingleSliceCategory() {
302      var selection = createSelectionWithSingleSlice(true);
303
304      var analysisEl = new TimelineAnalysisView();
305      analysisEl.selection = selection;
306      this.addHTMLOutput(undefined, analysisEl);
307    }
308
309    function testAnalysisViewWithMultipleSlices() {
310      var selection = createSelectionWithTwoSlices();
311
312      var analysisEl = new TimelineAnalysisView();
313      analysisEl.selection = selection;
314      this.addHTMLOutput(undefined, analysisEl);
315    }
316
317    function testAnalysisViewWithMultipleSlicesSameTitle() {
318      var selection = createSelectionWithTwoSlicesSameTitle();
319
320      var analysisEl = new TimelineAnalysisView();
321      analysisEl.selection = selection;
322      this.addHTMLOutput(undefined, analysisEl);
323    }
324
325    function testAnalysisViewWithSingleCounterWithTwoSeries() {
326      var selection = createSelectionWithTwoSeriesSingleCounter();
327
328      var analysisEl = new TimelineAnalysisView();
329      analysisEl.selection = selection;
330      this.addHTMLOutput(undefined, analysisEl);
331    }
332
333    function testAnalysisViewWithTwoCountersWithTwoSeries() {
334      var selection = createSelectionWithTwoSeriesTwoCounters();
335
336      var analysisEl = new TimelineAnalysisView();
337      analysisEl.selection = selection;
338      this.addHTMLOutput(undefined, analysisEl);
339    }
340
341    function testAnalysisViewWithSingleSliceSingleCounter() {
342      var selection = createSelectionWithSingleSliceSingleCounter();
343
344      var analysisEl = new TimelineAnalysisView();
345      analysisEl.selection = selection;
346      this.addHTMLOutput(undefined, analysisEl);
347    }
348
349    function testSelectionWithNormallyDistributedSamples() {
350      var numSlices = 1;
351      var selection = createSelectionWithNormallyDistributedSamples(numSlices);
352
353      var analysisEl = new TimelineAnalysisView();
354      analysisEl.selection = selection;
355      this.addHTMLOutput(undefined, analysisEl);
356    }
357
358    function StubAnalysisResults() {
359      this.tables = [];
360    }
361    StubAnalysisResults.prototype = {
362      __proto__: Object.protoype,
363
364      appendTable: function(parent, className) {
365        var table = {
366          className: className,
367          rows: []
368        };
369        table.className = className;
370        this.tables.push(table);
371        return table;
372      },
373
374      appendTableHeader: function(table, label) {
375        if (table.tableHeader)
376          throw new Error('Only one summary header allowed.');
377        table.tableHeader = label;
378      },
379
380      appendSummaryRow: function(table, label, opt_text) {
381        table.rows.push({label: label,
382                         text: opt_text});
383      },
384
385      appendSpacingRow: function(table) {
386        table.rows.push({spacing: true});
387      },
388
389      appendSummaryRowTime: function(table, label, time) {
390        table.rows.push({label: label,
391                         time: time});
392      },
393
394      appendDataRow: function(table, label, duration, occurences, details) {
395        table.rows.push({label: label,
396                         duration: duration,
397                         occurences: occurences,
398                         details: details});
399      }
400    };
401
402    function testAnalyzeSelectionWithSingleSlice() {
403      var selection = createSelectionWithSingleSlice();
404
405      var results = new StubAnalysisResults();
406      tracing.analyzeSelection_(results, selection);
407      assertEquals(1, results.tables.length);
408      var table = results.tables[0];
409      assertEquals('Selected slice:', table.tableHeader);
410      assertEquals(3, table.rows.length);
411
412      assertEquals('b', table.rows[0].text);
413      assertEquals(0, table.rows[1].time);
414      assertAlmostEquals(0.002, table.rows[2].time);
415    }
416
417    function testAnalyzeSelectionWithFalsyArgs() {
418      var model = new TimelineModel();
419      var t53 = model.getOrCreateProcess(52).getOrCreateThread(53);
420      var slice = newSliceNamed('b', 0, 0.002);
421      slice.args.bar = 0;
422      slice.args.foo = false;
423      t53.pushSlice(slice);
424      var t53track = new TimelineThreadTrack();
425      t53track.thread = t53;
426      var selection = new TimelineSelection();
427      t53track.addAllObjectsMatchingFilterToSelection(
428        new TimelineTitleFilter('b'), selection);
429      assertEquals(1, selection.length);
430
431      var analysisEl = new TimelineAnalysisView();
432      analysisEl.selection = selection;
433      this.addHTMLOutput(undefined, analysisEl);
434      var rows = analysisEl.querySelectorAll('tr');
435      assertEquals(rows.length, 7);
436      assertEquals(' bar', rows[5].children[0].textContent);
437      assertEquals('0', rows[5].children[1].textContent);
438      assertEquals(' foo', rows[6].children[0].textContent);
439      assertEquals('false', rows[6].children[1].textContent);
440    }
441
442    function testAnalyzeSelectionWithSingleSliceCategory() {
443      var selection = createSelectionWithSingleSlice(true);
444
445      var results = new StubAnalysisResults();
446      tracing.analyzeSelection_(results, selection);
447      assertEquals(1, results.tables.length);
448      var table = results.tables[0];
449      assertEquals('Selected slice:', table.tableHeader);
450      assertEquals(4, table.rows.length);
451
452      assertEquals('b', table.rows[0].text);
453      assertEquals('foo', table.rows[1].text);
454      assertEquals(0, table.rows[2].time);
455      assertAlmostEquals(0.002, table.rows[3].time);
456    }
457
458    function testAnalyzeSelectionWithTwoSlices() {
459      var selection = createSelectionWithTwoSlices();
460
461      var results = new StubAnalysisResults();
462      tracing.analyzeSelection_(results, selection);
463      assertEquals(1, results.tables.length);
464      var table = results.tables[0];
465      assertEquals('Slices:', table.tableHeader);
466      assertEquals(6, table.rows.length);
467
468      assertEquals('a', table.rows[0].label);
469      assertEquals(1, table.rows[0].occurences);
470      assertAlmostEquals(0.04, table.rows[0].duration);
471      assertEquals('aa', table.rows[1].label);
472      assertEquals(1, table.rows[1].occurences);
473      assertAlmostEquals(0.06, table.rows[1].duration);
474      assertEquals('*Totals', table.rows[2].label);
475      assertEquals(2, table.rows[2].occurences);
476      assertAlmostEquals(0.1, table.rows[2].duration);
477
478      assertEquals('Selection start', table.rows[4].label);
479      assertAlmostEquals(0, table.rows[4].time);
480
481      assertEquals('Selection extent', table.rows[5].label);
482      assertAlmostEquals(0.18, table.rows[5].time);
483    }
484
485    function testAnalyzeSelectionWithTwoSlicesSameTitle() {
486      var selection = createSelectionWithTwoSlicesSameTitle();
487
488      var results = new StubAnalysisResults();
489      tracing.analyzeSelection_(results, selection);
490      assertEquals(1, results.tables.length);
491      var table = results.tables[0];
492
493      assertEquals('Slices:', table.tableHeader);
494      assertEquals(5, table.rows.length);
495
496      assertEquals('c', table.rows[0].label);
497      assertEquals('2', table.rows[0].occurences);
498      assertAlmostEquals(0.04, table.rows[0].details.min);
499      assertAlmostEquals(0.05, table.rows[0].details.avg);
500      assertAlmostEquals(0.06, table.rows[0].details.max);
501      assertAlmostEquals(0.1, table.rows[0].duration);
502      assertEquals('*Totals', table.rows[1].label);
503      assertAlmostEquals(0.1, table.rows[1].duration);
504      assertEquals('Selection start', table.rows[3].label);
505      assertAlmostEquals(0, table.rows[3].time);
506      assertEquals('Selection extent', table.rows[4].label);
507      assertAlmostEquals(0.18, table.rows[4].time);
508    }
509
510    function testAnalyzeSelectionWithSingleCounter() {
511      var selection = createSelectionWithCounters(1);
512
513      var results = new StubAnalysisResults();
514      tracing.analyzeSelection_(results, selection);
515      assertEquals(1, results.tables.length);
516      var table = results.tables[0];
517      assertEquals('Selected counter:', table.tableHeader);
518      assertEquals(3, table.rows.length);
519
520      assertEquals('Title', table.rows[0].label);
521      assertEquals('Timestamp', table.rows[1].label);
522      assertEquals('value', table.rows[2].label);
523      assertEquals(10, table.rows[2].text);
524    }
525
526    function testAnalyzeSelectionWithBasicTwoSeriesTwoCounters() {
527      var selection = createSelectionWithTwoSeriesTwoCounters();
528
529      var results = new StubAnalysisResults();
530      tracing.analyzeSelection_(results, selection);
531      assertEquals(1, results.tables.length);
532      var table = results.tables[0];
533      assertEquals('Counters:', table.tableHeader);
534      assertEquals(4, table.rows.length);
535
536      assertEquals('ctr1: bytesallocated', table.rows[0].label);
537      assertEquals('ctr1: bytesfree', table.rows[1].label);
538      assertEquals('ctr2: bytesallocated', table.rows[2].label);
539      assertEquals('ctr2: bytesfree', table.rows[3].label);
540    }
541
542    function testAnalyzeSelectionWithComplexSeriesTwoCounters() {
543      var selection = createSelectionWithTwoCountersDiffSeriesDiffHits();
544
545      var results = new StubAnalysisResults();
546      tracing.analyzeSelection_(results, selection);
547      assertEquals(1, results.tables.length);
548      var table = results.tables[0];
549      assertEquals('Counters:', table.tableHeader);
550      assertEquals(3, table.rows.length);
551
552      assertEquals('a: bytesallocated', table.rows[0].label);
553      assertEquals('b: bytesallocated', table.rows[1].label);
554      assertEquals('b: bytesfree', table.rows[2].label);
555    }
556
557    function testAnalyzeSelectionWithCounterAndSlices() {
558      var selection = createSelectionWithSingleSliceSingleCounter();
559
560      var results = new StubAnalysisResults();
561      tracing.analyzeSelection_(results, selection);
562      assertEquals(2, results.tables.length);
563      var sliceTable = results.tables[0];
564      var counterTable = results.tables[1];
565
566      assertEquals('Selected slice:', sliceTable.tableHeader);
567      assertEquals(3, sliceTable.rows.length);
568
569      assertEquals('Selected counter:', counterTable.tableHeader);
570      assertEquals(4, counterTable.rows.length);
571    }
572
573    function testAnalyzeSelectionWithNormallyDistributedSamples() {
574      var numSlices = 2;
575      var selection = createSelectionWithNormallyDistributedSamples(numSlices);
576
577      var results = new StubAnalysisResults();
578      tracing.analyzeSelection_(results, selection);
579      assertEquals(1, results.tables.length);
580
581      assertEquals('slice0', results.tables[0].rows[0].label);
582      assertEquals(
583          63, Math.round(results.tables[0].rows[0].details.frequency));
584      assertEquals(
585          16, Math.round(results.tables[0].rows[0].details.frequency_stddev));
586
587      assertEquals('slice1', results.tables[0].rows[1].label);
588      assertEquals(
589          63, Math.round(results.tables[0].rows[1].details.frequency));
590      assertEquals(
591          16, Math.round(results.tables[0].rows[1].details.frequency_stddev));
592    }
593  </script>
594</body>
595</html>
596