Commit d879445d authored by pan.deng@intel.com's avatar pan.deng@intel.com

This CL add power profiler in DevTools frontend, and draw power data in...

This CL add power profiler in DevTools frontend, and draw power data in PowerOverview of Timeline panel.

BUG=337138

Review URL: https://codereview.chromium.org/104523002

git-svn-id: svn://svn.chromium.org/blink/trunk@169951 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent cfa40f88
...@@ -123,6 +123,7 @@ ...@@ -123,6 +123,7 @@
'front_end/Placard.js', 'front_end/Placard.js',
'front_end/Platform.js', 'front_end/Platform.js',
'front_end/Popover.js', 'front_end/Popover.js',
'front_end/PowerProfiler.js',
'front_end/PresentationConsoleMessageHelper.js', 'front_end/PresentationConsoleMessageHelper.js',
'front_end/Progress.js', 'front_end/Progress.js',
'front_end/ProgressIndicator.js', 'front_end/ProgressIndicator.js',
...@@ -320,6 +321,7 @@ ...@@ -320,6 +321,7 @@
'front_end/TimelineMemoryOverview.js', 'front_end/TimelineMemoryOverview.js',
'front_end/TimelineUIUtils.js', 'front_end/TimelineUIUtils.js',
'front_end/TimelineView.js', 'front_end/TimelineView.js',
'front_end/TimelinePowerOverview.js',
'front_end/TimelinePanel.js', 'front_end/TimelinePanel.js',
], ],
'devtools_profiles_js_files': [ 'devtools_profiles_js_files': [
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* @extends {WebInspector.Object}
*/
WebInspector.PowerProfiler = function()
{
WebInspector.Object.call(this);
this._dispatcher = new WebInspector.PowerDispatcher(this);
}
WebInspector.PowerProfiler.EventTypes = {
PowerEventRecorded: "PowerEventRecorded"
}
WebInspector.PowerProfiler.prototype = {
startProfile: function ()
{
PowerAgent.start();
},
stopProfile: function ()
{
PowerAgent.end();
},
__proto__: WebInspector.Object.prototype
}
/**
* @constructor
* @implements {WebInspector.PowerEventDispatcher}
*/
WebInspector.PowerDispatcher = function(profiler)
{
this._profiler = profiler;
InspectorBackend.registerPowerDispatcher(this);
}
WebInspector.PowerDispatcher.prototype = {
dataAvailable: function(events)
{
for (var i in events)
this._profiler.dispatchEventToListeners(WebInspector.PowerProfiler.EventTypes.PowerEventRecorded, events[i]);
}
}
/**
* @type {!WebInspector.PowerProfiler}
*/
WebInspector.powerProfiler;
...@@ -39,6 +39,7 @@ var Preferences = { ...@@ -39,6 +39,7 @@ var Preferences = {
var Capabilities = { var Capabilities = {
isMainFrontend: false, isMainFrontend: false,
canProfilePower: false,
} }
/** /**
...@@ -289,6 +290,7 @@ WebInspector.ExperimentsSettings = function(experimentsEnabled) ...@@ -289,6 +290,7 @@ WebInspector.ExperimentsSettings = function(experimentsEnabled)
this.heapSnapshotStatistics = this._createExperiment("heapSnapshotStatistics", "Show memory breakdown statistics in heap snapshots"); this.heapSnapshotStatistics = this._createExperiment("heapSnapshotStatistics", "Show memory breakdown statistics in heap snapshots");
this.timelineNoLiveUpdate = this._createExperiment("timelineNoLiveUpdate", "Timeline w/o live update"); this.timelineNoLiveUpdate = this._createExperiment("timelineNoLiveUpdate", "Timeline w/o live update");
this.cssStyleSearch = this._createExperiment("cssStyleSearch", "Enable Styles search and Computed style filtering"); this.cssStyleSearch = this._createExperiment("cssStyleSearch", "Enable Styles search and Computed style filtering");
this.powerProfiler = this._createExperiment("powerProfiler", "Enable power mode in Timeline");
this._cleanUpSetting(); this._cleanUpSetting();
} }
......
...@@ -17,6 +17,10 @@ WebInspector.Target = function(connection, callback) ...@@ -17,6 +17,10 @@ WebInspector.Target = function(connection, callback)
this.isMainFrontend = false; this.isMainFrontend = false;
this.pageAgent().canScreencast(this._initializeCapability.bind(this, "canScreencast", null)); this.pageAgent().canScreencast(this._initializeCapability.bind(this, "canScreencast", null));
if (WebInspector.experimentsSettings.powerProfiler.isEnabled())
this.powerAgent().canProfilePower(this._initializeCapability.bind(this, "canProfilePower", null));
this.workerAgent().canInspectWorkers(this._initializeCapability.bind(this, "isMainFrontend", this._loadedWithCapabilities.bind(this, callback))); this.workerAgent().canInspectWorkers(this._initializeCapability.bind(this, "isMainFrontend", this._loadedWithCapabilities.bind(this, callback)));
} }
...@@ -65,6 +69,9 @@ WebInspector.Target.prototype = { ...@@ -65,6 +69,9 @@ WebInspector.Target.prototype = {
if (!WebInspector.workerManager) if (!WebInspector.workerManager)
WebInspector.workerManager = this.workerManager; WebInspector.workerManager = this.workerManager;
if (this.canProfilePower)
WebInspector.powerProfiler = new WebInspector.PowerProfiler();
if (callback) if (callback)
callback(this); callback(this);
}, },
......
...@@ -355,6 +355,9 @@ WebInspector.TimelineOverviewBase.prototype = { ...@@ -355,6 +355,9 @@ WebInspector.TimelineOverviewBase.prototype = {
{ {
}, },
timelineStarted: function() { },
timelineStopped: function() { },
/** /**
* @param {number} windowLeft * @param {number} windowLeft
* @param {number} windowRight * @param {number} windowRight
......
...@@ -39,6 +39,7 @@ importScript("TimelineFrameModel.js"); ...@@ -39,6 +39,7 @@ importScript("TimelineFrameModel.js");
importScript("TimelineEventOverview.js"); importScript("TimelineEventOverview.js");
importScript("TimelineFrameOverview.js"); importScript("TimelineFrameOverview.js");
importScript("TimelineMemoryOverview.js"); importScript("TimelineMemoryOverview.js");
importScript("TimelinePowerOverview.js");
importScript("TimelineFlameChart.js"); importScript("TimelineFlameChart.js");
importScript("TimelineUIUtils.js"); importScript("TimelineUIUtils.js");
importScript("TimelineView.js"); importScript("TimelineView.js");
...@@ -128,7 +129,8 @@ WebInspector.TimelinePanel.Mode = { ...@@ -128,7 +129,8 @@ WebInspector.TimelinePanel.Mode = {
Events: "Events", Events: "Events",
Frames: "Frames", Frames: "Frames",
Memory: "Memory", Memory: "Memory",
FlameChart: "FlameChart" FlameChart: "FlameChart",
Power: "Power"
}; };
// Define row and header height, should be in sync with styles for timeline graphs. // Define row and header height, should be in sync with styles for timeline graphs.
...@@ -264,6 +266,10 @@ WebInspector.TimelinePanel.prototype = { ...@@ -264,6 +266,10 @@ WebInspector.TimelinePanel.prototype = {
views.overviewView = new WebInspector.TimelineFrameOverview(this._model, this._frameModel()); views.overviewView = new WebInspector.TimelineFrameOverview(this._model, this._frameModel());
views.mainViews = [new WebInspector.TimelineFlameChart(this, this._model, this._frameModel())]; views.mainViews = [new WebInspector.TimelineFlameChart(this, this._model, this._frameModel())];
break; break;
case WebInspector.TimelinePanel.Mode.Power:
views.overviewView = new WebInspector.TimelinePowerOverview(this._model);
views.mainViews = [this._timelineView()];
break;
default: default:
console.assert(false, "Unknown mode: " + mode); console.assert(false, "Unknown mode: " + mode);
} }
...@@ -288,7 +294,8 @@ WebInspector.TimelinePanel.prototype = { ...@@ -288,7 +294,8 @@ WebInspector.TimelinePanel.prototype = {
this._overviewItems = {}; this._overviewItems = {};
for (var mode in WebInspector.TimelinePanel.Mode) { for (var mode in WebInspector.TimelinePanel.Mode) {
if (mode === WebInspector.TimelinePanel.Mode.FlameChart && !WebInspector.experimentsSettings.timelineFlameChart.isEnabled()) if (mode === WebInspector.TimelinePanel.Mode.FlameChart && !WebInspector.experimentsSettings.timelineFlameChart.isEnabled() ||
mode === WebInspector.TimelinePanel.Mode.Power && !Capabilities.canProfilePower)
continue; continue;
this._overviewItems[mode] = new WebInspector.SidebarTreeElement("timeline-overview-sidebar-" + mode.toLowerCase(), WebInspector.UIString(mode)); this._overviewItems[mode] = new WebInspector.SidebarTreeElement("timeline-overview-sidebar-" + mode.toLowerCase(), WebInspector.UIString(mode));
var item = this._overviewItems[mode]; var item = this._overviewItems[mode];
...@@ -555,6 +562,9 @@ WebInspector.TimelinePanel.prototype = { ...@@ -555,6 +562,9 @@ WebInspector.TimelinePanel.prototype = {
{ {
this._userInitiatedRecording = userInitiated; this._userInitiatedRecording = userInitiated;
this._model.startRecording(true); this._model.startRecording(true);
for (var mode in WebInspector.TimelinePanel.Mode)
this._viewsForMode(mode).overviewView.timelineStarted();
if (userInitiated) if (userInitiated)
WebInspector.userMetrics.TimelineStarted.record(); WebInspector.userMetrics.TimelineStarted.record();
}, },
...@@ -563,6 +573,8 @@ WebInspector.TimelinePanel.prototype = { ...@@ -563,6 +573,8 @@ WebInspector.TimelinePanel.prototype = {
{ {
this._userInitiatedRecording = false; this._userInitiatedRecording = false;
this._model.stopRecording(); this._model.stopRecording();
for (var mode in WebInspector.TimelinePanel.Mode)
this._viewsForMode(mode).overviewView.timelineStopped();
}, },
/** /**
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @constructor
* @extends {WebInspector.Object}
*/
WebInspector.TimelinePowerOverviewDataProvider = function()
{
this._records = [];
if (Capabilities.canProfilePower)
WebInspector.powerProfiler.addEventListener(WebInspector.PowerProfiler.EventTypes.PowerEventRecorded, this._onRecordAdded, this);
}
WebInspector.TimelinePowerOverviewDataProvider.prototype = {
/**
* @return {Array.<PowerEvent>}
*/
records : function()
{
// The last record is not used, as its "value" is not set.
return this._records.slice(0, this._records.length - 1);
},
_onRecordAdded: function(event)
{
// "value" of original PowerEvent means the anverage power between previous sampling to current one.
// Here, it is converted to anverage power between current sampling to next one.
var record = event.data;
var length = this._records.length;
if (length)
this._records[length - 1].value = record.value;
this._records.push(record);
},
__proto__: WebInspector.Object.prototype
}
/**
* @constructor
* @extends {WebInspector.TimelineOverviewBase}
* @param {!WebInspector.TimelineModel} model
*/
WebInspector.TimelinePowerOverview = function(model)
{
WebInspector.TimelineOverviewBase.call(this, model);
this.element.id = "timeline-overview-power";
this._dataProvider = new WebInspector.TimelinePowerOverviewDataProvider();
this._maxPowerLabel = this.element.createChild("div", "max memory-graph-label");
this._minPowerLabel = this.element.createChild("div", "min memory-graph-label");
}
WebInspector.TimelinePowerOverview.prototype = {
timelineStarted: function()
{
if (Capabilities.canProfilePower)
WebInspector.powerProfiler.startProfile();
},
timelineStopped: function()
{
if (Capabilities.canProfilePower)
WebInspector.powerProfiler.stopProfile();
},
_resetPowerLabels: function()
{
this._maxPowerLabel.textContent = "";
this._minPowerLabel.textContent = "";
},
update: function()
{
this.resetCanvas();
var records = this._dataProvider.records();
if (!records.length) {
this._resetPowerLabels();
return;
}
const lowerOffset = 3;
var maxPower = 0;
var minPower = 100000000000;
var minTime = this._model.minimumRecordTime();
var maxTime = this._model.maximumRecordTime();
for (var i = 0; i < records.length; i++) {
var record = records[i];
if (record.timestamp < minTime || record.timestamp > maxTime)
continue;
maxPower = Math.max(maxPower, record.value);
minPower = Math.min(minPower, record.value);
}
minPower = Math.min(minPower, maxPower);
var width = this._canvas.width;
var height = this._canvas.height - lowerOffset;
var xFactor = width / (maxTime - minTime);
var yFactor = height / Math.max(maxPower - minPower, 1);
var histogram = new Array(width);
for (var i = 0; i < records.length - 1; i++) {
var record = records[i];
if (record.timestamp < minTime || record.timestamp > maxTime)
continue;
var x = Math.round((record.timestamp - minTime) * xFactor);
var y = Math.round((record.value- minPower ) * yFactor);
histogram[x] = Math.max(histogram[x] || 0, y);
}
var y = 0;
var isFirstPoint = true;
var ctx = this._context;
ctx.save();
ctx.translate(0.5, 0.5);
ctx.beginPath();
ctx.moveTo(-1, this._canvas.height);
for (var x = 0; x < histogram.length; x++) {
if (typeof histogram[x] === "undefined")
continue;
if (isFirstPoint) {
isFirstPoint = false;
y = histogram[x];
ctx.lineTo(-1, height - y);
}
ctx.lineTo(x, height - y);
y = histogram[x];
ctx.lineTo(x, height - y);
}
ctx.lineTo(width, height - y);
ctx.lineTo(width, this._canvas.height);
ctx.lineTo(-1, this._canvas.height);
ctx.closePath();
ctx.fillStyle = "rgba(255,192,0, 0.8);";
ctx.fill();
ctx.lineWidth = 0.5;
ctx.strokeStyle = "rgba(20,0,0,0.8)";
ctx.stroke();
ctx.restore();
this._maxPowerLabel.textContent = WebInspector.UIString("%.2f\u2009watts", maxPower);
this._minPowerLabel.textContent = WebInspector.UIString("%.2f\u2009watts", minPower);;
},
__proto__: WebInspector.TimelineOverviewBase.prototype
}
...@@ -91,6 +91,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -91,6 +91,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<script type="text/javascript" src="ResourceUtils.js"></script> <script type="text/javascript" src="ResourceUtils.js"></script>
<script type="text/javascript" src="ResourceType.js"></script> <script type="text/javascript" src="ResourceType.js"></script>
<script type="text/javascript" src="TimelineManager.js"></script> <script type="text/javascript" src="TimelineManager.js"></script>
<script type="text/javascript" src="PowerProfiler.js"></script>
<script type="text/javascript" src="OverridesSupport.js"></script> <script type="text/javascript" src="OverridesSupport.js"></script>
<script type="text/javascript" src="Database.js"></script> <script type="text/javascript" src="Database.js"></script>
<script type="text/javascript" src="DOMStorage.js"></script> <script type="text/javascript" src="DOMStorage.js"></script>
......
...@@ -265,7 +265,8 @@ ...@@ -265,7 +265,8 @@
} }
#timeline-overview-events, #timeline-overview-events,
#timeline-overview-memory { #timeline-overview-memory,
#timeline-overview-power {
position: absolute; position: absolute;
left: 0; left: 0;
right: 0; right: 0;
...@@ -274,7 +275,8 @@ ...@@ -274,7 +275,8 @@
z-index: 160; z-index: 160;
} }
#timeline-overview-memory { #timeline-overview-memory,
#timeline-overview-power {
top: 25px; top: 25px;
} }
...@@ -474,6 +476,10 @@ ...@@ -474,6 +476,10 @@
-webkit-mask-position: -224px -48px; -webkit-mask-position: -224px -48px;
} }
.timeline-overview-sidebar-power .icon {
-webkit-mask-position: -64px -120px;
}
.memory-graph-label { .memory-graph-label {
position: absolute; position: absolute;
left: 5px; left: 5px;
......
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
"NetworkUISourceCodeProvider.js", "NetworkUISourceCodeProvider.js",
"NotificationService.js", "NotificationService.js",
"OverridesSupport.js", "OverridesSupport.js",
"PowerProfiler.js",
"PresentationConsoleMessageHelper.js", "PresentationConsoleMessageHelper.js",
"WorkerManager.js", "WorkerManager.js",
"WorkerTargetManager.js", "WorkerTargetManager.js",
...@@ -303,6 +304,7 @@ ...@@ -303,6 +304,7 @@
"TimelineFrameModel.js", "TimelineFrameModel.js",
"TimelineFrameOverview.js", "TimelineFrameOverview.js",
"TimelineMemoryOverview.js", "TimelineMemoryOverview.js",
"TimelinePowerOverview.js",
"TimelineModel.js", "TimelineModel.js",
"TimelineOverviewPane.js", "TimelineOverviewPane.js",
"TimelineFlameChart.js", "TimelineFlameChart.js",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment