Profile request thread runtime on demand

This commit is contained in:
udo
2026-07-17 03:05:37 +00:00
parent 5a5450caa8
commit 8dbff881a1
6 changed files with 37 additions and 2 deletions
+31
View File
@@ -47,6 +47,8 @@
#include <limits.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sched.h>
#include <vector>
#include <algorithm>
#include <dirent.h>
@@ -126,6 +128,7 @@ struct WasmWorkerConfig
u64 epoch_deadline_ticks = 200; // ticker period × ticks = CPU budget
u64 mysql_persistent_pool_size = 8;
bool profile_hostcall_cpu = false;
bool profile_thread_runtime = false;
bool verbose = false;
// uce_host_* names (bare, without the "uce_host_" prefix) the sysadmin has
// disabled via UCE_HOSTCALL_BLOCKLIST. A blocked hostcall resolves to a trap
@@ -1224,6 +1227,9 @@ public:
f64 time_start = 0;
f64 workspace_wall_start = 0;
f64 workspace_cpu_start = 0;
struct rusage thread_runtime_start = {};
int thread_cpu_start = -1;
bool thread_runtime_profiled = false;
bool active = false;
} request_perf;
@@ -2351,6 +2357,25 @@ private:
response["hostcall_us"] = (f64)self->hostcall_total_us;
response["hostcall_cpu_profiled"].set_bool(self->worker.cfg.profile_hostcall_cpu);
response["hostcall_cpu_us"] = (f64)self->hostcall_cpu_total_us;
struct rusage runtime_now = {};
bool thread_runtime_profiled = self->request_perf.thread_runtime_profiled && getrusage(RUSAGE_THREAD, &runtime_now) == 0;
response["thread_runtime_profiled"].set_bool(thread_runtime_profiled);
if(thread_runtime_profiled)
{
auto timeval_us = [](const struct timeval& value) -> int64_t {
return((int64_t)value.tv_sec * 1000000 + value.tv_usec);
};
int cpu_now = sched_getcpu();
response["thread_user_cpu_us"] = (f64)std::max<int64_t>(0, timeval_us(runtime_now.ru_utime) - timeval_us(self->request_perf.thread_runtime_start.ru_utime));
response["thread_system_cpu_us"] = (f64)std::max<int64_t>(0, timeval_us(runtime_now.ru_stime) - timeval_us(self->request_perf.thread_runtime_start.ru_stime));
response["thread_voluntary_context_switches"] = (f64)std::max<int64_t>(0, runtime_now.ru_nvcsw - self->request_perf.thread_runtime_start.ru_nvcsw);
response["thread_involuntary_context_switches"] = (f64)std::max<int64_t>(0, runtime_now.ru_nivcsw - self->request_perf.thread_runtime_start.ru_nivcsw);
response["thread_minor_faults"] = (f64)std::max<int64_t>(0, runtime_now.ru_minflt - self->request_perf.thread_runtime_start.ru_minflt);
response["thread_major_faults"] = (f64)std::max<int64_t>(0, runtime_now.ru_majflt - self->request_perf.thread_runtime_start.ru_majflt);
response["thread_cpu_start"] = (f64)self->request_perf.thread_cpu_start;
response["thread_cpu_end"] = (f64)cpu_now;
response["thread_cpu_migrated"].set_bool(self->request_perf.thread_cpu_start >= 0 && cpu_now >= 0 && self->request_perf.thread_cpu_start != cpu_now);
}
std::vector<u64> invoked_hostcalls;
for(u64 i = 0; i < self->hostcall_operation_slots; i++)
if(self->hostcall_operation_counts[i] > 0)
@@ -3504,6 +3529,9 @@ inline WasmResponse wasm_worker_serve(WasmWorker& worker, const DValue& context_
f64 serve_started = time_precise();
auto workspace_start = std::chrono::steady_clock::now();
f64 cpu_started = wasm_thread_cpu_time();
struct rusage thread_runtime_start = {};
bool thread_runtime_profiled = request && worker.cfg.profile_thread_runtime && getrusage(RUSAGE_THREAD, &thread_runtime_start) == 0;
int thread_cpu_start = thread_runtime_profiled ? sched_getcpu() : -1;
WasmWorkspace workspace(worker);
f64 setup_cpu_finished = wasm_thread_cpu_time();
workspace.workspace_setup_us = (u64)std::chrono::duration_cast<std::chrono::microseconds>(
@@ -3515,6 +3543,9 @@ inline WasmResponse wasm_worker_serve(WasmWorker& worker, const DValue& context_
workspace.set_perf_snapshot(my_pid, (u64)parent_pid, request->server ? request->server->request_count : 0,
request->stats.time_init, request->stats.time_params, request->stats.time_input, request->stats.time_start,
serve_started, cpu_started);
workspace.request_perf.thread_runtime_start = thread_runtime_start;
workspace.request_perf.thread_cpu_start = thread_cpu_start;
workspace.request_perf.thread_runtime_profiled = thread_runtime_profiled;
if(request->stats.time_start > 0 && serve_started > request->stats.time_start)
workspace.dispatch_us = (u64)((serve_started - request->stats.time_start) * 1000000.0);
}