Skip to content

profiler

stable

A stateful code profiler that times named sections with nanosecond precision, recording call counts, totals, averages, and memory snapshots.

use plugin profiler::{Profiler, begin_section, end_section, …}
15 functions Utilities
/ filter jk navigate Esc clear
Functions (15)
  1. Profiler Creates a new profiler instance.
  2. begin_section Start timing a named section
  3. end_section Stop timing a section, return elapsed ns
  4. report Get timing stats for all sections
  5. reset Clear all recorded timings
  6. active_sections List currently active section names
  7. section_count Count of distinct recorded sections
  8. section_stats Get stats for a single named section
  9. elapsed_ns Nanoseconds elapsed in an active section
  10. push_section Begin a nested (hierarchical) section
  11. pop_section End innermost nested section
  12. record_memory Record a manual memory snapshot
  13. memory_report Get all recorded memory snapshots
  14. format_report Format a report table as text
  15. format_flamegraph_lines Format report as folded stack lines

Overview

profiler is a stateful, in-process code profiler built around a single handle object. You create one with Profiler(), then bracket the code you care about with begin_section / end_section pairs (or the stack-based push_section / pop_section for nested call trees). Every measurement is stored with nanosecond precision, so calling the same section repeatedly accumulates call counts, totals, averages, and min/max — exactly what you need to find a hot path across many iterations.

The mental model is: one profiler handle holds all your sections. Timings are recorded internally as you end sections; report and section_stats read those aggregates back as plain tables, memory_report reads manual memory snapshots, and the standalone format_report / format_flamegraph_lines helpers turn a report table into printable text or folded-stack lines for flamegraph tooling. Reach for it whenever you want lightweight, dependency-free timing without wiring up an external profiler.

Common patterns

Time a block, run it many times, then print the aggregated table:

use plugin profiler::{Profiler, format_report}

let p = Profiler()
for i in 0..1000 {
  p.begin_section("hash")
  // ... work to measure ...
  p.end_section("hash")
}
print(format_report(p.report()))

Build a nested call tree with the section stack and export it for a flamegraph:

use plugin profiler::{Profiler, format_flamegraph_lines}

let p = Profiler()
p.push_section("frame")
p.push_section("physics")
p.pop_section()
p.push_section("render")
p.pop_section()
p.pop_section()
print(format_flamegraph_lines(p.report()))

Pair timing with manual memory snapshots to see cost and growth side by side:

use plugin profiler::{Profiler}

let p = Profiler()
p.begin_section("load")
p.record_memory("before", 1048576)
// ... load work ...
p.record_memory("after", 4194304)
p.end_section("load")

for _, snap in p.memory_report() {
  print("{snap["label"]}: {snap["bytes"]} bytes")
}

Creates a new profiler instance.

Creates a new profiler instance. Use begin_section / end_section pairs to measure code.

use plugin profiler::{Profiler, format_report}

let p = Profiler()
p.begin_section("load")
// ... work ...
p.end_section("load")
let report = p.report()
print(format_report(report))

Start timing a named section

Starts a timer for a named section. Multiple sections can be active simultaneously.

p.begin_section("parse")
p.begin_section("validate")

Stop timing a section, return elapsed ns

Stops the timer for the named section and returns #{elapsed_ns: int}. The elapsed time is also stored internally.

let result = p.end_section("parse")
print("parse took {result["elapsed_ns"]} ns")

Calling the same section name repeatedly accumulates separate samples, so the average and call count grow with each begin_section / end_section pair:

use plugin profiler::{Profiler}

let p = Profiler()
for i in 0..3 {
  p.begin_section("step")
  p.end_section("step")
}
print("recorded {p.section_count()} distinct section")

Get timing stats for all sections

Returns a table of timing entries, one per recorded section, sorted alphabetically. Each entry has name, calls, total_ns, avg_ns, min_ns, max_ns.

let r = p.report()
for _, entry in r {
  print("{entry["name"]}: avg {entry["avg_ns"]} ns over {entry["calls"]} calls")
}

The report table feeds directly into either text formatter — pass it to format_report for an aligned table or to format_flamegraph_lines for folded stacks:

use plugin profiler::{Profiler, format_report}

let p = Profiler()
p.begin_section("a")
p.end_section("a")
p.begin_section("b")
p.end_section("b")
print(format_report(p.report()))

Clear all recorded timings

Clears all section timings and active timers. Useful for resetting between benchmark iterations.

p.reset()

List currently active section names

Returns a sorted list of section names that are currently being timed (started but not yet ended).

let active = p.active_sections()
print("still timing: {active[1]}")

Count of distinct recorded sections

Returns the number of distinct sections that have been recorded (ended at least once).

print("measured {p.section_count()} sections")

Get stats for a single named section

Returns timing stats for a single named section: name, calls, total_ns, avg_ns, min_ns, max_ns. Errors if the section has never been recorded.

let stats = p.section_stats("render")
print("render avg: {stats["avg_ns"]} ns")

Use it to inspect the spread of a single hot section without rendering the whole report:

use plugin profiler::{Profiler}

let p = Profiler()
for i in 0..5 {
  p.begin_section("query")
  p.end_section("query")
}
let s = p.section_stats("query")
print("query: {s["calls"]} calls, min {s["min_ns"]} / max {s["max_ns"]} ns")

Nanoseconds elapsed in an active section

Returns the nanoseconds elapsed so far for an active (not yet ended) section. Useful for progress logging inside long operations.

p.begin_section("import")
// ... some work ...
print("so far: {p.elapsed_ns("import")} ns")
p.end_section("import")

Begin a nested (hierarchical) section

Begins a nested section. The full name becomes parent/child, building a hierarchical call tree compatible with flamegraph tools.

p.push_section("frame")
p.push_section("physics")
// ... physics work ...
p.pop_section()
p.pop_section()

End innermost nested section

Ends the innermost pushed section and returns #{name: string, elapsed_ns: int}.

let r = p.pop_section()
print("finished {r["name"]} in {r["elapsed_ns"]} ns")

Record a manual memory snapshot

Records a manual memory measurement snapshot with a text label and a byte count.

p.record_memory("after_load", 1048576)
p.record_memory("after_parse", 2097152)

Get all recorded memory snapshots

Returns all memory snapshots in insertion order. Each entry has label and bytes.

let mem = p.memory_report()
for _, snap in mem {
  print("{snap["label"]}: {snap["bytes"]} bytes")
}

Format a report table as text

Formats a report table (from report()) as an aligned text table with columns: Section, Calls, Total(ns), Avg(ns), Min(ns), Max(ns).

use plugin profiler::{Profiler, format_report}

let p = Profiler()
p.begin_section("work")
p.end_section("work")
print(format_report(p.report()))

Format report as folded stack lines

Converts a report table into folded stack format (name total_ns), one line per section. Feed the output to inferno or similar tools.

use plugin profiler::{Profiler, format_flamegraph_lines}

let p = Profiler()
p.push_section("app")
p.push_section("db")
p.pop_section()
p.pop_section()
let lines = format_flamegraph_lines(p.report())
print(lines)
enespt-br