Reuse loaded component units per request
This commit is contained in:
parent
5e140d6a5a
commit
a5ad5042b7
@ -139,8 +139,12 @@ The request entry unit is already loaded by the host, so its selected handler
|
||||
and optional `ONCE` export are placed directly into the workspace table and
|
||||
passed to `uce_wasm_invoke_loaded_entry()`. Dynamic component and unit calls
|
||||
continue through `wasm_resolve_target()`, where relative-path resolution is
|
||||
required. Opt-in verbose response headers split entry invocation into load,
|
||||
presence lookup, table linking, and core dispatch time.
|
||||
required. Handler cache keys include the calling unit so identically named
|
||||
relative targets in different directories cannot alias. Once a unit has passed
|
||||
freshness checks and loaded into a request workspace, later handler lookups
|
||||
reuse that immutable request-local instance; `component_loaded_reuse_count`
|
||||
reports those lookups. Opt-in verbose response headers split entry invocation
|
||||
into load, presence lookup, table linking, and core dispatch time.
|
||||
|
||||
`wasm_backend_should_handle(request, entry_unit)` checks whether the wasm
|
||||
backend is initialized and the requested artifact/handler is currently
|
||||
|
||||
@ -69,6 +69,7 @@ if [[ "$action" == "run" ]]; then
|
||||
scripts/test_dependency_invalidation.sh
|
||||
scripts/test_cold_component_deadline.sh
|
||||
scripts/test_nested_component_props.sh
|
||||
scripts/test_relative_component_cache.sh
|
||||
scripts/test_password_hashing.sh
|
||||
scripts/test_mysql_epoch_refresh.sh
|
||||
scripts/test_mysql_persistent_pool.sh
|
||||
|
||||
38
scripts/test_relative_component_cache.sh
Executable file
38
scripts/test_relative_component_cache.sh
Executable file
@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
test_name="relative-component-cache-test-$$"
|
||||
site_directory="${UCE_TEST_SITE_DIRECTORY:-site}"
|
||||
if [[ -z "${UCE_TEST_SITE_DIRECTORY:-}" && -r /etc/uce/settings.cfg ]]; then
|
||||
configured_site_directory=$(awk -F= '/^[[:space:]]*SITE_DIRECTORY[[:space:]]*=/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' /etc/uce/settings.cfg)
|
||||
if [[ -n "${configured_site_directory:-}" ]]; then
|
||||
site_directory="$configured_site_directory"
|
||||
fi
|
||||
fi
|
||||
source_dir="$site_directory/$test_name"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$source_dir"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
mkdir -p "$source_dir/a" "$source_dir/b"
|
||||
|
||||
printf '%s\n' \
|
||||
'CLI(Request& context) {' \
|
||||
' print(component("a/parent", context));' \
|
||||
' print("/");' \
|
||||
' print(component("b/parent", context));' \
|
||||
'}' >"$source_dir/entry.uce"
|
||||
printf '%s\n' 'COMPONENT(Request& context) { print(component("child", context)); }' >"$source_dir/a/parent.uce"
|
||||
printf '%s\n' 'COMPONENT(Request& context) { print("relative-a"); }' >"$source_dir/a/child.uce"
|
||||
printf '%s\n' 'COMPONENT(Request& context) { print(component("child", context)); }' >"$source_dir/b/parent.uce"
|
||||
printf '%s\n' 'COMPONENT(Request& context) { print("relative-b"); }' >"$source_dir/b/child.uce"
|
||||
|
||||
output=$(scripts/uce-cli "/$test_name/entry.uce")
|
||||
if [[ "$output" != "relative-a/relative-b" ]]; then
|
||||
echo "relative component cache crossed caller boundaries: $output" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "relative component cache passed"
|
||||
@ -59,7 +59,7 @@ RENDER(Request& context)
|
||||
String unit_operations = json_encode(perf["unit_module_operations"]);
|
||||
check(
|
||||
"request_perf() separates entry code from dynamic component materialization",
|
||||
perf["entry_unit_load_count"].to_u64() == 1 && perf["entry_unit_materialize_us"].to_u64() > 0 && perf["dynamic_include_load_count"].to_u64() > 0 && perf["dynamic_include_materialize_us"].to_u64() > 0 && unit_operations.find("\"kind\": \"entry\"") != String::npos && unit_operations.find("\"kind\": \"component\"") != String::npos && unit_operations.find("\"materialize_us\"") != String::npos,
|
||||
perf["entry_unit_load_count"].to_u64() == 1 && perf["entry_unit_materialize_us"].to_u64() > 0 && perf["dynamic_include_load_count"].to_u64() > 0 && perf["dynamic_include_materialize_us"].to_u64() > 0 && perf["component_loaded_reuse_count"].to_u64() > 0 && unit_operations.find("\"kind\": \"entry\"") != String::npos && unit_operations.find("\"kind\": \"component\"") != String::npos && unit_operations.find("\"materialize_us\"") != String::npos,
|
||||
unit_operations
|
||||
);
|
||||
|
||||
|
||||
@ -181,11 +181,12 @@ RENDER(Request& context)
|
||||
u64 dropped_hostcall_operations = perf["hostcall_operations_dropped"].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 thread_runtime_profile_valid = perf["thread_runtime_profiled"].type == 'B' && (!perf["thread_runtime_profiled"].to_bool() || (perf["thread_cpu_start"].to_f64() >= 0 && perf["thread_cpu_end"].to_f64() >= 0 && perf["thread_cpu_migrated"].type == 'B' && perf["thread_user_cpu_us"].to_u64() + perf["thread_system_cpu_us"].to_u64() <= perf["workspace_wall_us"].to_u64() + 5 && perf["thread_voluntary_context_switches"].type != 'S' && perf["thread_involuntary_context_switches"].type != 'S' && perf["thread_minor_faults"].type != 'S' && perf["thread_major_faults"].type != 'S'));
|
||||
bool perf_stable = transport_profile_valid && workspace_cpu_profile_valid && unit_module_profile_valid && hostcall_operation_profile_valid && thread_runtime_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';
|
||||
bool perf_stable = transport_profile_valid && workspace_cpu_profile_valid && unit_module_profile_valid && hostcall_operation_profile_valid && thread_runtime_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_loaded_reuse_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();
|
||||
u64 profiled_hostcall_cpu_us = perf["hostcall_cpu_us"].to_u64();
|
||||
u64 profiled_components = perf["component_resolve_count"].to_u64();
|
||||
u64 profiled_component_loaded_reuses = perf["component_loaded_reuse_count"].to_u64();
|
||||
u64 profiled_component_path = perf["component_path_us"].to_u64();
|
||||
u64 profiled_component_artifact = perf["component_artifact_us"].to_u64();
|
||||
u64 profiled_component_load = perf["component_load_us"].to_u64();
|
||||
@ -203,7 +204,7 @@ RENDER(Request& context)
|
||||
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["hostcall_cpu_us"].to_u64() == profiled_hostcall_cpu_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_symbol_resolve_count"].to_u64() == profiled_unit_symbol_resolve_count && perf["unit_symbol_resolve_us"].to_u64() == profiled_unit_symbol_resolve && 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 && json_encode(perf["hostcall_operations"]) == profiled_hostcall_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["hostcall_cpu_us"].to_u64() == profiled_hostcall_cpu_us && perf["guest_us"].to_f64() > 0 && perf["component_resolve_count"].to_u64() == profiled_components && perf["component_loaded_reuse_count"].to_u64() == profiled_component_loaded_reuses && 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_symbol_resolve_count"].to_u64() == profiled_unit_symbol_resolve_count && perf["unit_symbol_resolve_us"].to_u64() == profiled_unit_symbol_resolve && 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 && json_encode(perf["hostcall_operations"]) == profiled_hostcall_operations;
|
||||
}
|
||||
check("request_perf() stages stable repeated snapshots", perf_stable, json_encode(perf));
|
||||
|
||||
|
||||
@ -221,6 +221,7 @@ String wasm_backend_serve(Request& request, const String& entry_unit, const Stri
|
||||
request.header["X-UCE-Wasm-Entry-Dispatch-Us"] = std::to_string(response.entry_dispatch_us);
|
||||
request.header["X-UCE-Wasm-Output-Collect-Us"] = std::to_string(response.output_collect_us);
|
||||
request.header["X-UCE-Wasm-Component-Resolve-Count"] = std::to_string(response.component_resolve_count);
|
||||
request.header["X-UCE-Wasm-Component-Loaded-Reuse-Count"] = std::to_string(response.component_loaded_reuse_count);
|
||||
request.header["X-UCE-Wasm-Component-Resolve-Total-Us"] = std::to_string(response.component_resolve_total_us);
|
||||
request.header["X-UCE-Wasm-Component-Resolve-Avg-Us"] = std::to_string(
|
||||
response.component_resolve_count ? response.component_resolve_total_us / response.component_resolve_count : 0);
|
||||
|
||||
@ -543,7 +543,8 @@ struct RequestPropsScope
|
||||
// probe that loads nothing). No per-mode kinds.
|
||||
static s32 wasm_resolve_target(String unit_target, String handler, String* resolved_out = 0)
|
||||
{
|
||||
String cache_key = handler + "\t" + unit_target;
|
||||
String current = context ? context->resources.current_unit_file : "";
|
||||
String cache_key = current + "\t" + handler + "\t" + unit_target;
|
||||
bool is_exists = (handler == "exists");
|
||||
auto cached = wasm_component_slots.find(cache_key);
|
||||
if(cached != wasm_component_slots.end() && !is_exists)
|
||||
@ -553,7 +554,6 @@ static s32 wasm_resolve_target(String unit_target, String handler, String* resol
|
||||
return(cached->second);
|
||||
}
|
||||
char resolved[512];
|
||||
String current = context ? context->resources.current_unit_file : "";
|
||||
s32 slot = uce_host_component_resolve(
|
||||
unit_target.data(), unit_target.size(), handler.data(), handler.size(),
|
||||
current.data(), current.size(),
|
||||
|
||||
@ -201,6 +201,7 @@ struct WasmRequestProfile
|
||||
u64 output_collect_us = 0;
|
||||
u64 workspace_complete_us = 0;
|
||||
u64 component_resolve_count = 0;
|
||||
u64 component_loaded_reuse_count = 0;
|
||||
u64 component_resolve_total_us = 0;
|
||||
u64 component_path_total_us = 0;
|
||||
u64 component_artifact_total_us = 0;
|
||||
@ -1732,6 +1733,7 @@ private:
|
||||
};
|
||||
std::vector<LoadedUnit> units;
|
||||
std::map<String, size_t> units_by_source;
|
||||
std::map<String, String> component_loaded_paths; // caller + target → request-loaded canonical source
|
||||
std::map<String, u32> handler_slots; // source + ":" + symbol → table slot
|
||||
bool stale_component_mutation_blocked = false;
|
||||
String stale_component_mutation_status;
|
||||
@ -2386,7 +2388,27 @@ private:
|
||||
return(0);
|
||||
}
|
||||
|
||||
String resolved = resolve_source_path(file_name, current_unit);
|
||||
String resolve_key = current_unit + "\t" + file_name;
|
||||
String resolved;
|
||||
String error;
|
||||
size_t unit_index = 0;
|
||||
bool loaded_reuse = false;
|
||||
auto loaded = units_by_source.find(file_name);
|
||||
if(loaded == units_by_source.end())
|
||||
{
|
||||
auto known_path = component_loaded_paths.find(resolve_key);
|
||||
if(known_path != component_loaded_paths.end())
|
||||
loaded = units_by_source.find(known_path->second);
|
||||
}
|
||||
if(loaded != units_by_source.end())
|
||||
{
|
||||
resolved = loaded->first;
|
||||
unit_index = loaded->second;
|
||||
loaded_reuse = true;
|
||||
component_loaded_reuse_count++;
|
||||
}
|
||||
else
|
||||
resolved = resolve_source_path(file_name, current_unit);
|
||||
component_path_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - probe_start).count();
|
||||
if(resolved == "")
|
||||
@ -2401,67 +2423,70 @@ private:
|
||||
return(1);
|
||||
}
|
||||
|
||||
auto artifact_start = std::chrono::steady_clock::now();
|
||||
bool artifact_exists = file_exists_host(worker.unit_wasm_path(resolved));
|
||||
bool can_serve_stale = compiler_request_can_serve_stale_artifact(context);
|
||||
String method = context ? to_upper(trim(context->params["REQUEST_METHOD"])) : String("");
|
||||
bool read_request = method == "GET" || method == "HEAD" || method == "OPTIONS";
|
||||
if(can_serve_stale && read_request && !component_source_generation_checked)
|
||||
if(!loaded_reuse)
|
||||
{
|
||||
component_source_generation = compiler_source_generation(context);
|
||||
component_source_generation_checked = true;
|
||||
}
|
||||
bool stale = false;
|
||||
if(artifact_exists)
|
||||
{
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto cached_freshness = worker.component_freshness.find(resolved);
|
||||
// HTTP reads may serve a complete stale artifact, so bound their graph
|
||||
// stat work; CLI and mutations always check the current graph.
|
||||
bool generation_available = component_source_generation != "";
|
||||
bool check_freshness = !can_serve_stale || !read_request ||
|
||||
cached_freshness == worker.component_freshness.end() ||
|
||||
(generation_available ?
|
||||
cached_freshness->second.source_generation != component_source_generation :
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now - cached_freshness->second.checked_at).count() >= 1000);
|
||||
if(check_freshness)
|
||||
auto artifact_start = std::chrono::steady_clock::now();
|
||||
bool artifact_exists = file_exists_host(worker.unit_wasm_path(resolved));
|
||||
bool can_serve_stale = compiler_request_can_serve_stale_artifact(context);
|
||||
String method = context ? to_upper(trim(context->params["REQUEST_METHOD"])) : String("");
|
||||
bool read_request = method == "GET" || method == "HEAD" || method == "OPTIONS";
|
||||
if(can_serve_stale && read_request && !component_source_generation_checked)
|
||||
{
|
||||
stale = compiler_unit_needs_recompile(context, resolved, 0, can_serve_stale && read_request, true);
|
||||
worker.component_freshness[resolved] = { now, stale, component_source_generation };
|
||||
component_source_generation = compiler_source_generation(context);
|
||||
component_source_generation_checked = true;
|
||||
}
|
||||
else
|
||||
stale = cached_freshness->second.stale;
|
||||
}
|
||||
if(stale && can_serve_stale)
|
||||
{
|
||||
compiler_prioritize_unit(context, resolved);
|
||||
if(!read_request)
|
||||
bool stale = false;
|
||||
if(artifact_exists)
|
||||
{
|
||||
stale_component_mutation_blocked = true;
|
||||
stale_component_mutation_status = context->params["GATEWAY_INTERFACE"] != "" ?
|
||||
"Status: 503 Service Unavailable" : "HTTP/1.1 503 Service Unavailable";
|
||||
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - artifact_start).count();
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
auto cached_freshness = worker.component_freshness.find(resolved);
|
||||
// HTTP reads may serve a complete stale artifact, so bound their graph
|
||||
// stat work; CLI and mutations always check the current graph.
|
||||
bool generation_available = component_source_generation != "";
|
||||
bool check_freshness = !can_serve_stale || !read_request ||
|
||||
cached_freshness == worker.component_freshness.end() ||
|
||||
(generation_available ?
|
||||
cached_freshness->second.source_generation != component_source_generation :
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
now - cached_freshness->second.checked_at).count() >= 1000);
|
||||
if(check_freshness)
|
||||
{
|
||||
stale = compiler_unit_needs_recompile(context, resolved, 0, can_serve_stale && read_request, true);
|
||||
worker.component_freshness[resolved] = { now, stale, component_source_generation };
|
||||
}
|
||||
else
|
||||
stale = cached_freshness->second.stale;
|
||||
}
|
||||
if(stale && can_serve_stale)
|
||||
{
|
||||
compiler_prioritize_unit(context, resolved);
|
||||
if(!read_request)
|
||||
{
|
||||
stale_component_mutation_blocked = true;
|
||||
stale_component_mutation_status = context->params["GATEWAY_INTERFACE"] != "" ?
|
||||
"Status: 503 Service Unavailable" : "HTTP/1.1 503 Service Unavailable";
|
||||
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - artifact_start).count();
|
||||
record_probe();
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if(!artifact_exists || (stale && !can_serve_stale))
|
||||
get_shared_unit(context, resolved);
|
||||
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - artifact_start).count();
|
||||
|
||||
auto load_start = std::chrono::steady_clock::now();
|
||||
error = load_unit(resolved, "component", unit_index);
|
||||
component_load_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - load_start).count();
|
||||
if(error != "")
|
||||
{
|
||||
fprintf(stderr, "[wasm] component load failed: %s\n", error.c_str());
|
||||
record_probe();
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if(!artifact_exists || (stale && !can_serve_stale))
|
||||
get_shared_unit(context, resolved);
|
||||
component_artifact_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - artifact_start).count();
|
||||
|
||||
auto load_start = std::chrono::steady_clock::now();
|
||||
size_t unit_index = 0;
|
||||
String error = load_unit(resolved, "component", unit_index);
|
||||
component_load_total_us += (u64)std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
std::chrono::steady_clock::now() - load_start).count();
|
||||
if(error != "")
|
||||
{
|
||||
fprintf(stderr, "[wasm] component load failed: %s\n", error.c_str());
|
||||
record_probe();
|
||||
return(0);
|
||||
component_loaded_paths[resolve_key] = resolved;
|
||||
}
|
||||
auto link_start = std::chrono::steady_clock::now();
|
||||
auto record_link = [&]() {
|
||||
@ -2723,6 +2748,7 @@ private:
|
||||
response["memcache_hostcall_count"] = (f64)self->memcache_hostcall_count;
|
||||
response["memcache_hostcall_us"] = (f64)self->memcache_hostcall_total_us;
|
||||
response["component_resolve_count"] = (f64)self->component_resolve_count;
|
||||
response["component_loaded_reuse_count"] = (f64)self->component_loaded_reuse_count;
|
||||
response["component_resolve_us"] = (f64)self->component_resolve_total_us;
|
||||
response["component_path_us"] = (f64)self->component_path_total_us;
|
||||
response["component_artifact_us"] = (f64)self->component_artifact_total_us;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user