From 0ac4c31a53f8927fe1dd6e806c4bbd522fbf83af Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Wed, 3 Sep 2025 12:51:49 -0400 Subject: [PATCH] Measure per metric in render scale bench --- benchmarks/bench_metric.cpp | 64 +++++++++++++------------------------ src/metric.cpp | 38 ++++++++++------------ 2 files changed, 40 insertions(+), 62 deletions(-) diff --git a/benchmarks/bench_metric.cpp b/benchmarks/bench_metric.cpp index 6645076..e802d6a 100644 --- a/benchmarks/bench_metric.cpp +++ b/benchmarks/bench_metric.cpp @@ -156,54 +156,30 @@ int main() { [&]() { histogram.observe(2.0); }); } - // Callback metrics performance - { - auto counter_family = - metric::create_counter("callback_counter", "Callback counter"); - auto gauge_family = - metric::create_gauge("callback_gauge", "Callback gauge"); - - std::atomic counter_value{0}; - std::atomic gauge_value{100}; - - // Register callbacks - counter_family.register_callback( - {{"type", "callback"}}, [&counter_value]() { - return counter_value.load(std::memory_order_relaxed); - }); - - gauge_family.register_callback({{"type", "callback"}}, [&gauge_value]() { - return gauge_value.load(std::memory_order_relaxed); - }); - - ArenaAllocator arena; - - bench.run("render() - with callback metrics", [&]() { - auto output = metric::render(arena); - ankerl::nanobench::doNotOptimizeAway(output); - arena.reset(); - }); - } - // Render performance scaling { bench.unit("metric"); + bench.title("render performance"); // Test render performance as number of metrics increases - std::vector counters; - std::vector gauges; - std::vector histograms; - - auto counter_family = - metric::create_counter("scale_counter", "Scale counter"); - auto gauge_family = metric::create_gauge("scale_gauge", "Scale gauge"); - auto histogram_family = metric::create_histogram( - "scale_histogram", "Scale histogram", - std::initializer_list{0.1, 0.5, 1.0, 2.5, 5.0, 10.0, 25.0, - 50.0}); // Create varying numbers of metrics for (int scale : {10, 100, 1000}) { - bench.batch(scale); + metric::reset_metrics_for_testing(); + std::vector counters; + std::vector gauges; + std::vector histograms; + + auto counter_family = + metric::create_counter("scale_counter", "Scale counter"); + auto gauge_family = metric::create_gauge("scale_gauge", "Scale gauge"); + auto buckets = std::initializer_list{0.1, 0.5, 1.0, 2.5, + 5.0, 10.0, 25.0, 50.0}; + auto histogram_family = metric::create_histogram( + "scale_histogram", "Scale histogram", buckets); + + std::atomic counter_value{3.1415924654}; + bench.batch(scale * (/*counter*/ 1 + /*gauge*/ 1 + /*callback*/ 1 + + /*histogram*/ (buckets.size() * 2 + 2))); // Clear previous metrics by creating new families // (Note: In real usage, metrics persist for application lifetime) for (int i = 0; i < scale; ++i) { @@ -217,6 +193,12 @@ int main() { counters.back().inc(static_cast(i)); gauges.back().set(static_cast(i * 2)); histograms.back().observe(static_cast(i) * 0.1); + // Register callbacks + counter_family.register_callback( + {{"type", "callback"}, {"id", std::to_string(i)}}, + [&counter_value]() { + return counter_value.load(std::memory_order_relaxed); + }); } ArenaAllocator arena; diff --git a/src/metric.cpp b/src/metric.cpp index 5be150e..9aa8c6f 100644 --- a/src/metric.cpp +++ b/src/metric.cpp @@ -1695,30 +1695,26 @@ void reset_metrics_for_testing() { std::lock_guard _{Metric::mutex}; ++Metric::registration_version; - // WARNING: This function assumes no metric objects are in use! - // Clear all family maps - this will leak the Family::State objects but - // that's acceptable for testing since they were allocated in the global arena + Metric::get_counter_families().clear(); + Metric::get_gauge_families().clear(); + Metric::get_histogram_families().clear(); + Metric::get_interned_labels().clear(); + Metric::get_interned_static_text().clear(); - // Get references to the maps - auto &counter_families = Metric::get_counter_families(); - auto &gauge_families = Metric::get_gauge_families(); - auto &histogram_families = Metric::get_histogram_families(); - auto &interned_labels = Metric::get_interned_labels(); - - // Clear all family registrations - counter_families.clear(); - gauge_families.clear(); - histogram_families.clear(); - interned_labels.clear(); - - // Clear interned static text - auto &interned_static_text = Metric::get_interned_static_text(); - interned_static_text.clear(); - - // Reset the global arena - this will invalidate all arena-allocated strings - // but since we're clearing everything, that's OK Metric::get_global_arena().reset(); + auto reset_arena = [](auto &m) { + using M = std::decay_t; + using A = M::allocator_type; + m = M{A{&Metric::get_global_arena()}}; + }; + + reset_arena(Metric::get_counter_families()); + reset_arena(Metric::get_gauge_families()); + reset_arena(Metric::get_histogram_families()); + reset_arena(Metric::get_interned_labels()); + reset_arena(Metric::get_interned_static_text()); + // Note: Thread-local arenas will be cleaned up by ThreadInit destructors // when threads exit naturally }