Home | History | Annotate | Download | only in timeline
      1 // Copyright 2014 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 /**
      6  * @constructor
      7  * @extends {WebInspector.Object}
      8  */
      9 WebInspector.TimelinePowerOverviewDataProvider = function()
     10 {
     11     this._records = [];
     12     this._energies = [];
     13     this._times = [];
     14     WebInspector.powerProfiler.addEventListener(WebInspector.PowerProfiler.EventTypes.PowerEventRecorded, this._onRecordAdded, this);
     15 }
     16 
     17 WebInspector.TimelinePowerOverviewDataProvider.prototype = {
     18     dispose: function()
     19     {
     20         WebInspector.powerProfiler.removeEventListener(WebInspector.PowerProfiler.EventTypes.PowerEventRecorded, this._onRecordAdded, this);
     21     },
     22 
     23     /**
     24      * @return {!Array.<!PowerAgent.PowerEvent>}
     25      */
     26     records : function()
     27     {
     28         // The last record is not used, as its "value" is not set.
     29         return this._records.slice(0, this._records.length - 1);
     30     },
     31 
     32     /**
     33      * @param {number} minTime
     34      * @param {number} maxTime
     35      * @return {number} energy in joules.
     36      */
     37     _calculateEnergy : function(minTime, maxTime)
     38     {
     39         var times = this._times;
     40         var energies = this._energies;
     41         var last = times.length - 1;
     42 
     43         if (last < 1 || minTime >= times[last] || maxTime <= times[0])
     44             return 0;
     45 
     46         // Maximum index of element whose time <= minTime.
     47         var start = Number.constrain(times.upperBound(minTime) - 1, 0, last);
     48 
     49         // Minimum index of element whose time >= maxTime.
     50         var end = Number.constrain(times.lowerBound(maxTime), 0, last);
     51 
     52         var startTime = minTime < times[0] ? times[0] : minTime;
     53         var endTime = maxTime > times[last] ? times[last] : maxTime;
     54 
     55         if (start + 1 === end)
     56            return (endTime - startTime) / (times[end] - times[start]) * (energies[end] - energies[start]) / 1000;
     57 
     58         var totalEnergy = 0;
     59         totalEnergy += energies[end - 1] - energies[start + 1];
     60         totalEnergy += (times[start + 1] - startTime) / (times[start + 1] - times[start]) * (energies[start + 1] - energies[start]);
     61         totalEnergy += (endTime - times[end - 1]) / (times[end] - times[end - 1]) * (energies[end] - energies[end - 1]);
     62         return totalEnergy / 1000;
     63     },
     64 
     65     _onRecordAdded: function(event)
     66     {
     67         // "value" of original PowerEvent means the average power between previous sampling to current one.
     68         // Here, it is converted to average power between current sampling to next one.
     69         var record = event.data;
     70         var curTime = record.timestamp;
     71         var length = this._records.length;
     72         var accumulatedEnergy = 0;
     73         if (length) {
     74             this._records[length - 1].value = record.value;
     75 
     76             var prevTime = this._records[length - 1].timestamp;
     77             accumulatedEnergy = this._energies[length - 1];
     78             accumulatedEnergy += (curTime - prevTime) * record.value;
     79         }
     80         this._energies.push(accumulatedEnergy);
     81         this._records.push(record);
     82         this._times.push(curTime);
     83     },
     84 
     85     __proto__: WebInspector.Object.prototype
     86 }
     87 
     88 /**
     89  * @constructor
     90  * @extends {WebInspector.TimelineOverviewBase}
     91  * @param {!WebInspector.TimelineModel} model
     92  */
     93 WebInspector.TimelinePowerOverview = function(model)
     94 {
     95     WebInspector.TimelineOverviewBase.call(this, model);
     96     this.element.id = "timeline-overview-power";
     97     this._dataProvider = new WebInspector.TimelinePowerOverviewDataProvider();
     98 
     99     this._maxPowerLabel = this.element.createChild("div", "max memory-graph-label");
    100     this._minPowerLabel = this.element.createChild("div", "min memory-graph-label");
    101 }
    102 
    103 WebInspector.TimelinePowerOverview.prototype = {
    104     dispose: function()
    105     {
    106         this._dataProvider.dispose();
    107     },
    108 
    109     timelineStarted: function()
    110     {
    111         if (WebInspector.targetManager.mainTarget().hasCapability(WebInspector.Target.Capabilities.CanProfilePower))
    112             WebInspector.powerProfiler.startProfile();
    113     },
    114 
    115     timelineStopped: function()
    116     {
    117         if (WebInspector.targetManager.mainTarget().hasCapability(WebInspector.Target.Capabilities.CanProfilePower))
    118             WebInspector.powerProfiler.stopProfile();
    119     },
    120 
    121     _resetPowerLabels: function()
    122     {
    123         this._maxPowerLabel.textContent = "";
    124         this._minPowerLabel.textContent = "";
    125     },
    126 
    127     update: function()
    128     {
    129         this.resetCanvas();
    130 
    131         var records = this._dataProvider.records();
    132         if (!records.length) {
    133             this._resetPowerLabels();
    134             return;
    135         }
    136 
    137         const lowerOffset = 3;
    138         var maxPower = 0;
    139         var minPower = 100000000000;
    140         var minTime = this._model.minimumRecordTime();
    141         var maxTime = this._model.maximumRecordTime();
    142         for (var i = 0; i < records.length; i++) {
    143             var record = records[i];
    144             if (record.timestamp < minTime || record.timestamp > maxTime)
    145                 continue;
    146             maxPower = Math.max(maxPower, record.value);
    147             minPower = Math.min(minPower, record.value);
    148         }
    149         minPower = Math.min(minPower, maxPower);
    150 
    151 
    152         var width = this._canvas.width;
    153         var height = this._canvas.height - lowerOffset;
    154         var xFactor = width / (maxTime - minTime);
    155         var yFactor = height / Math.max(maxPower - minPower, 1);
    156 
    157         var histogram = new Array(width);
    158         for (var i = 0; i < records.length - 1; i++) {
    159             var record = records[i];
    160             if (record.timestamp < minTime || record.timestamp > maxTime)
    161                 continue;
    162             var x = Math.round((record.timestamp - minTime) * xFactor);
    163             var y = Math.round((record.value- minPower ) * yFactor);
    164             histogram[x] = Math.max(histogram[x] || 0, y);
    165         }
    166 
    167         var y = 0;
    168         var isFirstPoint = true;
    169         var ctx = this._context;
    170         ctx.save();
    171         ctx.translate(0.5, 0.5);
    172         ctx.beginPath();
    173         ctx.moveTo(-1, this._canvas.height);
    174         for (var x = 0; x < histogram.length; x++) {
    175             if (typeof histogram[x] === "undefined")
    176                 continue;
    177             if (isFirstPoint) {
    178                 isFirstPoint = false;
    179                 y = histogram[x];
    180                 ctx.lineTo(-1, height - y);
    181             }
    182             ctx.lineTo(x, height - y);
    183             y = histogram[x];
    184             ctx.lineTo(x, height - y);
    185         }
    186 
    187         ctx.lineTo(width, height - y);
    188         ctx.lineTo(width, this._canvas.height);
    189         ctx.lineTo(-1, this._canvas.height);
    190         ctx.closePath();
    191 
    192         ctx.fillStyle = "rgba(255,192,0, 0.8);";
    193         ctx.fill();
    194 
    195         ctx.lineWidth = 0.5;
    196         ctx.strokeStyle = "rgba(20,0,0,0.8)";
    197         ctx.stroke();
    198         ctx.restore();
    199 
    200         this._maxPowerLabel.textContent = WebInspector.UIString("%.2f\u2009watts", maxPower);
    201         this._minPowerLabel.textContent = WebInspector.UIString("%.2f\u2009watts", minPower);
    202     },
    203 
    204     /**
    205      * @param {number} minTime
    206      * @param {number} maxTime
    207      * @return {number} energy in joules.
    208      */
    209     calculateEnergy: function(minTime, maxTime)
    210     {
    211         return this._dataProvider._calculateEnergy(minTime, maxTime);
    212     },
    213 
    214     __proto__: WebInspector.TimelineOverviewBase.prototype
    215 }
    216 
    217 
    218