1<!DOCTYPE html> 2<!-- 3Copyright 2015 The Chromium Authors. All rights reserved. 4Use of this source code is governed by a BSD-style license that can be 5found in the LICENSE file. 6--> 7 8<link rel="import" href="/tracing/model/event_set.html"> 9<link rel="import" href="/tracing/ui/base/line_chart.html"> 10 11<!-- 12@fileoverview A line chart showing milliseconds since the start of the frame on 13the x-axis and power consumption on the y-axis. Each frame is shown as a 14separate line in the chart. Vertical sync events are used as the start of each 15frame. 16 17This chart aims to help users understand the shape of the power consumption 18curve over the course of a frame or set of frames. 19--> 20<polymer-element name="tr-ui-a-frame-power-usage-chart"> 21 <template> 22 <div id="content"></div> 23 </template> 24</polymer-element> 25 26<script> 27'use strict'; 28 29var EventSet = tr.model.EventSet; 30 31var CHART_TITLE = 'Power (W) by ms since vertical sync'; 32// TODO(charliea): Find out how to make this specifiable via CSS. 33var CHART_WIDTH_FRACTION_OF_BODY = 0.5; 34 35Polymer('tr-ui-a-frame-power-usage-chart', { 36 ready: function() { 37 this.chart_ = undefined; 38 this.samples_ = new EventSet(); 39 this.vSyncTimestamps_ = []; 40 }, 41 42 get chart() { 43 return this.chart_; 44 }, 45 46 get samples() { 47 return this.samples_; 48 }, 49 50 get vSyncTimestamps() { 51 return this.vSyncTimestamps_; 52 }, 53 54 /** 55 * Sets the data that powers the chart. Vsync timestamps must be in 56 * chronological order. 57 */ 58 setData: function(samples, vSyncTimestamps) { 59 this.samples_ = (samples === undefined) ? new EventSet() : samples; 60 this.vSyncTimestamps_ = 61 (vSyncTimestamps === undefined) ? [] : vSyncTimestamps; 62 this.updateContents_(); 63 }, 64 65 updateContents_: function() { 66 this.clearChart_(); 67 68 var data = this.getDataForLineChart_(); 69 70 if (data.length === 0) 71 return; 72 73 this.chart_ = this.createChart_(data); 74 this.$.content.appendChild(this.chart_); 75 }, 76 77 createChart_: function(data) { 78 var chart = new tr.ui.b.LineChart(); 79 var width = document.body.clientWidth * CHART_WIDTH_FRACTION_OF_BODY; 80 chart.setSize({width: width, height: chart.height}); 81 chart.chartTitle = CHART_TITLE; 82 chart.data = data; 83 84 return chart; 85 }, 86 87 clearChart_: function() { 88 var content = this.$.content; 89 while (content.firstChild) 90 content.removeChild(content.firstChild); 91 92 this.chart_ = undefined; 93 }, 94 95 // TODO(charliea): Limit the ms since vsync to the median frame length. The 96 // vertical syncs are not 100% regular and highlighting any sample that's 97 // in one of these 'vertical sync lulls' makes the x-axis have a much larger 98 // scale than it should, effectively squishing the other samples into the 99 // left side of the chart. 100 /** 101 * Returns an array of data points for the chart. Each element in the array 102 * is of the form { x: <ms since vsync>, f<frame#>: <power in mW> }. 103 */ 104 getDataForLineChart_: function() { 105 var sortedSamples = this.sortSamplesByTimestampAscending_(this.samples); 106 var vSyncTimestamps = this.vSyncTimestamps.slice(); 107 108 var lastVSyncTimestamp = undefined; 109 var points = []; 110 111 // For each power sample, find and record the frame number that it belongs 112 // to as well as the amount of time elapsed since that frame began. 113 var frameNumber = 0; 114 sortedSamples.forEach(function(sample) { 115 while (vSyncTimestamps.length > 0 && vSyncTimestamps[0] <= sample.start) { 116 lastVSyncTimestamp = vSyncTimestamps.shift(); 117 frameNumber++; 118 } 119 120 // If no vertical sync occurred before the power sample, don't use the 121 // power sample. 122 if (lastVSyncTimestamp === undefined) 123 return; 124 125 var point = { x: sample.start - lastVSyncTimestamp }; 126 // Divide by 1000 to convert to Watts 127 point['f' + frameNumber] = sample.power / 1000; 128 points.push(point); 129 }); 130 131 return points; 132 }, 133 134 sortSamplesByTimestampAscending_: function(samples) { 135 return samples.toArray().sort(function(smpl1, smpl2) { 136 return smpl1.start - smpl2.start; 137 }); 138 } 139}); 140</script> 141