@@ -401,6 +401,27 @@ var (
401401 append ([]string {"fairness_id" , "priority" , "outcome" , "inference_pool" }, modelLabels ... ),
402402 )
403403
404+ flowControlSLORequestQueueDuration = prometheus .NewHistogramVec (
405+ prometheus.HistogramOpts {
406+ Subsystem : inferenceExtension ,
407+ Name : "flow_control_slo_request_queue_duration_seconds" ,
408+ Help : metricsutil .HelpMsgWithStability ("Distribution of the total time requests spend in the EPP flow control layer, partitioned by SLO class." , compbasemetrics .ALPHA ),
409+ Buckets : []float64 {
410+ 0.0001 , 0.0005 , 0.001 , 0.005 , 0.01 , 0.025 , 0.05 , 0.1 , 0.25 , 0.5 , 1.0 , 2.5 , 5.0 , 10.0 , 30.0 , 60.0 ,
411+ },
412+ },
413+ []string {"slo_class" , "outcome" , "inference_pool" },
414+ )
415+
416+ flowControlSLOIncomingRequestsTotal = prometheus .NewCounterVec (
417+ prometheus.CounterOpts {
418+ Subsystem : inferenceExtension ,
419+ Name : "flow_control_slo_incoming_requests_total" ,
420+ Help : metricsutil .HelpMsgWithStability ("Total number of requests that entered the EPP flow control layer via EnqueueAndWait." , compbasemetrics .ALPHA ),
421+ },
422+ []string {"slo_class" , "inference_pool" },
423+ )
424+
404425 flowControlDispatchCycleDuration = prometheus .NewHistogramVec (
405426 prometheus.HistogramOpts {
406427 Subsystem : inferenceExtension ,
@@ -431,7 +452,7 @@ var (
431452 Name : "flow_control_queue_size" ,
432453 Help : metricsutil .HelpMsgWithStability ("Current number of requests actively held in the Flow Control queue." , compbasemetrics .ALPHA ),
433454 },
434- append ([]string {"fairness_id" , "priority" , "inference_pool" }, modelLabels ... ),
455+ append ([]string {"fairness_id" , "priority" , "inference_pool" , "slo_class" }, modelLabels ... ),
435456 )
436457
437458 flowControlQueueBytes = prometheus .NewGaugeVec (
@@ -440,7 +461,7 @@ var (
440461 Name : "flow_control_queue_bytes" ,
441462 Help : metricsutil .HelpMsgWithStability ("Current total size in bytes of requests actively held in the Flow Control queue." , compbasemetrics .ALPHA ),
442463 },
443- append ([]string {"fairness_id" , "priority" , "inference_pool" }, modelLabels ... ),
464+ append ([]string {"fairness_id" , "priority" , "inference_pool" , "slo_class" }, modelLabels ... ),
444465 )
445466
446467 flowControlPoolSaturation = prometheus .NewGaugeVec (
@@ -505,6 +526,8 @@ func Register(customCollectors ...prometheus.Collector) {
505526 metrics .Registry .MustRegister (prefixCacheHitRatio )
506527 metrics .Registry .MustRegister (prefixCacheHitLength )
507528 metrics .Registry .MustRegister (flowControlRequestQueueDuration )
529+ metrics .Registry .MustRegister (flowControlSLORequestQueueDuration )
530+ metrics .Registry .MustRegister (flowControlSLOIncomingRequestsTotal )
508531 metrics .Registry .MustRegister (flowControlDispatchCycleDuration )
509532 metrics .Registry .MustRegister (flowControlQueueSize )
510533 metrics .Registry .MustRegister (flowControlQueueBytes )
@@ -556,6 +579,8 @@ func Reset() {
556579 prefixCacheHitRatio .Reset ()
557580 prefixCacheHitLength .Reset ()
558581 flowControlRequestQueueDuration .Reset ()
582+ flowControlSLORequestQueueDuration .Reset ()
583+ flowControlSLOIncomingRequestsTotal .Reset ()
559584 flowControlQueueSize .Reset ()
560585 flowControlQueueBytes .Reset ()
561586 flowControlPoolSaturation .Reset ()
@@ -858,6 +883,59 @@ func RecordFlowControlRequestQueueDuration(
858883 ).Observe (duration .Seconds ())
859884}
860885
886+ // SLO class constants label for flow control SLO metrics (bounded buckets for the TTFT SLO header in ms).
887+ const (
888+ SLOClassNone = "none"
889+ SLOClassBelowMS200 = "below_ms_200"
890+ SLOClassMS200to399 = "ms_200_399"
891+ SLOClassMS400to599 = "ms_400_599"
892+ SLOClassMS600to799 = "ms_600_799"
893+ SLOClassMS800to1000 = "ms_800_1000"
894+ SLOClassAboveMS1000 = "above_ms_1000"
895+ )
896+
897+ // ClassifySLO maps a raw SLO header value (in milliseconds) to a bounded SLO class label.
898+ // Returns SLOClassNone when the header is absent or unparseable.
899+ func ClassifySLO (rawHeaderValue string ) string {
900+ if rawHeaderValue == "" {
901+ return SLOClassNone
902+ }
903+ ms , err := strconv .ParseInt (rawHeaderValue , 10 , 64 )
904+ if err != nil || ms < 0 {
905+ return SLOClassNone
906+ }
907+ switch {
908+ case ms < 200 :
909+ return SLOClassBelowMS200
910+ case ms < 400 :
911+ return SLOClassMS200to399
912+ case ms < 600 :
913+ return SLOClassMS400to599
914+ case ms < 800 :
915+ return SLOClassMS600to799
916+ case ms <= 1000 :
917+ return SLOClassMS800to1000
918+ default :
919+ return SLOClassAboveMS1000
920+ }
921+ }
922+
923+ // RecordFlowControlSLORequestQueueDuration records the queue duration for a request partitioned by its
924+ // SLO class (derived from the TTFT SLO header "x-slo-ttft-ms").
925+ func RecordFlowControlSLORequestQueueDuration (
926+ sloClass , outcome , inferencePool string ,
927+ duration time.Duration ,
928+ ) {
929+ flowControlSLORequestQueueDuration .WithLabelValues (
930+ sloClass , outcome , inferencePool ,
931+ ).Observe (duration .Seconds ())
932+ }
933+
934+ // RecordFlowControlSLOIncomingRequest increments the count of requests that entered flow control at EnqueueAndWait.
935+ func RecordFlowControlSLOIncomingRequest (sloClass , inferencePool string ) {
936+ flowControlSLOIncomingRequestsTotal .WithLabelValues (sloClass , inferencePool ).Inc ()
937+ }
938+
861939// RecordFlowControlDispatchCycleDuration records the duration of a dispatch cycle in the Flow Control layer.
862940func RecordFlowControlDispatchCycleDuration (duration time.Duration ) {
863941 flowControlDispatchCycleDuration .WithLabelValues ().Observe (duration .Seconds ())
@@ -874,23 +952,23 @@ func RecordFlowControlRequestEnqueueDuration(
874952}
875953
876954// IncFlowControlQueueSize increments the Flow Control queue size gauge.
877- func IncFlowControlQueueSize (fairnessID , priority , inferencePool , modelName , targetModelName string ) {
878- flowControlQueueSize .WithLabelValues (fairnessID , priority , inferencePool , modelName , targetModelName ).Inc ()
955+ func IncFlowControlQueueSize (fairnessID , priority , inferencePool , sloClass , modelName , targetModelName string ) {
956+ flowControlQueueSize .WithLabelValues (fairnessID , priority , inferencePool , sloClass , modelName , targetModelName ).Inc ()
879957}
880958
881959// DecFlowControlQueueSize decrements the Flow Control queue size gauge.
882- func DecFlowControlQueueSize (fairnessID , priority , inferencePool , modelName , targetModelName string ) {
883- flowControlQueueSize .WithLabelValues (fairnessID , priority , inferencePool , modelName , targetModelName ).Dec ()
960+ func DecFlowControlQueueSize (fairnessID , priority , inferencePool , sloClass , modelName , targetModelName string ) {
961+ flowControlQueueSize .WithLabelValues (fairnessID , priority , inferencePool , sloClass , modelName , targetModelName ).Dec ()
884962}
885963
886964// AddFlowControlQueueBytes increments the Flow Control queue bytes gauge.
887- func AddFlowControlQueueBytes (fairnessID , priority , inferencePool , modelName , targetModelName string , bytes uint64 ) {
888- flowControlQueueBytes .WithLabelValues (fairnessID , priority , inferencePool , modelName , targetModelName ).Add (float64 (bytes ))
965+ func AddFlowControlQueueBytes (fairnessID , priority , inferencePool , sloClass , modelName , targetModelName string , bytes uint64 ) {
966+ flowControlQueueBytes .WithLabelValues (fairnessID , priority , inferencePool , sloClass , modelName , targetModelName ).Add (float64 (bytes ))
889967}
890968
891969// SubFlowControlQueueBytes decrements the Flow Control queue bytes gauge.
892- func SubFlowControlQueueBytes (fairnessID , priority , inferencePool , modelName , targetModelName string , bytes uint64 ) {
893- flowControlQueueBytes .WithLabelValues (fairnessID , priority , inferencePool , modelName , targetModelName ).Sub (float64 (bytes ))
970+ func SubFlowControlQueueBytes (fairnessID , priority , inferencePool , sloClass , modelName , targetModelName string , bytes uint64 ) {
971+ flowControlQueueBytes .WithLabelValues (fairnessID , priority , inferencePool , sloClass , modelName , targetModelName ).Sub (float64 (bytes ))
894972}
895973
896974// RecordFlowControlPoolSaturation records the current saturation level for an inference pool.
0 commit comments