зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1167300 - Consolidate the performance tool directory, r=jsantell
--HG-- rename : browser/devtools/shared/timeline/global.js => browser/devtools/performance/modules/global.js rename : browser/devtools/performance/modules/actors.js => browser/devtools/performance/modules/logic/actors.js rename : browser/devtools/performance/modules/compatibility.js => browser/devtools/performance/modules/logic/compatibility.js rename : browser/devtools/shared/profiler/frame-utils.js => browser/devtools/performance/modules/logic/frame-utils.js rename : browser/devtools/performance/modules/front.js => browser/devtools/performance/modules/logic/front.js rename : browser/devtools/performance/modules/io.js => browser/devtools/performance/modules/logic/io.js rename : browser/devtools/shared/profiler/jit.js => browser/devtools/performance/modules/logic/jit.js rename : browser/devtools/shared/timeline/marker-utils.js => browser/devtools/performance/modules/logic/marker-utils.js rename : browser/devtools/performance/modules/recording-model.js => browser/devtools/performance/modules/logic/recording-model.js rename : browser/devtools/performance/modules/recording-utils.js => browser/devtools/performance/modules/logic/recording-utils.js rename : browser/devtools/shared/profiler/tree-model.js => browser/devtools/performance/modules/logic/tree-model.js rename : browser/devtools/performance/modules/graphs.js => browser/devtools/performance/modules/widgets/graphs.js rename : browser/devtools/shared/timeline/marker-details.js => browser/devtools/performance/modules/widgets/marker-details.js rename : browser/devtools/shared/timeline/markers-overview.js => browser/devtools/performance/modules/widgets/markers-overview.js rename : browser/devtools/shared/profiler/tree-view.js => browser/devtools/performance/modules/widgets/tree-view.js rename : browser/devtools/shared/timeline/waterfall.js => browser/devtools/performance/modules/widgets/waterfall.js
This commit is contained in:
Родитель
8f77347ec6
Коммит
4b7d7bd9d0
|
@ -0,0 +1,357 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
loader.lazyRequireGetter(this, "ViewHelpers",
|
||||
"resource:///modules/devtools/ViewHelpers.jsm", true);
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
// String used to fill in platform data when it should be hidden.
|
||||
const GECKO_SYMBOL = "(Gecko)";
|
||||
|
||||
/**
|
||||
* Localization convenience methods.
|
||||
+ TODO: merge these into a single file: Bug 1082695.
|
||||
*/
|
||||
const TIMELINE_STRINGS_URI = "chrome://browser/locale/devtools/timeline.properties";
|
||||
const PROFILER_STRINGS_URI = "chrome://browser/locale/devtools/profiler.properties";
|
||||
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
|
||||
/**
|
||||
* A list of preferences for this tool. The values automatically update
|
||||
* if somebody edits edits about:config or the prefs change somewhere else.
|
||||
*/
|
||||
const Prefs = new ViewHelpers.Prefs("devtools.performance.ui", {
|
||||
showPlatformData: ["Bool", "show-platform-data"]
|
||||
}, {
|
||||
monitorChanges: true
|
||||
});
|
||||
|
||||
/**
|
||||
* Details about each profile entry cateogry.
|
||||
* @see CATEGORY_MAPPINGS.
|
||||
*/
|
||||
const CATEGORIES = [{
|
||||
ordinal: 7,
|
||||
color: "#5e88b0",
|
||||
abbrev: "other",
|
||||
label: L10N.getStr("category.other")
|
||||
}, {
|
||||
ordinal: 4,
|
||||
color: "#46afe3",
|
||||
abbrev: "css",
|
||||
label: L10N.getStr("category.css")
|
||||
}, {
|
||||
ordinal: 1,
|
||||
color: "#d96629",
|
||||
abbrev: "js",
|
||||
label: L10N.getStr("category.js")
|
||||
}, {
|
||||
ordinal: 2,
|
||||
color: "#eb5368",
|
||||
abbrev: "gc",
|
||||
label: L10N.getStr("category.gc")
|
||||
}, {
|
||||
ordinal: 0,
|
||||
color: "#df80ff",
|
||||
abbrev: "network",
|
||||
label: L10N.getStr("category.network")
|
||||
}, {
|
||||
ordinal: 5,
|
||||
color: "#70bf53",
|
||||
abbrev: "graphics",
|
||||
label: L10N.getStr("category.graphics")
|
||||
}, {
|
||||
ordinal: 6,
|
||||
color: "#8fa1b2",
|
||||
abbrev: "storage",
|
||||
label: L10N.getStr("category.storage")
|
||||
}, {
|
||||
ordinal: 3,
|
||||
color: "#d99b28",
|
||||
abbrev: "events",
|
||||
label: L10N.getStr("category.events")
|
||||
}];
|
||||
|
||||
/**
|
||||
* Mapping from category bitmasks in the profiler data to additional details.
|
||||
* To be kept in sync with the js::ProfileEntry::Category in ProfilingStack.h
|
||||
*/
|
||||
const CATEGORY_MAPPINGS = {
|
||||
"16": CATEGORIES[0], // js::ProfileEntry::Category::OTHER
|
||||
"32": CATEGORIES[1], // js::ProfileEntry::Category::CSS
|
||||
"64": CATEGORIES[2], // js::ProfileEntry::Category::JS
|
||||
"128": CATEGORIES[3], // js::ProfileEntry::Category::GC
|
||||
"256": CATEGORIES[3], // js::ProfileEntry::Category::CC
|
||||
"512": CATEGORIES[4], // js::ProfileEntry::Category::NETWORK
|
||||
"1024": CATEGORIES[5], // js::ProfileEntry::Category::GRAPHICS
|
||||
"2048": CATEGORIES[6], // js::ProfileEntry::Category::STORAGE
|
||||
"4096": CATEGORIES[7], // js::ProfileEntry::Category::EVENTS
|
||||
};
|
||||
|
||||
/**
|
||||
* A simple schema for mapping markers to the timeline UI. The keys correspond
|
||||
* to marker names, while the values are objects with the following format:
|
||||
*
|
||||
* - group: The row index in the timeline overview graph; multiple markers
|
||||
* can be added on the same row. @see <overview.js/buildGraphImage>
|
||||
* - label: The label used in the waterfall to identify the marker. Can be a
|
||||
* string or just a function that accepts the marker and returns a
|
||||
* string, if you want to use a dynamic property for the main label.
|
||||
* If you use a function for a label, it *must* handle the case where
|
||||
* no marker is provided for a main label to describe all markers of
|
||||
* this type.
|
||||
* - colorName: The label of the DevTools color used for this marker. If
|
||||
* adding a new color, be sure to check that there's an entry
|
||||
* for `.marker-details-bullet.{COLORNAME}` for the equivilent
|
||||
* entry in ./browser/themes/shared/devtools/performance.inc.css
|
||||
* https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
|
||||
* - fields: An optional array of marker properties you wish to display in the
|
||||
* marker details view. For example, a field in the array such as
|
||||
* { property: "aCauseName", label: "Cause" } would render a string
|
||||
* like `Cause: ${marker.aCauseName}` in the marker details view.
|
||||
* Each `field` item may take the following properties:
|
||||
* - property: The property that must exist on the marker to render,
|
||||
* and the value of the property will be displayed.
|
||||
* - label: The name of the property that should be displayed.
|
||||
* - formatter: If a formatter is provided, instead of directly using
|
||||
* the `property` property on the marker, the marker is
|
||||
* passed into the formatter function to determine the
|
||||
* displayed value.
|
||||
* Can also be a function that returns an object. Each key in the object
|
||||
* will be rendered as a field, with its value rendering as the value.
|
||||
*
|
||||
* Whenever this is changed, browser_timeline_waterfall-styles.js *must* be
|
||||
* updated as well.
|
||||
*/
|
||||
const TIMELINE_BLUEPRINT = {
|
||||
/* Group 0 - Reflow and Rendering pipeline */
|
||||
"Styles": {
|
||||
group: 0,
|
||||
colorName: "graphs-purple",
|
||||
label: L10N.getStr("timeline.label.styles2"),
|
||||
fields: getStylesFields,
|
||||
},
|
||||
"Reflow": {
|
||||
group: 0,
|
||||
colorName: "graphs-purple",
|
||||
label: L10N.getStr("timeline.label.reflow2")
|
||||
},
|
||||
"Paint": {
|
||||
group: 0,
|
||||
colorName: "graphs-green",
|
||||
label: L10N.getStr("timeline.label.paint")
|
||||
},
|
||||
|
||||
/* Group 1 - JS */
|
||||
"DOMEvent": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.domevent"),
|
||||
fields: getDOMEventFields,
|
||||
},
|
||||
"Javascript": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: getJSLabel,
|
||||
fields: getJSFields,
|
||||
},
|
||||
"Parse HTML": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.parseHTML")
|
||||
},
|
||||
"Parse XML": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.parseXML")
|
||||
},
|
||||
"GarbageCollection": {
|
||||
group: 1,
|
||||
colorName: "graphs-red",
|
||||
label: getGCLabel,
|
||||
fields: [
|
||||
{ property: "causeName", label: "Reason:" },
|
||||
{ property: "nonincrementalReason", label: "Non-incremental Reason:" }
|
||||
]
|
||||
},
|
||||
|
||||
/* Group 2 - User Controlled */
|
||||
"ConsoleTime": {
|
||||
group: 2,
|
||||
colorName: "graphs-grey",
|
||||
label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
|
||||
fields: [{
|
||||
property: "causeName",
|
||||
label: L10N.getStr("timeline.markerDetail.consoleTimerName")
|
||||
}]
|
||||
},
|
||||
"TimeStamp": {
|
||||
group: 2,
|
||||
colorName: "graphs-blue",
|
||||
label: sublabelForProperty(L10N.getStr("timeline.label.timestamp"), "causeName"),
|
||||
fields: [{
|
||||
property: "causeName",
|
||||
label: "Label:"
|
||||
}]
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* A series of formatters used by the blueprint.
|
||||
*/
|
||||
|
||||
function getGCLabel (marker={}) {
|
||||
let label = L10N.getStr("timeline.label.garbageCollection");
|
||||
// Only if a `nonincrementalReason` exists, do we want to label
|
||||
// this as a non incremental GC event.
|
||||
if ("nonincrementalReason" in marker) {
|
||||
label = `${label} (Non-incremental)`;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping of JS marker causes to a friendlier form. Only
|
||||
* markers that are considered "from content" should be labeled here.
|
||||
*/
|
||||
const JS_MARKER_MAP = {
|
||||
"<script> element": "Script Tag",
|
||||
"setInterval handler": "setInterval",
|
||||
"setTimeout handler": "setTimeout",
|
||||
"FrameRequestCallback": "requestAnimationFrame",
|
||||
"promise callback": "Promise Callback",
|
||||
"promise initializer": "Promise Init",
|
||||
"Worker runnable": "Worker",
|
||||
"javascript: URI": "JavaScript URI",
|
||||
// The difference between these two event handler markers are differences
|
||||
// in their WebIDL implementation, so distinguishing them is not necessary.
|
||||
"EventHandlerNonNull": "Event Handler",
|
||||
"EventListener.handleEvent": "Event Handler",
|
||||
};
|
||||
|
||||
function getJSLabel (marker={}) {
|
||||
let generic = L10N.getStr("timeline.label.javascript2");
|
||||
if ("causeName" in marker) {
|
||||
return JS_MARKER_MAP[marker.causeName] || generic;
|
||||
}
|
||||
return generic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash for computing a fields object for a JS marker. If the cause
|
||||
* is considered content (so an entry exists in the JS_MARKER_MAP), do not display it
|
||||
* since it's redundant with the label. Otherwise for Gecko code, either display
|
||||
* the cause, or "(Gecko)", depending on if "show-platform-data" is set.
|
||||
*/
|
||||
function getJSFields (marker) {
|
||||
if ("causeName" in marker && !JS_MARKER_MAP[marker.causeName]) {
|
||||
return { Reason: Prefs.showPlatformData ? marker.causeName : GECKO_SYMBOL };
|
||||
}
|
||||
}
|
||||
|
||||
function getDOMEventFields (marker) {
|
||||
let fields = Object.create(null);
|
||||
if ("type" in marker) {
|
||||
fields[L10N.getStr("timeline.markerDetail.DOMEventType")] = marker.type;
|
||||
}
|
||||
if ("eventPhase" in marker) {
|
||||
let phase;
|
||||
if (marker.eventPhase === Ci.nsIDOMEvent.AT_TARGET) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventTargetPhase");
|
||||
} else if (marker.eventPhase === Ci.nsIDOMEvent.CAPTURING_PHASE) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventCapturingPhase");
|
||||
} else if (marker.eventPhase === Ci.nsIDOMEvent.BUBBLING_PHASE) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventBubblingPhase");
|
||||
}
|
||||
fields[L10N.getStr("timeline.markerDetail.DOMEventPhase")] = phase;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
function getStylesFields (marker) {
|
||||
if ("restyleHint" in marker) {
|
||||
return { "Restyle Hint": marker.restyleHint.replace(/eRestyle_/g, "") };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a main label (like "Timestamp") and a property,
|
||||
* and returns a marker that will print out the property
|
||||
* value for a marker if it exists ("Timestamp (rendering)"),
|
||||
* or just the main label if it does not.
|
||||
*/
|
||||
function sublabelForProperty (mainLabel, prop) {
|
||||
return (marker={}) => marker[prop] ? `${mainLabel} (${marker[prop]})` : mainLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the numeric bitmask (or set of masks) for the given category
|
||||
* abbreviation. See CATEGORIES and CATEGORY_MAPPINGS above.
|
||||
*
|
||||
* CATEGORY_MASK can be called with just a name if it is expected that the
|
||||
* category is mapped to by exactly one bitmask. If the category is mapped
|
||||
* to by multiple masks, CATEGORY_MASK for that name must be called with
|
||||
* an additional argument specifying the desired id (in ascending order).
|
||||
*/
|
||||
const [CATEGORY_MASK, CATEGORY_MASK_LIST] = (function () {
|
||||
let bitmasksForCategory = {};
|
||||
let all = Object.keys(CATEGORY_MAPPINGS);
|
||||
|
||||
for (let category of CATEGORIES) {
|
||||
bitmasksForCategory[category.abbrev] = all
|
||||
.filter(mask => CATEGORY_MAPPINGS[mask] == category)
|
||||
.map(mask => +mask)
|
||||
.sort();
|
||||
}
|
||||
|
||||
return [
|
||||
function (name, index) {
|
||||
if (!(name in bitmasksForCategory)) {
|
||||
throw new Error(`Category abbreviation '${name}' does not exist.`);
|
||||
}
|
||||
if (arguments.length == 1) {
|
||||
if (bitmasksForCategory[name].length != 1) {
|
||||
throw new Error(`Expected exactly one category number for '${name}'.`);
|
||||
} else {
|
||||
return bitmasksForCategory[name][0];
|
||||
}
|
||||
} else {
|
||||
if (index > bitmasksForCategory[name].length) {
|
||||
throw new Error(`Index '${index}' too high for category '${name}'.`);
|
||||
} else {
|
||||
return bitmasksForCategory[name][index - 1];
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
function (name) {
|
||||
if (!(name in bitmasksForCategory)) {
|
||||
throw new Error(`Category abbreviation '${name}' does not exist.`);
|
||||
}
|
||||
return bitmasksForCategory[name];
|
||||
}
|
||||
];
|
||||
})();
|
||||
|
||||
// Human-readable "other" category bitmask. Older Geckos don't have all the
|
||||
// necessary instrumentation in the sampling profiler backend for creating
|
||||
// a categories graph, in which case we default to the "other" category.
|
||||
const CATEGORY_OTHER = CATEGORY_MASK('other');
|
||||
|
||||
// Human-readable JIT category bitmask. Certain pseudo-frames in a sample,
|
||||
// like "EnterJIT", don't have any associated `cateogry` information.
|
||||
const CATEGORY_JIT = CATEGORY_MASK('js');
|
||||
|
||||
// Exported symbols.
|
||||
exports.L10N = L10N;
|
||||
exports.TIMELINE_BLUEPRINT = TIMELINE_BLUEPRINT;
|
||||
exports.CATEGORIES = CATEGORIES;
|
||||
exports.CATEGORY_MAPPINGS = CATEGORY_MAPPINGS;
|
||||
exports.CATEGORY_MASK = CATEGORY_MASK;
|
||||
exports.CATEGORY_MASK_LIST = CATEGORY_MASK_LIST;
|
||||
exports.CATEGORY_OTHER = CATEGORY_OTHER;
|
||||
exports.CATEGORY_JIT = CATEGORY_JIT;
|
|
@ -23,7 +23,7 @@ const SUCCESSFUL_OUTCOMES = [
|
|||
* An OptimizationSite contains a record of how many times the
|
||||
* RawOptimizationSite was sampled, as well as the unique id based off of the
|
||||
* original profiler array, and the RawOptimizationSite itself as a reference.
|
||||
* @see browser/devtools/shared/profiler/tree-model.js
|
||||
* @see browser/devtools/performance/modules/logic/tree-model.js
|
||||
*
|
||||
* @struct RawOptimizationSite
|
||||
* A structure describing a location in a script that was attempted to be optimized.
|
|
@ -4,13 +4,22 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
EXTRA_JS_MODULES.devtools.performance += [
|
||||
'modules/actors.js',
|
||||
'modules/compatibility.js',
|
||||
'modules/front.js',
|
||||
'modules/graphs.js',
|
||||
'modules/io.js',
|
||||
'modules/recording-model.js',
|
||||
'modules/recording-utils.js',
|
||||
'modules/global.js',
|
||||
'modules/logic/actors.js',
|
||||
'modules/logic/compatibility.js',
|
||||
'modules/logic/frame-utils.js',
|
||||
'modules/logic/front.js',
|
||||
'modules/logic/io.js',
|
||||
'modules/logic/jit.js',
|
||||
'modules/logic/marker-utils.js',
|
||||
'modules/logic/recording-model.js',
|
||||
'modules/logic/recording-utils.js',
|
||||
'modules/logic/tree-model.js',
|
||||
'modules/widgets/graphs.js',
|
||||
'modules/widgets/marker-details.js',
|
||||
'modules/widgets/markers-overview.js',
|
||||
'modules/widgets/tree-view.js',
|
||||
'modules/widgets/waterfall.js',
|
||||
'panel.js'
|
||||
]
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
<script type="application/javascript" src="performance/system.js"/>
|
||||
<script type="application/javascript" src="performance/performance-controller.js"/>
|
||||
<script type="application/javascript" src="performance/performance-view.js"/>
|
||||
<script type="application/javascript" src="performance/recording-model.js"/>
|
||||
<script type="application/javascript" src="performance/views/overview.js"/>
|
||||
<script type="application/javascript" src="performance/views/toolbar.js"/>
|
||||
<script type="application/javascript" src="performance/views/details-subview.js"/>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
/**
|
||||
* Tests if the retrieved profiler data samples always have a (root) node.
|
||||
* If this ever changes, the |ThreadNode.prototype.insert| function in
|
||||
* browser/devtools/profiler/utils/tree-model.js will have to be changed.
|
||||
* browser/devtools/performance/modules/logic/tree-model.js will have to be changed.
|
||||
*/
|
||||
|
||||
const WAIT_TIME = 1000; // ms
|
||||
|
|
|
@ -12,7 +12,7 @@ const PROPNAME_MAX_LENGTH = 4;
|
|||
/**
|
||||
* View for rendering JIT Optimization data. The terminology and types
|
||||
* used here can be referenced:
|
||||
* @see browser/devtools/shared/profiler/jit.js
|
||||
* @see browser/devtools/performance/modules/logic/jit.js
|
||||
*/
|
||||
|
||||
let JITOptimizationsView = {
|
||||
|
@ -243,7 +243,7 @@ let JITOptimizationsView = {
|
|||
/**
|
||||
* Creates an element for insertion in the raw view for an IonType.
|
||||
*
|
||||
* @see browser/devtools/shared/profiler/jit.js
|
||||
* @see browser/devtools/performance/modules/logic/jit.js
|
||||
* @param {IonType} ionType
|
||||
* @return {Element}
|
||||
*/
|
||||
|
@ -258,7 +258,7 @@ let JITOptimizationsView = {
|
|||
/**
|
||||
* Creates an element for insertion in the raw view for an ObservedType.
|
||||
*
|
||||
* @see browser/devtools/shared/profiler/jit.js
|
||||
* @see browser/devtools/performance/modules/logic/jit.js
|
||||
* @param {ObservedType} type
|
||||
* @return {Element}
|
||||
*/
|
||||
|
@ -298,7 +298,7 @@ let JITOptimizationsView = {
|
|||
/**
|
||||
* Creates an element for insertion in the raw view for an OptimizationAttempt.
|
||||
*
|
||||
* @see browser/devtools/shared/profiler/jit.js
|
||||
* @see browser/devtools/performance/modules/logic/jit.js
|
||||
* @param {OptimizationAttempt} attempt
|
||||
* @return {Element}
|
||||
*/
|
||||
|
|
|
@ -30,22 +30,6 @@ EXTRA_JS_MODULES.devtools += [
|
|||
'widgets/ViewHelpers.jsm',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.devtools.shared.profiler += [
|
||||
'profiler/frame-utils.js',
|
||||
'profiler/global.js',
|
||||
'profiler/jit.js',
|
||||
'profiler/tree-model.js',
|
||||
'profiler/tree-view.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.devtools.shared.timeline += [
|
||||
'timeline/global.js',
|
||||
'timeline/marker-details.js',
|
||||
'timeline/marker-utils.js',
|
||||
'timeline/markers-overview.js',
|
||||
'timeline/waterfall.js',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES.devtools.shared += [
|
||||
'autocomplete-popup.js',
|
||||
'devices.js',
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
|
||||
Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
|
||||
|
||||
/**
|
||||
* Localization convenience methods.
|
||||
*/
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/profiler.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
|
||||
/**
|
||||
* Details about each profile entry cateogry.
|
||||
* @see CATEGORY_MAPPINGS.
|
||||
*/
|
||||
const CATEGORIES = [
|
||||
{ ordinal: 7, color: "#5e88b0", abbrev: "other", label: L10N.getStr("category.other") },
|
||||
{ ordinal: 4, color: "#46afe3", abbrev: "css", label: L10N.getStr("category.css") },
|
||||
{ ordinal: 1, color: "#d96629", abbrev: "js", label: L10N.getStr("category.js") },
|
||||
{ ordinal: 2, color: "#eb5368", abbrev: "gc", label: L10N.getStr("category.gc") },
|
||||
{ ordinal: 0, color: "#df80ff", abbrev: "network", label: L10N.getStr("category.network") },
|
||||
{ ordinal: 5, color: "#70bf53", abbrev: "graphics", label: L10N.getStr("category.graphics") },
|
||||
{ ordinal: 6, color: "#8fa1b2", abbrev: "storage", label: L10N.getStr("category.storage") },
|
||||
{ ordinal: 3, color: "#d99b28", abbrev: "events", label: L10N.getStr("category.events") }
|
||||
];
|
||||
|
||||
/**
|
||||
* Mapping from category bitmasks in the profiler data to additional details.
|
||||
* To be kept in sync with the js::ProfileEntry::Category in ProfilingStack.h
|
||||
*/
|
||||
const CATEGORY_MAPPINGS = {
|
||||
"16": CATEGORIES[0], // js::ProfileEntry::Category::OTHER
|
||||
"32": CATEGORIES[1], // js::ProfileEntry::Category::CSS
|
||||
"64": CATEGORIES[2], // js::ProfileEntry::Category::JS
|
||||
"128": CATEGORIES[3], // js::ProfileEntry::Category::GC
|
||||
"256": CATEGORIES[3], // js::ProfileEntry::Category::CC
|
||||
"512": CATEGORIES[4], // js::ProfileEntry::Category::NETWORK
|
||||
"1024": CATEGORIES[5], // js::ProfileEntry::Category::GRAPHICS
|
||||
"2048": CATEGORIES[6], // js::ProfileEntry::Category::STORAGE
|
||||
"4096": CATEGORIES[7], // js::ProfileEntry::Category::EVENTS
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the numeric bitmask (or set of masks) for the given category
|
||||
* abbreviation. See CATEGORIES and CATEGORY_MAPPINGS above.
|
||||
*
|
||||
* CATEGORY_MASK can be called with just a name if it is expected that the
|
||||
* category is mapped to by exactly one bitmask. If the category is mapped
|
||||
* to by multiple masks, CATEGORY_MASK for that name must be called with
|
||||
* an additional argument specifying the desired id (in ascending order).
|
||||
*/
|
||||
const [CATEGORY_MASK, CATEGORY_MASK_LIST] = (function () {
|
||||
let mappings = {};
|
||||
for (let category of CATEGORIES) {
|
||||
let numList = Object.keys(CATEGORY_MAPPINGS)
|
||||
.filter(k => CATEGORY_MAPPINGS[k] == category)
|
||||
.map(k => +k);
|
||||
numList.sort();
|
||||
mappings[category.abbrev] = numList;
|
||||
}
|
||||
|
||||
return [
|
||||
function (name, num) {
|
||||
if (!(name in mappings)) {
|
||||
throw new Error(`Category abbreviation '${name}' does not exist.`);
|
||||
}
|
||||
if (arguments.length == 1) {
|
||||
if (mappings[name].length != 1) {
|
||||
throw new Error(`Expected exactly one category number for '${name}'.`);
|
||||
}
|
||||
return mappings[name][0];
|
||||
}
|
||||
if (num > mappings[name].length) {
|
||||
throw new Error(`Num '${num}' too high for category '${name}'.`);
|
||||
}
|
||||
return mappings[name][num - 1];
|
||||
},
|
||||
|
||||
function (name) {
|
||||
if (!(name in mappings)) {
|
||||
throw new Error(`Category abbreviation '${name}' does not exist.`);
|
||||
}
|
||||
return mappings[name];
|
||||
}
|
||||
];
|
||||
})();
|
||||
|
||||
// Human-readable "other" category bitmask. Older Geckos don't have all the
|
||||
// necessary instrumentation in the sampling profiler backend for creating
|
||||
// a categories graph, in which case we default to the "other" category.
|
||||
const CATEGORY_OTHER = CATEGORY_MASK('other');
|
||||
|
||||
// Human-readable JIT category bitmask. Certain pseudo-frames in a sample,
|
||||
// like "EnterJIT", don't have any associated `cateogry` information.
|
||||
const CATEGORY_JIT = CATEGORY_MASK('js');
|
||||
|
||||
// Exported symbols.
|
||||
exports.L10N = L10N;
|
||||
exports.CATEGORIES = CATEGORIES;
|
||||
exports.CATEGORY_MAPPINGS = CATEGORY_MAPPINGS;
|
||||
exports.CATEGORY_OTHER = CATEGORY_OTHER;
|
||||
exports.CATEGORY_JIT = CATEGORY_JIT;
|
||||
exports.CATEGORY_MASK = CATEGORY_MASK;
|
||||
exports.CATEGORY_MASK_LIST = CATEGORY_MASK_LIST;
|
|
@ -1,230 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
|
||||
const {Cc, Ci, Cu, Cr} = require("chrome");
|
||||
loader.lazyRequireGetter(this, "ViewHelpers",
|
||||
"resource:///modules/devtools/ViewHelpers.jsm", true);
|
||||
loader.lazyRequireGetter(this, "Services");
|
||||
|
||||
// String used to fill in platform data when it should be hidden.
|
||||
const GECKO_SYMBOL = "(Gecko)";
|
||||
|
||||
/**
|
||||
* Localization convenience methods.
|
||||
*/
|
||||
const STRINGS_URI = "chrome://browser/locale/devtools/timeline.properties";
|
||||
const L10N = new ViewHelpers.L10N(STRINGS_URI);
|
||||
|
||||
/**
|
||||
* Monitor "show-platform-data" pref.
|
||||
*/
|
||||
const prefs = new ViewHelpers.Prefs("devtools.performance.ui", {
|
||||
showPlatformData: ["Bool", "show-platform-data"]
|
||||
});
|
||||
|
||||
let SHOW_PLATFORM_DATA = Services.prefs.getBoolPref("devtools.performance.ui.show-platform-data");
|
||||
prefs.registerObserver();
|
||||
prefs.on("pref-changed", (_, prefName, prefValue) => {
|
||||
if (prefName === "showPlatformData") {
|
||||
SHOW_PLATFORM_DATA = prefValue;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A simple schema for mapping markers to the timeline UI. The keys correspond
|
||||
* to marker names, while the values are objects with the following format:
|
||||
*
|
||||
* - group: the row index in the timeline overview graph; multiple markers
|
||||
* can be added on the same row. @see <overview.js/buildGraphImage>
|
||||
* - label: the label used in the waterfall to identify the marker. Can be a
|
||||
* string or just a function that accepts the marker and returns a string,
|
||||
* if you want to use a dynamic property for the main label.
|
||||
* If you use a function for a label, it *must* handle the case where
|
||||
* no marker is provided for a main label to describe all markers of this type.
|
||||
* - colorName: the label of the DevTools color used for this marker. If adding
|
||||
* a new color, be sure to check that there's an entry for
|
||||
* `.marker-details-bullet.{COLORNAME}` for the equivilent entry
|
||||
* in ./browser/themes/shared/devtools/performance.inc.css
|
||||
* https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
|
||||
* - fields: An optional array of marker properties you wish to display in the
|
||||
* marker details view. For example, a field of
|
||||
* { property: "aCauseName", label: "Cause" }
|
||||
* would render a field like `Cause: ${marker.aCauseName}`.
|
||||
* Each `field` item may take the following properties:
|
||||
*
|
||||
* - property: The property that must exist on the marker to render, and
|
||||
* the value of the property will be displayed.
|
||||
* - label: The name of the property that should be displayed.
|
||||
*
|
||||
* Can also be a function that returns an object. Each key in the object
|
||||
* will be rendered as a field, with its value rendering as the value.
|
||||
*
|
||||
* Whenever this is changed, browser_timeline_waterfall-styles.js *must* be
|
||||
* updated as well.
|
||||
*/
|
||||
const TIMELINE_BLUEPRINT = {
|
||||
/* Group 0 - Reflow and Rendering pipeline */
|
||||
"Styles": {
|
||||
group: 0,
|
||||
colorName: "graphs-purple",
|
||||
label: L10N.getStr("timeline.label.styles2"),
|
||||
fields: getStylesFields,
|
||||
},
|
||||
"Reflow": {
|
||||
group: 0,
|
||||
colorName: "graphs-purple",
|
||||
label: L10N.getStr("timeline.label.reflow2")
|
||||
},
|
||||
"Paint": {
|
||||
group: 0,
|
||||
colorName: "graphs-green",
|
||||
label: L10N.getStr("timeline.label.paint")
|
||||
},
|
||||
|
||||
/* Group 1 - JS */
|
||||
"DOMEvent": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.domevent"),
|
||||
fields: getDOMEventFields,
|
||||
},
|
||||
"Javascript": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: getJSLabel,
|
||||
fields: getJSFields,
|
||||
},
|
||||
"Parse HTML": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.parseHTML")
|
||||
},
|
||||
"Parse XML": {
|
||||
group: 1,
|
||||
colorName: "graphs-yellow",
|
||||
label: L10N.getStr("timeline.label.parseXML")
|
||||
},
|
||||
"GarbageCollection": {
|
||||
group: 1,
|
||||
colorName: "graphs-red",
|
||||
label: getGCLabel,
|
||||
fields: [
|
||||
{ property: "causeName", label: "Reason:" },
|
||||
{ property: "nonincrementalReason", label: "Non-incremental Reason:" }
|
||||
]
|
||||
},
|
||||
|
||||
/* Group 2 - User Controlled */
|
||||
"ConsoleTime": {
|
||||
group: 2,
|
||||
colorName: "graphs-grey",
|
||||
label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
|
||||
fields: [{
|
||||
property: "causeName",
|
||||
label: L10N.getStr("timeline.markerDetail.consoleTimerName")
|
||||
}]
|
||||
},
|
||||
"TimeStamp": {
|
||||
group: 2,
|
||||
colorName: "graphs-blue",
|
||||
label: sublabelForProperty(L10N.getStr("timeline.label.timestamp"), "causeName"),
|
||||
fields: [{
|
||||
property: "causeName",
|
||||
label: "Label:"
|
||||
}]
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* A series of formatters used by the blueprint.
|
||||
*/
|
||||
|
||||
function getGCLabel (marker={}) {
|
||||
let label = L10N.getStr("timeline.label.garbageCollection");
|
||||
// Only if a `nonincrementalReason` exists, do we want to label
|
||||
// this as a non incremental GC event.
|
||||
if ("nonincrementalReason" in marker) {
|
||||
label = `${label} (Non-incremental)`;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping of JS marker causes to a friendlier form. Only
|
||||
* markers that are considered "from content" should be labeled here.
|
||||
*/
|
||||
const JS_MARKER_MAP = {
|
||||
"<script> element": "Script Tag",
|
||||
"setInterval handler": "setInterval",
|
||||
"setTimeout handler": "setTimeout",
|
||||
"FrameRequestCallback": "requestAnimationFrame",
|
||||
"promise callback": "Promise Callback",
|
||||
"promise initializer": "Promise Init",
|
||||
"Worker runnable": "Worker",
|
||||
"javascript: URI": "JavaScript URI",
|
||||
// As far as I know, the difference between these two
|
||||
// event handler markers are differences in their webidl implementation.
|
||||
"EventHandlerNonNull": "Event Handler",
|
||||
"EventListener.handleEvent": "Event Handler",
|
||||
};
|
||||
|
||||
function getJSLabel (marker={}) {
|
||||
let generic = L10N.getStr("timeline.label.javascript2");
|
||||
if ("causeName" in marker) {
|
||||
return JS_MARKER_MAP[marker.causeName] || generic;
|
||||
}
|
||||
return generic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hash for computing a fields object for a JS marker. If the cause
|
||||
* is considered content (so an entry exists in the JS_MARKER_MAP), do not display it
|
||||
* since it's redundant with the label. Otherwise for Gecko code, either display
|
||||
* the cause, or "(Gecko)", depending on if "show-platform-data" is set.
|
||||
*/
|
||||
function getJSFields (marker) {
|
||||
if ("causeName" in marker && !JS_MARKER_MAP[marker.causeName]) {
|
||||
return { Reason: (SHOW_PLATFORM_DATA ? marker.causeName : GECKO_SYMBOL) };
|
||||
}
|
||||
}
|
||||
|
||||
function getDOMEventFields (marker) {
|
||||
let fields = Object.create(null);
|
||||
if ("type" in marker) {
|
||||
fields[L10N.getStr("timeline.markerDetail.DOMEventType")] = marker.type;
|
||||
}
|
||||
if ("eventPhase" in marker) {
|
||||
let phase;
|
||||
if (marker.eventPhase === Ci.nsIDOMEvent.AT_TARGET) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventTargetPhase");
|
||||
} else if (marker.eventPhase === Ci.nsIDOMEvent.CAPTURING_PHASE) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventCapturingPhase");
|
||||
} else if (marker.eventPhase === Ci.nsIDOMEvent.BUBBLING_PHASE) {
|
||||
phase = L10N.getStr("timeline.markerDetail.DOMEventBubblingPhase");
|
||||
}
|
||||
fields[L10N.getStr("timeline.markerDetail.DOMEventPhase")] = phase;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
function getStylesFields (marker) {
|
||||
if ("restyleHint" in marker) {
|
||||
return { "Restyle Hint": marker.restyleHint.replace(/eRestyle_/g, "") };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a main label (like "Timestamp") and a property,
|
||||
* and returns a marker that will print out the property
|
||||
* value for a marker if it exists ("Timestamp (rendering)"),
|
||||
* or just the main label if it does not.
|
||||
*/
|
||||
function sublabelForProperty (mainLabel, prop) {
|
||||
return (marker={}) => marker[prop] ? `${mainLabel} (${marker[prop]})` : mainLabel;
|
||||
}
|
||||
|
||||
// Exported symbols.
|
||||
exports.L10N = L10N;
|
||||
exports.TIMELINE_BLUEPRINT = TIMELINE_BLUEPRINT;
|
|
@ -409,8 +409,13 @@ ViewHelpers.L10N.prototype = {
|
|||
* The root path to the required preferences branch.
|
||||
* @param object aPrefsBlueprint
|
||||
* An object containing { accessorName: [prefType, prefName] } keys.
|
||||
* @param object aOptions
|
||||
* Additional options for this constructor. Currently supported:
|
||||
* - monitorChanges: true to update the stored values if they changed
|
||||
* when somebody edits about:config or the prefs
|
||||
* change somewhere else.
|
||||
*/
|
||||
ViewHelpers.Prefs = function(aPrefsRoot = "", aPrefsBlueprint = {}) {
|
||||
ViewHelpers.Prefs = function(aPrefsRoot = "", aPrefsBlueprint = {}, aOptions = {}) {
|
||||
EventEmitter.decorate(this);
|
||||
|
||||
this._cache = new Map();
|
||||
|
@ -442,6 +447,10 @@ ViewHelpers.Prefs = function(aPrefsRoot = "", aPrefsBlueprint = {}) {
|
|||
|
||||
this.registerObserver = () => observer.register();
|
||||
this.unregisterObserver = () => observer.unregister();
|
||||
|
||||
if (aOptions.monitorChanges) {
|
||||
this.registerObserver();
|
||||
}
|
||||
};
|
||||
|
||||
ViewHelpers.Prefs.prototype = {
|
||||
|
|
|
@ -70,7 +70,7 @@ class ProfileEntry
|
|||
CATEGORY_MASK = ~IS_CPP_ENTRY & ~FRAME_LABEL_COPY & ~BEGIN_PSEUDO_JS & ~OSR
|
||||
};
|
||||
|
||||
// Keep these in sync with browser/devtools/profiler/utils/global.js
|
||||
// Keep these in sync with browser/devtools/performance/modules/global.js
|
||||
enum class Category : uint32_t {
|
||||
OTHER = 0x10,
|
||||
CSS = 0x20,
|
||||
|
|
Загрузка…
Ссылка в новой задаче