Bug 1144423 - Display bytesize and percentages for both bytesize and counts in the allocations call tree. r=fitzgen,vp

This commit is contained in:
Jordan Santell 2015-08-25 22:30:04 -07:00
parent e06dc9e42a
commit 2c501dbad6
6 changed files with 135 additions and 73 deletions

View File

@ -13,36 +13,75 @@ const { L10N } = require("devtools/performance/global");
const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
const MILLISECOND_UNITS = L10N.getStr("table.ms");
const PERCENTAGE_UNITS = L10N.getStr("table.percentage");
const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
const VIEW_OPTIMIZATIONS_TOOLTIP = L10N.getStr("table.view-optimizations.tooltiptext");
const CALL_TREE_INDENTATION = 16; // px
// Used for rendering values in cells
const FORMATTERS = {
TIME: (value) => L10N.getFormatStr("table.ms2", L10N.numberWithDecimals(value, 2)),
PERCENT: (value) => L10N.getFormatStr("table.percentage2", L10N.numberWithDecimals(value, 2)),
NUMBER: (value) => value || 0,
BYTESIZE: (value) => L10N.getFormatStr("table.bytes", (value || 0))
};
/**
* Definitions for rendering cells. Triads of class name, property name from
* `frame.getInfo()`, and a formatter function.
*/
const CELLS = {
duration: ["duration", "totalDuration", FORMATTERS.TIME],
percentage: ["percentage", "totalPercentage", FORMATTERS.PERCENT],
selfDuration: ["self-duration", "selfDuration", FORMATTERS.TIME],
selfPercentage: ["self-percentage", "selfPercentage", FORMATTERS.PERCENT],
samples: ["samples", "samples", FORMATTERS.NUMBER],
selfSize: ["self-size", "selfSize", FORMATTERS.BYTESIZE],
selfSizePercentage: ["self-size-percentage", "selfSizePercentage", FORMATTERS.PERCENT],
selfCount: ["self-count", "selfCount", FORMATTERS.NUMBER],
selfCountPercentage: ["self-count-percentage", "selfCountPercentage", FORMATTERS.PERCENT],
size: ["size", "totalSize", FORMATTERS.BYTESIZE],
sizePercentage: ["size-percentage", "totalSizePercentage", FORMATTERS.PERCENT],
count: ["count", "totalCount", FORMATTERS.NUMBER],
countPercentage: ["count-percentage", "totalCountPercentage", FORMATTERS.PERCENT],
};
const CELL_TYPES = Object.keys(CELLS);
const DEFAULT_SORTING_PREDICATE = (frameA, frameB) => {
let dataA = frameA.getDisplayedData();
let dataB = frameB.getDisplayedData();
if (this.inverted) {
// Invert trees, sort by selfPercentage, and then totalPercentage
if (dataA.selfPercentage === dataB.selfPercentage) {
return dataA.totalPercentage < dataB.totalPercentage ? 1 : -1;
}
return dataA.selfPercentage < dataB.selfPercentage ? 1 : - 1;
let isAllocations = "totalSize" in dataA;
if (isAllocations) {
return this.inverted && dataA.selfSize !== dataB.selfSize ?
(dataA.selfSize < dataB.selfSize ? 1 : - 1) :
(dataA.totalSize < dataB.totalSize ? 1 : -1);
}
return dataA.totalPercentage < dataB.totalPercentage ? 1 : -1;
return this.inverted && dataA.selfPercentage !== dataB.selfPercentage ?
(dataA.selfPercentage < dataB.selfPercentage ? 1 : - 1) :
(dataA.totalPercentage < dataB.totalPercentage ? 1 : -1);
};
const DEFAULT_AUTO_EXPAND_DEPTH = 3; // depth
const DEFAULT_VISIBLE_CELLS = {
duration: true,
percentage: true,
count: false,
selfDuration: true,
selfPercentage: true,
selfCount: false,
samples: true,
function: true
function: true,
// allocation columns
count: false,
selfCount: false,
size: false,
selfSize: false,
countPercentage: false,
selfCountPercentage: false,
sizePercentage: false,
selfSizePercentage: false,
};
const clamp = (val, min, max) => Math.max(min, Math.min(max, val));
@ -136,27 +175,14 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
let frameInfo = this.getDisplayedData();
let cells = [];
if (this.visibleCells.duration) {
cells.push(this._createTimeCell(document, frameInfo.totalDuration));
}
if (this.visibleCells.percentage) {
cells.push(this._createExecutionCell(document, frameInfo.totalPercentage));
}
if (this.visibleCells.count) {
cells.push(this._createCountCell(document, frameInfo.totalCount));
}
if (this.visibleCells.selfDuration) {
cells.push(this._createTimeCell(document, frameInfo.selfDuration, true));
}
if (this.visibleCells.selfPercentage) {
cells.push(this._createExecutionCell(document, frameInfo.selfPercentage, true));
}
if (this.visibleCells.selfCount) {
cells.push(this._createCountCell(document, frameInfo.selfCount, true));
}
if (this.visibleCells.samples) {
cells.push(this._createSamplesCell(document, frameInfo.samples));
for (let type of CELL_TYPES) {
if (this.visibleCells[type]) {
// Inline for speed, but pass in the formatted value via
// cell definition, as well as the element type.
cells.push(this._createCell(document, CELLS[type][2](frameInfo[CELLS[type][1]]), CELLS[type][0]));
}
}
if (this.visibleCells.function) {
cells.push(this._createFunctionCell(document, arrowNode, frameInfo.name, frameInfo, this.level));
}
@ -204,38 +230,15 @@ CallView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
* Functions creating each cell in this call view.
* Invoked by `_displaySelf`.
*/
_createTimeCell: function(doc, duration, isSelf = false) {
_createCell: function (doc, value, type) {
let cell = doc.createElement("description");
cell.className = "plain call-tree-cell";
cell.setAttribute("type", isSelf ? "self-duration" : "duration");
cell.setAttribute("type", type);
cell.setAttribute("crop", "end");
cell.setAttribute("value", L10N.numberWithDecimals(duration, 2) + " " + MILLISECOND_UNITS);
return cell;
},
_createExecutionCell: function(doc, percentage, isSelf = false) {
let cell = doc.createElement("description");
cell.className = "plain call-tree-cell";
cell.setAttribute("type", isSelf ? "self-percentage" : "percentage");
cell.setAttribute("crop", "end");
cell.setAttribute("value", L10N.numberWithDecimals(percentage, 2) + PERCENTAGE_UNITS);
return cell;
},
_createCountCell: function(doc, count, isSelf = false) {
let cell = doc.createElement("description");
cell.className = "plain call-tree-cell";
cell.setAttribute("type", isSelf ? "self-count" : "count");
cell.setAttribute("crop", "end");
cell.setAttribute("value", count || 0);
return cell;
},
_createSamplesCell: function(doc, count) {
let cell = doc.createElement("description");
cell.className = "plain call-tree-cell";
cell.setAttribute("type", "samples");
cell.setAttribute("crop", "end");
cell.setAttribute("value", count || 0);
cell.setAttribute("value", value);
return cell;
},
_createFunctionCell: function(doc, arrowNode, frameName, frameInfo, frameLevel) {
let cell = doc.createElement("hbox");
cell.className = "call-tree-cell";

View File

@ -308,15 +308,45 @@
<vbox id="memory-calltree-view" flex="1">
<hbox class="call-tree-headers-container">
<label class="plain call-tree-header"
type="count"
type="self-size"
crop="end"
value="&performanceUI.table.totalAlloc;"
value="Self Bytes"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="self-size-percentage"
crop="end"
value="Self Bytes %"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="self-count"
crop="end"
value="&performanceUI.table.selfAlloc;"
tooltiptext="&performanceUI.table.selfAlloc.tooltip;"/>
value="Self Count"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="self-count-percentage"
crop="end"
value="Self Count %"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="size"
crop="end"
value="Total Size"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="size-percentage"
crop="end"
value="Total Size %"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="count"
crop="end"
value="Total Count"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="count-percentage"
crop="end"
value="Total Count %"
tooltiptext="&performanceUI.table.totalAlloc.tooltip;"/>
<label class="plain call-tree-header"
type="function"
crop="end"

View File

@ -24,9 +24,15 @@ function* spawnTest() {
"duration": false,
"percentage": false,
"count": true,
"count-percentage": true,
"size": true,
"size-percentage": true,
"self-duration": false,
"self-percentage": false,
"self-count": true,
"self-count-percentage": true,
"self-size": true,
"self-size-percentage": true,
"samples": false,
"function": true
});

View File

@ -88,8 +88,6 @@ let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
inverted: inverted,
// Root nodes are hidden in inverted call trees.
hidden: inverted,
// Memory call trees should be sorted by allocations.
sortingPredicate: (a, b) => a.frame.allocations < b.frame.allocations ? 1 : -1,
// Call trees should only auto-expand when not inverted. Passing undefined
// will default to the CALL_TREE_AUTO_EXPAND depth.
autoExpandDepth: inverted ? 0 : undefined,
@ -98,6 +96,12 @@ let MemoryCallTreeView = Heritage.extend(DetailsSubview, {
visibleCells: {
selfCount: true,
count: true,
selfSize: true,
size: true,
selfCountPercentage: true,
countPercentage: true,
selfSizePercentage: true,
sizePercentage: true,
function: true
}
});

View File

@ -92,13 +92,20 @@ category.storage=Storage
category.events=Input & Events
category.tools=Tools
# LOCALIZATION NOTE (table.ms):
# This string is displayed in the call tree after units of time in milliseconds.
table.ms=ms
# LOCALIZATION NOTE (table.bytes):
# This string is displayed in the call tree after bytesize units.
# %S represents the value in bytes.
table.bytes=%S B
# LOCALIZATION NOTE (table.percentage):
# LOCALIZATION NOTE (table.ms2):
# This string is displayed in the call tree after units of time in milliseconds.
# %S represents the value in milliseconds.
table.ms2=%S ms
# LOCALIZATION NOTE (table.percentage2):
# This string is displayed in the call tree after units representing percentages.
table.percentage=%
# %S represents the value in percentage with two decimal points, localized.
table.percentage2=%S%
# LOCALIZATION NOTE (table.root):
# This string is displayed in the call tree for the root node.
@ -165,4 +172,4 @@ timeline.records=RECORDS
# %S is the percentage of the buffer used -- there are two "%"s after to escape
# the % that is actually displayed.
# Example: "Buffer 54% full"
profiler.bufferFull=Buffer %S%% full
profiler.bufferFull=Buffer %S%% full

View File

@ -234,8 +234,20 @@
.call-tree-header[type="count"],
.call-tree-cell[type="count"],
.call-tree-header[type="self-count"],
.call-tree-cell[type="self-count"] {
width: 9vw;
.call-tree-cell[type="self-count"],
.call-tree-header[type="size"],
.call-tree-cell[type="size"],
.call-tree-header[type="self-size"],
.call-tree-cell[type="self-size"],
.call-tree-header[type="count-percentage"],
.call-tree-cell[type="count-percentage"],
.call-tree-header[type="self-count-percentage"],
.call-tree-cell[type="self-count-percentage"],
.call-tree-header[type="size-percentage"],
.call-tree-cell[type="size-percentage"],
.call-tree-header[type="self-size-percentage"],
.call-tree-cell[type="self-size-percentage"] {
width: 6vw;
}
.call-tree-header[type="function"],