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