Memoize read-only source graph stats

This commit is contained in:
udo 2026-07-17 22:00:37 +00:00
parent 7e0b8337ab
commit 9beec0dd03
3 changed files with 29 additions and 14 deletions

View File

@ -3,6 +3,7 @@
#include "hash.h"
#include <algorithm>
#include <cerrno>
#include <chrono>
#include <cstdlib>
#include <cctype>
#include <cstring>
@ -50,6 +51,7 @@ struct SharedUnitCompileCheck
struct UnitSourceSignatureEntry
{
std::chrono::steady_clock::time_point checked_at;
u64 modified_ns = 0;
u64 changed_ns = 0;
u64 size = 0;
@ -144,12 +146,22 @@ bool compiler_source_readable(String file_name, const struct stat& info, int* re
return(error == 0);
}
UnitSourceSignatureEntry compiler_unit_source_entry(String file_name)
UnitSourceSignatureEntry compiler_unit_source_entry(String file_name, bool allow_recent_stat)
{
auto checked_at = std::chrono::steady_clock::now();
if(allow_recent_stat)
{
std::lock_guard<std::mutex> lock(unit_source_signature_cache_mutex);
auto cached = unit_source_signature_cache.find(file_name);
if(cached != unit_source_signature_cache.end() &&
std::chrono::duration_cast<std::chrono::milliseconds>(checked_at - cached->second.checked_at).count() < 1000)
return(cached->second);
}
struct stat info;
UnitSourceSignatureEntry entry;
if(stat(file_name.c_str(), &info) != 0)
return(entry);
entry.checked_at = checked_at;
entry.modified_ns = (u64)info.st_mtim.tv_sec * 1000000000ull + (u64)info.st_mtim.tv_nsec;
entry.changed_ns = (u64)info.st_ctim.tv_sec * 1000000000ull + (u64)info.st_ctim.tv_nsec;
entry.size = (u64)info.st_size;
@ -158,7 +170,10 @@ UnitSourceSignatureEntry compiler_unit_source_entry(String file_name)
std::lock_guard<std::mutex> lock(unit_source_signature_cache_mutex);
auto cached = unit_source_signature_cache.find(file_name);
if(cached != unit_source_signature_cache.end() && cached->second.modified_ns == entry.modified_ns && cached->second.changed_ns == entry.changed_ns && cached->second.size == entry.size && cached->second.readable == entry.readable)
{
cached->second.checked_at = checked_at;
return(cached->second);
}
}
String content = file_get_contents(file_name);
entry.content_hash = gen_sha1(content);
@ -172,7 +187,7 @@ UnitSourceSignatureEntry compiler_unit_source_entry(String file_name)
return(entry);
}
void compiler_append_unit_source_signature(String file_name, std::set<String>& visited, String& signature)
void compiler_append_unit_source_signature(String file_name, std::set<String>& visited, String& signature, bool allow_recent_stat)
{
String normalized = path_real(file_name);
if(normalized == "")
@ -181,28 +196,28 @@ void compiler_append_unit_source_signature(String file_name, std::set<String>& v
return;
visited.insert(normalized);
UnitSourceSignatureEntry entry = compiler_unit_source_entry(normalized);
UnitSourceSignatureEntry entry = compiler_unit_source_entry(normalized, allow_recent_stat);
signature += normalized + ":" + entry.content_hash + (entry.readable ? String("") : String(":unreadable")) + "\n";
for(String loaded : entry.loaded_paths)
compiler_append_unit_source_signature(loaded, visited, signature);
compiler_append_unit_source_signature(loaded, visited, signature, allow_recent_stat);
}
String compiler_unit_source_signature(String file_name)
String compiler_unit_source_signature(String file_name, bool allow_recent_stat = false)
{
std::set<String> visited;
String signature = "uce-load-graph-v1\n";
compiler_append_unit_source_signature(file_name, visited, signature);
compiler_append_unit_source_signature(file_name, visited, signature, allow_recent_stat);
return(gen_sha1(signature));
}
String compiler_unit_input_signature(Request* context, SharedUnit* su)
String compiler_unit_input_signature(Request* context, SharedUnit* su, bool allow_recent_source_stat = false)
{
if(!context || !su || !file_exists(su->file_name))
return("");
String setup_template = context->server->config["COMPILER_SYS_PATH"] + "/" + context->server->config["SETUP_TEMPLATE"];
return(
compiler_unit_source_signature(su->file_name) + ":" +
compiler_unit_source_signature(su->file_name, allow_recent_source_stat) + ":" +
gen_sha1(file_get_contents(setup_template)) + ":" +
std::to_string(UCE_UNIT_ABI_VERSION)
);
@ -452,7 +467,7 @@ bool compiler_has_known_unit_cached(Request* context, String file_name)
}));
}
SharedUnitFilesystemState inspect_shared_unit_filesystem(Request* context, SharedUnit* su)
SharedUnitFilesystemState inspect_shared_unit_filesystem(Request* context, SharedUnit* su, bool allow_recent_source_stat = false)
{
SharedUnitFilesystemState state;
state.source_exists = file_exists(su->file_name);
@ -465,7 +480,7 @@ SharedUnitFilesystemState inspect_shared_unit_filesystem(Request* context, Share
state.compiler_abi_time = compiler_runtime_abi_time(context);
state.metadata_time = file_mtime(su->meta_file_name);
state.compile_output_time = file_mtime(su->compile_output_file_name);
state.current_input_signature = compiler_unit_input_signature(context, su);
state.current_input_signature = compiler_unit_input_signature(context, su, allow_recent_source_stat);
state.metadata_exists = (state.metadata_time != 0);
state.compile_output_exists = (state.compile_output_time != 0);
if(state.metadata_exists)
@ -1301,12 +1316,12 @@ void compiler_untrack_known_unit(Request* context, String file_name)
});
}
bool compiler_unit_needs_recompile(Request* context, String file_name, bool* source_missing)
bool compiler_unit_needs_recompile(Request* context, String file_name, bool* source_missing, bool allow_recent_source_stat)
{
file_name = compiler_normalize_unit_path(context, file_name);
SharedUnit su;
setup_unit_paths(context, &su, file_name);
auto state = inspect_shared_unit_filesystem(context, &su);
auto state = inspect_shared_unit_filesystem(context, &su, allow_recent_source_stat);
auto compile_check = shared_unit_compile_check(state);
if(source_missing)
*source_missing = compile_check.source_missing;

View File

@ -27,7 +27,7 @@ StringList compiler_list_known_units(Request* context);
void compiler_set_known_units(Request* context, StringList files);
void compiler_track_known_unit(Request* context, String file_name);
void compiler_untrack_known_unit(Request* context, String file_name);
bool compiler_unit_needs_recompile(Request* context, String file_name, bool* source_missing = 0);
bool compiler_unit_needs_recompile(Request* context, String file_name, bool* source_missing = 0, bool allow_recent_source_stat = false);
DValue unit_info(String path = "");
StringList units_list();
bool unit_compile(String path = "");

View File

@ -2210,7 +2210,7 @@ private:
now - cached_freshness->second.checked_at).count() >= 1000;
if(check_freshness)
{
stale = compiler_unit_needs_recompile(context, resolved, 0);
stale = compiler_unit_needs_recompile(context, resolved, 0, can_serve_stale && read_request);
worker.component_freshness[resolved] = { now, stale };
}
else