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 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. # AS SHORT AS POSSIBLE so they don't obstruct important parts of the graph.
category.other=Gecko category.other=Gecko
category.css=Styles category.layout=Layout
category.js=JIT category.js=JIT
category.gc=GC category.gc=GC
category.network=Network category.network=Network
category.graphics=Graphics category.graphics=Graphics
category.storage=Storage category.dom=DOM
category.events=Input & Events category.idle=Idle
category.tools=Tools category.tools=Tools
# LOCALIZATION NOTE (table.bytes): # LOCALIZATION NOTE (table.bytes):

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

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

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

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

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

@ -9,7 +9,7 @@
const { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model"); const { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model");
const { CallView } = require("devtools/client/performance/modules/widgets/tree-view"); 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"); const RecordingUtils = require("devtools/shared/performance/recording-utils");
add_task(function() { add_task(function() {
@ -89,20 +89,20 @@ const gProfile = RecordingUtils.deflateProfile({
{ location: "http://content/A" }, { location: "http://content/A" },
{ location: "http://content/E" }, { location: "http://content/E" },
{ location: "http://content/F" }, { location: "http://content/F" },
{ location: "platform_JS", category: CATEGORY_MASK("js") }, { location: "platform_JS", category: CATEGORY_INDEX("js") },
] ]
}, { }, {
time: 1 + 1 + 2 + 3, time: 1 + 1 + 2 + 3,
frames: [ frames: [
{ location: "(root)" }, { location: "(root)" },
{ location: "platform_JS2", category: CATEGORY_MASK("js") }, { location: "platform_JS2", category: CATEGORY_INDEX("js") },
] ]
}, { }, {
time: 1 + 1 + 2 + 3 + 5, time: 1 + 1 + 2 + 3 + 5,
frames: [ frames: [
{ location: "(root)" }, { location: "(root)" },
{ location: "http://content/A" }, { 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. * Generates a generalized profile with some samples.
*/ */
exports.synthesizeProfile = () => { 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"); const RecordingUtils = require("devtools/shared/performance/recording-utils");
return RecordingUtils.deflateProfile({ return RecordingUtils.deflateProfile({
@ -15,34 +15,34 @@ exports.synthesizeProfile = () => {
samples: [{ samples: [{
time: 1, time: 1,
frames: [ frames: [
{ category: CATEGORY_MASK("other"), location: "(root)" }, { category: CATEGORY_INDEX("other"), location: "(root)" },
{ category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" }, { category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" }, { category: CATEGORY_INDEX("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_MASK("js"), location: "C (http://foo/bar/baz:56)" } { category: CATEGORY_INDEX("js"), location: "C (http://foo/bar/baz:56)" }
] ]
}, { }, {
time: 1 + 1, time: 1 + 1,
frames: [ frames: [
{ category: CATEGORY_MASK("other"), location: "(root)" }, { category: CATEGORY_INDEX("other"), location: "(root)" },
{ category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" }, { category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" }, { category: CATEGORY_INDEX("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_MASK("gc", 1), location: "D (http://foo/bar/baz:78:9)" } { category: CATEGORY_INDEX("gc"), location: "D (http://foo/bar/baz:78:9)" }
] ]
}, { }, {
time: 1 + 1 + 2, time: 1 + 1 + 2,
frames: [ frames: [
{ category: CATEGORY_MASK("other"), location: "(root)" }, { category: CATEGORY_INDEX("other"), location: "(root)" },
{ category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" }, { category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_MASK("css"), location: "B (http://foo/bar/baz:34)" }, { category: CATEGORY_INDEX("css"), location: "B (http://foo/bar/baz:34)" },
{ category: CATEGORY_MASK("gc", 1), location: "D (http://foo/bar/baz:78:9)" } { category: CATEGORY_INDEX("gc"), location: "D (http://foo/bar/baz:78:9)" }
] ]
}, { }, {
time: 1 + 1 + 2 + 3, time: 1 + 1 + 2 + 3,
frames: [ frames: [
{ category: CATEGORY_MASK("other"), location: "(root)" }, { category: CATEGORY_INDEX("other"), location: "(root)" },
{ category: CATEGORY_MASK("other"), location: "A (http://foo/bar/baz:12)" }, { category: CATEGORY_INDEX("other"), location: "A (http://foo/bar/baz:12)" },
{ category: CATEGORY_MASK("gc", 2), location: "E (http://foo/bar/baz:90)" }, { category: CATEGORY_INDEX("gc"), location: "E (http://foo/bar/baz:90)" },
{ category: CATEGORY_MASK("network"), location: "F (http://foo/bar/baz:99)" } { category: CATEGORY_INDEX("network"), location: "F (http://foo/bar/baz:99)" }
] ]
}] }]
}] }]

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

@ -7,7 +7,7 @@
*/ */
add_task(function() { 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 { L10N } = require("devtools/client/performance/modules/global");
let count = CATEGORIES.length; let count = CATEGORIES.length;
@ -22,12 +22,4 @@ add_task(function() {
ok(CATEGORIES.every(e => e.label === L10N.getStr("category." + e.abbrev)), ok(CATEGORIES.every(e => e.label === L10N.getStr("category." + e.abbrev)),
"All categories have a correctly localized label."); "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. * 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() { add_task(function test() {
let { ThreadNode } = require("devtools/client/performance/modules/logic/tree-model"); 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"); equal(root.calls.length, 2, "root has 2 children");
ok(getFrameNodePath(root, url("A")), "root has content child"); ok(getFrameNodePath(root, url("A")), "root has content child");
ok(getFrameNodePath(root, "64"), "root has platform generalized child"); ok(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`),
equal(getFrameNodePath(root, "64").calls.length, 0, "root has platform generalized child");
equal(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`).calls.length, 0,
"platform generalized child is a leaf."); "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"); "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."); "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."); "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"); "A has platform generalized child of another type");
equal(getFrameNodePath(root, "64").category, equal(getFrameNodePath(root, `${CATEGORY_INDEX("js")}`).category,
getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 64`).category, getFrameNodePath(
root,
`${url("A")} > ${url("E")} > ${url("F")} > ${CATEGORY_INDEX("js")}`
).category,
"generalized frames of same type are duplicated in top-down view"); "generalized frames of same type are duplicated in top-down view");
}); });
@ -68,7 +75,7 @@ var gThread = synthesizeProfileForTest([{
{ location: "(root)" }, { location: "(root)" },
{ location: "http://content/A" }, { location: "http://content/A" },
{ location: "http://content/B" }, { location: "http://content/B" },
{ location: "contentY", category: CATEGORY_MASK("css") }, { location: "contentY", category: CATEGORY_INDEX("layout") },
{ location: "http://content/D" } { location: "http://content/D" }
] ]
}, { }, {
@ -76,22 +83,22 @@ var gThread = synthesizeProfileForTest([{
frames: [ frames: [
{ location: "(root)" }, { location: "(root)" },
{ location: "http://content/A" }, { location: "http://content/A" },
{ location: "contentY", category: CATEGORY_MASK("css") }, { location: "contentY", category: CATEGORY_INDEX("layout") },
{ location: "http://content/E" }, { location: "http://content/E" },
{ location: "http://content/F" }, { location: "http://content/F" },
{ location: "contentY", category: CATEGORY_MASK("js") }, { location: "contentY", category: CATEGORY_INDEX("js") },
] ]
}, { }, {
time: 5 + 20, time: 5 + 20,
frames: [ frames: [
{ location: "(root)" }, { location: "(root)" },
{ location: "contentX", category: CATEGORY_MASK("js") }, { location: "contentX", category: CATEGORY_INDEX("js") },
] ]
}, { }, {
time: 5 + 25, time: 5 + 25,
frames: [ frames: [
{ location: "(root)" }, { location: "(root)" },
{ location: "http://content/A" }, { 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() { add_task(function test() {
let FrameUtils = require("devtools/client/performance/modules/logic/frame-utils"); let FrameUtils = require("devtools/client/performance/modules/logic/frame-utils");
let { FrameNode } = require("devtools/client/performance/modules/logic/tree-model"); 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 => { let compute = frame => {
FrameUtils.computeIsContentAndCategory(frame); FrameUtils.computeIsContentAndCategory(frame);
return frame; return frame;
@ -39,7 +39,7 @@ add_task(function test() {
new FrameNode("Foo::Bar::Baz", compute({ new FrameNode("Foo::Bar::Baz", compute({
location: "Foo::Bar::Baz", location: "Foo::Bar::Baz",
line: 456, line: 456,
category: CATEGORY_MASK("other"), category: CATEGORY_INDEX("other"),
}), false), }), false),
new FrameNode("EnterJIT", compute({ new FrameNode("EnterJIT", compute({
location: "EnterJIT", location: "EnterJIT",

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

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

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

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