Skip to content

Commit

Permalink
DevTools: Initial implementation of line-level CPU profile.
Browse files Browse the repository at this point in the history
The JS CPU profile is available when there's a recorded timeline with a JS profile.
It is put behind an experiment.

Things to do:
  - support source maps.
  - make it possible to hide profile without reseting timeline.

BUG=590936

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

Cr-Commit-Position: refs/heads/master@{#380873}
  • Loading branch information
a1ph authored and Commit bot committed Mar 12, 2016
1 parent ac71c29 commit a4ae446
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 47 deletions.
1 change: 1 addition & 0 deletions front_end/sdk/CPUProfileDataModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ WebInspector.CPUProfileDataModel.prototype = {
return result;
}
profile.totalHitCount = totalHitCount(profile.head);
this.totalHitCount = profile.totalHitCount;

var duration = this.profileEndTime - this.profileStartTime;
var samplingInterval = duration / profile.totalHitCount;
Expand Down
91 changes: 51 additions & 40 deletions front_end/source_frame/cmdevtools.css
Original file line number Diff line number Diff line change
@@ -1,52 +1,58 @@
.CodeMirror {
line-height: 1.2em !important;
background-color: transparent !important;
line-height: 1.2em !important;
background-color: transparent !important;
}

.CodeMirror-linewidget {
overflow: visible !important;
overflow: visible !important;
}

.CodeMirror-gutter-performance {
width: 74px;
background-color: white;
margin-left: 3px;
}

.CodeMirror .source-frame-eval-expression {
outline: 0;
border: 1px solid rgb(163, 41, 34);
border-left-width: 0;
border-right-width: 0;
background-color: rgb(255, 255, 194);
outline: 0;
border: 1px solid rgb(163, 41, 34);
border-left-width: 0;
border-right-width: 0;
background-color: rgb(255, 255, 194);
}

.CodeMirror .source-frame-eval-expression-end {
border-right-width: 1px;
margin-right: -1px;
border-right-width: 1px;
margin-right: -1px;
}

.CodeMirror .source-frame-eval-expression-start {
border-left-width: 1px;
margin-left: -1px;
border-left-width: 1px;
margin-left: -1px;
}

.CodeMirror-readonly .CodeMirror-cursor {
display: none;
}

.CodeMirror .CodeMirror-gutters {
border-right: 1px solid rgb(187, 187, 187);
background-color: #eee;
border-right: 1px solid rgb(187, 187, 187);
background-color: #eee;
}

.CodeMirror .CodeMirror-linenumber {
color: rgb(128, 128, 128);
color: rgb(128, 128, 128);
}

.CodeMirror-linenumber {
min-width: 22px !important;
min-width: 22px !important;
}

.cm-highlight {
-webkit-animation: fadeout 2s 0s;
-webkit-animation: fadeout 2s 0s;
}
.-theme-with-dark-background .cm-highlight {
-webkit-animation: fadeout-dark 2s 0s;
-webkit-animation: fadeout-dark 2s 0s;
}
@-webkit-keyframes fadeout {
from {background-color: rgb(255, 255, 120); }
Expand All @@ -58,43 +64,43 @@
}

.cm-highlight.cm-execution-line {
-webkit-animation: fadeout-execution-line 1s 0s;
-webkit-animation: fadeout-execution-line 1s 0s;
}
@-webkit-keyframes fadeout-execution-line {
from {background-color: rgb(121, 141, 254); }
to { background-color: rgb(171, 191, 254); }
}

.cm-breakpoint .CodeMirror-linenumber {
color: white;
border-width: 1px 4px 1px 1px !important;
-webkit-border-image: url(Images/breakpoint.png) 1 4 1 1;
margin: 0 0 0 3px !important;
padding-right: 3px;
padding-left: 1px;
height: 11px;
line-height: 12px !important;
color: white;
border-width: 1px 4px 1px 1px !important;
-webkit-border-image: url(Images/breakpoint.png) 1 4 1 1;
margin: 0 0 0 3px !important;
padding-right: 3px;
padding-left: 1px;
height: 11px;
line-height: 12px !important;
}

.cm-line-without-source-mapping {
background-color: #fafafa;
background-color: #fafafa;
}

.cm-breakpoint.cm-breakpoint-conditional .CodeMirror-linenumber {
-webkit-border-image: url(Images/breakpointConditional.png) 1 4 1 1;
-webkit-border-image: url(Images/breakpointConditional.png) 1 4 1 1;
}

@media (-webkit-min-device-pixel-ratio: 1.5) {
.cm-breakpoint .CodeMirror-linenumber {
-webkit-border-image: url(Images/breakpoint_2x.png) 2 8 2 2;
-webkit-border-image: url(Images/breakpoint_2x.png) 2 8 2 2;
}
.cm-breakpoint.cm-breakpoint-conditional .CodeMirror-linenumber {
-webkit-border-image: url(Images/breakpointConditional_2x.png) 2 8 2 2;
-webkit-border-image: url(Images/breakpointConditional_2x.png) 2 8 2 2;
}
} /* media */

.cm-breakpoint-disabled .CodeMirror-linenumber {
opacity: 0.5;
opacity: 0.5;
}

.breakpoints-deactivated .cm-breakpoint .CodeMirror-linenumber {
Expand All @@ -106,12 +112,12 @@
}

.CodeMirror-matchingbracket {
border-bottom: 1px solid black;
color: #222 !important;
border-bottom: 1px solid black;
color: #222 !important;
}

.CodeMirror-nonmatchingbracket {
color: #222 !important;
color: #222 !important;
}

.cm-whitespace::before {
Expand Down Expand Up @@ -242,6 +248,11 @@
color: #eee;
}

.CodeMirror .text-editor-line-marker-performance {
text-align: right;
padding-right: 3px;
}

.CodeMirror .text-editor-line-decoration {
position: absolute;
}
Expand Down Expand Up @@ -309,9 +320,9 @@
}

.CodeMirror .text-editor-line-decoration-wave {
background-image: url(Images/errorWave.png);
background-repeat: repeat-x;
background-size: contain;
background-image: url(Images/errorWave.png);
background-repeat: repeat-x;
background-size: contain;
}

@media (-webkit-min-device-pixel-ratio: 1.5) {
Expand All @@ -322,11 +333,11 @@

/** @see crbug.com/358161 */
.CodeMirror .CodeMirror-vscrollbar, .CodeMirror .CodeMirror-hscrollbar {
transform: translateZ(0);
transform: translateZ(0);
}

.CodeMirror .CodeMirror-activeline-background {
background-color: transparent;
background-color: transparent;
}

.cm-trailing-whitespace {
Expand Down
7 changes: 2 additions & 5 deletions front_end/timeline/TimelineJSProfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@
WebInspector.TimelineJSProfileProcessor = { };

/**
* @param {!ProfilerAgent.CPUProfile} jsProfile
* @param {!WebInspector.CPUProfileDataModel} jsProfileModel
* @param {!WebInspector.TracingModel.Thread} thread
* @return {!Array<!WebInspector.TracingModel.Event>}
*/
WebInspector.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile = function(jsProfile, thread)
WebInspector.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile = function(jsProfileModel, thread)
{
if (!jsProfile.samples)
return [];
var jsProfileModel = new WebInspector.CPUProfileDataModel(jsProfile);
var idleNode = jsProfileModel.idleNode;
var programNode = jsProfileModel.programNode;
var gcNode = jsProfileModel.gcNode;
Expand Down
64 changes: 62 additions & 2 deletions front_end/timeline/TimelineModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -729,8 +729,11 @@ WebInspector.TimelineModel.prototype = {
var cpuProfileEvent = events.peekLast();
if (cpuProfileEvent && cpuProfileEvent.name === WebInspector.TimelineModel.RecordType.CpuProfile) {
var cpuProfile = cpuProfileEvent.args["data"]["cpuProfile"];
if (cpuProfile)
jsSamples = WebInspector.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile(cpuProfile, thread);
if (cpuProfile) {
var jsProfileModel = new WebInspector.CPUProfileDataModel(cpuProfile);
this._lineLevelCPUProfile.appendCPUProfile(jsProfileModel);
jsSamples = WebInspector.TimelineJSProfileProcessor.generateTracingEventsFromCpuProfile(jsProfileModel, thread);
}
}
}

Expand Down Expand Up @@ -1061,6 +1064,7 @@ WebInspector.TimelineModel.prototype = {

reset: function()
{
this._lineLevelCPUProfile = new WebInspector.TimelineModel.LineLevelProfile();
this._virtualThreads = [];
/** @type {!Array.<!WebInspector.TracingModel.Event>} */
this._mainThreadEvents = [];
Expand All @@ -1084,6 +1088,14 @@ WebInspector.TimelineModel.prototype = {
this._maximumRecordTime = 0;
},

/**
* @return {!WebInspector.TimelineModel.LineLevelProfile}
*/
lineLevelCPUProfile: function()
{
return this._lineLevelCPUProfile;
},

/**
* @return {number}
*/
Expand Down Expand Up @@ -1723,3 +1735,51 @@ WebInspector.TimelineAsyncEventTracker.prototype = {
event.initiator = initiatorMap.get(id) || null;
}
}

/**
* @constructor
*/
WebInspector.TimelineModel.LineLevelProfile = function()
{
/** @type {!Map<string, !Map<number, number>>} */
this._files = new Map();
}

WebInspector.TimelineModel.LineLevelProfile.prototype = {
/**
* @param {!WebInspector.CPUProfileDataModel} profile
*/
appendCPUProfile: function(profile)
{
var nodesToGo = [profile.profileHead];
var sampleDuration = (profile.profileEndTime - profile.profileStartTime) / profile.totalHitCount;
while (nodesToGo.length) {
var nodes = nodesToGo.pop().children;
for (var i = 0; i < nodes.length; ++i) {
var node = nodes[i];
nodesToGo.push(node);
if (!node.url || !node.positionTicks)
continue;
var fileInfo = this._files.get(node.url);
if (!fileInfo) {
fileInfo = new Map();
this._files.set(node.url, fileInfo);
}
for (var j = 0; j < node.positionTicks.length; ++j) {
var lineInfo = node.positionTicks[j];
var line = lineInfo.line - 1;
var time = lineInfo.ticks * sampleDuration;
fileInfo.set(line, (fileInfo.get(line) || 0) + time);
}
}
}
},

/**
* @return {!Map<string, !Map<number, number>>}
*/
files: function()
{
return this._files;
}
}
24 changes: 24 additions & 0 deletions front_end/timeline/TimelinePanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -679,6 +679,7 @@ WebInspector.TimelinePanel.prototype = {
{
this._tracingModel.reset();
this._model.reset();
this._resetLineLevelCPUProfile();
this._showRecordingHelpMessage();

this.requestWindowTimes(0, Infinity);
Expand Down Expand Up @@ -806,6 +807,7 @@ WebInspector.TimelinePanel.prototype = {
this._frameModel.addTraceEvents(this._model.target(), this._model.inspectedTargetEvents(), this._model.sessionId() || "");
if (this._irModel)
this._irModel.populate(this._model);
this._setLineLevelCPUProfile(this._model.lineLevelCPUProfile());
if (this._statusPane)
this._statusPane.hide();
delete this._statusPane;
Expand Down Expand Up @@ -1261,6 +1263,28 @@ WebInspector.TimelinePanel.prototype = {
this.requestWindowTimes(leftTime, rightTime);
},

/**
* @param {!WebInspector.TimelineModel.LineLevelProfile} profile
*/
_setLineLevelCPUProfile: function(profile)
{
for (var fileInfo of profile.files()) {
var uiSourceCode = WebInspector.workspace.uiSourceCodeForURL(/** @type {string} */ (fileInfo[0]));
if (!uiSourceCode)
continue;
for (var lineInfo of fileInfo[1]) {
var line = lineInfo[0];
var time = lineInfo[1];
uiSourceCode.addLineDecoration(line, WebInspector.TimelineUIUtils.PerformanceLineDecorator.type, time);
}
}
},

_resetLineLevelCPUProfile: function()
{
WebInspector.workspace.uiSourceCodes().forEach(uiSourceCode => uiSourceCode.removeAllLineDecorations(WebInspector.TimelineUIUtils.PerformanceLineDecorator.type));
},

__proto__: WebInspector.Panel.prototype
}

Expand Down
33 changes: 33 additions & 0 deletions front_end/timeline/TimelineUIUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2101,3 +2101,36 @@ WebInspector.TimelineUIUtils.eventWarning = function(event, warningType)
}
return span;
}

/**
* @constructor
* @implements {WebInspector.UISourceCodeFrame.LineDecorator}
*/
WebInspector.TimelineUIUtils.PerformanceLineDecorator = function()
{
}

WebInspector.TimelineUIUtils.PerformanceLineDecorator.type = "performance";

WebInspector.TimelineUIUtils.PerformanceLineDecorator.prototype = {
/**
* @override
* @param {!WebInspector.UISourceCode} uiSourceCode
* @param {!WebInspector.CodeMirrorTextEditor} textEditor
*/
decorate: function(uiSourceCode, textEditor)
{
var type = WebInspector.TimelineUIUtils.PerformanceLineDecorator.type;
var decorations = uiSourceCode.lineDecorations(type) || [];
textEditor.resetGutterDecorations(type);
for (var decoration of decorations) {
var time = /** @type {number} */ (decoration.data());
var text = WebInspector.UIString("%.1f\xa0ms", time);
var intensity = Number.constrain(Math.log10(1 + 2 * time) / 5, 0.02, 1);
var element = createElementWithClass("div", "text-editor-line-marker-performance");
element.textContent = text;
element.style.backgroundColor = `rgba(255, 0, 0, ${intensity.toFixed(3)})`;
textEditor.setGutterDecoration(decoration.line(), decoration.type(), element);
}
}
}
Loading

0 comments on commit a4ae446

Please sign in to comment.