Closures pipeline
Map/Filter/Map/Filter/Reduce over 100k integers, every stage a closure built by a factory function.
Compile time · median (cold)
Full statistics
| Runner | N | Compile | Runtime | P95 | Stddev | RSS | vs pipit | Status |
|---|---|---|---|---|---|---|---|---|
| Native Gocompiled | 7 | 109 ms | 2.57 ms | 2.75 ms | 98.7 µs | 1.62 GiB | 82.7× | OK |
| Pipitbytecode VM | 7 | 1.31 ms | 80.4 ms | 103 ms | 7.96 ms | 592 MiB | 1.00× | OK |
| CPython 3.14bytecode VM | 7 | 443 µs | 115 ms | 117 ms | 2.13 ms | n/a | 0.34× | OK |
| PyPy 7.3tracing JIT | 7 | 343 µs | 24.7 ms | 26.2 ms | 725 µs | n/a | 0.26× | OK |
| tengobytecode VM | 7 | 245 µs | 181 ms | 195 ms | 9.77 ms | 1.69 GiB | 0.19× | OK |
| scriggobytecode VM | 7 | 508 µs | 140 ms | 157 ms | 11.8 ms | 1.69 GiB | 0.39× | OK |
| mvmbytecode VM | 7 | 439 µs | 149 ms | 149 ms | 330 µs | 1.69 GiB | 0.33× | OK |
| yaegiAST walker | 7 | 439 µs | 656 ms | 681 ms | 9.08 ms | 1.69 GiB | 0.33× | OK |
Workload & symmetry rules
Workload
Generate 100,000 uint32 values from an LCG. Pipe them through five stages, each a closure built by a factory function that captures one constant:
applyMap(makeMultiply(3)), capturing factor 3applyFilter(makeDivisorFilter(7)), capturing divisor 7applyMap(makeAdd(1234)), capturing offset 1234applyFilter(makeThresholdFilter(1000)), capturing threshold 1000applyReduce(makeFold(5)), capturing shift 5
Symmetry rules
- Every stage is a real closure with captured state (not a top-level function).
- Pipeline composition through ordinary function calls, no tail-call tricks.
Why this benchmark exists
Measures first-class-function dispatch under load. Every element walks through five closure invocations. Closure allocation and upvalue access dominate the inner loop.
Source code
pipit / Go
pipit_source.gonative Go
native_main.goCPython / PyPy
cpython.pytengo
script.tengo