Tooling
Profiling
Zornux can profile a running program — where it spends time, what it
allocates, the shape of its live data, and an ordered timeline of what it
did — with no external, platform-specific tooling. Profiling is
off by default: a normal run pays nothing for it, and you
turn it on for a single run with zornux profile.
Getting started
zornux profile run app.zx # hot spots
zornux profile allocations app.zx # allocations by type and function
zornux profile heap app.zx # live data at program end
zornux profile timeline app.zx # an ordered timeline
Every form runs your program normally — you still see its output — then prints a report.
Commands
| Command | Shows |
|---|---|
profile run | Hot spots — where your program spends its time (tree-walking interpreter). |
profile vm-run | Hot spots on the bytecode virtual machine. |
profile allocations | What the program allocates, by type and function. |
profile heap | A snapshot of the live data at program end. |
profile timeline | An ordered timeline of what ran. |
profile serve | Profile a live web server; report on shutdown. |
What the report shows
Hot spots — the functions and methods your program spent the most time in, with how often each was called, how many execution samples landed in it, how many values it allocated, and its share of the total.
Hot spots
Function/Method Calls Samples Allocs Percent Source
render 1200 842 3600 71.30 app.zx:44
layout 1200 260 1200 22.01 app.zx:31
- Hot source lines — the individual lines most samples landed on.
- Allocations by type — how many numbers, text, lists, maps, and items were created. Reused values (small numbers,
yes/no,nothing) are shared, so they never inflate the count. - Allocations by call stack — the same allocations, joined to the callers that made them, so you can trace one back through the chain that produced it rather than only learning which function it happened in. Add
--allocation-stacks. The stack is bounded, and anything allocated outside a function belongs to the program itself. - Subsystems — how many async tasks, background jobs, messages, and database queries ran.
- Heap — a snapshot of the live data still reachable at the end: live counts by type and item class, the largest lists and maps, and how deeply data is nested.
Tracing
A trace is an ordered, redacted stream of what your program did. Turn on the categories you care about:
zornux profile run app.zx --trace calls # function/method enter and exit
zornux profile run app.zx --trace jobs # tasks, jobs, and message handlers
zornux profile run app.zx --trace queries # database queries
zornux profile run app.zx --trace requests # web requests
zornux profile run app.zx --trace all
Output and options
| Option | Does |
|---|---|
--json | Machine-readable JSON instead of a table. |
--output <file> | Write the report (or timeline) to a file. |
--trace <kind> | Capture a trace: calls, jobs, queries, requests, or all. |
--max-samples <n> | Cap on execution samples. |
--max-events <n> | Cap on timeline / trace events. |
--sampling-interval <n> | How much work passes between samples (smaller = finer). |
--allocation-stacks | Record the call stack behind each allocation. |
--timestamps | Stamp timeline events with elapsed microseconds. |
--gc-stats | Report memory-reclamation activity for the run. |
zornux profile run app.zx --json
zornux profile timeline app.zx --output run.timeline.json
Time and memory
Every timeline event carries a sequence number and a depth, and the sequence is
what orders a timeline: it's a counter, so two runs of the same program produce
the same order on every machine. --timestamps adds an elapsed time in
microseconds beside it — read it to see how long something took, never to sort by,
because a clock isn't deterministic and the sequence is.
--gc-stats reports how much memory reclamation the run provoked:
reclamation passes and total bytes allocated. These are measured at the run's edges,
so nothing is paused to collect them. They answer "did this run cause reclamation?",
while allocations answer how many values the program itself made.
Profiling a live server
Profile a running web service and get a report when you stop it. Every request — the route and everything it calls, queries, or publishes — is profiled while the server runs.
zornux profile serve app.zx # serve; Ctrl+C prints the profile
zornux profile serve app.zx --trace requests --output serve.json
From an editor
An editor that speaks the Debug Adapter Protocol can profile a debug session through optional Zornux profiling requests — start a profile, then ask for the report, heap snapshot, timeline, or allocation summary. Editors that don't support them are unaffected; standard debugging is unchanged.
A profile is names, counts, and source locations only — never a value. A secret is counted but never read, and a private field counts toward the live data but its contents are never shown. Counts and event order are deterministic; every stream is bounded and truncates rather than using unbounded memory; and with no profile requested, your program runs exactly as it would otherwise.