Skip to content

Commit fdb0dce

Browse files
authored
Add an --insert-label-frames argument to the profiler-edit tool (#5966)
Based on #6076. This lets us create profiles like https://share.firefox.dev/4mPPTgr with DOM label frames that show up in the JS-only view, for profiles from samply, based on function name matching. The matchers are declared in a toml file that is passed to the script. Example TOML file: https://gist.github.com/mstange/827c40404c987bc566b8b324efc0a04f
2 parents d058937 + 2cb282f commit fdb0dce

6 files changed

Lines changed: 793 additions & 2 deletions

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@
110110
"redux-logger": "^3.0.6",
111111
"redux-thunk": "^3.1.0",
112112
"reselect": "^4.1.8",
113+
"smol-toml": "^1.6.1",
113114
"source-map": "^0.7.6",
114115
"url": "^0.11.4",
115116
"valibot": "^1.4.1",

src/node-tools/profiler-edit.ts

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
44
import fs from 'fs';
55
import { Command, CommanderError, Option } from 'commander';
6+
import { parse as parseToml } from 'smol-toml';
67

78
import {
89
serializeProfileToJsonSlabsFile,
@@ -12,6 +13,7 @@ import {
1213
import { computeCompactedProfile } from 'firefox-profiler/profile-logic/profile-compacting';
1314
import { GOOGLE_STORAGE_BUCKET } from 'firefox-profiler/app-logic/constants';
1415
import { compress } from 'firefox-profiler/utils/gz';
16+
import { insertStackLabels } from 'firefox-profiler/profile-logic/insert-stack-labels';
1517
import { SymbolStore } from 'firefox-profiler/profile-logic/symbol-store';
1618
import {
1719
symbolicateProfile,
@@ -25,6 +27,11 @@ import {
2527
} from 'firefox-profiler/profile-logic/wasm-symbolication';
2628
import type { Profile } from 'firefox-profiler/types/profile';
2729
import { assertExhaustiveCheck } from 'firefox-profiler/utils/types';
30+
import {
31+
type AutoLabel,
32+
type LabelDescription,
33+
resolveAllLabels,
34+
} from 'firefox-profiler/utils/label-templates';
2835

2936
/**
3037
* A CLI tool for editing profiles.
@@ -42,6 +49,9 @@ import { assertExhaustiveCheck } from 'firefox-profiler/utils/types';
4249
* node node-tools-dist/profiler-edit.js -i input.json.gz -o out.json.gz \
4350
* --symbolicate-wasm http://host/a.wasm=./a-unstripped.wasm \
4451
* --symbolicate-wasm http://host/b.wasm=./b-unstripped.wasm
52+
*
53+
* node node-tools-dist/profiler-edit.js --from-hash w1spyw917hg... -o out.json.gz \
54+
* --insert-label-frames known-functions.toml
4555
*/
4656

4757
type ProfileSource =
@@ -65,6 +75,7 @@ export interface CliOptions {
6575
output: string;
6676
symbolicateWithServer?: string;
6777
symbolicateWasm: WasmSymbolicationCliSpec[];
78+
insertLabelFrames?: string;
6879
}
6980

7081
function loadWasmSymbolicationSpecs(
@@ -81,6 +92,42 @@ function loadWasmSymbolicationSpecs(
8192
});
8293
}
8394

95+
/**
96+
* Reconstruct the func-name strings used by insertStackLabels' prefix matcher
97+
* (mirrors getLabelIndexForFunc in insert-stack-labels.ts), so auto-discovery
98+
* sees the same strings the labeler will compare against.
99+
*/
100+
function collectFuncNames(profile: Profile): string[] {
101+
const { funcTable, sources, stringArray } = profile.shared;
102+
const result: string[] = [];
103+
for (let i = 0; i < funcTable.length; i++) {
104+
let name = stringArray[funcTable.name[i]];
105+
const sourceIndex = funcTable.source[i];
106+
if (sourceIndex !== null) {
107+
const filename = stringArray[sources.filename[sourceIndex]];
108+
name += ` (${filename})`;
109+
}
110+
result.push(name);
111+
}
112+
return result;
113+
}
114+
115+
export type ParsedLabelToml = {
116+
labels: LabelDescription[];
117+
autoLabels: AutoLabel[];
118+
};
119+
120+
export function parseLabelToml(tomlText: string): ParsedLabelToml {
121+
const data = parseToml(tomlText) as unknown as {
122+
labels?: LabelDescription[];
123+
auto_labels?: AutoLabel[];
124+
};
125+
return {
126+
labels: data.labels ?? [],
127+
autoLabels: data.auto_labels ?? [],
128+
};
129+
}
130+
84131
async function loadProfile(source: ProfileSource): Promise<Profile> {
85132
switch (source.type) {
86133
case 'FILE': {
@@ -151,7 +198,7 @@ async function encodeProfileWithFilename(
151198
}
152199

153200
export async function run(options: CliOptions) {
154-
const profile = await loadProfile(options.input);
201+
let profile = await loadProfile(options.input);
155202

156203
if (options.symbolicateWithServer !== undefined) {
157204
const server = options.symbolicateWithServer;
@@ -205,6 +252,19 @@ export async function run(options: CliOptions) {
205252
loadWasmSymbolicationSpecs(options.symbolicateWasm)
206253
);
207254

255+
if (options.insertLabelFrames !== undefined) {
256+
console.log('Inserting label frames...');
257+
const tomlText = fs.readFileSync(options.insertLabelFrames, 'utf8');
258+
const parsed = parseLabelToml(tomlText);
259+
const funcNames = collectFuncNames(profile);
260+
const labels = resolveAllLabels(
261+
parsed.autoLabels,
262+
parsed.labels,
263+
funcNames
264+
);
265+
profile = insertStackLabels(profile, labels);
266+
}
267+
208268
const { profile: compactedProfile } = computeCompactedProfile(profile);
209269

210270
const outputFilename = options.output;
@@ -263,7 +323,8 @@ export function makeOptionsFromArgv(processArgv: string[]): CliOptions {
263323
)
264324
.argParser(collectWasm)
265325
.default([] as WasmSymbolicationCliSpec[])
266-
);
326+
)
327+
.option('--insert-label-frames <path>', 'TOML file with label definitions');
267328

268329
program.parse(processArgv);
269330
const opts = program.opts();
@@ -310,6 +371,11 @@ export function makeOptionsFromArgv(processArgv: string[]): CliOptions {
310371
? opts.symbolicateWithServer
311372
: undefined,
312373
symbolicateWasm: opts.symbolicateWasm,
374+
insertLabelFrames:
375+
typeof opts.insertLabelFrames === 'string' &&
376+
opts.insertLabelFrames !== ''
377+
? opts.insertLabelFrames
378+
: undefined,
313379
};
314380
}
315381

0 commit comments

Comments
 (0)