1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5'use strict';
6
7base.requireStylesheet('tracing.analysis.analyze_slices');
8
9base.require('tracing.analysis.util');
10base.require('ui');
11base.exportTo('tracing.analysis', function() {
12
13  function analyzeSingleSliceHit(results, sliceHit) {
14    var slice = sliceHit.slice;
15    var table = results.appendTable('analysis-slice-table', 2);
16
17    results.appendTableHeader(table, 'Selected slice:');
18    results.appendSummaryRow(table, 'Title', slice.title);
19
20    if (slice.category)
21      results.appendSummaryRow(table, 'Category', slice.category);
22
23    results.appendSummaryRowTime(table, 'Start', slice.start);
24    results.appendSummaryRowTime(table, 'Duration', slice.duration);
25
26    if (slice.durationInUserTime) {
27      results.appendSummaryRowTime(
28          table, 'Duration (U)', slice.durationInUserTime);
29    }
30
31    var n = 0;
32    for (var argName in slice.args) {
33      n += 1;
34    }
35    if (n > 0) {
36      results.appendSummaryRow(table, 'Args');
37      for (var argName in slice.args) {
38        var argVal = slice.args[argName];
39        // TODO(sleffler) use span instead?
40        results.appendSummaryRow(table, ' ' + argName, argVal);
41      }
42    }
43  }
44
45  function analyzeMultipleSliceHits(results, sliceHits) {
46    var tsLo = sliceHits.bounds.min;
47    var tsHi = sliceHits.bounds.max;
48
49    // compute total sliceHits duration
50    var titles = sliceHits.map(function(i) { return i.slice.title; });
51
52    var numTitles = 0;
53    var sliceHitsByTitle = {};
54    for (var i = 0; i < sliceHits.length; i++) {
55      var slice = sliceHits[i].slice;
56      if (!sliceHitsByTitle[slice.title]) {
57        sliceHitsByTitle[slice.title] = {
58          hits: []
59        };
60        numTitles++;
61      }
62      var sliceGroup = sliceHitsByTitle[slice.title];
63      sliceGroup.hits.push(sliceHits[i]);
64    }
65
66    var table;
67    table = results.appendTable('analysis-slices-table', 3);
68    results.appendTableHeader(table, 'Slices:');
69
70    var totalDuration = 0;
71    base.iterItems(sliceHitsByTitle,
72        function(sliceHitGroupTitle, sliceHitGroup) {
73          var duration = 0;
74          var avg = 0;
75          var startOfFirstOccurrence = Number.MAX_VALUE;
76          var startOfLastOccurrence = -Number.MAX_VALUE;
77          var frequencyDetails = undefined;
78          var min = Number.MAX_VALUE;
79          var max = -Number.MAX_VALUE;
80          for (var i = 0; i < sliceHitGroup.hits.length; i++) {
81            var slice = sliceHitGroup.hits[i].slice;
82            duration += slice.duration;
83            startOfFirstOccurrence = Math.min(slice.start,
84                startOfFirstOccurrence);
85            startOfLastOccurrence = Math.max(slice.start,
86                startOfLastOccurrence);
87            min = Math.min(slice.duration, min);
88            max = Math.max(slice.duration, max);
89          }
90
91          totalDuration += duration;
92
93          if (sliceHitGroup.hits.length == 0)
94            avg = 0;
95          avg = duration / sliceHitGroup.hits.length;
96
97          var statistics = {min: min,
98            max: max,
99            avg: avg,
100            avg_stddev: undefined,
101            frequency: undefined,
102            frequency_stddev: undefined};
103
104          // Compute the stddev of the slice durations.
105          var sumOfSquaredDistancesToMean = 0;
106          for (var i = 0; i < sliceHitGroup.hits.length; i++) {
107            var signedDistance =
108                statistics.avg - sliceHitGroup.hits[i].slice.duration;
109            sumOfSquaredDistancesToMean += signedDistance * signedDistance;
110          }
111
112          statistics.avg_stddev = Math.sqrt(
113              sumOfSquaredDistancesToMean / (sliceHitGroup.hits.length - 1));
114
115          // We require at least 3 samples to compute the stddev.
116          var elapsed = startOfLastOccurrence - startOfFirstOccurrence;
117          if (sliceHitGroup.hits.length > 2 && elapsed > 0) {
118            var numDistances = sliceHitGroup.hits.length - 1;
119            statistics.frequency = (1000 * numDistances) / elapsed;
120
121            // Compute the stddev.
122            sumOfSquaredDistancesToMean = 0;
123            for (var i = 1; i < sliceHitGroup.hits.length; i++) {
124              var currentFrequency = 1000 /
125                  (sliceHitGroup.hits[i].slice.start -
126                  sliceHitGroup.hits[i - 1].slice.start);
127              var signedDistance = statistics.frequency - currentFrequency;
128              sumOfSquaredDistancesToMean += signedDistance * signedDistance;
129            }
130
131            statistics.frequency_stddev = Math.sqrt(
132                sumOfSquaredDistancesToMean / (numDistances - 1));
133          }
134          results.appendDataRow(
135              table, sliceHitGroupTitle, duration, sliceHitGroup.hits.length,
136              statistics,
137              function() {
138                return new tracing.Selection(sliceHitGroup.hits);
139              });
140
141          // The whole selection is a single type so list out the information
142          // for each sub slice.
143          if (numTitles === 1) {
144            for (var i = 0; i < sliceHitGroup.hits.length; i++) {
145              analyzeSingleSliceHit(results, sliceHitGroup.hits[i]);
146            }
147          }
148        });
149
150    // Only one row so we already know the totals.
151    if (numTitles !== 1) {
152      results.appendDataRow(table, '*Totals', totalDuration, sliceHits.length);
153      results.appendSpacingRow(table);
154    }
155
156    results.appendSummaryRowTime(table, 'Selection start', tsLo);
157    results.appendSummaryRowTime(table, 'Selection extent', tsHi - tsLo);
158  }
159
160  return {
161    analyzeSingleSliceHit: analyzeSingleSliceHit,
162    analyzeMultipleSliceHits: analyzeMultipleSliceHits
163  };
164});
165