Because measureTime and measureTimedValue are inline, what does that mean for using non-local return, suspend calls, and timing accuracy inside the block?
answer
- inline -> no lambda object, low overhead
- Non-local return allowed from the block
- suspend overload: can call delay/suspend fns inside
- Duration = elapsed incl. blocking + suspension, not CPU-only
- measureTime + discarded value can be JIT-eliminated; use JMH for microbench
basics
~20 sBecause the block is inlined, you can call suspend functions inside it and even return from the surrounding function. The timing is the real time the block ran, including any suspension or blocking that happens.
solid answer
~50 smeasureTime and measureTimedValue are inline functions, so the lambda you pass is compiled directly into the call site. Practical effects: (1) the lambda is not a separate object — minimal overhead and no allocation; (2) the block can call suspend functions when measureTime itself is invoked from a suspend context, because the inlined body inherits the caller's suspension ability — there is a suspend-compatible overload; (3) you can use a non-local return (return out of the enclosing function) from inside the block, since inline lambdas allow it. Timing-wise, the elapsed Duration covers everything the block actually did, including blocking I/O or, in a coroutine, time the coroutine was suspended/awaiting — so for async work the measured time is wall-of-execution time, which may include waiting, not pure CPU time. Be careful that the JIT can optimize away pure computations whose result you ignore (more relevant to measureTime than measureTimedValue, which uses the value).
code
kotlin · 9 linesimport kotlin.time.measureTime
import kotlin.time.measureTimedValue
import kotlinx.coroutines.delay
suspend fun demo() {
val d = measureTime { delay(100) } // works from suspend context; ~100ms
val (value, took) = measureTimedValue { delay(50); 42 }
println("$d, value=$value took=$took")
}go deeper
Knows you can put a normal block of code inside and get a Duration.
Explains inline implications: non-local return, suspend overload, and that timing includes blocking.
Adds that suspension time is counted, distinguishes latency vs CPU time, and flags JIT dead-code elimination.
Steers teams to JMH/kotlinx-benchmark for microbenchmarks and reserves these helpers for coarse latency logging.
## Inline, briefly An **inline** function has its body and its lambda parameter copied into the call site by the compiler. Consequences relevant here: ### 1. No lambda object / low overhead The timing block is not wrapped in a `Function0` object; there is no allocation just to measure, which is why these are safe to use even in hot paths. ### 2. Non-local return works Inside an inline lambda you may use a bare `return` that returns from the **enclosing** function, not just the lambda: ```kotlin fun find(): Int { val d = measureTime { if (cheapCase()) return 0 // non-local return: exits find(), not just the block heavyCompute() } log(d) return 1 } ``` Note: if you take that non-local return, the code after the block (the `log(d)`) is skipped, and `d` is never read. ### 3. suspend support There are overloads usable from coroutines. When you call `measureTime { ... }` from a `suspend` function, the inlined block inherits the caller's suspending context, so you can call `delay(...)` or other `suspend` functions inside it: ```kotlin suspend fun load() { val (data, took) = measureTimedValue { fetchOverNetwork() } // fetchOverNetwork is suspend log("fetched in $took") } ``` ## What the Duration actually includes The measured `Duration` is true **elapsed wall-of-execution time** for the block — it counts: - CPU work, - blocking calls (`Thread.sleep`, blocking I/O), - in a coroutine, time spent **suspended/awaiting** (e.g. `delay`, network). It is **not** CPU-only time. So timing a suspending fetch measures the whole round-trip including idle waiting. That is usually what you want for latency, but is not a CPU profile. ## JIT / dead-code caveat For `measureTime`, if the block computes a pure value you then discard, an aggressive JIT can eliminate the computation, giving misleadingly small timings — a microbenchmarking hazard. `measureTimedValue` is safer because the value escapes via `TimedValue.value`. For real microbenchmarks, prefer a harness like **kotlinx-benchmark / JMH** rather than these helpers.
- Does the measured Duration count time a coroutine spends suspended?Yes. It is elapsed wall-of-execution time for the block, including delay/await suspension, not pure CPU time.
- Why is measureTime risky for microbenchmarks?Because inlining plus a discarded result lets the JIT optimize the computation away; use kotlinx-benchmark/JMH for reliable microbenchmarks.
saying these in an interview costs you the question
- Saying you cannot call suspend functions inside measureTime
- Claiming the measured Duration is CPU-only time
- Believing inline lambdas cannot do non-local return
- Recommending measureTime as a proper microbenchmark tool