From 1a5f0c94452143cbaeb2d30dbfc0dc873990465d Mon Sep 17 00:00:00 2001 From: Nate Armstrong Date: Mon, 19 Oct 2026 16:17:12 -0700 Subject: [PATCH] perf(gateway): store each prometheus label set once and share it across metrics (#47427) Every metric family kept its own copy of a series' label strings, so a key x deployment combination cost about 9 KB across the ~20 families. Families now hold a shared, reference-counted label set. /metrics output is unchanged. Claude-Session: https://claude.ai/code/session_0138knkqKpkoSr6PApenZan5 Co-authored-by: Claude --- litellm-rust/crates/gateway/src/prometheus.rs | 129 +++++++++++++++--- 1 file changed, 110 insertions(+), 19 deletions(-) diff --git a/litellm-rust/crates/gateway/src/prometheus.rs b/litellm-rust/crates/gateway/src/prometheus.rs index 28cf7ef0dcd..b34caadb994 100644 --- a/litellm-rust/crates/gateway/src/prometheus.rs +++ b/litellm-rust/crates/gateway/src/prometheus.rs @@ -3,14 +3,15 @@ //! //! It is an observer, so nothing here runs on the request path. Each finished request updates a //! few series per metric: the label values are hashed without allocating, and a series is created -//! once, the first time its label values are seen. The text is built only when Prometheus scrapes. +//! once, the first time its label values are seen. Each combination of label values is stored once +//! and shared by every metric's series that has it. The text is built only when Prometheus scrapes. use std::{ collections::{HashMap, HashSet}, fmt::Write as _, hash::{BuildHasher, Hash, Hasher, RandomState}, sync::{ - RwLock, + Arc, RwLock, atomic::{AtomicU64, Ordering}, }, time::SystemTime, @@ -66,6 +67,9 @@ enum Label { use Label::*; +/// How many labels there are, to index a [`LabelSet`] by label. +const LABEL_COUNT: usize = ServiceTier as usize + 1; + const LLM_API_LATENCY: &[Label] = &[ ModelGroup, Model, @@ -390,8 +394,64 @@ struct GroupConfig { include_labels: Option>, } +/// One combination of label values, indexed by label, shared by the series of every family +/// that has these values. Labels no enabled family emits stay `None`. +type LabelSet = Arc<[Option>]>; + /// The series that share a hash of their label values, each with those values. -type Bucket = Vec<(Box<[Option>]>, Box)>; +type Bucket = Vec<(LabelSet, Box)>; + +/// The label value combinations seen so far, so that each is stored once however many families +/// have a series for it. +struct LabelSets { + /// The labels any enabled family emits; the others don't tell sets apart. + labels: Box<[Label]>, + sets: RwLock>>, +} + +impl LabelSets { + fn new(labels: Vec