Skip to content

Commit e9409a4

Browse files
committed
move SLO range definition to InferenceObjective
Signed-off-by: Loic Marchal <lmarchal@redhat.com>
1 parent cb32d24 commit e9409a4

13 files changed

Lines changed: 303 additions & 85 deletions

File tree

apix/v1alpha2/inferenceobjective_types.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,47 @@ type InferenceObjectiveSpec struct {
7676
//
7777
// +kubebuilder:validation:Required
7878
PoolRef PoolObjectReference `json:"poolRef"`
79+
80+
// SLO defines the expected Service Level Objective ranges for requests targeting this objective.
81+
// When set, the InferenceObjective name is used as the SLO class label in metrics.
82+
// The ranges define the expected bounds for SLO header values (e.g. x-slo-ttft-ms),
83+
// enabling mismatch detection between a request's SLO deadline and its declared objective.
84+
//
85+
// +optional
86+
SLO *SLOSpec `json:"slo,omitempty"`
87+
}
88+
89+
// SLOSpec defines the expected SLO ranges for this objective.
90+
type SLOSpec struct {
91+
// TTFT defines the expected Time To First Token SLO range in milliseconds.
92+
// The range bounds correspond to values expected in the x-slo-ttft-ms request header.
93+
//
94+
// +optional
95+
TTFT *SLORangeMs `json:"ttft,omitempty"`
96+
97+
// TPOT defines the expected Time Per Output Token SLO range in milliseconds.
98+
// The range bounds correspond to values expected in the x-slo-tpot-ms request header.
99+
//
100+
// +optional
101+
TPOT *SLORangeMs `json:"tpot,omitempty"`
102+
}
103+
104+
// SLORangeMs defines a millisecond range for an SLO metric.
105+
// MinMs is inclusive, MaxMs is exclusive: [MinMs, MaxMs).
106+
// Omitting MinMs implies 0 (no lower bound).
107+
// Omitting MaxMs implies no upper bound.
108+
type SLORangeMs struct {
109+
// MinMs is the inclusive lower bound of the SLO range in milliseconds.
110+
//
111+
// +optional
112+
// +kubebuilder:validation:Minimum=0
113+
MinMs *int64 `json:"minMs,omitempty"`
114+
115+
// MaxMs is the exclusive upper bound of the SLO range in milliseconds.
116+
//
117+
// +optional
118+
// +kubebuilder:validation:Minimum=0
119+
MaxMs *int64 `json:"maxMs,omitempty"`
79120
}
80121

81122
// InferenceObjectiveStatus defines the observed state of InferenceObjective

apix/v1alpha2/zz_generated.deepcopy.go

Lines changed: 55 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client-go/applyconfiguration/apix/v1alpha2/inferenceobjectivespec.go

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client-go/applyconfiguration/apix/v1alpha2/slorangems.go

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client-go/applyconfiguration/apix/v1alpha2/slospec.go

Lines changed: 38 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client-go/applyconfiguration/utils.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/llm-d.ai_inferenceobjectives.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,50 @@ spec:
9999
Similarly requests with a Priority of -10 will always be served after requests with Priority of 0.
100100
format: int32
101101
type: integer
102+
slo:
103+
description: |-
104+
SLO defines the expected Service Level Objective ranges for requests targeting this objective.
105+
When set, the InferenceObjective name is used as the SLO class label in metrics.
106+
The ranges define the expected bounds for SLO header values (e.g. x-slo-ttft-ms),
107+
enabling mismatch detection between a request's SLO deadline and its declared objective.
108+
properties:
109+
tpot:
110+
description: |-
111+
TPOT defines the expected Time Per Output Token SLO range in milliseconds.
112+
The range bounds correspond to values expected in the x-slo-tpot-ms request header.
113+
properties:
114+
maxMs:
115+
description: MaxMs is the exclusive upper bound of the SLO
116+
range in milliseconds.
117+
format: int64
118+
minimum: 0
119+
type: integer
120+
minMs:
121+
description: MinMs is the inclusive lower bound of the SLO
122+
range in milliseconds.
123+
format: int64
124+
minimum: 0
125+
type: integer
126+
type: object
127+
ttft:
128+
description: |-
129+
TTFT defines the expected Time To First Token SLO range in milliseconds.
130+
The range bounds correspond to values expected in the x-slo-ttft-ms request header.
131+
properties:
132+
maxMs:
133+
description: MaxMs is the exclusive upper bound of the SLO
134+
range in milliseconds.
135+
format: int64
136+
minimum: 0
137+
type: integer
138+
minMs:
139+
description: MinMs is the inclusive lower bound of the SLO
140+
range in milliseconds.
141+
format: int64
142+
minimum: 0
143+
type: integer
144+
type: object
145+
type: object
102146
required:
103147
- poolRef
104148
type: object

config/manifests/inferenceobjective.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ spec:
77
poolRef:
88
group: inference.networking.k8s.io
99
name: vllm-qwen3-32b
10+
slo:
11+
ttft:
12+
minMs: 500
1013
---
1114
apiVersion: llm-d.ai/v1alpha2
1215
kind: InferenceObjective
@@ -17,6 +20,9 @@ spec:
1720
poolRef:
1821
group: inference.networking.k8s.io
1922
name: vllm-qwen3-32b
23+
slo:
24+
ttft:
25+
maxMs: 100
2026
---
2127
apiVersion: llm-d.ai/v1alpha2
2228
kind: InferenceObjective
@@ -27,3 +33,7 @@ spec:
2733
poolRef:
2834
group: inference.networking.k8s.io
2935
name: vllm-qwen3-32b
36+
slo:
37+
ttft:
38+
minMs: 100
39+
maxMs: 500

pkg/epp/flowcontrol/controller/controller.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import (
3838
"github.com/llm-d/llm-d-router/pkg/epp/flowcontrol/types"
3939
fwkrequest "github.com/llm-d/llm-d-router/pkg/epp/framework/common/request"
4040
"github.com/llm-d/llm-d-router/pkg/epp/framework/interface/flowcontrol"
41+
"github.com/llm-d/llm-d-router/pkg/epp/metadata"
4142
"github.com/llm-d/llm-d-router/pkg/epp/metrics"
4243
)
4344

@@ -215,7 +216,10 @@ func (fc *FlowController) EnqueueAndWait(
215216
flowKey := req.FlowKey()
216217
priority := strconv.Itoa(flowKey.Priority)
217218
reqBytes := req.ByteSize()
218-
sloClass := metrics.ClassifySLO(extractHeader(req, fwkrequest.TTFTSLOMsHeaderKey))
219+
sloClass := extractHeader(req, metadata.ObjectiveKey)
220+
if sloClass == "" {
221+
sloClass = metrics.SLOClassNone
222+
}
219223
metrics.RecordFlowControlSLOIncomingRequest(sloClass, req.InferencePoolName())
220224
metrics.IncFlowControlQueueSize(
221225
flowKey.ID, priority,

pkg/epp/flowcontrol/controller/internal/item.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/llm-d/llm-d-router/pkg/epp/flowcontrol/types"
2929
"github.com/llm-d/llm-d-router/pkg/epp/framework/common/request"
3030
"github.com/llm-d/llm-d-router/pkg/epp/framework/interface/flowcontrol"
31+
"github.com/llm-d/llm-d-router/pkg/epp/metadata"
3132
"github.com/llm-d/llm-d-router/pkg/epp/metrics"
3233
)
3334

@@ -167,7 +168,10 @@ func (fi *FlowItem) finalizeInternal(outcome types.QueueOutcome, err error) {
167168
fi.OriginalRequest().ModelName(), fi.OriginalRequest().TargetModelName(),
168169
duration)
169170

170-
sloClass := metrics.ClassifySLO(extractHeader(fi.originalRequest, request.TTFTSLOMsHeaderKey))
171+
sloClass := extractHeader(fi.originalRequest, metadata.ObjectiveKey)
172+
if sloClass == "" {
173+
sloClass = metrics.SLOClassNone
174+
}
171175
metrics.RecordFlowControlSLORequestQueueDuration(
172176
sloClass, outcomeStr, fi.originalRequest.InferencePoolName(),
173177
duration)

0 commit comments

Comments
 (0)