Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions profiler-cli/guide.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ CORE WORKFLOW
All samples commands exclude idle by default so percentages reflect active CPU time.
Use --include-idle to include idle samples (e.g. to see what fraction of wall time is idle).

Use --strategy to summarize allocated bytes instead of CPU time on profiles with
allocation tracking. See DATA SOURCES below.

Use --search to focus the call tree on paths containing a specific function:
profiler-cli thread samples-top-down --search GC
profiler-cli thread samples-bottom-up --search "JS::Compile"
Expand Down Expand Up @@ -279,6 +282,29 @@ SOURCE MAPS
"function annotate f-N" can show it with per-line sample counts.


DATA SOURCES

By default the samples and functions commands summarize sample timing. Profiles
recorded with allocation tracking can be summarized by allocated bytes instead.

timing CPU sample counts (default)
js-allocations Bytes of JavaScript allocated
native-retained-allocations Bytes allocated and never freed
native-allocations Bytes allocated, freed or not
native-deallocations-memory Bytes freed, attributed to the allocation site
native-deallocations-sites Bytes freed, attributed to the free site

Allocation sources report bytes, so "total" and "self" read as sizes (e.g. 1.2MB)
rather than sample counts.

profiler-cli thread info Which sources this thread has
profiler-cli strategy native-allocations Sticky: applies to later commands
profiler-cli thread samples --strategy js-allocations Ephemeral: one command only

Asking for a source the thread has no data for is an error, so byte-free output
never gets mistaken for allocation data.


JSON OUTPUT

Add --json to any command to get structured JSON output, suitable for piping to jq
Expand Down
27 changes: 25 additions & 2 deletions profiler-cli/schemas.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,17 @@ SessionContext (present on all command results):
selectedThreadHandle,
selectedThreads: [{ threadIndex, name }],
currentViewRange: { start, startName, end, endName } | null,
rootRange: { start, end }
rootRange: { start, end },
callTreeSummaryStrategy: CallTreeSummaryStrategy
}

CallTreeSummaryStrategy:
"timing" | "js-allocations" | "native-retained-allocations" |
"native-allocations" | "native-deallocations-memory" |
"native-deallocations-sites"

WeightType:
"samples" | "tracing-ms" | "bytes"

profiler-cli profile info --json
{
Expand Down Expand Up @@ -105,6 +113,7 @@ profiler-cli thread info --json
cpuActivity: [{ startTime, startTimeName, startTimeStr,
endTime, endTimeName, endTimeStr, cpuMs, depthLevel }] | null,
networkActivity: ThreadNetworkSummary | null,
availableStrategies: [CallTreeSummaryStrategy],
context: SessionContext
}

Expand All @@ -121,6 +130,7 @@ profiler-cli thread samples --json
{
type: "thread-samples",
threadHandle, friendlyThreadName, activeOnly?,
callTreeSummaryStrategy: CallTreeSummaryStrategy, weightType: WeightType,
topFunctionsBySelf: [{ functionHandle, functionIndex, name, nameWithLibrary,
library?, selfSamples, selfPercentage,
totalSamples, totalPercentage }],
Expand Down Expand Up @@ -148,6 +158,7 @@ profiler-cli thread samples-top-down --json
{
type: "thread-samples-top-down",
threadHandle, friendlyThreadName, activeOnly?,
callTreeSummaryStrategy: CallTreeSummaryStrategy, weightType: WeightType,
regularCallTree: CallTreeNode,
activeFilters?, ephemeralFilters?,
context: SessionContext
Expand All @@ -157,6 +168,7 @@ profiler-cli thread samples-bottom-up --json
{
type: "thread-samples-bottom-up",
threadHandle, friendlyThreadName, activeOnly?,
callTreeSummaryStrategy: CallTreeSummaryStrategy, weightType: WeightType,
invertedCallTree: CallTreeNode | null,
activeFilters?, ephemeralFilters?,
context: SessionContext
Expand Down Expand Up @@ -195,6 +207,7 @@ profiler-cli thread functions --json
{
type: "thread-functions",
threadHandle, friendlyThreadName, activeOnly?,
callTreeSummaryStrategy: CallTreeSummaryStrategy, weightType: WeightType,
totalFunctionCount, filteredFunctionCount,
functions: [{ functionHandle, name, nameWithLibrary, library?,
selfSamples, selfPercentage, totalSamples, totalPercentage,
Expand Down Expand Up @@ -251,14 +264,24 @@ profiler-cli marker info --json
stack?: { frames: [{ name, nameWithLibrary }], truncated }
}

profiler-cli strategy --json
{
type: "strategy-select",
threadHandle,
strategy: CallTreeSummaryStrategy,
availableStrategies: [CallTreeSummaryStrategy],
context: SessionContext
}

profiler-cli status --json
{
type: "status",
selectedThreadHandle,
selectedThreads: [{ threadIndex, name }],
viewRanges: [{ start, startName, end, endName }],
rootRange: { start, end },
filterStacks: [{ threadHandle, filters: FilterEntry[] }]
filterStacks: [{ threadHandle, filters: FilterEntry[] }],
callTreeSummaryStrategy: CallTreeSummaryStrategy
}

profiler-cli sourcemap sources --json
Expand Down
52 changes: 30 additions & 22 deletions profiler-cli/src/commands/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
*/

import type { Command } from 'commander';
import { addGlobalOptions, runCommand } from './shared';
import {
addGlobalOptions,
addStrategyOption,
parseOptionalStrategyArg,
runCommand,
} from './shared';

export function registerFunctionCommand(
program: Command,
Expand Down Expand Up @@ -43,27 +48,29 @@ export function registerFunctionCommand(
);
});

addGlobalOptions(
fn
.command('annotate [handle]')
.description(
'Show annotated source/assembly with timing data (e.g. f-123)'
)
.option('--function <handle>', 'Function handle')
.option(
'--mode <mode>',
'Annotation mode: src, asm, or all (default: src)',
'src'
)
.option(
'--symbol-server <url>',
'Symbol server URL for asm mode. Defaults to the ?symbolServer= value from the loaded URL, or the Mozilla symbol server.'
)
.option(
'--context <context>',
'Source context: number of lines around annotated lines, or "file" for the whole file (default: 2)',
'2'
)
addStrategyOption(
addGlobalOptions(
fn
.command('annotate [handle]')
.description(
'Show annotated source/assembly with timing data (e.g. f-123)'
)
.option('--function <handle>', 'Function handle')
.option(
'--mode <mode>',
'Annotation mode: src, asm, or all (default: src)',
'src'
)
.option(
'--symbol-server <url>',
'Symbol server URL for asm mode. Defaults to the ?symbolServer= value from the loaded URL, or the Mozilla symbol server.'
)
.option(
'--context <context>',
'Source context: number of lines around annotated lines, or "file" for the whole file (default: 2)',
'2'
)
)
).action(async (handleArg: string | undefined, opts) => {
const funcHandle = handleArg ?? opts.function;
await runCommand(
Expand All @@ -75,6 +82,7 @@ export function registerFunctionCommand(
annotateMode: opts.mode,
symbolServerUrl: opts.symbolServer,
annotateContext: opts.context,
strategy: parseOptionalStrategyArg(opts.strategy),
},
opts
);
Expand Down
40 changes: 39 additions & 1 deletion profiler-cli/src/commands/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import { Option } from 'commander';
import { collectStrings } from '../utils/parse';
import { sendCommand } from '../client';
import { formatOutput } from '../output';
import type { ClientCommand } from '../protocol';
import { CALL_TREE_SUMMARY_STRATEGIES } from 'firefox-profiler/profile-logic/profile-data';
import type { ClientCommand, CallTreeSummaryStrategy } from '../protocol';

/**
* Options shared by every command action via `addGlobalOptions`.
Expand Down Expand Up @@ -77,6 +78,43 @@ export function parseFloatArg(
return v;
}

/**
* Parse a strategy name and exit with an error if it is not a valid strategy.
*/
export function parseStrategyArg(
flagName: string,
value: string
): CallTreeSummaryStrategy {
if (!(CALL_TREE_SUMMARY_STRATEGIES as string[]).includes(value)) {
console.error(
`Error: ${flagName} must be one of: ${CALL_TREE_SUMMARY_STRATEGIES.join(', ')}`
);
process.exit(1);
}
return value as CallTreeSummaryStrategy;
}

/**
* As parseStrategyArg, but for the optional --strategy flag.
*/
export function parseOptionalStrategyArg(
value: string | undefined
): CallTreeSummaryStrategy | undefined {
return value === undefined
? undefined
: parseStrategyArg('--strategy', value);
}

/**
* Add the --strategy option to a command.
*/
export function addStrategyOption(cmd: Command): Command {
return cmd.option(
'--strategy <name>',
`Data source to summarize: ${CALL_TREE_SUMMARY_STRATEGIES.join(', ')}. Allocation strategies report bytes instead of samples.`
);
}

/**
* Returns true if the given subcommand was explicitly typed by the user.
* Used to decide whether to print a "other subcommands" hint after a default action.
Expand Down
30 changes: 30 additions & 0 deletions profiler-cli/src/commands/strategy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* 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/. */

/**
* `profiler-cli strategy` command.
*/

import type { Command } from 'commander';
import { CALL_TREE_SUMMARY_STRATEGIES } from 'firefox-profiler/profile-logic/profile-data';
import { addGlobalOptions, parseStrategyArg, runCommand } from './shared';

export function registerStrategyCommand(
program: Command,
sessionDir: string
): void {
addGlobalOptions(
program
.command('strategy <name>')
.description(
`Set the data source that the samples and functions commands summarize: ${CALL_TREE_SUMMARY_STRATEGIES.join(', ')}`
)
).action(async (nameArg: string, opts) => {
await runCommand(
sessionDir,
{ command: 'strategy', strategy: parseStrategyArg('strategy', nameArg) },
opts
);
});
}
Loading
Loading