feat: request_perf() worker-side timing hostcall; restore demo System Info
Units run in the wasm sandbox, so my_pid/parent_pid/context.server->request_count
read as sandbox stubs — the demo System Info counters were broken, and there was
no authoritative server-side request timing available to unit code (client-side
measurement cannot see queue/dispatch latency).
Add a request_perf() unit API backed by a new uce_host_request_perf hostcall.
The native worker answers it live, returning a DValue:
worker_pid, parent_pid, request_count,
accept_us = (time_start - time_init)*1e6 (entry -> dispatch wait),
running_us = (now - time_start)*1e6 (since dispatch, live),
total_us = (now - time_init)*1e6 (since the request entered UCE),
workspace_birth_us.
time_init is captured at request entry (handle_request, with a handle_complete
fallback); a RequestPerfSnapshot {pids, request_count, time_init, time_start} is
threaded from wasm_backend_serve through wasm_worker_serve onto the workspace,
and the hostcall computes the live deltas at call time. Wired like uce_host_units
(sized DValue hostcall): core_hostcalls.syms + sys.cpp/sys.h request_perf().
site/demo/index.uce System Info now uses request_perf() and shows the real worker
PID, an incrementing per-worker request count, and the timing counters.
Implemented via the pi agent (gpt-5.3-codex-spark); a review of the live numbers
caught accept_us mistakenly computed as (now - time_init) (== total_us), fixed to
the dispatch wait (time_start - time_init). Independently verified on the host:
System Info shows non-zero PIDs, incrementing count, accept_us ~50us << total_us
~2.4ms with accept+running==total; run_cli_tests --include-wasm-kill => 87 passed,
0 failed, 0 skipped.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+50
-4
@@ -404,10 +404,30 @@ public:
|
||||
u64 component_resolve_count = 0;
|
||||
u64 component_resolve_total_us = 0;
|
||||
|
||||
struct RequestPerfSnapshot
|
||||
{
|
||||
u64 worker_pid = 0;
|
||||
u64 parent_pid = 0;
|
||||
u64 request_count = 0;
|
||||
f64 time_init = 0;
|
||||
f64 time_start = 0;
|
||||
bool active = false;
|
||||
} request_perf;
|
||||
|
||||
explicit WasmWorkspace(WasmWorker& w) : worker(w), store(w.engine)
|
||||
{
|
||||
}
|
||||
|
||||
void set_perf_snapshot(u64 worker_pid, u64 parent_pid, u64 request_count, f64 time_init, f64 time_start)
|
||||
{
|
||||
request_perf.worker_pid = worker_pid;
|
||||
request_perf.parent_pid = parent_pid;
|
||||
request_perf.request_count = request_count;
|
||||
request_perf.time_init = time_init;
|
||||
request_perf.time_start = time_start;
|
||||
request_perf.active = true;
|
||||
}
|
||||
|
||||
#ifdef UCE_WASM_HOST_CONNECTORS
|
||||
// Host-owned resource handle table (§3.1): connections opened by the guest
|
||||
// live here and are closed when the workspace drops at request end.
|
||||
@@ -1221,9 +1241,33 @@ private:
|
||||
}));
|
||||
if(mod == "env" && name == "uce_host_time_precise")
|
||||
return(add([](Caller, Span<const Val>, Span<Val> results) -> Result<std::monostate, Trap> {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, 0);
|
||||
results[0] = Val((double)tv.tv_sec + (double)tv.tv_usec / 1e6);
|
||||
results[0] = Val(time_precise());
|
||||
return(std::monostate());
|
||||
}));
|
||||
if(mod == "env" && name == "uce_host_request_perf")
|
||||
return(add([self](Caller, Span<const Val> args, Span<Val> results) -> Result<std::monostate, Trap> {
|
||||
DValue response;
|
||||
if(self->request_perf.active)
|
||||
{
|
||||
f64 now = time_precise();
|
||||
response["worker_pid"] = (f64)self->request_perf.worker_pid;
|
||||
response["parent_pid"] = (f64)self->request_perf.parent_pid;
|
||||
response["request_count"] = (f64)self->request_perf.request_count;
|
||||
if(self->request_perf.time_start > 0 && self->request_perf.time_init > 0)
|
||||
response["accept_us"] = (f64)((self->request_perf.time_start - self->request_perf.time_init) * 1000000.0);
|
||||
if(self->request_perf.time_start > 0)
|
||||
response["running_us"] = (f64)((now - self->request_perf.time_start) * 1000000.0);
|
||||
if(self->request_perf.time_init > 0)
|
||||
response["total_us"] = (f64)((now - self->request_perf.time_init) * 1000000.0);
|
||||
if(self->workspace_birth_us > 0)
|
||||
response["workspace_birth_us"] = (f64)self->workspace_birth_us;
|
||||
}
|
||||
String encoded = ucb_encode(response);
|
||||
u32 cap = (u32)args[3].i32();
|
||||
int32_t buf = args[2].i32();
|
||||
if(buf != 0 && cap >= encoded.size())
|
||||
self->hostcall_write(buf, encoded);
|
||||
results[0] = Val((int32_t)encoded.size());
|
||||
return(std::monostate());
|
||||
}));
|
||||
if(mod == "env" && name == "uce_host_env")
|
||||
@@ -1898,10 +1942,12 @@ private:
|
||||
// ---- public entry: one request through one workspace -----------------------
|
||||
|
||||
inline WasmResponse wasm_worker_serve(WasmWorker& worker, const DValue& context_tree, const String& entry_source_path,
|
||||
const String& handler = "render")
|
||||
const String& handler = "render", const Request* request = 0)
|
||||
{
|
||||
WasmResponse response;
|
||||
WasmWorkspace workspace(worker);
|
||||
if(request)
|
||||
workspace.set_perf_snapshot(my_pid, (u64)parent_pid, request->server ? request->server->request_count : 0, request->stats.time_init, request->stats.time_start);
|
||||
auto birth_start = std::chrono::steady_clock::now();
|
||||
String error = workspace.birth();
|
||||
workspace.workspace_birth_us = (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
|
||||
Reference in New Issue
Block a user