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.
|
following allocator/relocation call even though no guest loop consumed it.
|
||||||
|
|
||||||
The proactive compiler and request workers coordinate through per-unit file
|
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
|
compilation writes and validates a process-unique temporary wasm file, then
|
||||||
publishes it with an atomic rename. When proactive compilation is enabled,
|
publishes it with an atomic rename. When proactive compilation is enabled,
|
||||||
read-only HTTP requests keep using the last complete artifact while requesting
|
read-only HTTP requests keep using the last complete artifact while requesting
|
||||||
|
|||||||
+96
-48
@@ -16,6 +16,7 @@ ServerState server_state;
|
|||||||
|
|
||||||
FastCGIServer server;
|
FastCGIServer server;
|
||||||
pid_t proactive_compiler_pid = 0;
|
pid_t proactive_compiler_pid = 0;
|
||||||
|
pid_t priority_compiler_pid = 0;
|
||||||
|
|
||||||
// The central WS broker process: owns the WS port + every connection, forwards
|
// 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
|
// 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);
|
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()
|
void run_proactive_compiler()
|
||||||
{
|
{
|
||||||
Request background_context;
|
Request background_context;
|
||||||
@@ -1317,39 +1351,13 @@ void run_proactive_compiler()
|
|||||||
auto retry_it = retry_after.find(file_name);
|
auto retry_it = retry_after.find(file_name);
|
||||||
if(retry_it != retry_after.end() && time_precise() < retry_it->second)
|
if(retry_it != retry_after.end() && time_precise() < retry_it->second)
|
||||||
continue;
|
continue;
|
||||||
bool failed = false;
|
bool failed = proactive_compile_unit(background_context, file_name, source_missing);
|
||||||
String wasm_path = server_state.config["BIN_DIRECTORY"] + file_name + ".wasm";
|
if(source_missing)
|
||||||
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);
|
|
||||||
retry_after.erase(file_name);
|
retry_after.erase(file_name);
|
||||||
}
|
else if(failed)
|
||||||
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)
|
|
||||||
retry_after[file_name] = time_precise() + failure_retry_interval;
|
retry_after[file_name] = time_precise() + failure_retry_interval;
|
||||||
else if(!source_missing)
|
else
|
||||||
retry_after.erase(file_name);
|
retry_after.erase(file_name);
|
||||||
background_context.session.clear();
|
|
||||||
background_context.session_loaded_hash = "";
|
|
||||||
clear_shared_unit_cache(server_state);
|
|
||||||
usleep(250000);
|
usleep(250000);
|
||||||
continue;
|
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()
|
bool proactive_compiler_alive()
|
||||||
{
|
{
|
||||||
return(proactive_compiler_pid > 0 && task_kill(proactive_compiler_pid, 0) == 0);
|
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()
|
void ensure_proactive_compiler()
|
||||||
{
|
{
|
||||||
if(!to_bool(server_state.config["PROACTIVE_COMPILE_ENABLED"], true))
|
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)
|
if(float_val(server_state.config["PROACTIVE_COMPILE_CHECK_INTERVAL"]) <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(proactive_compiler_alive())
|
if(!proactive_compiler_alive())
|
||||||
return;
|
proactive_compiler_pid = spawn_compiler("proactive compiler", run_proactive_compiler);
|
||||||
|
if(priority_compiler_pid <= 0 || task_kill(priority_compiler_pid, 0) != 0)
|
||||||
pid_t p = fork();
|
priority_compiler_pid = spawn_compiler("priority compiler", run_priority_compiler);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void listen_for_connections()
|
void listen_for_connections()
|
||||||
@@ -1557,6 +1601,8 @@ int main(int argc, char** argv)
|
|||||||
{
|
{
|
||||||
if(!proactive_compiler_alive())
|
if(!proactive_compiler_alive())
|
||||||
proactive_compiler_pid = 0;
|
proactive_compiler_pid = 0;
|
||||||
|
if(priority_compiler_pid > 0 && task_kill(priority_compiler_pid, 0) != 0)
|
||||||
|
priority_compiler_pid = 0;
|
||||||
if(!termination_signal_received)
|
if(!termination_signal_received)
|
||||||
ensure_proactive_compiler();
|
ensure_proactive_compiler();
|
||||||
|
|
||||||
@@ -1581,6 +1627,8 @@ int main(int argc, char** argv)
|
|||||||
kill(worker.first, SIGTERM);
|
kill(worker.first, SIGTERM);
|
||||||
if(proactive_compiler_pid > 0)
|
if(proactive_compiler_pid > 0)
|
||||||
kill(proactive_compiler_pid, SIGTERM);
|
kill(proactive_compiler_pid, SIGTERM);
|
||||||
|
if(priority_compiler_pid > 0)
|
||||||
|
kill(priority_compiler_pid, SIGTERM);
|
||||||
if(ws_broker_pid > 0)
|
if(ws_broker_pid > 0)
|
||||||
kill(ws_broker_pid, SIGTERM);
|
kill(ws_broker_pid, SIGTERM);
|
||||||
f64 drain_deadline = time_precise() + (f64)to_u64(server_state.config["WORKER_DRAIN_TIMEOUT_SECONDS"], 10);
|
f64 drain_deadline = time_precise() + (f64)to_u64(server_state.config["WORKER_DRAIN_TIMEOUT_SECONDS"], 10);
|
||||||
|
|||||||
Reference in New Issue
Block a user