modules/home/programs/cli-agents/shared/skills/samply-profiler/SKILL.md
Use when running samply to capture CPU profiles, profiling benchmark commands, analyzing `profile.json.gz` or `profile.json` files emitted by samply, working with Firefox Profiler captures or profiler.firefox.com URLs, finding CPU hot paths, resolving symbols, reading call trees, or comparing sampled performance profiles.
npx skillsauth add not-matthias/dotfiles-nix samply-profilerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Run samply to capture CPU profiles for benchmark commands, then analyze the resulting Firefox Profiler JSON offline. The bundled analyzer extracts thread lists, libraries, flat hot functions, and top-down call trees from profile.json.gz files.
samply.profile.json, profile.json.gz, or profiler.firefox.com/from-url/... link.0x1234abcd.samply for recording profiles.uv for running the bundled Python analyzer.addr2line, llvm-symbolizer, or similar symbol tools if raw addresses need resolving.Profile a repeatable command. Prefer an existing benchmark or test harness over ad-hoc manual interaction.
Record these details before profiling:
For compiled languages, profile an optimized build unless the user explicitly wants debug-mode behavior. Keep debug symbols available for symbolication.
Use --save-only so the agent gets a local profile file without depending on the browser UI.
samply record --save-only -o /tmp/profile.json.gz -- <benchmark-command> <args>
For very short commands, run repeated iterations so the profile has enough samples:
samply record --save-only -o /tmp/profile.json.gz --iteration-count 30 -- <short-command> <args>
For long-running services or benchmark servers on Linux, attach to the existing process for a fixed duration:
samply record --save-only -o /tmp/profile.json.gz --duration 30 --pid <pid>
Useful capture options:
| Option | Use when |
| --------------------------- | ----------------------------------------------------------------------------------------------------- |
| --rate <hz> | Adjust sampling frequency. Default is usually enough; lower it if overhead or file size is a problem. |
| --duration <seconds> | Bound captures of long-running processes. |
| --iteration-count <n> | Repeat short benchmark commands to collect enough samples. |
| --profile-name <name> | Label captures clearly, especially before/after runs. |
| --symbol-dir <dir> | Point samply at separate debug symbols. |
| --unstable-presymbolicate | Preserve gathered symbol data next to the profile when future symbol access may be hard. |
For before/after comparisons, keep the command, inputs, sampling rate, duration, iteration count, build mode, and machine conditions the same.
Resolve the analyzer path relative to this skill directory.
SKILL_DIR=/path/to/samply-profiler
uv run python "$SKILL_DIR/scripts/analyze_profile.py" /tmp/profile.json.gz threads
uv run python "$SKILL_DIR/scripts/analyze_profile.py" /tmp/profile.json.gz libs
Pick the hottest workload thread by sample count unless the user points to a specific thread. Verify it is not an idle thread, runtime helper, or background service thread.
uv run python "$SKILL_DIR/scripts/analyze_profile.py" /tmp/profile.json.gz flat --auto --top 40
Use self time to identify leaf work that directly burns CPU. Use total time to identify high-level routines that contain the hot work.
If frames are raw hex addresses, resolve them with addr2line:
uv run python "$SKILL_DIR/scripts/analyze_profile.py" /tmp/profile.json.gz flat --auto --resolve --top 40
If auto-detection cannot find the original binary path from libs[], provide it explicitly:
uv run python "$SKILL_DIR/scripts/analyze_profile.py" /tmp/profile.json.gz flat --auto --resolve --binary ./target/release/my-binary
uv run python "$SKILL_DIR/scripts/analyze_profile.py" /tmp/profile.json.gz tree --auto --depth 12 --min-pct 1.0
Read the tree top-down. The percentages are inclusive sample percentages; self= marks leaf time spent directly in that frame.
threads[].samples.stack indexes into stackTable.stackTable.frame indexes into frameTable; stackTable.prefix walks toward the root.frameTable.func indexes into funcTable.funcTable.name indexes into stringArray or stringTable.stackTable, frameTable, funcTable, resourceTable, and stringArray under top-level shared; older samply captures often store them per thread.libs[] records library and binary paths used for offline symbolication.## Profile Summary
- Capture: `<path>`
- Command: `<samply record ... -- command>` or `<provided profile>`
- Settings: rate `<hz>`, duration `<seconds or n/a>`, iterations `<n or n/a>`
- Thread: `[N] <name>` with `<samples>` samples
- Symbol status: `<resolved/partially resolved/unresolved>`
- Main bottleneck: `<one sentence>`
## Hottest Call Chain
1. `<root or entry>` – `<pct>%`
2. `<parent>` – `<pct>%`
3. `<leaf>` – `<pct>% self`
## Hot Functions
| Self % | Total % | Function | Note |
| -----: | ------: | -------- | ---- |
| ... | ... | ... | ... |
## Recommendations
1. `<specific optimization or next measurement>`
profile.json URL with curl; do not rely on headless browser automation.libs[].path may point to a path on another machine. Use --binary.--thread N.scripts/analyze_profile.py – main offline analyzer for threads, libraries, flat hot spots, call trees, and addr2line symbolication.references/capture-workflows.md – detailed samply record recipes for benchmark commands, short commands, services, and before/after captures.references/scripts.md – bundled script interface, rationale, and optional future scripts.references/firefox-profiler-format.md – compact reference for Firefox Profiler table relationships.documentation
Save notes, journal entries, and research to the personal-notes Obsidian vault (personal-vault-v2). Use when the user asks to 'save note', 'save to notes', 'write to personal notes', 'save to daily notes', 'note this down', or wants to persist findings/analysis to their personal vault.
documentation
Use whenever the user asks to address, fix, resolve, review, or respond to pull-request comments or review feedback.
development
Apply Not Matthias's Rust-first personal coding style. Use whenever the user explicitly asks to apply or review their code style, make Rust match their preferences, perform a style pass, or simplify/refactor according to their conventions. Inspect only task-touched code, honor local project conventions first, and make only safe opt-out style edits.
development
Guide for writing ast-grep rules to perform structural code search and analysis. Use when users need to search codebases using Abstract Syntax Tree (AST) patterns, find specific code structures, or perform complex code queries that go beyond simple text search. This skill should be used when users ask to search for code patterns, find specific language constructs, or locate code with particular structural characteristics.