Reuse loaded component units per request

This commit is contained in:
udo
2026-07-18 05:01:27 +00:00
parent 5e140d6a5a
commit a5ad5042b7
8 changed files with 133 additions and 62 deletions
+81 -55
View File
@@ -201,6 +201,7 @@ struct WasmRequestProfile
u64 output_collect_us = 0;
u64 workspace_complete_us = 0;
u64 component_resolve_count = 0;
u64 component_loaded_reuse_count = 0;
u64 component_resolve_total_us = 0;
u64 component_path_total_us = 0;
u64 component_artifact_total_us = 0;
@@ -1732,6 +1733,7 @@ private:
};
std::vector<LoadedUnit> units;
std::map<String, size_t> units_by_source;
std::map<String, String> component_loaded_paths; // caller + target → request-loaded canonical source
std::map<String, u32> handler_slots; // source + ":" + symbol → table slot
bool stale_component_mutation_blocked = false;
String stale_component_mutation_status;
@@ -2386,7 +2388,27 @@ private:
return(0);
}
String resolved = resolve_source_path(file_name, current_unit);
String resolve_key = current_unit + "\t" + file_name;
String resolved;
String error;
size_t unit_index = 0;
bool loaded_reuse = false;
auto loaded = units_by_source.find(file_name);
if(loaded == units_by_source.end())
{
auto known_path = component_loaded_paths.find(resolve_key);
if(known_path != component_loaded_paths.end())
loaded = units_by_source.find(known_path->second);
}
if(loaded != units_by_source.end())
{
resolved = loaded->first;
unit_index = loaded->second;
loaded_reuse = true;
component_loaded_reuse_count++;
}
else
resolved = resolve_source_path(file_name, current_unit);
component_path_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - probe_start).count();
if(resolved == "")
@@ -2401,67 +2423,70 @@ private:
return(1);
}
auto artifact_start = std::chrono::steady_clock::now();
bool artifact_exists = file_exists_host(worker.unit_wasm_path(resolved));
bool can_serve_stale = compiler_request_can_serve_stale_artifact(context);
String method = context ? to_upper(trim(context->params["REQUEST_METHOD"])) : String("");
bool read_request = method == "GET" || method == "HEAD" || method == "OPTIONS";
if(can_serve_stale && read_request && !component_source_generation_checked)
if(!loaded_reuse)
{
component_source_generation = compiler_source_generation(context);
component_source_generation_checked = true;
}
bool stale = false;
if(artifact_exists)
{
auto now = std::chrono::steady_clock::now();
auto cached_freshness = worker.component_freshness.find(resolved);
// HTTP reads may serve a complete stale artifact, so bound their graph
// stat work; CLI and mutations always check the current graph.
bool generation_available = component_source_generation != "";
bool check_freshness = !can_serve_stale || !read_request ||
cached_freshness == worker.component_freshness.end() ||
(generation_available ?
cached_freshness->second.source_generation != component_source_generation :
std::chrono::duration_cast<std::chrono::milliseconds>(
now - cached_freshness->second.checked_at).count() >= 1000);
if(check_freshness)
auto artifact_start = std::chrono::steady_clock::now();
bool artifact_exists = file_exists_host(worker.unit_wasm_path(resolved));
bool can_serve_stale = compiler_request_can_serve_stale_artifact(context);
String method = context ? to_upper(trim(context->params["REQUEST_METHOD"])) : String("");
bool read_request = method == "GET" || method == "HEAD" || method == "OPTIONS";
if(can_serve_stale && read_request && !component_source_generation_checked)
{
stale = compiler_unit_needs_recompile(context, resolved, 0, can_serve_stale && read_request, true);
worker.component_freshness[resolved] = { now, stale, component_source_generation };
component_source_generation = compiler_source_generation(context);
component_source_generation_checked = true;
}
else
stale = cached_freshness->second.stale;
}
if(stale && can_serve_stale)
{
compiler_prioritize_unit(context, resolved);
if(!read_request)
bool stale = false;
if(artifact_exists)
{
stale_component_mutation_blocked = true;
stale_component_mutation_status = context->params["GATEWAY_INTERFACE"] != "" ?
"Status: 503 Service Unavailable" : "HTTP/1.1 503 Service Unavailable";
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - artifact_start).count();
auto now = std::chrono::steady_clock::now();
auto cached_freshness = worker.component_freshness.find(resolved);
// HTTP reads may serve a complete stale artifact, so bound their graph
// stat work; CLI and mutations always check the current graph.
bool generation_available = component_source_generation != "";
bool check_freshness = !can_serve_stale || !read_request ||
cached_freshness == worker.component_freshness.end() ||
(generation_available ?
cached_freshness->second.source_generation != component_source_generation :
std::chrono::duration_cast<std::chrono::milliseconds>(
now - cached_freshness->second.checked_at).count() >= 1000);
if(check_freshness)
{
stale = compiler_unit_needs_recompile(context, resolved, 0, can_serve_stale && read_request, true);
worker.component_freshness[resolved] = { now, stale, component_source_generation };
}
else
stale = cached_freshness->second.stale;
}
if(stale && can_serve_stale)
{
compiler_prioritize_unit(context, resolved);
if(!read_request)
{
stale_component_mutation_blocked = true;
stale_component_mutation_status = context->params["GATEWAY_INTERFACE"] != "" ?
"Status: 503 Service Unavailable" : "HTTP/1.1 503 Service Unavailable";
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - artifact_start).count();
record_probe();
return(0);
}
}
if(!artifact_exists || (stale && !can_serve_stale))
get_shared_unit(context, resolved);
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - artifact_start).count();
auto load_start = std::chrono::steady_clock::now();
error = load_unit(resolved, "component", unit_index);
component_load_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - load_start).count();
if(error != "")
{
fprintf(stderr, "[wasm] component load failed: %s\n", error.c_str());
record_probe();
return(0);
}
}
if(!artifact_exists || (stale && !can_serve_stale))
get_shared_unit(context, resolved);
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - artifact_start).count();
auto load_start = std::chrono::steady_clock::now();
size_t unit_index = 0;
String error = load_unit(resolved, "component", unit_index);
component_load_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::steady_clock::now() - load_start).count();
if(error != "")
{
fprintf(stderr, "[wasm] component load failed: %s\n", error.c_str());
record_probe();
return(0);
component_loaded_paths[resolve_key] = resolved;
}
auto link_start = std::chrono::steady_clock::now();
auto record_link = [&]() {
@@ -2723,6 +2748,7 @@ private:
response["memcache_hostcall_count"] = (f64)self->memcache_hostcall_count;
response["memcache_hostcall_us"] = (f64)self->memcache_hostcall_total_us;
response["component_resolve_count"] = (f64)self->component_resolve_count;
response["component_loaded_reuse_count"] = (f64)self->component_loaded_reuse_count;
response["component_resolve_us"] = (f64)self->component_resolve_total_us;
response["component_path_us"] = (f64)self->component_path_total_us;
response["component_artifact_us"] = (f64)self->component_artifact_total_us;