perf: extend the compiled-module disk cache to per-unit modules
Follow-up to 560290c. Per-unit .wasm modules were still Cranelift-compiled per worker on first use (~40-70ms each), so with 8-call worker recycling fresh workers re-JIT every unit they touch. Refactor the core cache logic into a shared WasmWorker helper: - cached_wasm_path(p): maps <...>.wasm -> <...>.cwasm. - load_or_compile_cached_module(engine, cached, wasm, bytes, err): deserialize_file the .cwasm when it is newer than the .wasm; otherwise Module::compile + serialize, written atomically (temp+rename); deserialize failure falls back to compile. Both the core module load and unit_module() now go through this helper, so unit artifacts get the same <unit>.uce.cwasm cache the core got. Independently verified on the host: fresh-worker first-hit unit latency ~40-70ms -> ~3-21ms; full suite wall-clock 20.5s -> 6.5s (and ~40s before any caching); run_cli_tests --include-wasm-kill => 87 passed, 0 failed, 0 skipped. Implemented via the pi agent (gpt-5.3-codex-spark sub-model). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
560290ca1d
commit
83ab9e10f7
@ -249,53 +249,12 @@ public:
|
||||
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());
|
||||
}
|
||||
}
|
||||
String core_cached_path = cached_wasm_path(cfg.core_wasm_path);
|
||||
String compile_error;
|
||||
auto compiled_or_cached = load_or_compile_cached_module(engine, core_cached_path, cfg.core_wasm_path, bytes, compile_error);
|
||||
if(!compiled_or_cached)
|
||||
return("core module compile failed: " + compile_error);
|
||||
core_module.emplace(std::move(*compiled_or_cached));
|
||||
return("");
|
||||
}
|
||||
|
||||
@ -347,18 +306,74 @@ public:
|
||||
error = wasm_path + ": missing uce.abi stamp";
|
||||
return(nullptr);
|
||||
}
|
||||
auto compiled = wasmtime::Module::compile(engine, bytes);
|
||||
if(!compiled)
|
||||
String unit_cached_path = cached_wasm_path(wasm_path);
|
||||
String compile_error;
|
||||
auto compiled_or_cached = load_or_compile_cached_module(engine, unit_cached_path, wasm_path, bytes, compile_error);
|
||||
if(!compiled_or_cached)
|
||||
{
|
||||
error = wasm_path + ": compile failed: " + String(compiled.err().message());
|
||||
error = wasm_path + ": compile failed: " + compile_error;
|
||||
return(nullptr);
|
||||
}
|
||||
unit->module.emplace(compiled.ok());
|
||||
unit->module.emplace(std::move(*compiled_or_cached));
|
||||
module_cache[wasm_path] = unit;
|
||||
return(unit);
|
||||
}
|
||||
|
||||
private:
|
||||
static String cached_wasm_path(const String& wasm_path)
|
||||
{
|
||||
if(wasm_path.size() >= 5 && wasm_path.rfind(".wasm", wasm_path.size() - 5) == wasm_path.size() - 5)
|
||||
return(wasm_path.substr(0, wasm_path.size() - 5) + ".cwasm");
|
||||
return(wasm_path + ".cwasm");
|
||||
}
|
||||
|
||||
static std::optional<wasmtime::Module> load_or_compile_cached_module(wasmtime::Engine& engine, const String& cached_path, const String& wasm_path,
|
||||
std::vector<u8>& bytes, String& compile_error)
|
||||
{
|
||||
struct stat wasm_stat;
|
||||
struct stat cached_stat;
|
||||
if(stat(cached_path.c_str(), &cached_stat) == 0 && stat(wasm_path.c_str(), &wasm_stat) == 0)
|
||||
{
|
||||
if(cached_stat.st_mtime > wasm_stat.st_mtime)
|
||||
{
|
||||
auto deserialized = wasmtime::Module::deserialize_file(engine, cached_path);
|
||||
if(deserialized)
|
||||
return(deserialized.ok());
|
||||
}
|
||||
}
|
||||
|
||||
auto compiled = wasmtime::Module::compile(engine, bytes);
|
||||
if(!compiled)
|
||||
{
|
||||
compile_error = String(compiled.err().message());
|
||||
return(std::nullopt);
|
||||
}
|
||||
auto result = compiled.ok();
|
||||
auto serialized = result.serialize();
|
||||
if(serialized)
|
||||
{
|
||||
String tmp = 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(), cached_path.c_str()) != 0)
|
||||
(void)std::remove(tmp.c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
(void)std::remove(tmp.c_str());
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
static wasmtime::Engine make_engine()
|
||||
{
|
||||
wasmtime::Config config;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user