Backends
Every Kernel lowers to one backend-neutral IR, which a backend runs. Choose with --backend:
| Backend | Implementation | Notes |
|---|---|---|
cpu |
interpreter | the reference; what trace walks |
jit |
native code through Cranelift (WASM in the WebAssembly build) | bit for bit the interpreter’s results; the CLI’s default |
gpu |
WGSL compute through wgpu | keeps Fields on the device; small runs and what the device cannot take go to the JIT, said with why |
best |
the GPU where there is a device, else the JIT | the Player’s default |
entelechy run examples/showcase/scene.esn --backend gpu --out showcase.ppmOne expression, one answer on every backend
Section titled “One expression, one answer on every backend”Where a machine leaves a result to its hardware, the language decides it once (docs/DECISIONS.md):
- Float
maxandminare IEEE 754-2019 maximumNumber/minimumNumber: a NaN gives way, andmax(-0.0, 0.0)is0.0either way round. - An integer
sumof a scatter or prefix is each element’s whole total, failing only when it does not fit. - The clock crosses into a Kernel whole, a
Doubleof seconds:clock()reads it so,time()rounded once to aFloatby the context.
Held by the conformance matrix in crates/backends/conformance and the JIT’s random programs.
Placement and routing
Section titled “Placement and routing”Beside a device, a run goes to the JIT when its elements times its Kernel’s typical work are at most --small, and to the device otherwise; a run that reads what the device just made stays there. A chain of small runs goes to the JIT together. The choice reads runs and Kernels, never a clock, so a replay places every run alike.
- A Kernel the device’s own compiler cannot build runs on the JIT from then on;
- a shader the backend emitted that the device refuses is the backend’s fault and still refuses the document;
entelechy checksays when a Kernel is large for a device’s compiler; a session says so with alargeevent as it publishes.- When a node’s placement leaves the main backend,
syncreportsrouted {node, backend, why}; an evaluation’splacementsgive each node’s backend, why, and bytes uploaded/downloaded. - A replay can assert placement:
expect placed ring main.
Where a run goes is the backend’s; what it computes is not.
Host budgets
Section titled “Host budgets”| Flag | Default | Meaning |
|---|---|---|
--memory <MB> |
2048 | mebibytes of Fields the Host may hold at once |
--work <M> |
4000 | million loop iterations one run of a Kernel may take, all elements together |
--small <operations> |
— | runs below this work go to the JIT rather than the device |
run, render, replay, serve, graph, trace and bench all take them.
Measuring
Section titled “Measuring”entelechy run scene.esn --profile --out out.ppmentelechy bench examples/collapse/scene.esn --window 640x400 --backend all --frames 20 --repeat 3 --nodesReal --profile output (first scene, JIT):
tint 0.521 ms jit (sum) 0.521 ms (the call and the wait after it; ...)preparing, ms a Kernel on the thread that prepared it — compiling, then building on its device ...: 0.4 0.0 fused.tint@1evaluated in 1.151584ms: executed [tint+rings], reused 0 -> /tmp/c.ppmbench prints the least run in milliseconds a frame, the median, and the ratio to the first backend; --json and --compare keep and compare a measurement.
Native operations
Section titled “Native operations”A backend may publish native operations a node binds directly: native.rasterize@1, native.rasterize@3, native.cover@1 and others (natives in status: 4 in a JIT session here). They appear in kernels at generation 0, cannot be republished or retired by a document, and never fuse. The rasterizer itself is a package; the native one is its fast path (see Packages).

