Bug 1462784 - Update the devtools performance panel for the new category list. r=gregtatum

MozReview-Commit-ID: HwRFEfgA4L

--HG--
extra : rebase_source : 56e48e2bac9db59da7706392f3f57d0f66763eee
This commit is contained in:
Markus Stange 2018-05-23 23:11:41 -04:00
Родитель 1b73b9762e
Коммит 2d2563cbdc
10 изменённых файлов: 94 добавлений и 142 удалений

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

@ -63,13 +63,13 @@ graphs.memory=MB
# as the legend for each block in every bar. These labels should be kept
# AS SHORT AS POSSIBLE so they don't obstruct important parts of the graph.
category.other=Gecko
category.css=Styles
category.layout=Layout
category.js=JIT
category.gc=GC
category.network=Network
category.graphics=Graphics
category.storage=Storage
category.events=Input & Events
category.dom=DOM
category.idle=Idle
category.tools=Tools
# LOCALIZATION NOTE (table.bytes):

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

@ -7,16 +7,20 @@ const { L10N } = require("devtools/client/performance/modules/global");
/**
* Details about each label stack frame category.
* @see CATEGORY_MAPPINGS.
* To be kept in sync with the js::ProfilingStackFrame::Category in ProfilingStack.h
*/
const CATEGORIES = [{
color: "#d99b28",
abbrev: "idle",
label: L10N.getStr("category.idle")
}, {
color: "#5e88b0",
abbrev: "other",
label: L10N.getStr("category.other")
}, {
color: "#46afe3",
abbrev: "css",
label: L10N.getStr("category.css")
abbrev: "layout",
label: L10N.getStr("category.layout")
}, {
color: "#d96629",
abbrev: "js",
@ -35,94 +39,35 @@ const CATEGORIES = [{
label: L10N.getStr("category.graphics")
}, {
color: "#8fa1b2",
abbrev: "storage",
label: L10N.getStr("category.storage")
}, {
color: "#d99b28",
abbrev: "events",
label: L10N.getStr("category.events")
abbrev: "dom",
label: L10N.getStr("category.dom")
}, {
// The devtools-only "tools" category which gets computed by
// computeIsContentAndCategory and is not part of the category list in
// ProfilingStack.h.
color: "#8fa1b2",
abbrev: "tools",
label: L10N.getStr("category.tools")
}];
/**
* Mapping from category bitmasks in the profiler data to additional details.
* To be kept in sync with the js::ProfilingStackFrame::Category in ProfilingStack.h
* Get the numeric index for the given category abbreviation.
* See `CATEGORIES` above.
*/
const CATEGORY_MAPPINGS = {
// js::ProfilingStackFrame::Category::OTHER
"16": CATEGORIES[0],
// js::ProfilingStackFrame::Category::CSS
"32": CATEGORIES[1],
// js::ProfilingStackFrame::Category::JS
"64": CATEGORIES[2],
// js::ProfilingStackFrame::Category::GC
"128": CATEGORIES[3],
// js::ProfilingStackFrame::Category::CC
"256": CATEGORIES[3],
// js::ProfilingStackFrame::Category::NETWORK
"512": CATEGORIES[4],
// js::ProfilingStackFrame::Category::GRAPHICS
"1024": CATEGORIES[5],
// js::ProfilingStackFrame::Category::STORAGE
"2048": CATEGORIES[6],
// js::ProfilingStackFrame::Category::EVENTS
"4096": CATEGORIES[7],
// non-bitmasks for specially-assigned categories
"9000": CATEGORIES[8],
};
/**
* 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] = (() => {
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();
const CATEGORY_INDEX = (() => {
let indexForCategory = {};
for (let categoryIndex = 0; categoryIndex < CATEGORIES.length; categoryIndex++) {
const category = CATEGORIES[categoryIndex];
indexForCategory[category.abbrev] = categoryIndex;
}
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}".`);
}
return bitmasksForCategory[name][index - 1];
}
},
function(name) {
if (!(name in bitmasksForCategory)) {
throw new Error(`Category abbreviation "${name}" does not exist.`);
}
return bitmasksForCategory[name];
return function(name) {
if (!(name in indexForCategory)) {
throw new Error(`Category abbreviation "${name}" does not exist.`);
}
];
return indexForCategory[name];
};
})();
exports.CATEGORIES = CATEGORIES;
exports.CATEGORY_MAPPINGS = CATEGORY_MAPPINGS;
exports.CATEGORY_MASK = CATEGORY_MASK;
exports.CATEGORY_MASK_LIST = CATEGORY_MASK_LIST;
exports.CATEGORY_INDEX = CATEGORY_INDEX;

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

@ -9,7 +9,7 @@ const { assert } = require("devtools/shared/DevToolsUtils");
const { isChromeScheme, isContentScheme, isWASM, parseURL } =
require("devtools/client/shared/source-utils");
const { CATEGORY_MASK, CATEGORY_MAPPINGS } = require("devtools/client/performance/modules/categories");
const { CATEGORY_INDEX, CATEGORIES } = require("devtools/client/performance/modules/categories");
// Character codes used in various parsing helper functions.
const CHAR_CODE_R = "r".charCodeAt(0);
@ -190,7 +190,7 @@ function parseLocation(location, fallbackLine, fallbackColumn) {
*/
function computeIsContentAndCategory(frame) {
// Only C++ stack frames have associated category information.
if (frame.category) {
if (frame.category !== null && frame.category !== undefined) {
return;
}
@ -234,18 +234,18 @@ function computeIsContentAndCategory(frame) {
isChromeScheme(location, j) &&
(location.includes("resource://devtools") ||
location.includes("resource://devtools"))) {
frame.category = CATEGORY_MASK("tools");
frame.category = CATEGORY_INDEX("tools");
return;
}
}
}
if (location === "EnterJIT") {
frame.category = CATEGORY_MASK("js");
frame.category = CATEGORY_INDEX("js");
return;
}
frame.category = CATEGORY_MASK("other");
frame.category = CATEGORY_INDEX("other");
}
/**
@ -393,7 +393,7 @@ function getFrameInfo(node, options) {
data.isMetaCategory = node.isMetaCategory;
}
data.samples = node.youngestFrameSamples;
data.categoryData = CATEGORY_MAPPINGS[node.category] || {};
data.categoryData = CATEGORIES[node.category] || CATEGORIES[CATEGORY_INDEX("other")];
data.nodeType = node.nodeType;
// Frame name (function location or some meta information)

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

@ -9,7 +9,7 @@
const { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
const { CallView } = require("devtools/client/performance/modules/widgets/tree-view");
const { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
const { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
const RecordingUtils = require("devtools/shared/performance/recording-utils");
add_task(function() {
@ -89,20 +89,20 @@ const gProfile = RecordingUtils.deflateProfile({
{ location: "http://content/A" },
{ location: "http://content/E" },
{ location: "http://content/F" },
{ location: "platform_JS", category: CATEGORY_MASK("js") },
{ location: "platform_JS", category: CATEGORY_INDEX("js") },
]
}, {
time: 1 + 1 + 2 + 3,
frames: [
{ location: "(root)" },
{ location: "platform_JS2", category: CATEGORY_MASK("js") },
{ location: "platform_JS2", category: CATEGORY_INDEX("js") },
]
}, {
time: 1 + 1 + 2 + 3 + 5,
frames: [
{ location: "(root)" },
{ location: "http://content/A" },
{ location: "platform_GC", category: CATEGORY_MASK("gc", 1) },
{ location: "platform_GC", category: CATEGORY_INDEX("gc") },
]
}]
}]

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

@ -6,7 +6,7 @@
* Generates a generalized profile with some samples.
*/
exports.synthesizeProfile = () => {
const { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
const { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
const RecordingUtils = require("devtools/shared/performance/recording-utils");
return RecordingUtils.deflateProfile({
@ -15,34 +15,34 @@ exports.synthesizeProfile = () => {
samples: [{
time: 1,
frames: [
{ category: CATEGORY_MASK("other"), location: "(root)" },
{ category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_MASK("js"), location: "C (http://foo/bar/baz:56)" }
{ category: CATEGORY_INDEX("other"), location: "(root)" },
{ category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_INDEX("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_INDEX("js"), location: "C (http://foo/bar/baz:56)" }
]
}, {
time: 1 + 1,
frames: [
{ category: CATEGORY_MASK("other"), location: "(root)" },
{ category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_MASK("gc", 1), location: "D (http://foo/bar/baz:78:9)" }
{ category: CATEGORY_INDEX("other"), location: "(root)" },
{ category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_INDEX("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_INDEX("gc"), location: "D (http://foo/bar/baz:78:9)" }
]
}, {
time: 1 + 1 + 2,
frames: [
{ category: CATEGORY_MASK("other"), location: "(root)" },
{ category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_MASK("gc", 1), location: "D (http://foo/bar/baz:78:9)" }
{ category: CATEGORY_INDEX("other"), location: "(root)" },
{ category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_INDEX("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_INDEX("gc"), location: "D (http://foo/bar/baz:78:9)" }
]
}, {
time: 1 + 1 + 2 + 3,
frames: [
{ category: CATEGORY_MASK("other"), location: "(root)" },
{ category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_MASK("gc", 2), location: "E (http://foo/bar/baz:90)" },
{ category: CATEGORY_MASK("network"), location: "F (http://foo/bar/baz:99)" }
{ category: CATEGORY_INDEX("other"), location: "(root)" },
{ category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_INDEX("gc"), location: "E (http://foo/bar/baz:90)" },
{ category: CATEGORY_INDEX("network"), location: "F (http://foo/bar/baz:99)" }
]
}]
}]

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

@ -7,7 +7,7 @@
*/
add_task(function() {
let { CATEGORIES, CATEGORY_MAPPINGS } = require("devtools/client/performance/modules/categories");
let { CATEGORIES } = require("devtools/client/performance/modules/categories");
let { L10N } = require("devtools/client/performance/modules/global");
let count = CATEGORIES.length;
@ -22,12 +22,4 @@ add_task(function() {
ok(CATEGORIES.every(e => e.label === L10N.getStr("category." + e.abbrev)),
"All categories have a correctly localized label.");
ok(Object.keys(CATEGORY_MAPPINGS).every(e => (Number(e) >= 9000 && Number(e) <= 9999) ||
Number.isInteger(Math.log2(e))),
"All bitmask mappings keys are powers of 2, or between 9000-9999 for special " +
"categories.");
ok(Object.keys(CATEGORY_MAPPINGS).every(e => CATEGORIES.includes(CATEGORY_MAPPINGS[e])),
"All bitmask mappings point to a category.");
});

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

@ -6,7 +6,7 @@
* Tests that when displaying only content nodes, platform nodes are generalized.
*/
var { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
var { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
add_task(function test() {
let { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
@ -35,22 +35,29 @@ add_task(function test() {
equal(root.calls.length, 2, "root has 2 children");
ok(getFrameNodePath(root, url("A")), "root has content child");
ok(getFrameNodePath(root, "64"), "root has platform generalized child");
equal(getFrameNodePath(root, "64").calls.length, 0,
ok(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`),
"root has platform generalized child");
equal(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`).calls.length, 0,
"platform generalized child is a leaf.");
ok(getFrameNodePath(root, `${url("A")} > 128`),
ok(getFrameNodePath(root, `${url("A")} > ${CATEGORY_INDEX("gc")}`),
"A has platform generalized child of another type");
equal(getFrameNodePath(root, `${url("A")} > 128`).calls.length, 0,
equal(getFrameNodePath(root, `${url("A")} > ${CATEGORY_INDEX("gc")}`).calls.length, 0,
"second generalized type is a leaf.");
ok(getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 64`),
ok(getFrameNodePath(
root,
`${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("js")}`
),
"a second leaf of the first generalized type exists deep in the tree.");
ok(getFrameNodePath(root, `${url("A")} > 128`),
ok(getFrameNodePath(root, `${url("A")} > ${CATEGORY_INDEX("gc")}`),
"A has platform generalized child of another type");
equal(getFrameNodePath(root, "64").category,
getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 64`).category,
equal(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`).category,
getFrameNodePath(
root,
`${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("js")}`
).category,
"generalized frames of same type are duplicated in top-down view");
});
@ -68,7 +75,7 @@ var gThread = synthesizeProfileForTest([{
{ location: "(root)" },
{ location: "http://content/A" },
{ location: "http://content/B" },
{ location: "contentY", category: CATEGORY_MASK("css") },
{ location: "contentY", category: CATEGORY_INDEX("layout") },
{ location: "http://content/D" }
]
}, {
@ -76,22 +83,22 @@ var gThread = synthesizeProfileForTest([{
frames: [
{ location: "(root)" },
{ location: "http://content/A" },
{ location: "contentY", category: CATEGORY_MASK("css") },
{ location: "contentY", category: CATEGORY_INDEX("layout") },
{ location: "http://content/E" },
{ location: "http://content/F" },
{ location: "contentY", category: CATEGORY_MASK("js") },
{ location: "contentY", category: CATEGORY_INDEX("js") },
]
}, {
time: 5 + 20,
frames: [
{ location: "(root)" },
{ location: "contentX", category: CATEGORY_MASK("js") },
{ location: "contentX", category: CATEGORY_INDEX("js") },
]
}, {
time: 5 + 25,
frames: [
{ location: "(root)" },
{ location: "http://content/A" },
{ location: "contentZ", category: CATEGORY_MASK("gc", 1) },
{ location: "contentZ", category: CATEGORY_INDEX("gc") },
]
}]);

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

@ -9,7 +9,7 @@
add_task(function test() {
let FrameUtils = require("devtools/client/performance/modules/logic/frame-utils");
let { FrameNode } = require("devtools/client/performance/modules/logic/tree-model");
let { CATEGORY_MASK } = require("devtools/client/performance/modules/categories");
let { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
let compute = frame => {
FrameUtils.computeIsContentAndCategory(frame);
return frame;
@ -39,7 +39,7 @@ add_task(function test() {
new FrameNode("Foo::Bar::Baz", compute({
location: "Foo::Bar::Baz",
line: 456,
category: CATEGORY_MASK("other"),
category: CATEGORY_INDEX("other"),
}), false),
new FrameNode("EnterJIT", compute({
location: "EnterJIT",

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

@ -6,6 +6,8 @@
* Tests that when displaying only content nodes, platform nodes are generalized.
*/
var { CATEGORY_INDEX } = require("devtools/client/performance/modules/categories");
add_task(function test() {
let { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
let url = (n) => `http://content/${n}`;
@ -32,16 +34,19 @@ add_task(function test() {
equal(root.calls.length, 2, "root has 2 children");
ok(getFrameNodePath(root, url("A")), "root has content child");
ok(getFrameNodePath(root, "9000"),
ok(getFrameNodePath(root, `${CATEGORY_INDEX("tools")}`),
"root has platform generalized child from Chrome JS");
equal(getFrameNodePath(root, "9000").calls.length, 0,
equal(getFrameNodePath(root, `${CATEGORY_INDEX("tools")}`).calls.length, 0,
"platform generalized child is a leaf.");
ok(getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 9000`),
ok(getFrameNodePath(root,
`${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("tools")}`),
"a second leaf of the generalized Chrome JS exists.");
equal(getFrameNodePath(root, "9000").category,
getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 9000`).category,
equal(getFrameNodePath(root, `${CATEGORY_INDEX("tools")}`).category,
getFrameNodePath(root,
`${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("tools")}`
).category,
"generalized frames of same type are duplicated in top-down view");
});

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

@ -13,7 +13,9 @@ loader.lazyRequireGetter(this, "EventEmitter",
loader.lazyRequireGetter(this, "getColor",
"devtools/client/shared/theme", true);
loader.lazyRequireGetter(this, "CATEGORY_MAPPINGS",
loader.lazyRequireGetter(this, "CATEGORIES",
"devtools/client/performance/modules/categories", true);
loader.lazyRequireGetter(this, "CATEGORY_INDEX",
"devtools/client/performance/modules/categories", true);
loader.lazyRequireGetter(this, "FrameUtils",
"devtools/client/performance/modules/logic/frame-utils");
@ -1292,7 +1294,8 @@ var FlameGraphUtils = {
if (frameKey !== "" && frameKey !== "(root)") {
// If the frame is a meta category, use the category label.
if (mutableFrameKeyOptions.isMetaCategoryOut) {
frameKey = CATEGORY_MAPPINGS[frameKey].label;
let category = CATEGORIES[frameKey] || CATEGORIES[CATEGORY_INDEX("other")];
frameKey = category.label;
}
sampleFrames[stackDepth] = inflatedFrame;