跳转到内容
查看源码

后端

每个 Kernel 都降低为同一种与后端无关的 IR,再由后端执行。用 --backend 选择:

后端 实现 说明
cpu 解释器 参考实现;trace 逐步走的就是它
jit Cranelift 生成原生代码(WebAssembly 构建中用 WASM) 与解释器结果逐位一致;CLI 的默认值
gpu WGSL compute,经 wgpu Field 保留在设备上;小任务和设备无法接受的部分交给 JIT,并说明原因
best 有设备时用 GPU,否则 JIT Player 的默认值
终端窗口
entelechy run examples/showcase/scene.esn --backend gpu --out showcase.ppm

一个表达式,在每个后端上一个答案

Section titled “一个表达式,在每个后端上一个答案”

当机器把结果留给硬件决定时,语言替它决定一次(docs/DECISIONS.md):

  • Float 的 max、min 是 IEEE 754-2019 的 maximumNumber/minimumNumber:NaN 让步,max(-0.0, 0.0) 不论顺序都是 0.0。
  • scatter 或 prefix 的整数 sum 是每个元素的完整总和,只有总和溢出时才失败。
  • 时钟以 Double 秒整体进入 Kernel:clock() 原样读取,time() 由上下文舍入一次为 Float。

这由 crates/backends/conformance 的一致性矩阵和 JIT 的随机程序测试保证。

与设备并存时,一次运行在“元素数 × Kernel 的典型工作量 ≤ --small”时交给 JIT,否则交给设备;读取设备刚产生结果的运行留在设备上。一串小的运行会一起去 JIT。选择只看运行和 Kernel,从不看时钟,所以回放每次放置都一样。

  • 设备自己的编译器无法构建的 Kernel,此后在 JIT 上运行;
  • 后端生成而设备拒绝的着色器是后端的错,仍会拒绝文档;
  • entelechy check 会提示某个 Kernel 对设备编译器来说过大;会话发布时用 large 事件说明。
  • 节点的放置离开主后端时,sync 报告 routed {node, backend, why};求值报告中的 placements 给出每个节点的后端、原因和上传/下载字节。
  • 回放中可以断言放置:expect placed ring main。

运行去哪里由后端决定;它计算什么不由后端决定。

参数 默认 含义
--memory <MB> 2048 Host 同时可持有的 Field 内存(MiB)
--work <M> 4000 一个 Kernel 一次运行(所有元素合计)可执行的循环迭代数(百万)
--small <operations> — 低于此工作量的运行交给 JIT 而不是设备

run、render、replay、serve、graph、trace、bench 都接受这些参数。

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

--profile 的真实输出(第一个场景,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 打印每帧最少用时、中位数以及与第一个后端的比值;--json 和 --compare 保存并比较测量结果。

后端可以发布原生操作,节点直接绑定:native.rasterize@1、native.rasterize@3、native.cover@1 等(status 中的 natives,本机 JIT 会话为 4 个)。它们以代数 0 出现在 kernels 列表中,不能被文档重新发布或撤回,也从不融合。光栅化器本身是一个包,原生版本是它的快速路径(见包)。