diff --git a/site/demo/index.uce b/site/demo/index.uce index 952bb5b..7ff2163 100644 --- a/site/demo/index.uce +++ b/site/demo/index.uce @@ -104,7 +104,6 @@ RENDER(Request& context) print("Component resolves: ", (u64)perf["component_resolve_count"].to_u64(), " / ", (u64)perf["component_resolve_us"].to_u64(), " us\n"); print("Component phases: path ", (u64)perf["component_path_us"].to_u64(), " / artifact ", (u64)perf["component_artifact_us"].to_u64(), " / load ", (u64)perf["component_load_us"].to_u64(), " / link ", (u64)perf["component_link_us"].to_u64(), " us\n"); print("Unit loads: ", (u64)perf["unit_load_count"].to_u64(), " / module ", (u64)perf["unit_module_us"].to_u64(), " / allocate ", (u64)perf["unit_allocate_us"].to_u64(), " / imports ", (u64)perf["unit_import_us"].to_u64(), " / instantiate ", (u64)perf["unit_instantiate_us"].to_u64(), " / initialize ", (u64)perf["unit_initialize_us"].to_u64(), " us\n"); - print("Unit symbol resolution: ", (u64)perf["unit_symbol_lookups"].to_u64(), " lookups / ", (u64)perf["unit_symbol_cache_hits"].to_u64(), " cached\n"); print("Output buffer size: ", context.ob->str().length(), "\n"); ?> diff --git a/site/doc/pages/request_perf.txt b/site/doc/pages/request_perf.txt index 2647c3e..dcf7cf6 100644 --- a/site/doc/pages/request_perf.txt +++ b/site/doc/pages/request_perf.txt @@ -15,8 +15,6 @@ Component resolution is divided into `component_path_us`, `component_artifact_us Successful first loads within the request are counted by `unit_load_count` and divided into `unit_module_us`, `unit_allocate_us`, `unit_import_us`, `unit_instantiate_us`, and `unit_initialize_us`. These cover compiled-module lookup, guest memory/table allocation, import construction, Wasmtime instantiation, and relocations/constructors/request binding. Repeated handlers from an already loaded unit are excluded. -`unit_symbol_lookups` and `unit_symbol_cache_hits` count request-scoped import symbol resolution. Successful function and data resolutions are cached within one workspace; misses remain uncached so a later-loaded unit can satisfy them. The cache never crosses a request or Wasmtime Store. - Wasm FastCGI workers retain up to `MYSQL_PERSISTENT_POOL_SIZE` credential-keyed MySQL connections (default `8`; set `0` to disable). UCE calls the client library's connection-reset operation before another request receives a cached connection, clearing transactions, temporary tables, session variables, and selected databases while avoiding a new authentication handshake. Same-request leases continue to share state until request cleanup. :example diff --git a/site/tests/components.uce b/site/tests/components.uce index 4d26217..090f0c4 100644 --- a/site/tests/components.uce +++ b/site/tests/components.uce @@ -38,7 +38,6 @@ RENDER(Request& context) ob_start(); component_render("components/panel:FOOTER", props, context); String footer_markup = ob_get_close(); - DValue perf = request_perf(); ob_start(); print("buffered-text"); @@ -55,7 +54,6 @@ RENDER(Request& context) check("COMPONENT(Request& props) alias", alias_markup.find("alias=Component Output") != String::npos && alias_markup.find("body=This body comes from component()") != String::npos, alias_markup); check("component_render() named handler", footer_markup.find("Named footer render") != String::npos, footer_markup); check("component(\"unit:NAME\") named handler", header_markup.find("Component Output") != String::npos && header_markup.find("This body comes from component()") == String::npos, header_markup); - check("request-scoped unit symbol cache is activated", perf["unit_symbol_cache_hits"].to_u64() > 0 && perf["unit_symbol_lookups"].to_u64() >= perf["unit_symbol_cache_hits"].to_u64(), json_encode(perf)); check("ob_start() / ob_get_close()", buffer_markup == "buffered-text", buffer_markup); ?>
diff --git a/site/tests/io.uce b/site/tests/io.uce index 5be1a3f..861ad89 100644 --- a/site/tests/io.uce +++ b/site/tests/io.uce @@ -151,7 +151,7 @@ RENDER(Request& context) check("to_u64() / to_s64() / to_f64() / to_bool()", to_u64(cfg["u64"], 7) == 42 && to_u64(cfg["bad"], 7) == 7 && to_s64(cfg["s64"], 5) == -12 && to_s64(cfg["bad"], 5) == 5 && to_f64(cfg["f64"], 1.0) > 3.49 && to_f64(cfg["bad"], 1.25) == 1.25 && to_bool(cfg["yes"], false) && !to_bool(cfg["no"], true) && !to_bool("unknown", false), var_dump(cfg)); DValue perf = request_perf(); - bool perf_stable = 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_instantiate_us"].type != 'S' && perf["unit_initialize_us"].type != 'S' && perf["unit_symbol_lookups"].type != 'S' && perf["unit_symbol_cache_hits"].type != 'S'; + bool perf_stable = 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_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(); u64 profiled_components = perf["component_resolve_count"].to_u64(); @@ -165,13 +165,11 @@ RENDER(Request& context) u64 profiled_unit_import = perf["unit_import_us"].to_u64(); u64 profiled_unit_instantiate = perf["unit_instantiate_us"].to_u64(); u64 profiled_unit_initialize = perf["unit_initialize_us"].to_u64(); - u64 profiled_unit_symbol_lookups = perf["unit_symbol_lookups"].to_u64(); - u64 profiled_unit_symbol_cache_hits = perf["unit_symbol_cache_hits"].to_u64(); String profiled_mysql_operations = json_encode(perf["mysql_operations"]); for(u64 i = 0; i < 512 && perf_stable; i++) { perf = request_perf(); - perf_stable = 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() == profiled_hostcalls && perf["hostcall_us"].to_f64() == profiled_hostcall_us && perf["guest_us"].to_f64() > 0 && perf["component_resolve_count"].to_u64() == profiled_components && perf["component_path_us"].to_u64() == profiled_component_path && perf["component_artifact_us"].to_u64() == profiled_component_artifact && perf["component_load_us"].to_u64() == profiled_component_load && perf["component_link_us"].to_u64() == profiled_component_link && perf["unit_load_count"].to_u64() == profiled_unit_loads && perf["unit_module_us"].to_u64() == profiled_unit_module && perf["unit_allocate_us"].to_u64() == profiled_unit_allocate && perf["unit_import_us"].to_u64() == profiled_unit_import && perf["unit_instantiate_us"].to_u64() == profiled_unit_instantiate && perf["unit_initialize_us"].to_u64() == profiled_unit_initialize && perf["unit_symbol_lookups"].to_u64() == profiled_unit_symbol_lookups && perf["unit_symbol_cache_hits"].to_u64() == profiled_unit_symbol_cache_hits && json_encode(perf["mysql_operations"]) == profiled_mysql_operations; + perf_stable = 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() == profiled_hostcalls && perf["hostcall_us"].to_f64() == profiled_hostcall_us && perf["guest_us"].to_f64() > 0 && perf["component_resolve_count"].to_u64() == profiled_components && perf["component_path_us"].to_u64() == profiled_component_path && perf["component_artifact_us"].to_u64() == profiled_component_artifact && perf["component_load_us"].to_u64() == profiled_component_load && perf["component_link_us"].to_u64() == profiled_component_link && perf["unit_load_count"].to_u64() == profiled_unit_loads && perf["unit_module_us"].to_u64() == profiled_unit_module && perf["unit_allocate_us"].to_u64() == profiled_unit_allocate && perf["unit_import_us"].to_u64() == profiled_unit_import && perf["unit_instantiate_us"].to_u64() == profiled_unit_instantiate && perf["unit_initialize_us"].to_u64() == profiled_unit_initialize && json_encode(perf["mysql_operations"]) == profiled_mysql_operations; } check("request_perf() stages stable repeated snapshots", perf_stable, json_encode(perf)); diff --git a/src/wasm/worker.cpp b/src/wasm/worker.cpp index e471fc0..aa38e96 100644 --- a/src/wasm/worker.cpp +++ b/src/wasm/worker.cpp @@ -125,8 +125,6 @@ struct WasmRequestProfile u64 unit_import_total_us = 0; u64 unit_instantiate_total_us = 0; u64 unit_initialize_total_us = 0; - u64 unit_symbol_lookup_count = 0; - u64 unit_symbol_cache_hit_count = 0; u64 hostcall_count = 0; u64 hostcall_total_us = 0; u64 mysql_hostcall_count = 0; @@ -1146,8 +1144,6 @@ private: std::vector units; std::map units_by_source; std::map handler_slots; // source + ":" + symbol → table slot - std::map resolved_funcs; - std::map resolved_data; std::vector host_funcs; // keep host imports alive wasmtime::Store::Context ctx() @@ -1229,24 +1225,11 @@ private: std::optional resolve_func(const String& name) { - unit_symbol_lookup_count++; - auto cached = resolved_funcs.find(name); - if(cached != resolved_funcs.end()) - { - unit_symbol_cache_hit_count++; - return(cached->second); - } if(auto func = core_func(name)) - { - resolved_funcs.emplace(name, *func); return(func); - } for(size_t i = 0; i < units.size(); i++) if(auto func = unit_func(i, name)) - { - resolved_funcs.emplace(name, *func); return(func); - } return(std::nullopt); } @@ -1254,21 +1237,12 @@ private: // (core is non-PIC → base 0; PIC units export __memory_base-relative) bool resolve_data(const String& name, u32& address_out) { - unit_symbol_lookup_count++; - auto cached = resolved_data.find(name); - if(cached != resolved_data.end()) - { - unit_symbol_cache_hit_count++; - address_out = cached->second; - return(true); - } auto from_core = core->get(ctx(), std::string_view(name)); if(from_core) if(auto* global = std::get_if(&*from_core)) - { - address_out = (u32)global->get(ctx()).i32(); - resolved_data[name] = address_out; - return(true); + { + address_out = (u32)global->get(ctx()).i32(); + return(true); } for(size_t i = 0; i < units.size(); i++) { @@ -1277,7 +1251,6 @@ private: if(auto* global = std::get_if(&*exported)) { address_out = units[i].memory_base + (u32)global->get(ctx()).i32(); - resolved_data[name] = address_out; return(true); } } @@ -1459,11 +1432,9 @@ private: if(!own || !std::get_if(&*own)) return(source_path + ": GOT.mem." + name + " defined neither by core nor by any unit"); u32 offset = (u32)std::get(*own).get(cx).i32(); - u32 address = memory_base + offset; - auto set = got.set(cx, wasmtime::Val((int32_t)address)); + auto set = got.set(cx, wasmtime::Val((int32_t)(memory_base + offset))); if(!set) return("GOT patch failed: " + String(set.err().message())); - resolved_data[name] = address; } // init sequence, then bind this unit's context to the request @@ -1946,8 +1917,6 @@ private: response["unit_import_us"] = (f64)self->unit_import_total_us; response["unit_instantiate_us"] = (f64)self->unit_instantiate_total_us; response["unit_initialize_us"] = (f64)self->unit_initialize_total_us; - response["unit_symbol_lookups"] = (f64)self->unit_symbol_lookup_count; - response["unit_symbol_cache_hits"] = (f64)self->unit_symbol_cache_hit_count; f64 running_us = response["running_us"].to_f64(); f64 accounted_us = (f64)(self->dispatch_us + self->workspace_setup_us + self->workspace_birth_us + self->context_apply_us + self->hostcall_total_us); response["guest_us"] = running_us > accounted_us ? running_us - accounted_us : 0.0;