1 // Copyright (c) 2012 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 7 /** 8 * @fileoverview TimelineView visualizes TRACE_EVENT events using the 9 * tracing.Timeline component and adds in selection summary and control buttons. 10 */ 11 cr.define('tracing', function() { 12 function tsRound(ts) { 13 return Math.round(ts * 1000.0) / 1000.0; 14 } 15 16 function getPadding(text, width) { 17 width = width || 0; 18 19 if (typeof text != 'string') 20 text = String(text); 21 22 if (text.length >= width) 23 return ''; 24 25 var pad = ''; 26 for (var i = 0; i < width - text.length; i++) 27 pad += ' '; 28 return pad; 29 } 30 31 function leftAlign(text, width) { 32 return text + getPadding(text, width); 33 } 34 35 function rightAlign(text, width) { 36 return getPadding(text, width) + text; 37 } 38 39 40 function getTextForSelection(selection) { 41 var text = ''; 42 var sliceHits = selection.getSliceHits(); 43 var counterSampleHits = selection.getCounterSampleHits(); 44 45 if (sliceHits.length == 1) { 46 var c0Width = 14; 47 var slice = sliceHits[0].slice; 48 text = 'Selected item:\n'; 49 text += leftAlign('Title', c0Width) + ': ' + slice.title + '\n'; 50 text += leftAlign('Start', c0Width) + ': ' + 51 tsRound(slice.start) + ' ms\n'; 52 text += leftAlign('Duration', c0Width) + ': ' + 53 tsRound(slice.duration) + ' ms\n'; 54 if (slice.durationInUserTime) 55 text += leftAlign('Duration (U)', c0Width) + ': ' + 56 tsRound(slice.durationInUserTime) + ' ms\n'; 57 58 var n = 0; 59 for (var argName in slice.args) { 60 n += 1; 61 } 62 if (n > 0) { 63 text += leftAlign('Args', c0Width) + ':\n'; 64 for (var argName in slice.args) { 65 var argVal = slice.args[argName]; 66 text += leftAlign(' ' + argName, c0Width) + ': ' + argVal + '\n'; 67 } 68 } 69 } else if (sliceHits.length > 1) { 70 var c0Width = 55; 71 var c1Width = 12; 72 var c2Width = 5; 73 text = 'Slices:\n'; 74 var tsLo = sliceHits.range.min; 75 var tsHi = sliceHits.range.max; 76 77 // compute total sliceHits duration 78 var titles = sliceHits.map(function(i) { return i.slice.title; }); 79 80 var slicesByTitle = {}; 81 for (var i = 0; i < sliceHits.length; i++) { 82 var slice = sliceHits[i].slice; 83 if (!slicesByTitle[slice.title]) 84 slicesByTitle[slice.title] = { 85 slices: [] 86 }; 87 slicesByTitle[slice.title].slices.push(slice); 88 } 89 var totalDuration = 0; 90 for (var sliceGroupTitle in slicesByTitle) { 91 var sliceGroup = slicesByTitle[sliceGroupTitle]; 92 var duration = 0; 93 for (i = 0; i < sliceGroup.slices.length; i++) 94 duration += sliceGroup.slices[i].duration; 95 totalDuration += duration; 96 97 text += ' ' + 98 leftAlign(sliceGroupTitle, c0Width) + ': ' + 99 rightAlign(tsRound(duration) + 'ms', c1Width) + ' ' + 100 rightAlign(String(sliceGroup.slices.length), c2Width) + 101 ' occurrences' + '\n'; 102 } 103 104 text += leftAlign('*Totals', c0Width) + ' : ' + 105 rightAlign(tsRound(totalDuration) + 'ms', c1Width) + ' ' + 106 rightAlign(String(sliceHits.length), c2Width) + ' occurrences' + 107 '\n'; 108 109 text += '\n'; 110 111 text += leftAlign('Selection start', c0Width) + ' : ' + 112 rightAlign(tsRound(tsLo) + 'ms', c1Width) + 113 '\n'; 114 text += leftAlign('Selection extent', c0Width) + ' : ' + 115 rightAlign(tsRound(tsHi - tsLo) + 'ms', c1Width) + 116 '\n'; 117 } 118 119 if (counterSampleHits.length == 1) { 120 text = 'Selected counter:\n'; 121 var c0Width = 55; 122 var hit = counterSampleHits[0]; 123 var ctr = hit.counter; 124 var sampleIndex = hit.sampleIndex; 125 var values = []; 126 for (var i = 0; i < ctr.numSeries; ++i) 127 values.push(ctr.samples[ctr.numSeries * sampleIndex + i]); 128 text += leftAlign('Title', c0Width) + ': ' + ctr.name + '\n'; 129 text += leftAlign('Timestamp', c0Width) + ': ' + 130 tsRound(ctr.timestamps[sampleIndex]) + ' ms\n'; 131 if (ctr.numSeries > 1) 132 text += leftAlign('Values', c0Width) + ': ' + values.join('\n') + '\n'; 133 else 134 text += leftAlign('Value', c0Width) + ': ' + values.join('\n') + '\n'; 135 136 } else if (counterSampleHits.length > 1 && sliceHits.length == 0) { 137 text += 'Analysis of multiple counters not yet implemented. ' + 138 'Pick a single counter.'; 139 } 140 return text; 141 } 142 143 var TimelineAnalysisView = cr.ui.define('div'); 144 145 TimelineAnalysisView.prototype = { 146 __proto__: HTMLDivElement.prototype, 147 148 decorate: function() { 149 this.className = 'timeline-analysis'; 150 }, 151 152 set selection(selection) { 153 this.textContent = getTextForSelection(selection); 154 } 155 }; 156 157 return { 158 TimelineAnalysisView: TimelineAnalysisView, 159 }; 160 }); 161