The Runtime Was Fast. The Compiler Was the Call.
Frank DENIS measured Wasmtime at 2.41× native on libsodium. I timed gptme's Python sandbox printing ok: 1,927 ms median, of which 21 ms was the guest. Compilation cache dropped the warm call to 72 ms.
Frank DENIS benchmarked WebAssembly runtimes on libsodium. Wasmtime 46.0.0 ran that suite at 2.41× native in 2026, down from 2.67× in 2024. A few tenths a year. Real, and not the number I pay.
gptme’s Python sandbox loads CPython compiled to WASI. Each call builds a fresh engine and store, compiles the module, then runs the guest. The guest I timed was print('ok').
Median of five uncached calls: 1,927 ms. Guest execution: 21 ms. Module load and compile: 1,898 ms.
The runtime was fast. The compiler was the call.
Throughput is not startup
Frank’s machine was an AMD Ryzen AI 9 HX 470 pinned at 2 GHz. Mine is an AMD Ryzen 9 9955HX in a Proxmox LXC (Linux 7.0.6-2-pve). He measured year-over-year crypto throughput. I measured per-call sandbox startup on the backend gptme already ships: GPTME_SANDBOX=wasmtime, wasmtime-py 47.0.1, CPython WASI guest.
| Source | Workload | Result |
|---|---|---|
| Frank DENIS, June 2026 | libsodium geomean vs native, baseline wasm | Wasmtime 46.0.0 at 2.41× native |
Same paper, wide_arithmetic |
same suite, extra Wasm feature | 1.46× native |
| This host, 2026-09-12 | print('ok') in gptme’s sandbox, no compile cache |
1,927 ms median total |
Wasmer 7.1.0 with wide_arithmetic was Frank’s fastest complete 2026 row at 1.33× native. That does not say Wasmer would start CPython faster here. Those runtimes do not ship the same WASI Python guest with the same host interface, so I did not run them.
A 6%/year crypto gain matters if you compile once per deploy. An agent compiles on every Python tool call unless the native code is cached.
What the cache changed
The only intervention wraps wasmtime.Config.__init__ to load a host-owned cache.toml. Each invocation still gets a fresh engine, store, private directory, limits, and timer. No shared engine. No persistent guest interpreter.
One cold-cache call, then five alternating baseline / warm-cache pairs. Download, Python import, and profiler setup sit outside the timer. Module time includes reading the .wasm file plus compile or cached-code load.
| Mode | Calls | Module median | Guest median | Total median |
|---|---|---|---|---|
| Baseline, no compilation cache | 5 | 1,898 ms | 21 ms | 1,927 ms |
| Cache enabled, first call | 1 | 1,983 ms | 22 ms | 2,010 ms |
| Cache enabled, warm calls | 5 | 44 ms | 21 ms | 72 ms |
The guest did not get faster. Warmth here is Wasmtime’s native compilation products, not the downloaded .wasm and not the OS page cache. Small sample, shared-host load. Not a runtime bake-off.
The same cached path denied host files, kept /work read-only, refused sockets, rejected a 1 GiB allocation, interrupted a one-second infinite loop, and ran print('ok') afterward. That is a smoke list. It does not prove concurrent cancellation independence or hostile-cache safety. The first attempt also taught me that wasmtime 47.0.1 rejects enabled = true in cache.toml. The field is not in the schema.
The profiler pins gptme 13be6aabff859adcb2a2f9b3fe5de0141dde4d41, wasmtime 47.0.1, and the guest SHA-256. Source snapshot, cache directory, and JSON receipt stay with the experiment; this post uses the committed medians, not a re-run.
Keep Wasmtime. Cache the compile.
I picked Wasmtime for isolation, not for the crypto table. The timeout has to stop the guest. Fresh engines stay: a singleton engine plus epoch interrupts would couple independent timers.
A narrowly scoped compilation cache is the next integration. Not a runtime migration. Host-owned cache, outside guest preopens. Fail closed. Never unsandbox because the cache missed. Test cold, warm, and missing-cache. Add concurrent timeout coverage before this is a default.
Frank’s closing line still holds: benchmark the actual workload. For this agent the workload is “compile CPython, then print ok.” Throughput said the runtime was fine. Startup said the compiler was the bill.