Add weaseldb_metrics_memory_bytes

This commit is contained in:
2025-09-03 13:06:34 -04:00
parent 0ac4c31a53
commit f067f4e85b

View File

@@ -425,10 +425,22 @@ struct Metric {
return *internedStaticText; return *internedStaticText;
} }
// Registry of all thread arenas for memory tracking
static auto &get_thread_arenas() {
using ThreadArenaMap =
std::unordered_map<std::thread::id, ArenaAllocator *>;
static ThreadArenaMap *threadArenas = new ThreadArenaMap();
return *threadArenas;
}
// Thread cleanup for per-family thread-local storage // Thread cleanup for per-family thread-local storage
struct ThreadInit { struct ThreadInit {
ArenaAllocator arena; ArenaAllocator arena;
ThreadInit() {} ThreadInit() {
// Register this thread's arena for memory tracking
std::unique_lock<std::mutex> _{mutex};
get_thread_arenas()[std::this_thread::get_id()] = &arena;
}
~ThreadInit() { ~ThreadInit() {
// Accumulate thread-local state into global state before cleanup // Accumulate thread-local state into global state before cleanup
// THREAD SAFETY: All operations below are protected by the global mutex, // THREAD SAFETY: All operations below are protected by the global mutex,
@@ -442,6 +454,9 @@ struct Metric {
++Metric::registration_version; ++Metric::registration_version;
auto thread_id = std::this_thread::get_id(); auto thread_id = std::this_thread::get_id();
// Unregister this thread's arena from memory tracking
get_thread_arenas().erase(thread_id);
// Accumulate counter families // Accumulate counter families
for (auto &[name, family] : Metric::get_counter_families()) { for (auto &[name, family] : Metric::get_counter_families()) {
auto thread_it = family->per_thread_state.find(thread_id); auto thread_it = family->per_thread_state.find(thread_id);
@@ -1609,8 +1624,38 @@ union MetricValue {
uint64_t as_uint64; uint64_t as_uint64;
}; };
// Memory usage calculation callback for metrics system self-monitoring
static double calculate_metrics_memory_usage() {
std::size_t total_bytes = 0;
// 1. Global arena memory
total_bytes += Metric::get_global_arena().total_allocated();
// 2. Per-thread arenas (safe because we're already holding the global mutex)
for (const auto &[thread_id, arena_ptr] : Metric::get_thread_arenas()) {
total_bytes += arena_ptr->total_allocated();
}
// 3. Cached plan arena
if (Metric::cached_plan) {
total_bytes += Metric::cached_plan->arena.total_allocated();
}
return static_cast<double>(total_bytes);
}
// New three-phase render implementation // New three-phase render implementation
std::span<std::string_view> render(ArenaAllocator &arena) { std::span<std::string_view> render(ArenaAllocator &arena) {
// Initialize self-monitoring metrics (before taking global lock)
static auto memory_gauge = []() {
auto gauge = create_gauge("weaseldb_metrics_memory_bytes",
"Total memory usage of the metrics system "
"including global and per-thread arenas");
gauge.register_callback({}, calculate_metrics_memory_usage);
return gauge;
}();
(void)memory_gauge; // Suppress unused variable warning
// Hold lock throughout all phases to prevent registry changes // Hold lock throughout all phases to prevent registry changes
// THREAD SAFETY: Global mutex protects cached_plan initialization and access, // THREAD SAFETY: Global mutex protects cached_plan initialization and access,
// prevents races during static member initialization at program startup // prevents races during static member initialization at program startup