profile
A function-level profiler for Jda programs. Measures execution time and call counts using clock_gettime(CLOCK_MONOTONIC). Supports up to 64 profiling slots with enter/leave instrumentation and a flat profile report.
Usage
import profile
fn main() {
prof_init()
prof_enable()
// Profile a hot function
prof_enter(0, "sort")
sort_vec(v)
prof_leave(0)
prof_enter(1, "search")
binary_search(v, 42)
prof_leave(1)
// Print flat profile report
prof_report()
// Output:
// === Profile Report ===
// sort 1 calls 1234 us 1234 us/call
// search 1 calls 12 us 12 us/call
// === End Report ===
ret 0
}Function Reference
| Function | Signature | Description |
|---|---|---|
prof_init | () | Initialise profiler state |
prof_enable | () | Enable profiling |
prof_disable | () | Disable profiling |
prof_enabled | () -> i64 | Check if profiling is enabled |
prof_enter | (slot: i64, name: &i8) | Start timing a slot |
prof_leave | (slot: i64) | Stop timing a slot |
prof_calls | (slot: i64) -> i64 | Return call count for a slot |
prof_total_ns | (slot: i64) -> i64 | Return total nanoseconds for a slot |
prof_avg_ns | (slot: i64) -> i64 | Return average nanoseconds per call |
prof_name | (slot: i64) -> &i8 | Return name of a slot |
prof_slot_count | () -> i64 | Return number of used slots |
prof_reset | (slot: i64) | Reset a single slot |
prof_reset_all | () | Reset all slots |
prof_report | () | Print flat profile report |
Detailed API
prof_init
fn prof_init()Initialise the profiler. Resets all 64 slots and enables profiling. Call once at program start.
prof_enable
fn prof_enable()Enable profiling. When disabled, prof_enter and prof_leave calls are no-ops for minimal overhead.
prof_disable
fn prof_disable()Disable profiling. Timing calls become no-ops. Useful for disabling profiling in production while keeping instrumentation in the code.
prof_enter
fn prof_enter(slot: i64, name: &i8)Start timing slot slot (0-63). Records the current timestamp and associates name with the slot. If profiling is disabled, this is a no-op.
prof_enter(0, "parse_json")
let doc = json_parse(input)
prof_leave(0)Note: Slots can be reused across different call sites with the same name. The profiler accumulates time and call counts per slot.
prof_leave
fn prof_leave(slot: i64)Stop timing slot slot. Computes elapsed time since the matching prof_enter and adds it to the slot’s total. Increments the call count.
Important: Always pair prof_leave with prof_enter. Calling prof_leave on a slot that wasn’t entered is undefined.
prof_calls
fn prof_calls(slot: i64) -> i64Return the number of times prof_leave was called on this slot.
prof_enter(0, "process")
process_item(a)
prof_leave(0)
prof_enter(0, "process")
process_item(b)
prof_leave(0)
let n = prof_calls(0) // n == 2prof_total_ns
fn prof_total_ns(slot: i64) -> i64Return the total accumulated time in nanoseconds for this slot across all enter/leave pairs.
prof_avg_ns
fn prof_avg_ns(slot: i64) -> i64Return the average time per call in nanoseconds: total_ns / calls. Returns 0 if the slot has no calls.
prof_report
fn prof_report()Print a flat profile report to stdout. Lists all used slots with name, call count, total microseconds, and average microseconds per call.
=== Profile Report ===
parse 1000 calls 45231 us 45 us/call
transform 500 calls 12044 us 24 us/call
emit 1000 calls 8921 us 8 us/call
=== End Report ===Only slots that have been entered at least once are printed.
Example: Profiling a Pipeline
import profile
fn process_pipeline(data: &i8) {
prof_enter(0, "parse")
let parsed = parse(data)
prof_leave(0)
prof_enter(1, "validate")
validate(parsed)
prof_leave(1)
prof_enter(2, "transform")
let result = transform(parsed)
prof_leave(2)
prof_enter(3, "serialize")
serialize(result)
prof_leave(3)
}
fn main() {
prof_init()
prof_enable()
for i in range(1000) {
process_pipeline(input)
}
prof_report()
ret 0
}