How do I measure elapsed time for benchmarking in EK9?

← Date, Time, and Duration · Ref: Q544

Use SystemClock().millisecond() before and after the code section, then subtract to get elapsed Millisecond.

BASIC TIMING PATTERN

  startMs <- SystemClock().millisecond()
  // ... code to measure ...
  endMs <- SystemClock().millisecond()
  elapsed <- endMs - startMs
  stdout.println(`Elapsed: ${elapsed}`)

The result is a typed Millisecond value, not a raw integer. You can convert it to Duration with .duration() or get the raw value.

BUILT-IN PROFILING FLAGS

EK9 also has built-in profiling of the code your tests exercise: append 'p' to a test flag.

  ek9 -tp program.ek9 tests, coverage, then the top functions by self-time
  ek9 -t2p program.ek9 writes the full profiling JSON to .ek9/coverage.json

(-P is packaging, not profiling.) The compiler instruments the code automatically. For micro-benchmarks, manual SystemClock timing gives you control over exactly what is measured.

MILLISECOND ARITHMETIC

You can accumulate timing results:

  totalMs <- 0ms
  totalMs += elapsed

Or compute averages:

  averageMs <- totalMs / iterations

CONVERT TO DURATION

  asDuration <- elapsed.duration()   // a Duration, for display in hours/minutes/seconds format

See Q41 for Millisecond type details. See Q543 for Unix timestamps. See Q322 for the profiling system. See Q631 for benchmarking two approaches.

Example

#!ek9
defines module qa.elapsed.time.benchmarking

  defines program
    ElapsedTimeBenchmarkingDemo()
      stdout <- Stdout()

      // Basic timing pattern
      startMs <- SystemClock().millisecond()

      // Simulate work with a loop
      counter <- 0
      for i in 1 ... 1000
        counter += i

      endMs <- SystemClock().millisecond()
      elapsed <- endMs - startMs
      stdout.println(`Loop elapsed: ${elapsed}`)
      stdout.println(`Counter: ${counter}`)

      // Convert to Duration
      asDuration <- elapsed.duration()
      stdout.println(`As Duration: ${asDuration}`)

      // Accumulate multiple measurements
      totalMs <- 0ms
      for run in 1 ... 3
        runStart <- SystemClock().millisecond()
        sum <- 0
        for j in 1 ... 500
          sum += j
        runEnd <- SystemClock().millisecond()
        runElapsed <- runEnd - runStart
        totalMs += runElapsed
        stdout.println(`Run ${run}: ${runElapsed}`)

      stdout.println(`Total: ${totalMs}`)

      // Millisecond comparison for thresholds
      threshold <- 1000ms
      if totalMs < threshold
        stdout.println("Fast enough")
      else
        stdout.println("Too slow")

Common mistakes

E50001 — A name in the subtraction that was never declared (here a mistyped startMs) is not resolved, triggering E50001. See ek9 -h E50001 for details.

Incorrect:

elapsed <- endMs - startMsTypo

Correct:

elapsed <- endMs - startMs

E50001 — EK9 uses SystemClock().millisecond(), not static Java-style methods. SystemClock is instantiated then millisecond() is called on it. Triggers E50001 — method not resolved. See ek9 -h SystemClock for the full API.

Incorrect:

startMs <- SystemClock.currentTimeMillis()

Correct:

startMs <- SystemClock().millisecond()
Other ways to ask this
  • How do I time how long something takes in EK9?
  • How do I use SystemClock for performance measurement?
  • How do I profile code execution time in EK9?

Coming from another language?

Java: System.nanoTime() for benchmarking (not currentTimeMillis which has clock adjustment issues). Python: time.perf_counter() or timeit module. JavaScript: performance.now() for high-resolution timing. Go: time.Now() with time.Since(). Rust: std::time::Instant::now() with elapsed(). EK9: SystemClock().millisecond() with typed subtraction, built-in profiling by appending 'p' to a test flag (-tp, -t2p).

Keywords: benchmark, date, duration, elapsed, measure, millisecond, performance, profile, systemclock, time, timezone, timing