Keep demand compilation responsive
This commit is contained in:
@@ -233,7 +233,14 @@ whose compilation outlasted the guest CPU budget would immediately trap in the
|
||||
following allocator/relocation call even though no guest loop consumed it.
|
||||
|
||||
The proactive compiler and request workers coordinate through per-unit file
|
||||
locks and a lock-protected demand-priority queue under `BIN_DIRECTORY`. Unit
|
||||
locks and a lock-protected demand-priority queue under `BIN_DIRECTORY`. A small
|
||||
priority-only compiler process drains that queue independently of the full-site
|
||||
scanner. This matters when the scanner is already inside a long transitive C++
|
||||
compile: a requested stale component can rebuild immediately instead of waiting
|
||||
for that unrelated compile to finish. Both compiler processes use the same
|
||||
per-unit lock, so concurrent demand and scan discovery cannot publish duplicate
|
||||
artifacts. The priority worker is idle when there is no demand and never scans
|
||||
the site on its own. Unit
|
||||
compilation writes and validates a process-unique temporary wasm file, then
|
||||
publishes it with an atomic rename. When proactive compilation is enabled,
|
||||
read-only HTTP requests keep using the last complete artifact while requesting
|
||||
|
||||
+96
-48
@@ -16,6 +16,7 @@ ServerState server_state;
|
||||
|
||||
FastCGIServer server;
|
||||
pid_t proactive_compiler_pid = 0;
|
||||
pid_t priority_compiler_pid = 0;
|
||||
|
||||
// The central WS broker process: owns the WS port + every connection, forwards
|
||||
// renders to the worker pool over uce.sock, and applies ws_* commands flushed
|
||||
@@ -1217,6 +1218,39 @@ void proactive_compile_queue_push(StringList& queue, String file_name)
|
||||
queue.push_back(file_name);
|
||||
}
|
||||
|
||||
bool proactive_compile_unit(Request& context, String file_name, bool& source_missing)
|
||||
{
|
||||
bool failed = false;
|
||||
String wasm_path = server_state.config["BIN_DIRECTORY"] + file_name + ".wasm";
|
||||
if(compiler_unit_needs_recompile(&context, file_name, &source_missing))
|
||||
{
|
||||
printf("(i) proactive compile %s\n", file_name.c_str());
|
||||
auto su = get_shared_unit(&context, file_name);
|
||||
failed = !su || su->compiler_messages != "";
|
||||
if(su)
|
||||
wasm_path = su->wasm_name;
|
||||
}
|
||||
else if(source_missing)
|
||||
{
|
||||
printf("(i) proactive compiler forget removed unit %s\n", file_name.c_str());
|
||||
compiler_untrack_known_unit(&context, file_name);
|
||||
}
|
||||
if(!source_missing && !failed && wasm_serialized_module_needs_refresh(wasm_path))
|
||||
{
|
||||
printf("(i) proactive serialize %s\n", file_name.c_str());
|
||||
String serialize_error = wasm_serialize_module_artifact(wasm_path);
|
||||
if(serialize_error != "")
|
||||
{
|
||||
printf("(!) proactive serialize failed for %s: %s\n", file_name.c_str(), serialize_error.c_str());
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
context.session.clear();
|
||||
context.session_loaded_hash = "";
|
||||
clear_shared_unit_cache(server_state);
|
||||
return(failed);
|
||||
}
|
||||
|
||||
void run_proactive_compiler()
|
||||
{
|
||||
Request background_context;
|
||||
@@ -1317,39 +1351,13 @@ void run_proactive_compiler()
|
||||
auto retry_it = retry_after.find(file_name);
|
||||
if(retry_it != retry_after.end() && time_precise() < retry_it->second)
|
||||
continue;
|
||||
bool failed = false;
|
||||
String wasm_path = server_state.config["BIN_DIRECTORY"] + file_name + ".wasm";
|
||||
if(compiler_unit_needs_recompile(&background_context, file_name, &source_missing))
|
||||
{
|
||||
printf("(i) proactive compile %s\n", file_name.c_str());
|
||||
auto su = get_shared_unit(&background_context, file_name);
|
||||
failed = !su || su->compiler_messages != "";
|
||||
if(su)
|
||||
wasm_path = su->wasm_name;
|
||||
}
|
||||
else if(source_missing)
|
||||
{
|
||||
printf("(i) proactive compiler forget removed unit %s\n", file_name.c_str());
|
||||
compiler_untrack_known_unit(&background_context, file_name);
|
||||
bool failed = proactive_compile_unit(background_context, file_name, source_missing);
|
||||
if(source_missing)
|
||||
retry_after.erase(file_name);
|
||||
}
|
||||
if(!source_missing && !failed && wasm_serialized_module_needs_refresh(wasm_path))
|
||||
{
|
||||
printf("(i) proactive serialize %s\n", file_name.c_str());
|
||||
String serialize_error = wasm_serialize_module_artifact(wasm_path);
|
||||
if(serialize_error != "")
|
||||
{
|
||||
printf("(!) proactive serialize failed for %s: %s\n", file_name.c_str(), serialize_error.c_str());
|
||||
failed = true;
|
||||
}
|
||||
}
|
||||
if(!source_missing && failed)
|
||||
else if(failed)
|
||||
retry_after[file_name] = time_precise() + failure_retry_interval;
|
||||
else if(!source_missing)
|
||||
else
|
||||
retry_after.erase(file_name);
|
||||
background_context.session.clear();
|
||||
background_context.session_loaded_hash = "";
|
||||
clear_shared_unit_cache(server_state);
|
||||
usleep(250000);
|
||||
continue;
|
||||
}
|
||||
@@ -1371,11 +1379,61 @@ void run_proactive_compiler()
|
||||
}
|
||||
}
|
||||
|
||||
void run_priority_compiler()
|
||||
{
|
||||
Request background_context;
|
||||
background_context.server = &server_state;
|
||||
set_active_request(background_context);
|
||||
my_pid = getpid();
|
||||
close_inherited_server_sockets();
|
||||
signal(SIGSEGV, on_segfault);
|
||||
signal(SIGABRT, on_segfault);
|
||||
signal(SIGBUS, on_segfault);
|
||||
signal(SIGILL, on_segfault);
|
||||
signal(SIGFPE, on_segfault);
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
setpriority(PRIO_PROCESS, 0, 5);
|
||||
while(!termination_signal_received)
|
||||
{
|
||||
auto units = compiler_take_priority_units(&background_context);
|
||||
if(units.empty())
|
||||
{
|
||||
usleep(100000);
|
||||
continue;
|
||||
}
|
||||
for(auto& file_name : units)
|
||||
{
|
||||
if(termination_signal_received)
|
||||
break;
|
||||
bool source_missing = false;
|
||||
proactive_compile_unit(background_context, file_name, source_missing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool proactive_compiler_alive()
|
||||
{
|
||||
return(proactive_compiler_pid > 0 && task_kill(proactive_compiler_pid, 0) == 0);
|
||||
}
|
||||
|
||||
pid_t spawn_compiler(const char* label, void (*runner)())
|
||||
{
|
||||
pid_t p = fork();
|
||||
if(p < 0)
|
||||
{
|
||||
perror((String("fork ") + label).c_str());
|
||||
return(0);
|
||||
}
|
||||
if(p == 0)
|
||||
{
|
||||
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
||||
runner();
|
||||
exit(0);
|
||||
}
|
||||
printf("(P) %s spawned: PID %i\n", label, p);
|
||||
return(p);
|
||||
}
|
||||
|
||||
void ensure_proactive_compiler()
|
||||
{
|
||||
if(!to_bool(server_state.config["PROACTIVE_COMPILE_ENABLED"], true))
|
||||
@@ -1383,24 +1441,10 @@ void ensure_proactive_compiler()
|
||||
if(float_val(server_state.config["PROACTIVE_COMPILE_CHECK_INTERVAL"]) <= 0)
|
||||
return;
|
||||
|
||||
if(proactive_compiler_alive())
|
||||
return;
|
||||
|
||||
pid_t p = fork();
|
||||
if(p < 0)
|
||||
{
|
||||
perror("fork proactive compiler");
|
||||
return;
|
||||
}
|
||||
if(p == 0)
|
||||
{
|
||||
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
||||
run_proactive_compiler();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
proactive_compiler_pid = p;
|
||||
printf("(P) proactive compiler spawned: PID %i\n", p);
|
||||
if(!proactive_compiler_alive())
|
||||
proactive_compiler_pid = spawn_compiler("proactive compiler", run_proactive_compiler);
|
||||
if(priority_compiler_pid <= 0 || task_kill(priority_compiler_pid, 0) != 0)
|
||||
priority_compiler_pid = spawn_compiler("priority compiler", run_priority_compiler);
|
||||
}
|
||||
|
||||
void listen_for_connections()
|
||||
@@ -1557,6 +1601,8 @@ int main(int argc, char** argv)
|
||||
{
|
||||
if(!proactive_compiler_alive())
|
||||
proactive_compiler_pid = 0;
|
||||
if(priority_compiler_pid > 0 && task_kill(priority_compiler_pid, 0) != 0)
|
||||
priority_compiler_pid = 0;
|
||||
if(!termination_signal_received)
|
||||
ensure_proactive_compiler();
|
||||
|
||||
@@ -1581,6 +1627,8 @@ int main(int argc, char** argv)
|
||||
kill(worker.first, SIGTERM);
|
||||
if(proactive_compiler_pid > 0)
|
||||
kill(proactive_compiler_pid, SIGTERM);
|
||||
if(priority_compiler_pid > 0)
|
||||
kill(priority_compiler_pid, SIGTERM);
|
||||
if(ws_broker_pid > 0)
|
||||
kill(ws_broker_pid, SIGTERM);
|
||||
f64 drain_deadline = time_precise() + (f64)to_u64(server_state.config["WORKER_DRAIN_TIMEOUT_SECONDS"], 10);
|
||||
|
||||
Reference in New Issue
Block a user