From d0f2b6550aee9fd7cf8fa5179cf17a3a15c80c61 Mon Sep 17 00:00:00 2001 From: Andrew Noyes Date: Thu, 28 Aug 2025 17:32:34 -0400 Subject: [PATCH] More scaffolding --- src/metric.cpp | 110 ++++++++++++++++++++++++++++++++++++++++++++----- src/metric.hpp | 3 +- 2 files changed, 100 insertions(+), 13 deletions(-) diff --git a/src/metric.cpp b/src/metric.cpp index 4fa03ad..1977ff3 100644 --- a/src/metric.cpp +++ b/src/metric.cpp @@ -1,9 +1,15 @@ #include "metric.hpp" + +#include +#include +#include #include #include #include +#include #include #include + namespace metric { struct MetricKey { std::string_view name; @@ -33,9 +39,24 @@ template <> struct hash { namespace metric { -struct Counter::State {}; -struct Gauge::State {}; -struct Histogram::State {}; +using AtomicWord = std::atomic; + +struct Counter::State { + AtomicWord value; +}; + +struct Gauge::State { + std::mutex mutex; + double value; +}; + +struct Histogram::State { + std::vector thresholds; + std::vector counts; + AtomicWord sum; + AtomicWord observations; +}; + struct Metric { static std::mutex mutex; @@ -47,6 +68,8 @@ struct Metric { static std::unordered_map perThreadState; + static std::unordered_map gauges; + struct ThreadInit { ThreadInit() { std::unique_lock _{mutex}; @@ -58,23 +81,88 @@ struct Metric { } }; static thread_local ThreadInit thread_init; + + static Counter + create_counter(std::string_view name, + std::vector> labels) { + std::unique_lock _{mutex}; + Counter result; + result.p = &perThreadState[std::this_thread::get_id()] + .counters[MetricKey{name, labels}]; + return result; + } + + static Gauge + create_gauge(std::string_view name, + std::vector> labels) { + std::unique_lock _{mutex}; + Gauge result; + result.p = &gauges[MetricKey{name, labels}]; + return result; + } + + static Histogram + create_histogram(std::string_view name, + std::vector> labels) { + std::unique_lock _{mutex}; + Histogram result; + result.p = &perThreadState[std::this_thread::get_id()] + .histograms[MetricKey{name, labels}]; + return result; + } }; -void Counter::inc(double x) {} -void Gauge::inc(double x) {} -void Gauge::dec(double x) {} -void Gauge::set(double x) {} -void Histogram::observe(double x) {} +template U reinterpret(V v) { + static_assert(sizeof(U) == sizeof(V)); + static_assert(std::is_arithmetic_v); + static_assert(std::is_arithmetic_v); + U u; + memcpy(&u, &v, sizeof(u)); + return u; +} + +void Counter::inc(double x) { + assert(x >= 0); + p->value.fetch_add(x, std::memory_order_relaxed); +} +void Gauge::inc(double x) { + std::unique_lock _{p->mutex}; + p->value += x; +} +void Gauge::dec(double x) { + std::unique_lock _{p->mutex}; + p->value -= x; +} +void Gauge::set(double x) { + std::unique_lock _{p->mutex}; + p->value = x; +} +void Histogram::observe(double x) { + assert(p->thresholds.size() == p->counts.size()); + for (size_t i = 0; i < p->thresholds.size(); ++i) { + p->counts[i].fetch_add(x <= p->thresholds[i], std::memory_order_relaxed); + } + auto sum = reinterpret(p->sum.load(std::memory_order_relaxed)); + sum += x; + p->sum.store(reinterpretsum.load())>(sum)); + p->observations.fetch_add(1, std::memory_order_relaxed); +} template <> Counter Family::create( - std::initializer_list>) {} + std::vector> labels) { + return Metric::create_counter(name, labels); +} template <> Gauge Family::create( - std::initializer_list>) {} + std::vector> labels) { + return Metric::create_gauge(name, labels); +} template <> Histogram Family::create( - std::initializer_list>) {} + std::vector> labels) { + return Metric::create_histogram(name, labels); +} Family create_counter(std::string_view name, std::string_view help) {} Family create_gauge(std::string_view name, std::string_view help) {} diff --git a/src/metric.hpp b/src/metric.hpp index 3be5949..ee62dcd 100644 --- a/src/metric.hpp +++ b/src/metric.hpp @@ -45,8 +45,7 @@ private: template struct Family { static_assert(std::is_same_v || std::is_same_v || std::is_same_v); - T create( - std::initializer_list>); + T create(std::vector>); private: friend struct Metric;