From 560290ca1d18d4d5a0d204bb187d1aa68c3b5ac7 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 15 Jun 2026 00:02:22 +0000 Subject: [PATCH] perf: cache the compiled core module so fresh workers deserialize, not recompile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workers recycle every 8 requests (calls_until_termination=8). Each fresh worker ran wasmtime::Module::compile() on the 6.8MB bin/wasm/core.wasm — a ~1.3s Cranelift JIT — on its first request, so every ~8th request spiked to ~1.3s and dominated suite wall-clock. Cache the compiled artifact: on worker core-module load, if bin/wasm/core.cwasm exists and is newer than core.wasm, load it via Module::deserialize_file() (mmap, ~ms); otherwise Module::compile() as before and atomically (temp+rename) write the serialized artifact for the next worker. Deserialize failure / stale cache falls back to a normal compile, so it is self-healing; rebuilding core.wasm (newer mtime) invalidates the cache. Engine config (epoch_interruption, signals_based_traps(false)) is unchanged, which the serialized format requires. Implemented via the pi agent (delegated to a gpt-5.3-codex-spark sub-model). Independently verified on the host: worker-startup request latency drops from ~1.3s to ~23ms (warm 12x /demo/hello.uce: all <=0.023s, no spikes); full suite wall-clock ~40s -> 20.5s; run_cli_tests --include-wasm-kill => 87 passed, 0 failed, 0 skipped. Co-Authored-By: Claude Opus 4.8 --- src/wasm/worker.cpp | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp index 35ec87e..9bbcdb4 100644 --- a/src/wasm/worker.cpp +++ b/src/wasm/worker.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -247,10 +248,54 @@ public: String parse_error; if(!wasm_parse_sections(bytes, core_dylink, abi_ignored, parse_error)) return("core module: " + parse_error); + + String core_cached_path = cfg.core_wasm_path; + if(core_cached_path.size() >= 5 && core_cached_path.rfind(".wasm", core_cached_path.size() - 5) == core_cached_path.size() - 5) + core_cached_path = core_cached_path.substr(0, core_cached_path.size() - 5) + ".cwasm"; + else + core_cached_path += ".cwasm"; + struct stat core_stat; + struct stat cached_stat; + if(stat(core_cached_path.c_str(), &cached_stat) == 0 && stat(cfg.core_wasm_path.c_str(), &core_stat) == 0) + { + if(cached_stat.st_mtime > core_stat.st_mtime) + { + auto deserialized = wasmtime::Module::deserialize_file(engine, core_cached_path); + if(deserialized) + { + core_module.emplace(deserialized.ok()); + return(""); + } + } + } + auto compiled = wasmtime::Module::compile(engine, bytes); if(!compiled) return("core module compile failed: " + String(compiled.err().message())); core_module.emplace(compiled.ok()); + + auto serialized = core_module->serialize(); + if(serialized) + { + String tmp = core_cached_path + "." + std::to_string((long long)getpid()) + ".tmp"; + auto data = serialized.ok(); + { + std::ofstream out(tmp, std::ios::binary | std::ios::trunc); + if(out) + { + out.write((const char*)data.data(), (std::streamsize)data.size()); + if(out) + { + out.flush(); + out.close(); + if(std::rename(tmp.c_str(), core_cached_path.c_str()) != 0) + (void)std::remove(tmp.c_str()); + } + } + else + (void)std::remove(tmp.c_str()); + } + } return(""); }