How do I profile an EK9 program?
← Profiling · Ref: Q627
EK9 has built-in profiling. Append 'p' to any test flag to enable performance profiling.
BASIC PROFILING
ek9 -tp myproject.ek9
This runs all tests with profiling instrumentation and produces a human-readable summary showing call counts and timing for each function and method.
PROFILING OUTPUT FORMATS
The 'p' suffix works with every test format:
ek9 -tp myproject.ek9 Human-readable profiling summary. ek9 -t0p myproject.ek9 Terse profiling (CI pass/fail). ek9 -t2p myproject.ek9 JSON profiling data (for AI and tools). ek9 -t3p myproject.ek9 JUnit XML with profiling annotations. ek9 -t6p myproject.ek9 HTML dashboard with flame graph.
WHAT GETS MEASURED
For each function and method the profiler records:
- Call count: how many times it was invoked.
- Total time: wall-clock time including calls to other functions.
- Self time: time in this function only, excluding callees.
- Average, minimum, and maximum call times.
- Percentile distribution: p50, p95, p99.
NO OPTIMISATION
Profiling automatically forces -O0 (no optimisation). This ensures that probe-to-source mapping is accurate. Every function call is measured as written, with no inlining or dead code elimination.
See Q628 for profiling tests specifically. See Q629 for reading flame graphs. See Q630 for identifying hot methods. See Q631 for benchmarking two approaches. See Q322 for profiling overview. See Q207 for test output formats. See Q752 for fuzz HTML dashboard (similar report pattern).
Example
defines module qa.profilingdeep.program defines function <?- Recursive function that shows up as a hot method in profiling. The profiler records call count and self-time for each invocation. -?> factorial() as pure -> number as Integer <- result as Integer: 1 recursionBase <- 1 if number > recursionBase subResult <- factorial(number - 1) result: number * subResult sumUpTo() as pure -> limit as Integer <- total as Integer: 0 for i in 1 ... limit total: total + i defines program ProfileProgramDemo() stdout <- Stdout() tenFactorial <- 10 result <- factorial(tenFactorial) stdout.println(`10! = ${result}`) hundredSum <- 100 sum <- sumUpTo(hundredSum) stdout.println(`Sum 1..100 = ${sum}`)
Common mistakes
E50001 — Removing the variable declaration means later references to the variable become unresolved, triggering E50001. See ek9 -h E50001 for details.
Incorrect:
factorial(tenFactorial)
Correct:
result <- factorial(tenFactorial)
Other ways to ask this
- How do I find performance bottlenecks in EK9?
- What is the ek9 -tp flag for?
- How do I measure function call times in EK9?
Coming from another language?
Java: async-profiler, JFR, or VisualVM (all external tools, require JVM flags). Python: cProfile (stdlib), py-spy (external, sampling). Rust: perf, flamegraph crate (external). Go: go tool pprof with -cpuprofile flag (built-in but requires code changes). JavaScript: Chrome DevTools profiler (browser only). EK9: append 'p' to any test flag for built-in profiling, zero code changes, multiple output formats including JSON and HTML flame graph.
Keywords: call, program, bottleneck, total, performance, time, profile, count, tp, self, profiling, flame-graph, O0