зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1152992 - If markers do not have a definition, classify them as "Unknown" in the perftools. r=vp
This commit is contained in:
Родитель
19cfc15257
Коммит
91df9dbb13
|
@ -8,7 +8,7 @@
|
||||||
* and parsing out the blueprint to generate correct values for markers.
|
* and parsing out the blueprint to generate correct values for markers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { Ci } = require("chrome");
|
const { Cu, Ci } = require("chrome");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "L10N",
|
loader.lazyRequireGetter(this, "L10N",
|
||||||
"devtools/performance/global", true);
|
"devtools/performance/global", true);
|
||||||
|
@ -22,6 +22,18 @@ loader.lazyRequireGetter(this, "WebConsoleUtils",
|
||||||
// String used to fill in platform data when it should be hidden.
|
// String used to fill in platform data when it should be hidden.
|
||||||
const GECKO_SYMBOL = "(Gecko)";
|
const GECKO_SYMBOL = "(Gecko)";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a marker, blueprint, and filter list and
|
||||||
|
* determines if this marker should be filtered or not.
|
||||||
|
*/
|
||||||
|
function isMarkerValid (marker, filter) {
|
||||||
|
let isUnknown = !(marker.name in TIMELINE_BLUEPRINT);
|
||||||
|
if (isUnknown) {
|
||||||
|
return filter.indexOf("UNKNOWN") === -1;
|
||||||
|
}
|
||||||
|
return filter.indexOf(marker.name) === -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the correct label to display for passed in marker, based
|
* Returns the correct label to display for passed in marker, based
|
||||||
* off of the blueprints.
|
* off of the blueprints.
|
||||||
|
@ -30,7 +42,7 @@ const GECKO_SYMBOL = "(Gecko)";
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
function getMarkerLabel (marker) {
|
function getMarkerLabel (marker) {
|
||||||
let blueprint = TIMELINE_BLUEPRINT[marker.name];
|
let blueprint = getBlueprintFor(marker);
|
||||||
// Either use the label function in the blueprint, or use it directly
|
// Either use the label function in the blueprint, or use it directly
|
||||||
// as a string.
|
// as a string.
|
||||||
return typeof blueprint.label === "function" ? blueprint.label(marker) : blueprint.label;
|
return typeof blueprint.label === "function" ? blueprint.label(marker) : blueprint.label;
|
||||||
|
@ -44,7 +56,7 @@ function getMarkerLabel (marker) {
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
function getMarkerClassName (type) {
|
function getMarkerClassName (type) {
|
||||||
let blueprint = TIMELINE_BLUEPRINT[type];
|
let blueprint = getBlueprintFor({ name: type });
|
||||||
// Either use the label function in the blueprint, or use it directly
|
// Either use the label function in the blueprint, or use it directly
|
||||||
// as a string.
|
// as a string.
|
||||||
let className = typeof blueprint.label === "function" ? blueprint.label() : blueprint.label;
|
let className = typeof blueprint.label === "function" ? blueprint.label() : blueprint.label;
|
||||||
|
@ -72,7 +84,7 @@ function getMarkerClassName (type) {
|
||||||
* @return {Array<object>}
|
* @return {Array<object>}
|
||||||
*/
|
*/
|
||||||
function getMarkerFields (marker) {
|
function getMarkerFields (marker) {
|
||||||
let blueprint = TIMELINE_BLUEPRINT[marker.name];
|
let blueprint = getBlueprintFor(marker);
|
||||||
|
|
||||||
// If blueprint.fields is a function, use that
|
// If blueprint.fields is a function, use that
|
||||||
if (typeof blueprint.fields === "function") {
|
if (typeof blueprint.fields === "function") {
|
||||||
|
@ -111,7 +123,7 @@ const DOM = {
|
||||||
* @return {Array<Element>}
|
* @return {Array<Element>}
|
||||||
*/
|
*/
|
||||||
buildFields: function (doc, marker) {
|
buildFields: function (doc, marker) {
|
||||||
let blueprint = TIMELINE_BLUEPRINT[marker.name];
|
let blueprint = getBlueprintFor(marker);
|
||||||
let fields = getMarkerFields(marker);
|
let fields = getMarkerFields(marker);
|
||||||
|
|
||||||
return fields.map(({ label, value }) => DOM.buildNameValueLabel(doc, label, value));
|
return fields.map(({ label, value }) => DOM.buildNameValueLabel(doc, label, value));
|
||||||
|
@ -125,7 +137,7 @@ const DOM = {
|
||||||
* @return {Element}
|
* @return {Element}
|
||||||
*/
|
*/
|
||||||
buildTitle: function (doc, marker) {
|
buildTitle: function (doc, marker) {
|
||||||
let blueprint = TIMELINE_BLUEPRINT[marker.name];
|
let blueprint = getBlueprintFor(marker);
|
||||||
|
|
||||||
let hbox = doc.createElement("hbox");
|
let hbox = doc.createElement("hbox");
|
||||||
hbox.setAttribute("align", "center");
|
hbox.setAttribute("align", "center");
|
||||||
|
@ -377,6 +389,14 @@ const JS_MARKER_MAP = {
|
||||||
* A series of formatters used by the blueprint.
|
* A series of formatters used by the blueprint.
|
||||||
*/
|
*/
|
||||||
const Formatters = {
|
const Formatters = {
|
||||||
|
/**
|
||||||
|
* Uses the marker name as the label for markers that do not have
|
||||||
|
* a blueprint entry. Uses "Other" in the marker filter menu.
|
||||||
|
*/
|
||||||
|
UnknownLabel: function (marker={}) {
|
||||||
|
return marker.name || L10N.getStr("timeline.label.unknown");
|
||||||
|
},
|
||||||
|
|
||||||
GCLabel: function (marker={}) {
|
GCLabel: function (marker={}) {
|
||||||
let label = L10N.getStr("timeline.label.garbageCollection");
|
let label = L10N.getStr("timeline.label.garbageCollection");
|
||||||
// Only if a `nonincrementalReason` exists, do we want to label
|
// Only if a `nonincrementalReason` exists, do we want to label
|
||||||
|
@ -444,9 +464,22 @@ const Formatters = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a marker and returns the definition for that marker type,
|
||||||
|
* falling back to the UNKNOWN definition if undefined.
|
||||||
|
*
|
||||||
|
* @param {Marker} marker
|
||||||
|
* @return {object}
|
||||||
|
*/
|
||||||
|
function getBlueprintFor (marker) {
|
||||||
|
return TIMELINE_BLUEPRINT[marker.name] || TIMELINE_BLUEPRINT.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.isMarkerValid = isMarkerValid;
|
||||||
exports.getMarkerLabel = getMarkerLabel;
|
exports.getMarkerLabel = getMarkerLabel;
|
||||||
exports.getMarkerClassName = getMarkerClassName;
|
exports.getMarkerClassName = getMarkerClassName;
|
||||||
exports.getMarkerFields = getMarkerFields;
|
exports.getMarkerFields = getMarkerFields;
|
||||||
exports.DOM = DOM;
|
exports.DOM = DOM;
|
||||||
exports.CollapseFunctions = CollapseFunctions;
|
exports.CollapseFunctions = CollapseFunctions;
|
||||||
exports.Formatters = Formatters;
|
exports.Formatters = Formatters;
|
||||||
|
exports.getBlueprintFor = getBlueprintFor;
|
||||||
|
|
|
@ -196,55 +196,6 @@ function getProfileThreadFromAllocations(allocations) {
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current timeline blueprint without the hidden markers.
|
|
||||||
*
|
|
||||||
* @param blueprint
|
|
||||||
* The default timeline blueprint.
|
|
||||||
* @param array hiddenMarkers
|
|
||||||
* A list of hidden markers' names.
|
|
||||||
* @return object
|
|
||||||
* The filtered timeline blueprint.
|
|
||||||
*/
|
|
||||||
function getFilteredBlueprint({ blueprint, hiddenMarkers }) {
|
|
||||||
// Clone functions here just to prevent an error, as the blueprint
|
|
||||||
// contains functions (even though we do not use them).
|
|
||||||
let filteredBlueprint = Cu.cloneInto(blueprint, {}, { cloneFunctions: true });
|
|
||||||
let maybeRemovedGroups = new Set();
|
|
||||||
let removedGroups = new Set();
|
|
||||||
|
|
||||||
// 1. Remove hidden markers from the blueprint.
|
|
||||||
|
|
||||||
for (let hiddenMarkerName of hiddenMarkers) {
|
|
||||||
maybeRemovedGroups.add(filteredBlueprint[hiddenMarkerName].group);
|
|
||||||
delete filteredBlueprint[hiddenMarkerName];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Get a list of all the groups that will be removed.
|
|
||||||
|
|
||||||
for (let maybeRemovedGroup of maybeRemovedGroups) {
|
|
||||||
let markerNames = Object.keys(filteredBlueprint);
|
|
||||||
let isGroupRemoved = markerNames.every(e => filteredBlueprint[e].group != maybeRemovedGroup);
|
|
||||||
if (isGroupRemoved) {
|
|
||||||
removedGroups.add(maybeRemovedGroup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Offset groups so that their indices are consecutive.
|
|
||||||
|
|
||||||
for (let removedGroup of removedGroups) {
|
|
||||||
let markerNames = Object.keys(filteredBlueprint);
|
|
||||||
for (let markerName of markerNames) {
|
|
||||||
let markerDetails = filteredBlueprint[markerName];
|
|
||||||
if (markerDetails.group > removedGroup) {
|
|
||||||
markerDetails.group--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredBlueprint;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deduplicates a profile by deduplicating stacks, frames, and strings.
|
* Deduplicates a profile by deduplicating stacks, frames, and strings.
|
||||||
*
|
*
|
||||||
|
@ -571,7 +522,6 @@ exports.offsetSampleTimes = offsetSampleTimes;
|
||||||
exports.offsetMarkerTimes = offsetMarkerTimes;
|
exports.offsetMarkerTimes = offsetMarkerTimes;
|
||||||
exports.offsetAndScaleTimestamps = offsetAndScaleTimestamps;
|
exports.offsetAndScaleTimestamps = offsetAndScaleTimestamps;
|
||||||
exports.getProfileThreadFromAllocations = getProfileThreadFromAllocations;
|
exports.getProfileThreadFromAllocations = getProfileThreadFromAllocations;
|
||||||
exports.getFilteredBlueprint = getFilteredBlueprint;
|
|
||||||
exports.deflateProfile = deflateProfile;
|
exports.deflateProfile = deflateProfile;
|
||||||
exports.deflateThread = deflateThread;
|
exports.deflateThread = deflateThread;
|
||||||
exports.UniqueStrings = UniqueStrings;
|
exports.UniqueStrings = UniqueStrings;
|
||||||
|
|
|
@ -7,27 +7,25 @@
|
||||||
* Utility functions for collapsing markers into a waterfall.
|
* Utility functions for collapsing markers into a waterfall.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
|
loader.lazyRequireGetter(this, "getBlueprintFor",
|
||||||
"devtools/performance/markers", true);
|
"devtools/performance/marker-utils", true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collapses markers into a tree-like structure.
|
* Collapses markers into a tree-like structure.
|
||||||
* @param object markerNode
|
* @param object markerNode
|
||||||
* @param array markersList
|
* @param array markersList
|
||||||
* @param ?object blueprint
|
|
||||||
*/
|
*/
|
||||||
function collapseMarkersIntoNode({ markerNode, markersList, blueprint }) {
|
function collapseMarkersIntoNode({ markerNode, markersList }) {
|
||||||
let { getCurrentParentNode, collapseMarker, addParentNode, popParentNode } = createParentNodeFactory(markerNode);
|
let { getCurrentParentNode, collapseMarker, addParentNode, popParentNode } = createParentNodeFactory(markerNode);
|
||||||
blueprint = blueprint || TIMELINE_BLUEPRINT;
|
|
||||||
|
|
||||||
for (let i = 0, len = markersList.length; i < len; i++) {
|
for (let i = 0, len = markersList.length; i < len; i++) {
|
||||||
let curr = markersList[i];
|
let curr = markersList[i];
|
||||||
|
|
||||||
let parentNode = getCurrentParentNode();
|
let parentNode = getCurrentParentNode();
|
||||||
let def = blueprint[curr.name];
|
let blueprint = getBlueprintFor(curr);
|
||||||
let collapse = def.collapseFunc || (() => null);
|
|
||||||
|
let collapse = blueprint.collapseFunc || (() => null);
|
||||||
let peek = distance => markersList[i + distance];
|
let peek = distance => markersList[i + distance];
|
||||||
let foundParent = false;
|
|
||||||
|
|
||||||
let collapseInfo = collapse(parentNode, curr, peek);
|
let collapseInfo = collapse(parentNode, curr, peek);
|
||||||
if (collapseInfo) {
|
if (collapseInfo) {
|
||||||
|
|
|
@ -55,6 +55,16 @@ const { Formatters, CollapseFunctions: collapse } = require("devtools/performanc
|
||||||
* updated as well.
|
* updated as well.
|
||||||
*/
|
*/
|
||||||
const TIMELINE_BLUEPRINT = {
|
const TIMELINE_BLUEPRINT = {
|
||||||
|
/* Default definition used for markers that occur but
|
||||||
|
* are not defined here. Should ultimately be defined, but this gives
|
||||||
|
* us room to work on the front end separately from the platform. */
|
||||||
|
"UNKNOWN": {
|
||||||
|
group: 2,
|
||||||
|
colorName: "graphs-grey",
|
||||||
|
collapseFunc: collapse.child,
|
||||||
|
label: Formatters.UnknownLabel
|
||||||
|
},
|
||||||
|
|
||||||
/* Group 0 - Reflow and Rendering pipeline */
|
/* Group 0 - Reflow and Rendering pipeline */
|
||||||
"Styles": {
|
"Styles": {
|
||||||
group: 0,
|
group: 0,
|
||||||
|
@ -131,7 +141,7 @@ const TIMELINE_BLUEPRINT = {
|
||||||
/* Group 2 - User Controlled */
|
/* Group 2 - User Controlled */
|
||||||
"ConsoleTime": {
|
"ConsoleTime": {
|
||||||
group: 2,
|
group: 2,
|
||||||
colorName: "graphs-grey",
|
colorName: "graphs-blue",
|
||||||
label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
|
label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
|
||||||
fields: [{
|
fields: [{
|
||||||
property: "causeName",
|
property: "causeName",
|
||||||
|
|
|
@ -135,8 +135,8 @@ MemoryGraph.prototype = Heritage.extend(PerformanceGraph.prototype, {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function TimelineGraph(parent, blueprint) {
|
function TimelineGraph(parent, filter) {
|
||||||
MarkersOverview.call(this, parent, blueprint);
|
MarkersOverview.call(this, parent, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineGraph.prototype = Heritage.extend(MarkersOverview.prototype, {
|
TimelineGraph.prototype = Heritage.extend(MarkersOverview.prototype, {
|
||||||
|
@ -163,7 +163,6 @@ const GRAPH_DEFINITIONS = {
|
||||||
timeline: {
|
timeline: {
|
||||||
constructor: TimelineGraph,
|
constructor: TimelineGraph,
|
||||||
selector: "#markers-overview",
|
selector: "#markers-overview",
|
||||||
needsBlueprints: true,
|
|
||||||
primaryLink: true
|
primaryLink: true
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -174,15 +173,15 @@ const GRAPH_DEFINITIONS = {
|
||||||
*
|
*
|
||||||
* @param {object} definition
|
* @param {object} definition
|
||||||
* @param {DOMElement} root
|
* @param {DOMElement} root
|
||||||
* @param {function} getBlueprint
|
* @param {function} getFilter
|
||||||
* @param {function} getTheme
|
* @param {function} getTheme
|
||||||
*/
|
*/
|
||||||
function GraphsController ({ definition, root, getBlueprint, getTheme }) {
|
function GraphsController ({ definition, root, getFilter, getTheme }) {
|
||||||
this._graphs = {};
|
this._graphs = {};
|
||||||
this._enabled = new Set();
|
this._enabled = new Set();
|
||||||
this._definition = definition || GRAPH_DEFINITIONS;
|
this._definition = definition || GRAPH_DEFINITIONS;
|
||||||
this._root = root;
|
this._root = root;
|
||||||
this._getBlueprint = getBlueprint;
|
this._getFilter = getFilter;
|
||||||
this._getTheme = getTheme;
|
this._getTheme = getTheme;
|
||||||
this._primaryLink = Object.keys(this._definition).filter(name => this._definition[name].primaryLink)[0];
|
this._primaryLink = Object.keys(this._definition).filter(name => this._definition[name].primaryLink)[0];
|
||||||
this.$ = root.ownerDocument.querySelector.bind(root.ownerDocument);
|
this.$ = root.ownerDocument.querySelector.bind(root.ownerDocument);
|
||||||
|
@ -369,8 +368,8 @@ GraphsController.prototype = {
|
||||||
_construct: Task.async(function *(graphName) {
|
_construct: Task.async(function *(graphName) {
|
||||||
let def = this._definition[graphName];
|
let def = this._definition[graphName];
|
||||||
let el = this.$(def.selector);
|
let el = this.$(def.selector);
|
||||||
let blueprint = def.needsBlueprints ? this._getBlueprint() : void 0;
|
let filter = this._getFilter();
|
||||||
let graph = this._graphs[graphName] = new def.constructor(el, blueprint);
|
let graph = this._graphs[graphName] = new def.constructor(el, filter);
|
||||||
graph.graphName = graphName;
|
graph.graphName = graphName;
|
||||||
|
|
||||||
yield graph.ready();
|
yield graph.ready();
|
||||||
|
|
|
@ -13,8 +13,6 @@ loader.lazyRequireGetter(this, "EventEmitter",
|
||||||
"devtools/toolkit/event-emitter");
|
"devtools/toolkit/event-emitter");
|
||||||
loader.lazyRequireGetter(this, "L10N",
|
loader.lazyRequireGetter(this, "L10N",
|
||||||
"devtools/performance/global", true);
|
"devtools/performance/global", true);
|
||||||
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
|
|
||||||
"devtools/performance/markers", true);
|
|
||||||
loader.lazyRequireGetter(this, "MarkerUtils",
|
loader.lazyRequireGetter(this, "MarkerUtils",
|
||||||
"devtools/performance/marker-utils");
|
"devtools/performance/marker-utils");
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,10 @@
|
||||||
const { Cc, Ci, Cu, Cr } = require("chrome");
|
const { Cc, Ci, Cu, Cr } = require("chrome");
|
||||||
const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
|
const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
|
||||||
const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
|
const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
|
||||||
const { TIMELINE_BLUEPRINT: ORIGINAL_BP } = require("devtools/performance/markers");
|
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "MarkerUtils",
|
loader.lazyRequireGetter(this, "MarkerUtils",
|
||||||
"devtools/performance/marker-utils");
|
"devtools/performance/marker-utils");
|
||||||
|
|
||||||
|
|
||||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||||
|
|
||||||
const LEVEL_INDENT = 10; // px
|
const LEVEL_INDENT = 10; // px
|
||||||
|
@ -60,15 +59,14 @@ MarkerView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a list of names and colors used to paint markers.
|
* Sets a list of marker types to be filtered out of this view.
|
||||||
* @see TIMELINE_BLUEPRINT in timeline/widgets/global.js
|
* @param Array<String> filter
|
||||||
* @param object blueprint
|
|
||||||
*/
|
*/
|
||||||
set blueprint(blueprint) {
|
set filter(filter) {
|
||||||
this.root._blueprint = blueprint;
|
this.root._filter = filter;
|
||||||
},
|
},
|
||||||
get blueprint() {
|
get filter() {
|
||||||
return this.root._blueprint;
|
return this.root._filter;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -139,7 +137,6 @@ MarkerView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||||
if (!submarkers || !submarkers.length) {
|
if (!submarkers || !submarkers.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let blueprint = this.root._blueprint;
|
|
||||||
let startTime = this.root._interval.startTime;
|
let startTime = this.root._interval.startTime;
|
||||||
let endTime = this.root._interval.endTime;
|
let endTime = this.root._interval.endTime;
|
||||||
let newLevel = this.level + 1;
|
let newLevel = this.level + 1;
|
||||||
|
@ -147,17 +144,15 @@ MarkerView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||||
for (let i = 0, len = submarkers.length; i < len; i++) {
|
for (let i = 0, len = submarkers.length; i < len; i++) {
|
||||||
let marker = submarkers[i];
|
let marker = submarkers[i];
|
||||||
|
|
||||||
// If this marker isn't in the global timeline blueprint, don't display
|
// Skip filtered markers
|
||||||
// it, but dump a warning message to the console.
|
if (!MarkerUtils.isMarkerValid(marker, this.filter)) {
|
||||||
if (!(marker.name in blueprint)) {
|
|
||||||
if (!(marker.name in ORIGINAL_BP)) {
|
|
||||||
console.warn(`Marker not found in timeline blueprint: ${marker.name}.`);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isMarkerInRange(marker, startTime|0, endTime|0)) {
|
if (!isMarkerInRange(marker, startTime|0, endTime|0)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
children.push(new MarkerView({
|
children.push(new MarkerView({
|
||||||
owner: this,
|
owner: this,
|
||||||
marker: marker,
|
marker: marker,
|
||||||
|
@ -175,15 +170,12 @@ MarkerView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
|
||||||
*/
|
*/
|
||||||
_buildMarkerCells: function(doc, targetNode, arrowNode) {
|
_buildMarkerCells: function(doc, targetNode, arrowNode) {
|
||||||
let marker = this.marker;
|
let marker = this.marker;
|
||||||
let style = this.root._blueprint[marker.name];
|
let blueprint = MarkerUtils.getBlueprintFor(marker);
|
||||||
let startTime = this.root._interval.startTime;
|
let startTime = this.root._interval.startTime;
|
||||||
let endTime = this.root._interval.endTime;
|
let endTime = this.root._interval.endTime;
|
||||||
|
|
||||||
let sidebarCell = this._buildMarkerSidebar(
|
let sidebarCell = this._buildMarkerSidebar(doc, blueprint, marker);
|
||||||
doc, style, marker);
|
let timebarCell = this._buildMarkerTimebar(doc, blueprint, marker, startTime, endTime, arrowNode);
|
||||||
|
|
||||||
let timebarCell = this._buildMarkerTimebar(
|
|
||||||
doc, style, marker, startTime, endTime, arrowNode);
|
|
||||||
|
|
||||||
targetNode.appendChild(sidebarCell);
|
targetNode.appendChild(sidebarCell);
|
||||||
targetNode.appendChild(timebarCell);
|
targetNode.appendChild(timebarCell);
|
||||||
|
|
|
@ -21,6 +21,10 @@ loader.lazyRequireGetter(this, "L10N",
|
||||||
"devtools/performance/global", true);
|
"devtools/performance/global", true);
|
||||||
loader.lazyRequireGetter(this, "TickUtils",
|
loader.lazyRequireGetter(this, "TickUtils",
|
||||||
"devtools/performance/waterfall-ticks", true);
|
"devtools/performance/waterfall-ticks", true);
|
||||||
|
loader.lazyRequireGetter(this, "MarkerUtils",
|
||||||
|
"devtools/performance/marker-utils");
|
||||||
|
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
|
||||||
|
"devtools/performance/markers", true);
|
||||||
|
|
||||||
const OVERVIEW_HEADER_HEIGHT = 14; // px
|
const OVERVIEW_HEADER_HEIGHT = 14; // px
|
||||||
const OVERVIEW_ROW_HEIGHT = 11; // px
|
const OVERVIEW_ROW_HEIGHT = 11; // px
|
||||||
|
@ -28,14 +32,12 @@ const OVERVIEW_ROW_HEIGHT = 11; // px
|
||||||
const OVERVIEW_SELECTION_LINE_COLOR = "#666";
|
const OVERVIEW_SELECTION_LINE_COLOR = "#666";
|
||||||
const OVERVIEW_CLIPHEAD_LINE_COLOR = "#555";
|
const OVERVIEW_CLIPHEAD_LINE_COLOR = "#555";
|
||||||
|
|
||||||
const FIND_OPTIMAL_TICK_INTERVAL_MAX_ITERS = 100;
|
|
||||||
const OVERVIEW_HEADER_TICKS_MULTIPLE = 100; // ms
|
const OVERVIEW_HEADER_TICKS_MULTIPLE = 100; // ms
|
||||||
const OVERVIEW_HEADER_TICKS_SPACING_MIN = 75; // px
|
const OVERVIEW_HEADER_TICKS_SPACING_MIN = 75; // px
|
||||||
const OVERVIEW_HEADER_TEXT_FONT_SIZE = 9; // px
|
const OVERVIEW_HEADER_TEXT_FONT_SIZE = 9; // px
|
||||||
const OVERVIEW_HEADER_TEXT_FONT_FAMILY = "sans-serif";
|
const OVERVIEW_HEADER_TEXT_FONT_FAMILY = "sans-serif";
|
||||||
const OVERVIEW_HEADER_TEXT_PADDING_LEFT = 6; // px
|
const OVERVIEW_HEADER_TEXT_PADDING_LEFT = 6; // px
|
||||||
const OVERVIEW_HEADER_TEXT_PADDING_TOP = 1; // px
|
const OVERVIEW_HEADER_TEXT_PADDING_TOP = 1; // px
|
||||||
const OVERVIEW_MARKERS_COLOR_STOPS = [0, 0.1, 0.75, 1];
|
|
||||||
const OVERVIEW_MARKER_WIDTH_MIN = 4; // px
|
const OVERVIEW_MARKER_WIDTH_MIN = 4; // px
|
||||||
const OVERVIEW_GROUP_VERTICAL_PADDING = 5; // px
|
const OVERVIEW_GROUP_VERTICAL_PADDING = 5; // px
|
||||||
|
|
||||||
|
@ -44,13 +46,13 @@ const OVERVIEW_GROUP_VERTICAL_PADDING = 5; // px
|
||||||
*
|
*
|
||||||
* @param nsIDOMNode parent
|
* @param nsIDOMNode parent
|
||||||
* The parent node holding the overview.
|
* The parent node holding the overview.
|
||||||
* @param Object blueprint
|
* @param Array<String> filter
|
||||||
* List of names and colors defining markers.
|
* List of names of marker types that should not be shown.
|
||||||
*/
|
*/
|
||||||
function MarkersOverview(parent, blueprint, ...args) {
|
function MarkersOverview(parent, filter=[], ...args) {
|
||||||
AbstractCanvasGraph.apply(this, [parent, "markers-overview", ...args]);
|
AbstractCanvasGraph.apply(this, [parent, "markers-overview", ...args]);
|
||||||
this.setTheme();
|
this.setTheme();
|
||||||
this.setBlueprint(blueprint);
|
this.setFilter(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||||
|
@ -64,21 +66,36 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||||
* Compute the height of the overview.
|
* Compute the height of the overview.
|
||||||
*/
|
*/
|
||||||
get fixedHeight() {
|
get fixedHeight() {
|
||||||
return this.headerHeight + this.rowHeight * (this._lastGroup + 1);
|
return this.headerHeight + this.rowHeight * this._numberOfGroups;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of names and colors used to paint this overview.
|
* List of marker types that should not be shown in the graph.
|
||||||
* @see TIMELINE_BLUEPRINT in timeline/widgets/global.js
|
|
||||||
*/
|
*/
|
||||||
setBlueprint: function(blueprint) {
|
setFilter: function (filter) {
|
||||||
this._paintBatches = new Map();
|
this._paintBatches = new Map();
|
||||||
this._lastGroup = 0;
|
this._filter = filter;
|
||||||
|
this._groupMap = Object.create(null);
|
||||||
|
|
||||||
for (let type in blueprint) {
|
let observedGroups = new Set();
|
||||||
this._paintBatches.set(type, { style: blueprint[type], batch: [] });
|
|
||||||
this._lastGroup = Math.max(this._lastGroup, blueprint[type].group || 0);
|
for (let type in TIMELINE_BLUEPRINT) {
|
||||||
|
if (filter.indexOf(type) !== -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
this._paintBatches.set(type, { definition: TIMELINE_BLUEPRINT[type], batch: [] });
|
||||||
|
observedGroups.add(TIMELINE_BLUEPRINT[type].group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Take our set of observed groups and order them and map
|
||||||
|
// the group numbers to fill in the holes via `_groupMap`.
|
||||||
|
// This normalizes our rows by removing rows that aren't used
|
||||||
|
// if filters are enabled.
|
||||||
|
let actualPosition = 0;
|
||||||
|
for (let groupNumber of Array.from(observedGroups).sort()) {
|
||||||
|
this._groupMap[groupNumber] = actualPosition++;
|
||||||
|
}
|
||||||
|
this._numberOfGroups = Object.keys(this._groupMap).length;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,17 +120,19 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||||
|
|
||||||
// Group markers into separate paint batches. This is necessary to
|
// Group markers into separate paint batches. This is necessary to
|
||||||
// draw all markers sharing the same style at once.
|
// draw all markers sharing the same style at once.
|
||||||
|
|
||||||
for (let marker of markers) {
|
for (let marker of markers) {
|
||||||
let markerType = this._paintBatches.get(marker.name);
|
// Again skip over markers that we're filtering -- we don't want them
|
||||||
if (markerType) {
|
// to be labeled as "Unknown"
|
||||||
markerType.batch.push(marker);
|
if (!MarkerUtils.isMarkerValid(marker, this._filter)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let markerType = this._paintBatches.get(marker.name) || this._paintBatches.get("UNKNOWN");
|
||||||
|
markerType.batch.push(marker);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate each row's height, and the time-based scaling.
|
// Calculate each row's height, and the time-based scaling.
|
||||||
|
|
||||||
let totalGroups = this._lastGroup + 1;
|
|
||||||
let groupHeight = this.rowHeight * this._pixelRatio;
|
let groupHeight = this.rowHeight * this._pixelRatio;
|
||||||
let groupPadding = this.groupPadding * this._pixelRatio;
|
let groupPadding = this.groupPadding * this._pixelRatio;
|
||||||
let headerHeight = this.headerHeight * this._pixelRatio;
|
let headerHeight = this.headerHeight * this._pixelRatio;
|
||||||
|
@ -132,7 +151,7 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||||
ctx.fillStyle = this.alternatingBackgroundColor;
|
ctx.fillStyle = this.alternatingBackgroundColor;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
|
|
||||||
for (let i = 0; i < totalGroups; i += 2) {
|
for (let i = 0; i < this._numberOfGroups; i += 2) {
|
||||||
let top = headerHeight + i * groupHeight;
|
let top = headerHeight + i * groupHeight;
|
||||||
ctx.rect(0, top, canvasWidth, groupHeight);
|
ctx.rect(0, top, canvasWidth, groupHeight);
|
||||||
}
|
}
|
||||||
|
@ -172,11 +191,12 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
|
||||||
|
|
||||||
// Draw the timeline markers.
|
// Draw the timeline markers.
|
||||||
|
|
||||||
for (let [, { style, batch }] of this._paintBatches) {
|
for (let [, { definition, batch }] of this._paintBatches) {
|
||||||
let top = headerHeight + style.group * groupHeight + groupPadding / 2;
|
let group = this._groupMap[definition.group];
|
||||||
|
let top = headerHeight + group * groupHeight + groupPadding / 2;
|
||||||
let height = groupHeight - groupPadding;
|
let height = groupHeight - groupPadding;
|
||||||
|
|
||||||
let color = getColor(style.colorName, this.theme);
|
let color = getColor(definition.colorName, this.theme);
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
|
|
||||||
|
|
|
@ -398,16 +398,6 @@ let PerformanceController = {
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current timeline blueprint without the hidden markers.
|
|
||||||
* @return object
|
|
||||||
*/
|
|
||||||
getTimelineBlueprint: function() {
|
|
||||||
let blueprint = TIMELINE_BLUEPRINT;
|
|
||||||
let hiddenMarkers = this.getPref("hidden-markers");
|
|
||||||
return RecordingUtils.getFilteredBlueprint({ blueprint, hiddenMarkers });
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired from RecordingsView, we listen on the PerformanceController so we can
|
* Fired from RecordingsView, we listen on the PerformanceController so we can
|
||||||
* set it here and re-emit on the controller, where all views can listen.
|
* set it here and re-emit on the controller, where all views can listen.
|
||||||
|
|
|
@ -13,7 +13,6 @@ support-files =
|
||||||
# that need to be moved over to performance tool
|
# that need to be moved over to performance tool
|
||||||
|
|
||||||
[browser_aaa-run-first-leaktest.js]
|
[browser_aaa-run-first-leaktest.js]
|
||||||
[browser_marker-utils.js]
|
|
||||||
[browser_markers-cycle-collection.js]
|
[browser_markers-cycle-collection.js]
|
||||||
[browser_markers-gc.js]
|
[browser_markers-gc.js]
|
||||||
[browser_markers-parse-html.js]
|
[browser_markers-parse-html.js]
|
||||||
|
@ -137,7 +136,6 @@ support-files =
|
||||||
[browser_profiler_tree-view-08.js]
|
[browser_profiler_tree-view-08.js]
|
||||||
[browser_profiler_tree-view-09.js]
|
[browser_profiler_tree-view-09.js]
|
||||||
[browser_profiler_tree-view-10.js]
|
[browser_profiler_tree-view-10.js]
|
||||||
[browser_timeline-blueprint.js]
|
|
||||||
[browser_timeline-filters.js]
|
[browser_timeline-filters.js]
|
||||||
[browser_timeline-waterfall-background.js]
|
[browser_timeline-waterfall-background.js]
|
||||||
[browser_timeline-waterfall-generic.js]
|
[browser_timeline-waterfall-generic.js]
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the marker utils methods.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function* spawnTest() {
|
|
||||||
let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
|
|
||||||
let Utils = devtools.require("devtools/performance/marker-utils");
|
|
||||||
|
|
||||||
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
|
|
||||||
|
|
||||||
is(Utils.getMarkerLabel({ name: "DOMEvent" }), "DOM Event",
|
|
||||||
"getMarkerLabel() returns a simple label");
|
|
||||||
is(Utils.getMarkerLabel({ name: "Javascript", causeName: "setTimeout handler" }), "setTimeout",
|
|
||||||
"getMarkerLabel() returns a label defined via function");
|
|
||||||
|
|
||||||
ok(Utils.getMarkerFields({ name: "Paint" }).length === 0,
|
|
||||||
"getMarkerFields() returns an empty array when no fields defined");
|
|
||||||
|
|
||||||
let fields = Utils.getMarkerFields({ name: "ConsoleTime", causeName: "snowstorm" });
|
|
||||||
is(fields[0].label, "Timer Name:", "getMarkerFields() returns an array with proper label");
|
|
||||||
is(fields[0].value, "snowstorm", "getMarkerFields() returns an array with proper value");
|
|
||||||
|
|
||||||
fields = Utils.getMarkerFields({ name: "DOMEvent", type: "mouseclick" });
|
|
||||||
is(fields.length, 1, "getMarkerFields() ignores fields that are not found on marker");
|
|
||||||
is(fields[0].label, "Event Type:", "getMarkerFields() returns an array with proper label");
|
|
||||||
is(fields[0].value, "mouseclick", "getMarkerFields() returns an array with proper value");
|
|
||||||
|
|
||||||
fields = Utils.getMarkerFields({ name: "DOMEvent", eventPhase: Ci.nsIDOMEvent.AT_TARGET, type: "mouseclick" });
|
|
||||||
is(fields.length, 2, "getMarkerFields() returns multiple fields when using a fields function");
|
|
||||||
is(fields[0].label, "Event Type:", "getMarkerFields() correctly returns fields via function (1)");
|
|
||||||
is(fields[0].value, "mouseclick", "getMarkerFields() correctly returns fields via function (2)");
|
|
||||||
is(fields[1].label, "Phase:", "getMarkerFields() correctly returns fields via function (3)");
|
|
||||||
is(fields[1].value, "Target", "getMarkerFields() correctly returns fields via function (4)");
|
|
||||||
|
|
||||||
is(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "(Gecko)",
|
|
||||||
"Correctly obfuscates JS markers when platform data is off.");
|
|
||||||
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
|
|
||||||
is(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "Some Platform Field",
|
|
||||||
"Correctly deobfuscates JS markers when platform data is on.");
|
|
||||||
|
|
||||||
is(Utils.getMarkerClassName("Javascript"), "Function Call",
|
|
||||||
"getMarkerClassName() returns correct string when defined via function");
|
|
||||||
is(Utils.getMarkerClassName("GarbageCollection"), "GC Event",
|
|
||||||
"getMarkerClassName() returns correct string when defined via function");
|
|
||||||
is(Utils.getMarkerClassName("Reflow"), "Layout",
|
|
||||||
"getMarkerClassName() returns correct string when defined via string");
|
|
||||||
|
|
||||||
TIMELINE_BLUEPRINT["fakemarker"] = { group: 0 };
|
|
||||||
try {
|
|
||||||
Utils.getMarkerClassName("fakemarker");
|
|
||||||
ok(false, "getMarkerClassName() should throw when no label on blueprint.");
|
|
||||||
} catch (e) {
|
|
||||||
ok(true, "getMarkerClassName() should throw when no label on blueprint.");
|
|
||||||
}
|
|
||||||
|
|
||||||
TIMELINE_BLUEPRINT["fakemarker"] = { group: 0, label: () => void 0};
|
|
||||||
try {
|
|
||||||
Utils.getMarkerClassName("fakemarker");
|
|
||||||
ok(false, "getMarkerClassName() should throw when label function returnd undefined.");
|
|
||||||
} catch (e) {
|
|
||||||
ok(true, "getMarkerClassName() should throw when label function returnd undefined.");
|
|
||||||
}
|
|
||||||
|
|
||||||
delete TIMELINE_BLUEPRINT["fakemarker"];
|
|
||||||
|
|
||||||
finish();
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests if the timeline blueprint has a correct structure.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function* spawnTest() {
|
|
||||||
let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
|
|
||||||
|
|
||||||
ok(TIMELINE_BLUEPRINT,
|
|
||||||
"A timeline blueprint should be available.");
|
|
||||||
|
|
||||||
ok(Object.keys(TIMELINE_BLUEPRINT).length,
|
|
||||||
"The timeline blueprint has at least one entry.");
|
|
||||||
|
|
||||||
for (let [key, value] of Iterator(TIMELINE_BLUEPRINT)) {
|
|
||||||
if (key.startsWith("meta::")) {
|
|
||||||
ok(!("group" in value),
|
|
||||||
"No meta entry in the timeline blueprint can contain a `group` key.");
|
|
||||||
ok("colorName" in value,
|
|
||||||
"Each meta entry in the timeline blueprint contains a `colorName` key.");
|
|
||||||
ok("label" in value,
|
|
||||||
"Each meta entry in the timeline blueprint contains a `label` key.");
|
|
||||||
} else {
|
|
||||||
ok("group" in value,
|
|
||||||
"Each entry in the timeline blueprint contains a `group` key.");
|
|
||||||
ok("colorName" in value,
|
|
||||||
"Each entry in the timeline blueprint contains a `colorName` key.");
|
|
||||||
ok("label" in value,
|
|
||||||
"Each entry in the timeline blueprint contains a `label` key.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,6 +5,8 @@
|
||||||
* Tests markers filtering mechanism.
|
* Tests markers filtering mechanism.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const EPSILON = 0.00000001;
|
||||||
|
|
||||||
function* spawnTest() {
|
function* spawnTest() {
|
||||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||||
let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
|
let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
|
||||||
|
@ -24,20 +26,34 @@ function* spawnTest() {
|
||||||
|
|
||||||
yield stopRecording(panel);
|
yield stopRecording(panel);
|
||||||
|
|
||||||
|
// Push some fake markers of a type we do not have a blueprint for
|
||||||
|
let markers = PerformanceController.getCurrentRecording().getMarkers();
|
||||||
|
let endTime = markers[markers.length - 1].end;
|
||||||
|
markers.push({ name: "CustomMarker", start: endTime + EPSILON, end: endTime + (EPSILON * 2) });
|
||||||
|
markers.push({ name: "CustomMarker", start: endTime + (EPSILON * 3), end: endTime + (EPSILON * 4) });
|
||||||
|
|
||||||
|
// Invalidate marker cache
|
||||||
|
WaterfallView._cache.delete(markers);
|
||||||
|
|
||||||
// Select everything
|
// Select everything
|
||||||
OverviewView.setTimeInterval({ startTime: 0, endTime: Number.MAX_VALUE })
|
let waterfallRendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
|
||||||
|
OverviewView.setTimeInterval({ startTime: 0, endTime: Number.MAX_VALUE });
|
||||||
|
|
||||||
$("#filter-button").click();
|
$("#filter-button").click();
|
||||||
let menuItem1 = $("menuitem[marker-type=Styles]");
|
let menuItem1 = $("menuitem[marker-type=Styles]");
|
||||||
let menuItem2 = $("menuitem[marker-type=Reflow]");
|
let menuItem2 = $("menuitem[marker-type=Reflow]");
|
||||||
let menuItem3 = $("menuitem[marker-type=Paint]");
|
let menuItem3 = $("menuitem[marker-type=Paint]");
|
||||||
|
let menuItem4 = $("menuitem[marker-type=UNKNOWN]");
|
||||||
|
|
||||||
let overview = OverviewView.graphs.get("timeline");
|
let overview = OverviewView.graphs.get("timeline");
|
||||||
let originalHeight = overview.fixedHeight;
|
let originalHeight = overview.fixedHeight;
|
||||||
|
|
||||||
|
yield waterfallRendered;
|
||||||
|
|
||||||
ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (1)");
|
ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (1)");
|
||||||
ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (1)");
|
ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (1)");
|
||||||
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (1)");
|
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (1)");
|
||||||
|
ok($(".waterfall-marker-bar[type=CustomMarker]"), "Found at least one 'Unknown' marker (1)");
|
||||||
|
|
||||||
let heightBefore = overview.fixedHeight;
|
let heightBefore = overview.fixedHeight;
|
||||||
EventUtils.synthesizeMouseAtCenter(menuItem1, {type: "mouseup"}, panel.panelWin);
|
EventUtils.synthesizeMouseAtCenter(menuItem1, {type: "mouseup"}, panel.panelWin);
|
||||||
|
@ -47,6 +63,7 @@ function* spawnTest() {
|
||||||
ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (2)");
|
ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (2)");
|
||||||
ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (2)");
|
ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (2)");
|
||||||
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (2)");
|
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (2)");
|
||||||
|
ok($(".waterfall-marker-bar[type=CustomMarker]"), "Found at least one 'Unknown' marker (2)");
|
||||||
|
|
||||||
heightBefore = overview.fixedHeight;
|
heightBefore = overview.fixedHeight;
|
||||||
EventUtils.synthesizeMouseAtCenter(menuItem2, {type: "mouseup"}, panel.panelWin);
|
EventUtils.synthesizeMouseAtCenter(menuItem2, {type: "mouseup"}, panel.panelWin);
|
||||||
|
@ -56,6 +73,7 @@ function* spawnTest() {
|
||||||
ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (3)");
|
ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (3)");
|
||||||
ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (3)");
|
ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (3)");
|
||||||
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (3)");
|
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (3)");
|
||||||
|
ok($(".waterfall-marker-bar[type=CustomMarker]"), "Found at least one 'Unknown' marker (3)");
|
||||||
|
|
||||||
heightBefore = overview.fixedHeight;
|
heightBefore = overview.fixedHeight;
|
||||||
EventUtils.synthesizeMouseAtCenter(menuItem3, {type: "mouseup"}, panel.panelWin);
|
EventUtils.synthesizeMouseAtCenter(menuItem3, {type: "mouseup"}, panel.panelWin);
|
||||||
|
@ -65,15 +83,25 @@ function* spawnTest() {
|
||||||
ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (4)");
|
ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (4)");
|
||||||
ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (4)");
|
ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (4)");
|
||||||
ok(!$(".waterfall-marker-bar[type=Paint]"), "No 'Paint' marker (4)");
|
ok(!$(".waterfall-marker-bar[type=Paint]"), "No 'Paint' marker (4)");
|
||||||
|
ok($(".waterfall-marker-bar[type=CustomMarker]"), "Found at least one 'Unknown' marker (4)");
|
||||||
|
|
||||||
|
EventUtils.synthesizeMouseAtCenter(menuItem4, {type: "mouseup"}, panel.panelWin);
|
||||||
|
yield waitForOverviewAndCommand(overview, menuItem4);
|
||||||
|
|
||||||
|
ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (5)");
|
||||||
|
ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (5)");
|
||||||
|
ok(!$(".waterfall-marker-bar[type=Paint]"), "No 'Paint' marker (5)");
|
||||||
|
ok(!$(".waterfall-marker-bar[type=CustomMarker]"), "No 'Unknown' marker (5)");
|
||||||
|
|
||||||
for (let item of [menuItem1, menuItem2, menuItem3]) {
|
for (let item of [menuItem1, menuItem2, menuItem3]) {
|
||||||
EventUtils.synthesizeMouseAtCenter(item, {type: "mouseup"}, panel.panelWin);
|
EventUtils.synthesizeMouseAtCenter(item, {type: "mouseup"}, panel.panelWin);
|
||||||
yield waitForOverviewAndCommand(overview, item);
|
yield waitForOverviewAndCommand(overview, item);
|
||||||
}
|
}
|
||||||
|
|
||||||
ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (5)");
|
ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (6)");
|
||||||
ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (5)");
|
ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (6)");
|
||||||
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (5)");
|
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (6)");
|
||||||
|
ok(!$(".waterfall-marker-bar[type=CustomMarker]"), "No 'Unknown' marker (6)");
|
||||||
|
|
||||||
is(overview.fixedHeight, originalHeight, "Overview restored");
|
is(overview.fixedHeight, originalHeight, "Overview restored");
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ let DEFAULT_PREFS = [
|
||||||
"devtools.performance.profiler.buffer-size",
|
"devtools.performance.profiler.buffer-size",
|
||||||
"devtools.performance.profiler.sample-frequency-khz",
|
"devtools.performance.profiler.sample-frequency-khz",
|
||||||
"devtools.performance.ui.experimental",
|
"devtools.performance.ui.experimental",
|
||||||
|
"devtools.performance.timeline.hidden-markers",
|
||||||
].reduce((prefs, pref) => {
|
].reduce((prefs, pref) => {
|
||||||
prefs[pref] = Preferences.get(pref);
|
prefs[pref] = Preferences.get(pref);
|
||||||
return prefs;
|
return prefs;
|
||||||
|
|
|
@ -5,8 +5,11 @@
|
||||||
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
||||||
|
|
||||||
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||||
|
let { Services } = Cu.import("resource://gre/modules/Services.jsm", {});
|
||||||
const RecordingUtils = devtools.require("devtools/performance/recording-utils");
|
const RecordingUtils = devtools.require("devtools/performance/recording-utils");
|
||||||
|
|
||||||
|
const PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a path in a FrameNode call tree.
|
* Get a path in a FrameNode call tree.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests if the timeline blueprint has a correct structure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(function () {
|
||||||
|
let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
|
||||||
|
|
||||||
|
ok(TIMELINE_BLUEPRINT,
|
||||||
|
"A timeline blueprint should be available.");
|
||||||
|
|
||||||
|
ok(Object.keys(TIMELINE_BLUEPRINT).length,
|
||||||
|
"The timeline blueprint has at least one entry.");
|
||||||
|
|
||||||
|
for (let [key, value] of Iterator(TIMELINE_BLUEPRINT)) {
|
||||||
|
ok("group" in value,
|
||||||
|
"Each entry in the timeline blueprint contains a `group` key.");
|
||||||
|
ok("colorName" in value,
|
||||||
|
"Each entry in the timeline blueprint contains a `colorName` key.");
|
||||||
|
ok("label" in value,
|
||||||
|
"Each entry in the timeline blueprint contains a `label` key.");
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,88 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the marker utils methods.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
add_task(function () {
|
||||||
|
let { TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/markers");
|
||||||
|
let Utils = devtools.require("devtools/performance/marker-utils");
|
||||||
|
|
||||||
|
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
|
||||||
|
|
||||||
|
equal(Utils.getMarkerLabel({ name: "DOMEvent" }), "DOM Event",
|
||||||
|
"getMarkerLabel() returns a simple label");
|
||||||
|
equal(Utils.getMarkerLabel({ name: "Javascript", causeName: "setTimeout handler" }), "setTimeout",
|
||||||
|
"getMarkerLabel() returns a label defined via function");
|
||||||
|
|
||||||
|
ok(Utils.getMarkerFields({ name: "Paint" }).length === 0,
|
||||||
|
"getMarkerFields() returns an empty array when no fields defined");
|
||||||
|
|
||||||
|
let fields = Utils.getMarkerFields({ name: "ConsoleTime", causeName: "snowstorm" });
|
||||||
|
equal(fields[0].label, "Timer Name:", "getMarkerFields() returns an array with proper label");
|
||||||
|
equal(fields[0].value, "snowstorm", "getMarkerFields() returns an array with proper value");
|
||||||
|
|
||||||
|
fields = Utils.getMarkerFields({ name: "DOMEvent", type: "mouseclick" });
|
||||||
|
equal(fields.length, 1, "getMarkerFields() ignores fields that are not found on marker");
|
||||||
|
equal(fields[0].label, "Event Type:", "getMarkerFields() returns an array with proper label");
|
||||||
|
equal(fields[0].value, "mouseclick", "getMarkerFields() returns an array with proper value");
|
||||||
|
|
||||||
|
fields = Utils.getMarkerFields({ name: "DOMEvent", eventPhase: Ci.nsIDOMEvent.AT_TARGET, type: "mouseclick" });
|
||||||
|
equal(fields.length, 2, "getMarkerFields() returns multiple fields when using a fields function");
|
||||||
|
equal(fields[0].label, "Event Type:", "getMarkerFields() correctly returns fields via function (1)");
|
||||||
|
equal(fields[0].value, "mouseclick", "getMarkerFields() correctly returns fields via function (2)");
|
||||||
|
equal(fields[1].label, "Phase:", "getMarkerFields() correctly returns fields via function (3)");
|
||||||
|
equal(fields[1].value, "Target", "getMarkerFields() correctly returns fields via function (4)");
|
||||||
|
|
||||||
|
equal(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "(Gecko)",
|
||||||
|
"Correctly obfuscates JS markers when platform data is off.");
|
||||||
|
Services.prefs.setBoolPref(PLATFORM_DATA_PREF, true);
|
||||||
|
equal(Utils.getMarkerFields({ name: "Javascript", causeName: "Some Platform Field" })[0].value, "Some Platform Field",
|
||||||
|
"Correctly deobfuscates JS markers when platform data is on.");
|
||||||
|
|
||||||
|
equal(Utils.getMarkerClassName("Javascript"), "Function Call",
|
||||||
|
"getMarkerClassName() returns correct string when defined via function");
|
||||||
|
equal(Utils.getMarkerClassName("GarbageCollection"), "GC Event",
|
||||||
|
"getMarkerClassName() returns correct string when defined via function");
|
||||||
|
equal(Utils.getMarkerClassName("Reflow"), "Layout",
|
||||||
|
"getMarkerClassName() returns correct string when defined via string");
|
||||||
|
|
||||||
|
TIMELINE_BLUEPRINT["fakemarker"] = { group: 0 };
|
||||||
|
try {
|
||||||
|
Utils.getMarkerClassName("fakemarker");
|
||||||
|
ok(false, "getMarkerClassName() should throw when no label on blueprint.");
|
||||||
|
} catch (e) {
|
||||||
|
ok(true, "getMarkerClassName() should throw when no label on blueprint.");
|
||||||
|
}
|
||||||
|
|
||||||
|
TIMELINE_BLUEPRINT["fakemarker"] = { group: 0, label: () => void 0};
|
||||||
|
try {
|
||||||
|
Utils.getMarkerClassName("fakemarker");
|
||||||
|
ok(false, "getMarkerClassName() should throw when label function returnd undefined.");
|
||||||
|
} catch (e) {
|
||||||
|
ok(true, "getMarkerClassName() should throw when label function returnd undefined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
delete TIMELINE_BLUEPRINT["fakemarker"];
|
||||||
|
|
||||||
|
let customBlueprint = {
|
||||||
|
UNKNOWN: {
|
||||||
|
group: 1,
|
||||||
|
label: "MyDefault"
|
||||||
|
},
|
||||||
|
custom: {
|
||||||
|
group: 0,
|
||||||
|
label: "MyCustom"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
equal(Utils.getBlueprintFor({ name: "Reflow" }).label, "Layout",
|
||||||
|
"Utils.getBlueprintFor() should return marker def for passed in marker.");
|
||||||
|
equal(Utils.getBlueprintFor({ name: "Not sure!" }).label(), "Unknown",
|
||||||
|
"Utils.getBlueprintFor() should return a default marker def if the marker is undefined.");
|
||||||
|
});
|
|
@ -5,9 +5,11 @@ tail =
|
||||||
firefox-appdir = browser
|
firefox-appdir = browser
|
||||||
skip-if = toolkit == 'android' || toolkit == 'gonk'
|
skip-if = toolkit == 'android' || toolkit == 'gonk'
|
||||||
|
|
||||||
[test_profiler-categories.js]
|
|
||||||
[test_frame-utils-01.js]
|
[test_frame-utils-01.js]
|
||||||
[test_frame-utils-02.js]
|
[test_frame-utils-02.js]
|
||||||
|
[test_marker-blueprint.js]
|
||||||
|
[test_marker-utils.js]
|
||||||
|
[test_profiler-categories.js]
|
||||||
[test_tree-model-01.js]
|
[test_tree-model-01.js]
|
||||||
[test_tree-model-02.js]
|
[test_tree-model-02.js]
|
||||||
[test_tree-model-03.js]
|
[test_tree-model-03.js]
|
||||||
|
|
|
@ -32,6 +32,7 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
|
||||||
this._onMarkerSelected = this._onMarkerSelected.bind(this);
|
this._onMarkerSelected = this._onMarkerSelected.bind(this);
|
||||||
this._onResize = this._onResize.bind(this);
|
this._onResize = this._onResize.bind(this);
|
||||||
this._onViewSource = this._onViewSource.bind(this);
|
this._onViewSource = this._onViewSource.bind(this);
|
||||||
|
this._hiddenMarkers = PerformanceController.getPref("hidden-markers");
|
||||||
|
|
||||||
this.headerContainer = $("#waterfall-header");
|
this.headerContainer = $("#waterfall-header");
|
||||||
this.breakdownContainer = $("#waterfall-breakdown");
|
this.breakdownContainer = $("#waterfall-breakdown");
|
||||||
|
@ -111,8 +112,7 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
|
||||||
* Called whenever an observed pref is changed.
|
* Called whenever an observed pref is changed.
|
||||||
*/
|
*/
|
||||||
_onObservedPrefChange: function(_, prefName) {
|
_onObservedPrefChange: function(_, prefName) {
|
||||||
let blueprint = PerformanceController.getTimelineBlueprint();
|
this._hiddenMarkers = PerformanceController.getPref("hidden-markers");
|
||||||
this._markersRoot.blueprint = blueprint;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -136,7 +136,7 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
|
||||||
|
|
||||||
WaterfallUtils.collapseMarkersIntoNode({
|
WaterfallUtils.collapseMarkersIntoNode({
|
||||||
markerNode: rootMarkerNode,
|
markerNode: rootMarkerNode,
|
||||||
markersList: markers
|
markersList: markers,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._cache.set(markers, rootMarkerNode);
|
this._cache.set(markers, rootMarkerNode);
|
||||||
|
@ -160,8 +160,7 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
|
||||||
this._markersRoot = root;
|
this._markersRoot = root;
|
||||||
this._waterfallHeader = header;
|
this._waterfallHeader = header;
|
||||||
|
|
||||||
let blueprint = PerformanceController.getTimelineBlueprint();
|
root.filter = this._hiddenMarkers;
|
||||||
root.blueprint = blueprint;
|
|
||||||
root.interval = interval;
|
root.interval = interval;
|
||||||
root.on("selected", this._onMarkerSelected);
|
root.on("selected", this._onMarkerSelected);
|
||||||
root.on("unselected", this._onMarkerSelected);
|
root.on("unselected", this._onMarkerSelected);
|
||||||
|
|
|
@ -42,7 +42,7 @@ let OverviewView = {
|
||||||
initialize: function () {
|
initialize: function () {
|
||||||
this.graphs = new GraphsController({
|
this.graphs = new GraphsController({
|
||||||
root: $("#overview-pane"),
|
root: $("#overview-pane"),
|
||||||
getBlueprint: () => PerformanceController.getTimelineBlueprint(),
|
getFilter: () => PerformanceController.getPref("hidden-markers"),
|
||||||
getTheme: () => PerformanceController.getTheme(),
|
getTheme: () => PerformanceController.getTheme(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -331,8 +331,8 @@ let OverviewView = {
|
||||||
case "hidden-markers": {
|
case "hidden-markers": {
|
||||||
let graph;
|
let graph;
|
||||||
if (graph = yield this.graphs.isAvailable("timeline")) {
|
if (graph = yield this.graphs.isAvailable("timeline")) {
|
||||||
let blueprint = PerformanceController.getTimelineBlueprint();
|
let filter = PerformanceController.getPref("hidden-markers");
|
||||||
graph.setBlueprint(blueprint);
|
graph.setFilter(filter);
|
||||||
graph.refresh({ force: true });
|
graph.refresh({ force: true });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,6 +46,7 @@ timeline.label.domevent=DOM Event
|
||||||
timeline.label.consoleTime=Console
|
timeline.label.consoleTime=Console
|
||||||
timeline.label.garbageCollection=GC Event
|
timeline.label.garbageCollection=GC Event
|
||||||
timeline.label.timestamp=Timestamp
|
timeline.label.timestamp=Timestamp
|
||||||
|
timeline.label.unknown=Unknown
|
||||||
|
|
||||||
# LOCALIZATION NOTE (graphs.memory):
|
# LOCALIZATION NOTE (graphs.memory):
|
||||||
# This string is displayed in the memory graph of the Performance tool,
|
# This string is displayed in the memory graph of the Performance tool,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче