How do I see how many times code was called and how long it took?

← Code Quality · Ref: Q322

EK9 has built-in profiling. Append 'p' to any test flag to enable profiling data collection.

ENABLING PROFILING

  ek9 -tp myproject.ek9     Human-readable profiling summary.
  ek9 -t2p myproject.ek9    JSON profiling data (for AI and CI tools).
  ek9 -t6p myproject.ek9    HTML dashboard with flame graph.

METRICS COLLECTED

For each function and method:
- Call count: how many times it was invoked.
- Total time: wall-clock time including callees.
- Self time: time spent in this function only, excluding callees.
- Average time per call.
- Minimum and maximum call times.
- Percentiles: p50, p95, p99 for latency distribution.

FLAME GRAPH (-t6p)
The HTML dashboard includes an interactive flame graph. Each frame represents a function. Width represents total time.
- Wide red frames: high self-time. These are the functions doing the most work. Optimise these first.
- Wide blue frames: orchestrators that call many other functions. High total time but low self-time. Optimising these means restructuring call patterns.
- Narrow frames: rarely called or fast functions. Usually not worth optimising.

HOT FUNCTION TABLE

Below the flame graph, a sorted table lists functions by self-time. The top entries are your optimisation targets. Each entry links to the source view.

JSON OUTPUT FOR CI

The -t2p flag produces JSON output suitable for automated analysis:
- CI pipelines can fail builds if p99 latency exceeds thresholds.
- AI assistants can read JSON profiling data to suggest optimisations.
- Trend analysis tools can track performance over time.

See Q321 for the quality report dashboard. See Q157 for running tests. See Q252 for compiler flags. See Q207 for test output formats. See Q246 for debugging strategies. See Q627 for profiling deep dive. See Q629 for reading flame graphs. See Q630 for identifying hot methods. See Q631 for benchmarking approaches.
See Q694 for named arguments pattern. See Q696 for complexity within limits.
See Q728 for nesting depth boundary. See Q733 for combined complexity boundary.

Example

defines module qa.codequality.profiling

  defines function

    <?-
      Functions that would show different profiling characteristics.
      A frequently called helper vs a one-time orchestrator.
    -?>
    fibonacci() as pure
      -> position as Integer
      <- rtn as Integer: 0

      firstBase <- 0
      secondBase <- 1
      thresholdForRecursion <- 2
      if position == firstBase
        rtn: firstBase
      else if position == secondBase
        rtn: secondBase
      else if position >= thresholdForRecursion
        previousValue <- fibonacci(position - 1)
        beforePrevious <- fibonacci(position - 2)
        rtn: previousValue + beforePrevious

    formatResult() as pure
      ->
        label as String
        number as Integer
      <-
        rtn as String: `${label}: ${number}`

  defines program

    ProfilingDemo()
      stdout <- Stdout()

      targetPosition <- 10
      result <- fibonacci(targetPosition)
      output <- formatResult("Fibonacci", result)
      stdout.println(output)

Common mistakes

E50001 — Using raw literals 0, 1, 2 in comparisons is a magic literal error. Extract them into named constants like firstBase, secondBase, and thresholdForRecursion. See ek9 -h E50001 for details.

Incorrect:

if position == 0
        rtn: 0
      else if position == 1
        rtn: 1

Correct:

firstBase <- 0
      secondBase <- 1
      thresholdForRecursion <- 2

E50001 — Removing the variable declaration means later references to the variable become unresolved, triggering E50001. See ek9 -h E50001 for details.

Incorrect:

fibonacci(targetPosition)

Correct:

result <- fibonacci(targetPosition)
Other ways to ask this
  • How do I profile EK9 code?
  • Does EK9 have a built-in profiler?
  • How do I identify slow code in EK9?

Coming from another language?

Java: JMH for microbenchmarks, async-profiler or JFR for profiling (all external tools). Python: cProfile, line_profiler, py-spy (all external). Rust: perf, flamegraph crate, criterion for benchmarks (all external). Go: go tool pprof built-in with -cpuprofile flag. JavaScript: Chrome DevTools profiler. EK9: append 'p' to any test flag for built-in profiling, flame graph in HTML dashboard, JSON output for AI/CI integration.

Keywords: count, graph, self, p95, profile, profiling, bottleneck, total, quality, call, flame, time, metric, performance, clean-code, p99