Note
This package is in beta and I'm excited for you to try it! Share suggestions, bug reports, and feature requests by filing an issue.
# CPU profile
Took 2.49s over 2,659 samples (939.9µs per sample).
| Category | % | Time | Samples |
| ------------------ | ----: | ------: | ------: |
| Third-party | 87.4% | 2.18s | 2,410 |
| Garbage collector | 7.6% | 191.0ms | 156 |
| Standard library | 3.9% | 96.8ms | 70 |
| Native | 0.9% | 22.7ms | 20 |
| Regular expression | 0.1% | 2.5ms | 2 |
| Ours | 0.1% | 1.3ms | 1 |
## Hottest functions
### Self time
Functions ranked by time spent directly in the function body, excluding callees.
| % | Time | Samples | Function | Location |
| ---: | ------: | ------: | ------------------------------- | ---------------------------------------------------- |
| 7.6% | 191.0ms | 156 | `(garbage collector)` | `<unknown>` |
| 2.9% | 71.5ms | 57 | `wrapSafe` | `node:internal/modules/cjs/loader:1671:18` |
| 2.8% | 69.0ms | 66 | `recursiveTypeRelatedTo` | `node_modules/typescript/lib/typescript.js:64383:38` |
| 2.5% | 63.0ms | 66 | `isRelatedTo` | `node_modules/typescript/lib/typescript.js:63813:27` |
| 2.1% | 51.7ms | 43 | `checkTypeRelatedTo` | `node_modules/typescript/lib/typescript.js:63505:32` |
…The output continues with the hottest functions by total time, the hottest call
stacks, and per-line, caller, and callee detail. See the
full output, or
examples/output/ for heap snapshots and diffs.
- Polyglot: profile, call graph, and heap snapshot formats across many languages
- Profile analysis: sampling rates, category breakdowns, and the hottest functions, call stacks, lines, callers, and callees
- Heap analysis: self and dominator-based retained sizes, retainer paths, and the largest constructors and strings
- Multi-profile inputs: one
allJFR recording becomes CPU, allocation, and lock contention profiles - Diffing: ranked regressions and improvements between two profiles or two heap snapshots, across formats and profilers
- Source maps: resolves minified and transpiled locations back to original sources
- Zero config: auto-detects the format and profiler
- Configurable: top entry counts, base URLs, categorization, filtering, and diff matching
- CLI and API: a command line and a fully-typed API with sync and async variants (API docs)
- Self-documenting:
--help <language>and--help <format>explain how to generate and read each profile type - Agent-ready: ships a skill that guides an agent through profiling and optimizing your code
# npm
$ npm i -g profiler-md
# Homebrew
$ brew install tomeraberbach/tap/profiler-mdShell completions (optional)
# Bash (Linux)
$ profiler-md --completion bash > ~/.local/share/bash-completion/completions/profiler-md
# Bash (macOS/Homebrew)
$ profiler-md --completion bash > $(brew --prefix)/etc/bash_completion.d/profiler-md
# Fish
$ profiler-md --completion fish > ~/.config/fish/completions/profiler-md.fish
# Zsh
$ profiler-md --completion zsh > ~/.zfunc/_profiler-md
# PowerShell
$ profiler-md --completion pwsh >> $PROFILE.CurrentUserCurrentHost# Convert a profile, paged and syntax highlighted
$ profiler-md profile.cpuprofile
# Diff two profiles or two heap snapshots
$ profiler-md base.cpuprofile current.cpuprofile
# Write the Markdown to a file
$ profiler-md profile.pb.gz -o profile.md
# Read a profile from stdin
$ node --cpu-prof app.js && cat *.cpuprofile | profiler-md
# Show how to profile a language
$ profiler-md --help pythonAll flags
$ profiler-md --help
Converts performance profiles to human and LLM friendly Markdown.
Usage: profiler-md [OPTIONS] [FILE]
profiler-md [OPTIONS] BASE CURRENT
profiler-md --help [TOPIC]
Examples:
# Convert a profile, paged and syntax highlighted
$ profiler-md profile.cpuprofile
# Diff two profiles or two heap snapshots
$ profiler-md base.cpuprofile current.cpuprofile
# Write the Markdown to a file
$ profiler-md profile.pb.gz -o profile.md
# Read a profile from stdin
$ node --cpu-prof app.js && cat *.cpuprofile | profiler-md
# Show how to profile a language
$ profiler-md --help python
FILE Profile to convert (default: stdin)
BASE Base profile to diff
CURRENT Current profile to diff against the base
Output:
-o, --output FILE Output file (default: - for stdout)
--no-pager Disable stdout paging (default: auto)
--color, --no-color Enable or disable ANSI syntax
highlighting (default: auto)
Input:
-f, --format FORMAT Input profile format (default: auto)
-r, --origin ORIGIN Input profile origin (default: auto)
--source-maps GLOB Source maps (JSON or inline) to apply to
locations (repeatable)
--base-url STRING Base URL or path to show paths relative
to, or auto for their common ancestor
(default: cwd)
Ranking:
--top-n N Entries to show per ranking, including
category subsections (default: 20)
--min-category-share FRACTION Share of a profile a category needs for
its own subsection, from 0 to 1 (default:
0.01)
Filtering:
--category REGEX=CATEGORY Categorize functions whose name or
location matches REGEX as CATEGORY, first
rule winning (repeatable)
--hide REGEX Hide entries whose name or location
matches REGEX, still counting hidden
entries in totals (repeatable)
--show REGEX Show only entries whose name or location
matches REGEX, still counting hidden
entries in totals (repeatable)
--hide-category CATEGORY Hide entries of CATEGORY, still counting
hidden entries in totals (repeatable)
--show-category CATEGORY Show only entries of CATEGORY, still
counting hidden entries in totals
(repeatable)
Diffing:
--match-name REGEX=REPLACEMENT Rewrite names matching REGEX to
REPLACEMENT when pairing diffed entries
(repeatable)
--match-location REGEX=REPLACEMENT Rewrite locations (URL, path, or logical
name) matching REGEX to REPLACEMENT when
pairing diffed entries (repeatable)
Help:
-h, --help [TOPIC] Show this help message or topic docs
--version Show the version
--completion SHELL Print a completion script for SHELL
(bash, fish, nu, pwsh, or zsh)
Formats:
callgrind, collapsed, ghc-eventlog, ghc-json-profile, hprof, jfr,
jsc-heap-snapshot, memray, perf, pprof, speedscope, systing, v8-cpu-profile,
v8-heap-profile, v8-heap-snapshot, webkit-timeline-recording
Origins:
async-profiler, bun, chrome, deno, dotnet-trace, eflambe, excimer, ghc, go,
gperftools, jdk, memray, node, node-pprof, perf, pprof-jl, pprof-rs,
profile-jl, py-spy, pyinstrument, rbspy, safari, simpleperf, systing, tachyon,
unknown, valgrind
Function categories:
ours, third-party, stdlib, native, unknown, garbage-collector, compiler, jit,
regexp, kernel, idle
Heap snapshot categories:
object, array, string, concatenated-string, sliced-string, function, code,
regexp, number, big-number, symbol, native, object-shape, internal, synthetic,
unknown
Languages:
c/cpp, csharp/fsharp, elixir/erlang, fortran, go, haskell, java/kotlin/groovy,
javascript/typescript, julia, php, python, ruby, rust, swift, zig
Docs: https://github.com/TomerAberbach/profiler-md
Bugs: https://github.com/TomerAberbach/profiler-md/issuesimport { openAsBlob } from 'node:fs'
import { diffProfilesAsync, profileToMdAsync } from 'profiler-md'
// Convert a profile or heap snapshot. The format and origin are auto-detected
console.log(await profileToMdAsync(await openAsBlob(`example.cpuprofile`)))
// Diff two profiles or two heap snapshots
console.log(
await diffProfilesAsync(
await openAsBlob(`base.cpuprofile`),
await openAsBlob(`current.cpuprofile`),
),
)See the API docs for sync variants, explicit formats and origins, and configuration callbacks.
Use the profiler-md skill to have an
agent profile and optimize your code:
$ npx skills add TomerAberbach/profiler-md --skill profile-optimizeSee skills.sh for more info.
Fun fact: the skill has profiled and optimized profiler-md itself!
The table lists only the formats each language's own tools generate. Third-party tools convert others. Each format's docs explain how to generate and read it.
| Language | Formats |
|---|---|
| C/C++ | |
| C#/F# | |
| Elixir/Erlang | |
| Fortran | |
| Go |
pprof
|
| Haskell | |
| Java/Kotlin/Groovy |
Collapsed stacks
JFR
|
| JavaScript/TypeScript | |
| Julia | |
| PHP | |
| Python |
Collapsed stacks
|
| Ruby | |
| Rust | |
| Swift | |
| Zig |
Stars are always welcome!
For bugs and feature requests, create an issue.
