Intern label sets
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <immintrin.h>
|
#include <immintrin.h>
|
||||||
@@ -81,6 +82,7 @@ static std::string_view arena_copy_string(std::string_view str,
|
|||||||
struct LabelsKey {
|
struct LabelsKey {
|
||||||
ArenaVector<std::pair<std::string_view, std::string_view>> labels;
|
ArenaVector<std::pair<std::string_view, std::string_view>> labels;
|
||||||
|
|
||||||
|
// Arena-owning constructor (copies strings into arena)
|
||||||
LabelsKey(std::span<const std::pair<std::string_view, std::string_view>> l,
|
LabelsKey(std::span<const std::pair<std::string_view, std::string_view>> l,
|
||||||
ArenaAllocator &arena)
|
ArenaAllocator &arena)
|
||||||
: labels(&arena) {
|
: labels(&arena) {
|
||||||
@@ -302,6 +304,16 @@ struct Metric {
|
|||||||
return *histogramFamilies;
|
return *histogramFamilies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Global label interning set to avoid duplicate LabelsKey allocations
|
||||||
|
static auto &get_interned_labels() {
|
||||||
|
using InternSet = std::unordered_set<LabelsKey, std::hash<LabelsKey>,
|
||||||
|
std::equal_to<LabelsKey>,
|
||||||
|
ArenaStlAllocator<LabelsKey>>;
|
||||||
|
static InternSet *internedLabels =
|
||||||
|
new InternSet(ArenaStlAllocator<LabelsKey>(&get_global_arena()));
|
||||||
|
return *internedLabels;
|
||||||
|
}
|
||||||
|
|
||||||
// Thread cleanup for per-family thread-local storage
|
// Thread cleanup for per-family thread-local storage
|
||||||
struct ThreadInit {
|
struct ThreadInit {
|
||||||
ArenaAllocator arena;
|
ArenaAllocator arena;
|
||||||
@@ -379,6 +391,27 @@ struct Metric {
|
|||||||
|
|
||||||
// Thread cleanup now handled by ThreadInit RAII
|
// Thread cleanup now handled by ThreadInit RAII
|
||||||
|
|
||||||
|
// Intern labels to avoid duplicate arena allocations
|
||||||
|
static const LabelsKey &intern_labels(
|
||||||
|
std::span<const std::pair<std::string_view, std::string_view>> labels) {
|
||||||
|
auto &interned_set = get_interned_labels();
|
||||||
|
|
||||||
|
// Create temporary lookup key using stack-allocated arena
|
||||||
|
ArenaAllocator lookup_arena(1024); // Small arena for lookups
|
||||||
|
LabelsKey lookup_key{labels, lookup_arena};
|
||||||
|
|
||||||
|
// Use standard hash set lookup
|
||||||
|
auto it = interned_set.find(lookup_key);
|
||||||
|
if (it != interned_set.end()) {
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not found - create and intern new key
|
||||||
|
LabelsKey new_key{labels, get_global_arena()};
|
||||||
|
auto result = interned_set.emplace(std::move(new_key));
|
||||||
|
return *result.first;
|
||||||
|
}
|
||||||
|
|
||||||
static Counter create_counter_instance(
|
static Counter create_counter_instance(
|
||||||
Family<Counter> *family,
|
Family<Counter> *family,
|
||||||
std::span<const std::pair<std::string_view, std::string_view>> labels) {
|
std::span<const std::pair<std::string_view, std::string_view>> labels) {
|
||||||
@@ -386,7 +419,7 @@ struct Metric {
|
|||||||
(void)thread_init;
|
(void)thread_init;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> _{mutex};
|
std::unique_lock<std::mutex> _{mutex};
|
||||||
LabelsKey key{labels, get_global_arena()};
|
const LabelsKey &key = intern_labels(labels);
|
||||||
|
|
||||||
// Validate that labels aren't already registered as callback
|
// Validate that labels aren't already registered as callback
|
||||||
validate_or_abort(family->p->callbacks.find(key) ==
|
validate_or_abort(family->p->callbacks.find(key) ==
|
||||||
@@ -419,7 +452,7 @@ struct Metric {
|
|||||||
Family<Gauge> *family,
|
Family<Gauge> *family,
|
||||||
std::span<const std::pair<std::string_view, std::string_view>> labels) {
|
std::span<const std::pair<std::string_view, std::string_view>> labels) {
|
||||||
std::unique_lock<std::mutex> _{mutex};
|
std::unique_lock<std::mutex> _{mutex};
|
||||||
LabelsKey key{labels, get_global_arena()};
|
const LabelsKey &key = intern_labels(labels);
|
||||||
|
|
||||||
// Validate that labels aren't already registered as callback
|
// Validate that labels aren't already registered as callback
|
||||||
validate_or_abort(family->p->callbacks.find(key) ==
|
validate_or_abort(family->p->callbacks.find(key) ==
|
||||||
@@ -444,7 +477,7 @@ struct Metric {
|
|||||||
(void)thread_init;
|
(void)thread_init;
|
||||||
|
|
||||||
std::unique_lock<std::mutex> _{mutex};
|
std::unique_lock<std::mutex> _{mutex};
|
||||||
LabelsKey key{labels, get_global_arena()};
|
const LabelsKey &key = intern_labels(labels);
|
||||||
|
|
||||||
// Ensure thread state exists
|
// Ensure thread state exists
|
||||||
auto thread_id = std::this_thread::get_id();
|
auto thread_id = std::this_thread::get_id();
|
||||||
@@ -1163,7 +1196,7 @@ void Family<Counter>::register_callback(
|
|||||||
std::span<const std::pair<std::string_view, std::string_view>> labels,
|
std::span<const std::pair<std::string_view, std::string_view>> labels,
|
||||||
MetricCallback<Counter> callback) {
|
MetricCallback<Counter> callback) {
|
||||||
std::unique_lock<std::mutex> _{Metric::mutex};
|
std::unique_lock<std::mutex> _{Metric::mutex};
|
||||||
LabelsKey key{labels, Metric::get_global_arena()};
|
const LabelsKey &key = Metric::intern_labels(labels);
|
||||||
|
|
||||||
// Validate that labels aren't already in use by create() calls
|
// Validate that labels aren't already in use by create() calls
|
||||||
for (const auto &[thread_id, per_thread] : p->per_thread_state) {
|
for (const auto &[thread_id, per_thread] : p->per_thread_state) {
|
||||||
@@ -1186,7 +1219,7 @@ void Family<Gauge>::register_callback(
|
|||||||
std::span<const std::pair<std::string_view, std::string_view>> labels,
|
std::span<const std::pair<std::string_view, std::string_view>> labels,
|
||||||
MetricCallback<Gauge> callback) {
|
MetricCallback<Gauge> callback) {
|
||||||
std::unique_lock<std::mutex> _{Metric::mutex};
|
std::unique_lock<std::mutex> _{Metric::mutex};
|
||||||
LabelsKey key{labels, Metric::get_global_arena()};
|
const LabelsKey &key = Metric::intern_labels(labels);
|
||||||
|
|
||||||
// Validate that labels aren't already in use by create() calls
|
// Validate that labels aren't already in use by create() calls
|
||||||
validate_or_abort(p->instances.find(key) == p->instances.end(),
|
validate_or_abort(p->instances.find(key) == p->instances.end(),
|
||||||
|
|||||||
Reference in New Issue
Block a user