Bug 1152992 - If markers do not have a definition, classify them as "Other" in the perftools. r=vp

This commit is contained in:
Jordan Santell 2015-06-03 11:09:53 -07:00
Родитель 3b0521bff7
Коммит 772f325a61
18 изменённых файлов: 277 добавлений и 201 удалений

Просмотреть файл

@ -8,13 +8,13 @@
* and parsing out the blueprint to generate correct values for markers.
*/
const { Ci } = require("chrome");
const { Cu, Ci } = require("chrome");
loader.lazyRequireGetter(this, "L10N",
"devtools/performance/global", true);
loader.lazyRequireGetter(this, "PREFS",
"devtools/performance/global", true);
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
loader.lazyRequireGetter(this, "getBlueprintFor",
"devtools/performance/markers", true);
loader.lazyRequireGetter(this, "WebConsoleUtils",
"devtools/toolkit/webconsole/utils");
@ -30,7 +30,7 @@ const GECKO_SYMBOL = "(Gecko)";
* @return {string}
*/
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
// as a string.
return typeof blueprint.label === "function" ? blueprint.label(marker) : blueprint.label;
@ -44,7 +44,7 @@ function getMarkerLabel (marker) {
* @return {string}
*/
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
// as a string.
let className = typeof blueprint.label === "function" ? blueprint.label() : blueprint.label;
@ -72,7 +72,7 @@ function getMarkerClassName (type) {
* @return {Array<object>}
*/
function getMarkerFields (marker) {
let blueprint = TIMELINE_BLUEPRINT[marker.name];
let blueprint = getBlueprintFor(marker);
// If blueprint.fields is a function, use that
if (typeof blueprint.fields === "function") {
@ -111,7 +111,7 @@ const DOM = {
* @return {Array<Element>}
*/
buildFields: function (doc, marker) {
let blueprint = TIMELINE_BLUEPRINT[marker.name];
let blueprint = getBlueprintFor(marker);
let fields = getMarkerFields(marker);
return fields.map(({ label, value }) => DOM.buildNameValueLabel(doc, label, value));
@ -125,7 +125,7 @@ const DOM = {
* @return {Element}
*/
buildTitle: function (doc, marker) {
let blueprint = TIMELINE_BLUEPRINT[marker.name];
let blueprint = getBlueprintFor(marker);
let hbox = doc.createElement("hbox");
hbox.setAttribute("align", "center");
@ -377,6 +377,14 @@ const JS_MARKER_MAP = {
* A series of formatters used by the blueprint.
*/
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.
*/
DefaultLabel: function (marker={}) {
return marker.name || L10N.getStr("timeline.label.other");
},
GCLabel: function (marker={}) {
let label = L10N.getStr("timeline.label.garbageCollection");
// Only if a `nonincrementalReason` exists, do we want to label
@ -437,9 +445,59 @@ const Formatters = {
},
};
/**
* 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);
filteredBlueprint[hiddenMarkerName].hidden = true;
}
// 2. Get a list of all the groups that will be removed.
let markerNames = Object.keys(filteredBlueprint).filter(name => !filteredBlueprint[name].hidden);
for (let maybeRemovedGroup of maybeRemovedGroups) {
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) {
for (let markerName of markerNames) {
let markerDetails = filteredBlueprint[markerName];
if (markerDetails.group > removedGroup) {
markerDetails.group--;
}
}
}
return filteredBlueprint;
}
exports.getMarkerLabel = getMarkerLabel;
exports.getMarkerClassName = getMarkerClassName;
exports.getMarkerFields = getMarkerFields;
exports.getFilteredBlueprint = getFilteredBlueprint;
exports.DOM = DOM;
exports.CollapseFunctions = CollapseFunctions;
exports.Formatters = Formatters;

Просмотреть файл

@ -196,55 +196,6 @@ function getProfileThreadFromAllocations(allocations) {
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.
*
@ -571,7 +522,6 @@ exports.offsetSampleTimes = offsetSampleTimes;
exports.offsetMarkerTimes = offsetMarkerTimes;
exports.offsetAndScaleTimestamps = offsetAndScaleTimestamps;
exports.getProfileThreadFromAllocations = getProfileThreadFromAllocations;
exports.getFilteredBlueprint = getFilteredBlueprint;
exports.deflateProfile = deflateProfile;
exports.deflateThread = deflateThread;
exports.UniqueStrings = UniqueStrings;

Просмотреть файл

@ -7,25 +7,25 @@
* Utility functions for collapsing markers into a waterfall.
*/
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
loader.lazyRequireGetter(this, "getBlueprintFor",
"devtools/performance/markers", true);
/**
* Collapses markers into a tree-like structure.
* @param object markerNode
* @param array markersList
* @param ?object blueprint
* @param object blueprint
*/
function collapseMarkersIntoNode({ markerNode, markersList, blueprint }) {
let { getCurrentParentNode, collapseMarker, addParentNode, popParentNode } = createParentNodeFactory(markerNode);
blueprint = blueprint || TIMELINE_BLUEPRINT;
for (let i = 0, len = markersList.length; i < len; i++) {
let curr = markersList[i];
let parentNode = getCurrentParentNode();
let def = blueprint[curr.name];
let collapse = def.collapseFunc || (() => null);
let definition = getBlueprintFor(curr, blueprint);
let collapse = definition.collapseFunc || (() => null);
let peek = distance => markersList[i + distance];
let foundParent = false;

Просмотреть файл

@ -55,6 +55,16 @@ const { Formatters, CollapseFunctions: collapse } = require("devtools/performanc
* updated as well.
*/
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.DefaultLabel
},
/* Group 0 - Reflow and Rendering pipeline */
"Styles": {
group: 0,
@ -117,7 +127,7 @@ const TIMELINE_BLUEPRINT = {
/* Group 2 - User Controlled */
"ConsoleTime": {
group: 2,
colorName: "graphs-grey",
colorName: "graphs-blue",
label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
fields: [{
property: "causeName",
@ -126,7 +136,7 @@ const TIMELINE_BLUEPRINT = {
},
"TimeStamp": {
group: 2,
colorName: "graphs-blue",
colorName: "graphs-yellow",
collapseFunc: collapse.child,
label: sublabelForProperty(L10N.getStr("timeline.label.timestamp"), "causeName"),
fields: [{
@ -136,6 +146,19 @@ const TIMELINE_BLUEPRINT = {
},
};
/**
* Takes a marker and returns the definition for that marker type,
* falling back to the UNKNOWN definition if undefined. Takes an optional
* second argument if using another blueprint, rather than TIMELINE_BLUEPRINT.
*
* @param {Marker} marker
* @param {?object} blueprint
* @return {object}
*/
function getBlueprintFor (marker, blueprint=TIMELINE_BLUEPRINT) {
return blueprint[marker.name] || blueprint.UNKNOWN;
}
/**
* Helper for creating a function that returns the first defined result from
* a list of functions passed in as params, in order.
@ -163,3 +186,4 @@ function sublabelForProperty (mainLabel, prop) {
// Exported symbols.
exports.TIMELINE_BLUEPRINT = TIMELINE_BLUEPRINT;
exports.getBlueprintFor = getBlueprintFor;

Просмотреть файл

@ -13,8 +13,6 @@ loader.lazyRequireGetter(this, "EventEmitter",
"devtools/toolkit/event-emitter");
loader.lazyRequireGetter(this, "L10N",
"devtools/performance/global", true);
loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
"devtools/performance/markers", true);
loader.lazyRequireGetter(this, "MarkerUtils",
"devtools/performance/marker-utils");

Просмотреть файл

@ -11,7 +11,7 @@
const { Cc, Ci, Cu, Cr } = require("chrome");
const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
const { TIMELINE_BLUEPRINT: ORIGINAL_BP } = require("devtools/performance/markers");
const { getBlueprintFor } = require("devtools/performance/markers");
loader.lazyRequireGetter(this, "MarkerUtils",
"devtools/performance/marker-utils");
@ -139,7 +139,6 @@ MarkerView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
if (!submarkers || !submarkers.length) {
return;
}
let blueprint = this.root._blueprint;
let startTime = this.root._interval.startTime;
let endTime = this.root._interval.endTime;
let newLevel = this.level + 1;
@ -147,14 +146,6 @@ MarkerView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
for (let i = 0, len = submarkers.length; i < len; i++) {
let marker = submarkers[i];
// If this marker isn't in the global timeline blueprint, don't display
// it, but dump a warning message to the console.
if (!(marker.name in blueprint)) {
if (!(marker.name in ORIGINAL_BP)) {
console.warn(`Marker not found in timeline blueprint: ${marker.name}.`);
}
continue;
}
if (!isMarkerInRange(marker, startTime|0, endTime|0)) {
continue;
}
@ -175,15 +166,20 @@ MarkerView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
*/
_buildMarkerCells: function(doc, targetNode, arrowNode) {
let marker = this.marker;
let style = this.root._blueprint[marker.name];
let blueprint = getBlueprintFor(marker, this.root._blueprint);
let startTime = this.root._interval.startTime;
let endTime = this.root._interval.endTime;
let sidebarCell = this._buildMarkerSidebar(
doc, style, marker);
// If this marker type has been marked hidden via marker filtering,
// then don't display it. This is so we can also handle "Unknown" markers
// that do not have a blueprint, but we want to show those anyway unless "Unknown"
// markers are filtered.
if (blueprint.hidden) {
return;
}
let timebarCell = this._buildMarkerTimebar(
doc, style, marker, startTime, endTime, arrowNode);
let sidebarCell = this._buildMarkerSidebar(doc, blueprint, marker);
let timebarCell = this._buildMarkerTimebar(doc, blueprint, marker, startTime, endTime, arrowNode);
targetNode.appendChild(sidebarCell);
targetNode.appendChild(timebarCell);

Просмотреть файл

@ -75,7 +75,7 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
this._paintBatches = new Map();
this._lastGroup = 0;
for (let type in blueprint) {
for (let type of Object.keys(blueprint).filter(e => !blueprint[e].hidden)) {
this._paintBatches.set(type, { style: blueprint[type], batch: [] });
this._lastGroup = Math.max(this._lastGroup, blueprint[type].group || 0);
}
@ -103,9 +103,9 @@ MarkersOverview.prototype = Heritage.extend(AbstractCanvasGraph.prototype, {
// Group markers into separate paint batches. This is necessary to
// draw all markers sharing the same style at once.
for (let marker of markers) {
let markerType = this._paintBatches.get(marker.name);
let markerType = this._paintBatches.get(marker.name) || this._paintBatches.get("UNKNOWN");
// We don't have batches for filtered markers
if (markerType) {
markerType.batch.push(marker);
}

Просмотреть файл

@ -407,7 +407,7 @@ let PerformanceController = {
getTimelineBlueprint: function() {
let blueprint = TIMELINE_BLUEPRINT;
let hiddenMarkers = this.getPref("hidden-markers");
return RecordingUtils.getFilteredBlueprint({ blueprint, hiddenMarkers });
return MarkerUtils.getFilteredBlueprint({ blueprint, hiddenMarkers });
},
/**

Просмотреть файл

@ -12,7 +12,6 @@ support-files =
# that need to be moved over to performance tool
[browser_aaa-run-first-leaktest.js]
[browser_marker-utils.js]
[browser_markers-gc.js]
[browser_markers-parse-html.js]
[browser_markers-styles.js]
@ -134,7 +133,6 @@ support-files =
[browser_profiler_tree-view-08.js]
[browser_profiler_tree-view-09.js]
[browser_profiler_tree-view-10.js]
[browser_timeline-blueprint.js]
[browser_timeline-filters.js]
[browser_timeline-waterfall-background.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.
*/
const EPSILON = 0.00000001;
function* spawnTest() {
let { panel } = yield initPerformance(SIMPLE_URL);
let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
@ -24,20 +26,34 @@ function* spawnTest() {
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
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();
let menuItem1 = $("menuitem[marker-type=Styles]");
let menuItem2 = $("menuitem[marker-type=Reflow]");
let menuItem3 = $("menuitem[marker-type=Paint]");
let menuItem4 = $("menuitem[marker-type=UNKNOWN]");
let overview = OverviewView.graphs.get("timeline");
let originalHeight = overview.fixedHeight;
yield waterfallRendered;
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=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;
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=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=CustomMarker]"), "Found at least one 'Unknown' marker (2)");
heightBefore = overview.fixedHeight;
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=Reflow]"), "No 'Reflow' 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;
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=Reflow]"), "No 'Reflow' 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]) {
EventUtils.synthesizeMouseAtCenter(item, {type: "mouseup"}, panel.panelWin);
yield waitForOverviewAndCommand(overview, item);
}
ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (5)");
ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (5)");
ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' 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 (6)");
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");

Просмотреть файл

@ -5,8 +5,11 @@
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
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 PLATFORM_DATA_PREF = "devtools.performance.ui.show-platform-data";
/**
* 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,92 @@
/* 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, getBlueprintFor } = 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(getBlueprintFor({ name: "Reflow" }).label, "Layout",
"getBlueprintFor() should return marker def for passed in marker.");
equal(getBlueprintFor({ name: "Not sure!" }).label(), "Other",
"getBlueprintFor() should return a default marker def if the marker is undefined.");
equal(getBlueprintFor({ name: "custom" }, customBlueprint).label, "MyCustom",
"getBlueprintFor() should return a marker def if also passed in a non-default blueprint");
equal(getBlueprintFor({ name: "CHAOS!" }, customBlueprint).label, "MyDefault",
"getBlueprintFor() should return a default marker def if also passed in a non-default blueprint");
});

Просмотреть файл

@ -5,9 +5,11 @@ tail =
firefox-appdir = browser
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_profiler-categories.js]
[test_frame-utils-01.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-02.js]
[test_tree-model-03.js]

Просмотреть файл

@ -32,6 +32,7 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
this._onMarkerSelected = this._onMarkerSelected.bind(this);
this._onResize = this._onResize.bind(this);
this._onViewSource = this._onViewSource.bind(this);
this._blueprint = PerformanceController.getTimelineBlueprint();
this.headerContainer = $("#waterfall-header");
this.breakdownContainer = $("#waterfall-breakdown");
@ -111,8 +112,8 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
* Called whenever an observed pref is changed.
*/
_onObservedPrefChange: function(_, prefName) {
let blueprint = PerformanceController.getTimelineBlueprint();
this._markersRoot.blueprint = blueprint;
this._blueprint = PerformanceController.getTimelineBlueprint();
this._markersRoot.blueprint = this._blueprint;
},
/**
@ -136,7 +137,8 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
WaterfallUtils.collapseMarkersIntoNode({
markerNode: rootMarkerNode,
markersList: markers
markersList: markers,
blueprint: this._blueprint
});
this._cache.set(markers, rootMarkerNode);
@ -160,8 +162,7 @@ let WaterfallView = Heritage.extend(DetailsSubview, {
this._markersRoot = root;
this._waterfallHeader = header;
let blueprint = PerformanceController.getTimelineBlueprint();
root.blueprint = blueprint;
root.blueprint = this._blueprint;
root.interval = interval;
root.on("selected", this._onMarkerSelected);
root.on("unselected", this._onMarkerSelected);

Просмотреть файл

@ -46,6 +46,7 @@ timeline.label.domevent=DOM Event
timeline.label.consoleTime=Console
timeline.label.garbageCollection=GC Event
timeline.label.timestamp=Timestamp
timeline.label.other=Other
# LOCALIZATION NOTE (graphs.memory):
# This string is displayed in the memory graph of the Performance tool,