diff --git a/etc/uce/settings.cfg b/etc/uce/settings.cfg index 059d038..8368303 100644 --- a/etc/uce/settings.cfg +++ b/etc/uce/settings.cfg @@ -38,7 +38,7 @@ WASM_COMPILE_SCRIPT=scripts/compile_wasm_unit # WASM RUNTIME SETTINGS. Unit execution is always routed through wasm. WASM_BACKEND_VERBOSE=0 -WASM_PROFILE_HOSTCALL_CPU=1 +WASM_PROFILE_HOSTCALL_CPU=0 WASM_CORE_PATH=bin/wasm/core.wasm WASM_MEMORY_LIMIT_BYTES=536870912 WASM_EPOCH_DEADLINE_TICKS=200 diff --git a/site/doc/pages/request_perf.txt b/site/doc/pages/request_perf.txt index 29b1c43..f63fe28 100644 --- a/site/doc/pages/request_perf.txt +++ b/site/doc/pages/request_perf.txt @@ -11,7 +11,7 @@ return value : performance snapshot for the active request/workspace :content Returns a DValue with timing and process metadata such as worker pid, parent pid, request count, request start times, native dispatch, workspace setup and birth, context application, guest execution, and hostcall timing. `accept_us` is divided into `transport_params_us` (FastCGI begin through the end of parameters), `transport_input_us` (parameters through the end of input), and `handler_queue_us` (input close through handler entry). This distinguishes upstream request delivery from work inside the UCE handler. -Hostcall totals include component resolution; `hostcall_cpu_us` separates thread CPU from hostcall wall time, and each bounded `hostcall_operations` item includes the same `cpu_us` attribution. `WASM_PROFILE_HOSTCALL_CPU=0` disables those per-hostcall thread-CPU samples and leaves their counters at zero when profiling cost matters more than that split. MySQL, memcache, and component resolution also expose their own count and microsecond fields. Workspace setup, birth, and context application expose matching wall and thread-CPU microseconds. `execution_cpu_us` is the remaining workspace thread CPU through the snapshot after those three phases. `unit_module_operations` is a source-root-relative list of up to 32 unit loads. Each item attributes module lookup/read/parse/build/classification plus allocation, import construction, symbol resolution, instantiation, and initialization; no caller-supplied paths are exposed. `mysql_operations` is an ordered, query-text-free list of up to 64 logical MySQL operations and their microsecond durations. A connect operation also identifies its source as `new`, cross-request `worker`, or same-request `request`; the corresponding `mysql_connection_open_count`, `mysql_connection_reuse_count`, and `mysql_request_pool_hit_count` fields provide totals. `mysql_operations_dropped` reports any overflow. The profiling hostcall itself is excluded from those totals so repeated snapshots remain comparable. +Hostcall totals include component resolution. When `WASM_PROFILE_HOSTCALL_CPU=1`, `hostcall_cpu_us` separates thread CPU from hostcall wall time and each bounded `hostcall_operations` item includes the same `cpu_us` attribution. This diagnostic is off by default because sampling thread CPU around every hostcall adds hot-path cost; `hostcall_cpu_profiled` identifies whether the current request used it, and disabled counters remain zero. MySQL, memcache, and component resolution also expose their own count and microsecond fields. Workspace setup, birth, and context application expose matching wall and thread-CPU microseconds. `execution_cpu_us` is the remaining workspace thread CPU through the snapshot after those three phases. `unit_module_operations` is a source-root-relative list of up to 32 unit loads. Each item attributes module lookup/read/parse/build/classification plus allocation, import construction, symbol resolution, instantiation, and initialization; no caller-supplied paths are exposed. `mysql_operations` is an ordered, query-text-free list of up to 64 logical MySQL operations and their microsecond durations. A connect operation also identifies its source as `new`, cross-request `worker`, or same-request `request`; the corresponding `mysql_connection_open_count`, `mysql_connection_reuse_count`, and `mysql_request_pool_hit_count` fields provide totals. `mysql_operations_dropped` reports any overflow. The profiling hostcall itself is excluded from those totals so repeated snapshots remain comparable. Component resolution is divided into `component_path_us`, `component_artifact_us`, `component_load_us`, and `component_link_us`. These aggregate path resolution, artifact readiness/freshness, Wasmtime side-module loading, and exported-handler lookup/table placement without exposing source paths. diff --git a/site/tests/io.uce b/site/tests/io.uce index 7954d19..45bfc41 100644 --- a/site/tests/io.uce +++ b/site/tests/io.uce @@ -177,7 +177,7 @@ RENDER(Request& context) hostcall_operation_profile_valid = hostcall_operation_profile_valid && name != "" && !contains(name, "uce_host_") && !contains(name, "/") && operation["count"].to_u64() > 0 && operation["cpu_us"].to_u64() <= operation["us"].to_u64() + 2; }); u64 dropped_hostcall_operations = perf["hostcall_operations_dropped"].to_u64(); - hostcall_operation_profile_valid = hostcall_operation_profile_valid && perf["hostcall_cpu_us"].to_u64() <= perf["hostcall_us"].to_u64() + 2 && operation_kinds > 0 && operation_kinds <= 32 && ((dropped_hostcall_operations == 0 && operation_hostcalls == perf["hostcall_count"].to_u64() && operation_hostcall_us == perf["hostcall_us"].to_u64() && operation_hostcall_cpu_us == perf["hostcall_cpu_us"].to_u64()) || (dropped_hostcall_operations > 0 && operation_kinds == 32 && operation_hostcalls < perf["hostcall_count"].to_u64() && operation_hostcall_us <= perf["hostcall_us"].to_u64() && operation_hostcall_cpu_us <= perf["hostcall_cpu_us"].to_u64())); + hostcall_operation_profile_valid = hostcall_operation_profile_valid && perf["hostcall_cpu_profiled"].type == 'B' && perf["hostcall_cpu_us"].to_u64() <= perf["hostcall_us"].to_u64() + 2 && operation_kinds > 0 && operation_kinds <= 32 && ((dropped_hostcall_operations == 0 && operation_hostcalls == perf["hostcall_count"].to_u64() && operation_hostcall_us == perf["hostcall_us"].to_u64() && operation_hostcall_cpu_us == perf["hostcall_cpu_us"].to_u64()) || (dropped_hostcall_operations > 0 && operation_kinds == 32 && operation_hostcalls < perf["hostcall_count"].to_u64() && operation_hostcall_us <= perf["hostcall_us"].to_u64() && operation_hostcall_cpu_us <= perf["hostcall_cpu_us"].to_u64())); bool perf_stable = transport_profile_valid && workspace_cpu_profile_valid && unit_module_profile_valid && hostcall_operation_profile_valid && perf["worker_pid"].to_u64() > 0 && perf["running_us"].to_f64() > 0 && perf["dispatch_us"].type != 'S' && perf["workspace_setup_us"].type != 'S' && perf["workspace_birth_us"].type != 'S' && perf["context_apply_us"].type != 'S' && perf["hostcall_count"].to_u64() > 0 && perf["hostcall_us"].type != 'S' && perf["guest_us"].to_f64() > 0 && perf["component_resolve_count"].type != 'S' && perf["component_path_us"].type != 'S' && perf["component_artifact_us"].type != 'S' && perf["component_load_us"].type != 'S' && perf["component_link_us"].type != 'S' && perf["unit_load_count"].to_u64() > 0 && perf["unit_module_us"].type != 'S' && perf["unit_allocate_us"].type != 'S' && perf["unit_import_us"].type != 'S' && perf["unit_symbol_resolve_count"].type != 'S' && perf["unit_symbol_resolve_us"].type != 'S' && perf["unit_instantiate_us"].type != 'S' && perf["unit_initialize_us"].type != 'S'; u64 profiled_hostcalls = perf["hostcall_count"].to_u64(); f64 profiled_hostcall_us = perf["hostcall_us"].to_f64(); diff --git a/src/lib/sys.cpp b/src/lib/sys.cpp index 00a7d8e..1f76a5d 100644 --- a/src/lib/sys.cpp +++ b/src/lib/sys.cpp @@ -1676,7 +1676,7 @@ StringMap make_server_settings() cfg["BIN_DIRECTORY"] = "/tmp/uce/work"; cfg["WASM_COMPILE_SCRIPT"] = "scripts/compile_wasm_unit"; cfg["WASM_BACKEND_VERBOSE"] = "0"; - cfg["WASM_PROFILE_HOSTCALL_CPU"] = "1"; + cfg["WASM_PROFILE_HOSTCALL_CPU"] = "0"; cfg["WASM_CORE_PATH"] = ""; cfg["WASM_MEMORY_LIMIT_BYTES"] = std::to_string(512ull * 1024 * 1024); cfg["WASM_EPOCH_DEADLINE_TICKS"] = "200"; diff --git a/src/wasm/backend.cpp b/src/wasm/backend.cpp index 497c50c..1d83d53 100644 --- a/src/wasm/backend.cpp +++ b/src/wasm/backend.cpp @@ -53,7 +53,7 @@ static String wasm_backend_ensure_started(Request* context) wc.memory_limit = (int64_t)to_u64(cfg["WASM_MEMORY_LIMIT_BYTES"], 512ull * 1024 * 1024); wc.epoch_deadline_ticks = to_u64(cfg["WASM_EPOCH_DEADLINE_TICKS"], 200); wc.mysql_persistent_pool_size = std::min(to_u64(cfg["MYSQL_PERSISTENT_POOL_SIZE"], 8), 64); - wc.profile_hostcall_cpu = to_bool(cfg["WASM_PROFILE_HOSTCALL_CPU"], true); + wc.profile_hostcall_cpu = to_bool(cfg["WASM_PROFILE_HOSTCALL_CPU"], false); wc.verbose = to_bool(cfg["WASM_BACKEND_VERBOSE"], false); // UCE_HOSTCALL_BLOCKLIST: comma-separated uce_host_* names (with or without // the "uce_host_" prefix) the sysadmin disables; each blocked call traps into diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp index a18c23d..3b97ef1 100644 --- a/src/wasm/worker.cpp +++ b/src/wasm/worker.cpp @@ -125,7 +125,7 @@ struct WasmWorkerConfig u32 table_headroom = 4096; u64 epoch_deadline_ticks = 200; // ticker period × ticks = CPU budget u64 mysql_persistent_pool_size = 8; - bool profile_hostcall_cpu = true; + bool profile_hostcall_cpu = 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 @@ -2349,6 +2349,7 @@ private: response["execution_cpu_us"] = (f64)(workspace_cpu_us > phase_cpu_us ? workspace_cpu_us - phase_cpu_us : 0); response["hostcall_count"] = (f64)self->hostcall_count; 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; std::vector invoked_hostcalls; for(u64 i = 0; i < self->hostcall_operation_slots; i++)