Skip to content
View source

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.ppm

One 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 max and min are IEEE 754-2019 maximumNumber/minimumNumber: a NaN gives way, and max(-0.0, 0.0) is 0.0 either way round.
  • An integer sum of 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 Double of seconds: clock() reads it so, time() rounded once to a Float by the context.

Held by the conformance matrix in crates/backends/conformance and the JIT’s random programs.

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 check says when a Kernel is large for a device’s compiler; a session says so with a large event as it publishes.
  • When a node’s placement leaves the main backend, sync reports routed {node, backend, why}; an evaluation’s placements give 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.

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.

终端窗口
entelechy run scene.esn --profile --out out.ppm
entelechy bench examples/collapse/scene.esn --window 640x400 --backend all --frames 20 --repeat 3 --nodes

Real --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@1
evaluated in 1.151584ms: executed [tint+rings], reused 0 -> /tmp/c.ppm

bench 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.

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).