Skip to content

Commit 259ecdb

Browse files
committed
Replace custom GPU filter/scorer with generic endpoint-attribute plugins
The DCGM extractor now emits ScalarMetricValue (instead of a custom GPUUtilization type), making it compatible with the generic endpoint-attribute-filter and endpoint-attribute-scorer already in main. Signed-off-by: noalimoy <nlimoy@redhat.com>
1 parent 5b3cdd7 commit 259ecdb

14 files changed

Lines changed: 122 additions & 638 deletions

File tree

cmd/epp/runner/runner.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ import (
108108
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/requesthandling/parsers/vllmhttp"
109109
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/filter/bylabel"
110110
endpointattributefilter "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/filter/endpointattribute"
111-
filtergpuutil "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/filter/gpuutilization"
112111
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/filter/prefixcacheaffinity"
113112
sessionaffinityfilter "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/filter/sessionaffinity"
114113
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/filter/sloheadroomtier"
@@ -121,7 +120,6 @@ import (
121120
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/scorer/activerequest"
122121
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/scorer/contextlengthaware"
123122
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/scorer/endpointattribute"
124-
scorergpuutil "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/scorer/gpuutilization"
125123
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/scorer/kvcacheutilization"
126124
latencyscorer "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/scorer/latency"
127125
"github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/scheduling/scorer/loadaware"
@@ -577,10 +575,6 @@ func (r *Runner) registerInTreePlugins() {
577575
fwkplugin.Register(srcdcgm.DCGMDataSourceType, srcdcgm.DCGMDataSourceFactory)
578576
fwkplugin.Register(attrgpu.DCGMExtractorType, extdcgm.DCGMExtractorFactory)
579577

580-
// GPU utilization filter/scorer
581-
fwkplugin.Register(filtergpuutil.PluginType, filtergpuutil.Factory)
582-
fwkplugin.Register(scorergpuutil.PluginType, scorergpuutil.Factory)
583-
584578
fwkplugin.Register(prefix.PrefixCacheScorerPluginType, prefix.PrefixCachePluginFactory)
585579
fwkplugin.Register(maxscore.MaxScorePickerType, maxscore.MaxScorePickerFactory)
586580
fwkplugin.Register(random.RandomPickerType, random.RandomPickerFactory)

deploy/config/sim-epp-gpu-config.yaml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,27 @@ plugins:
99
port: 9400
1010
- type: dcgm-extractor
1111
name: dcgm-extractor
12-
- type: gpu-utilization-filter
12+
- type: endpoint-attribute-filter
13+
name: gpu-utilization-filter
1314
parameters:
14-
threshold: 0.90
15-
- type: gpu-utilization-scorer
15+
attribute: "GPUUtilization/dcgm-extractor"
16+
onMissing: "Pass"
17+
fallbackOnEmpty: true
18+
algorithm:
19+
type: "threshold"
20+
threshold:
21+
operator: "LessThanOrEqual"
22+
value: 0.90
23+
- type: endpoint-attribute-scorer
24+
name: gpu-utilization-scorer
25+
parameters:
26+
attributeKey: "GPUUtilization/dcgm-extractor"
27+
algorithm:
28+
type: "linear_lower_is_better"
29+
normalization:
30+
fixedRange:
31+
min: 0.0
32+
max: 1.0
1633
- type: kv-cache-utilization-scorer
1734
- type: max-score-picker
1835
- type: single-profile-handler
Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
# GPU Attributes
22

3-
This package defines the data structures for GPU hardware metrics collected from NVIDIA DCGM Exporter.
3+
This package defines the data key for GPU hardware metrics collected from NVIDIA DCGM Exporter.
44

5-
## `GPUUtilization`
5+
## `GPUUtilizationDataKey`
66

7-
A normalized GPU compute utilization value in [0.0, 1.0], derived from `DCGM_FI_DEV_GPU_UTIL` (which reports 0-100). For multi-GPU pods the extractor aggregates across visible devices using `max`.
7+
Identifies per-endpoint GPU utilization stored as `ScalarMetricValue` in [0.0, 1.0], derived from `DCGM_FI_DEV_GPU_UTIL` (which reports 0-100). For multi-GPU pods the extractor aggregates across visible devices using `max`.
88

9-
- **Key**: `GPUUtilizationDataKey` (`GPUUtilization/dcgm-extractor`)
9+
- **Key string**: `GPUUtilization/dcgm-extractor`
1010

1111
## Producers
1212

13-
The following plugins produce this attribute:
14-
1513
- **`dcgm-extractor`** (Data Layer): Extracts GPU utilization from the DCGM Exporter Prometheus endpoint.
14+
15+
## Consumers
16+
17+
- **`endpoint-attribute-filter`** (Scheduling): Filters endpoints exceeding a configurable GPU utilization threshold.
18+
- **`endpoint-attribute-scorer`** (Scheduling): Scores endpoints inversely to their GPU utilization.

pkg/epp/framework/plugins/datalayer/attribute/gpu/data_types.go

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ limitations under the License.
1717
package gpu
1818

1919
import (
20-
fwkdl "github.com/llm-d/llm-d-router/pkg/epp/framework/interface/datalayer"
2120
"github.com/llm-d/llm-d-router/pkg/epp/framework/interface/plugin"
2221
)
2322

@@ -27,19 +26,6 @@ const (
2726
)
2827

2928
// GPUUtilizationDataKey identifies per-endpoint GPU utilization published
30-
// by the DCGM extractor and consumed by GPU-aware filters and scorers.
29+
// by the DCGM extractor and consumed by the generic endpoint-attribute
30+
// filter and scorer.
3131
var GPUUtilizationDataKey = plugin.NewDataKey("GPUUtilization", DCGMExtractorType)
32-
33-
// GPUUtilization is a normalized GPU compute utilization value in [0.0, 1.0],
34-
// derived from DCGM_FI_DEV_GPU_UTIL (which reports 0-100).
35-
// For multi-GPU pods the extractor aggregates across visible devices.
36-
type GPUUtilization float64
37-
38-
func (v GPUUtilization) Clone() fwkdl.Cloneable {
39-
return v
40-
}
41-
42-
// ReadGPUUtilization retrieves GPU utilization from an endpoint's AttributeMap.
43-
func ReadGPUUtilization(attrs fwkdl.AttributeMap, key string) (GPUUtilization, bool) {
44-
return fwkdl.ReadAttribute[GPUUtilization](attrs, key)
45-
}

pkg/epp/framework/plugins/datalayer/extractor/dcgm/README.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
The DCGM Extractor converts the Prometheus metrics response from a
66
`dcgm-data-source` into a per-endpoint GPU utilization attribute consumed by
7-
GPU-aware filters and scorers.
7+
the generic `endpoint-attribute-filter` and `endpoint-attribute-scorer`.
88

99
## What it does
1010

@@ -16,16 +16,28 @@ GPU-aware filters and scorers.
1616
- If the sample has no `pod` label, it is kept (sidecar / unlabeled payloads).
1717
4. Aggregates matching samples using `max` (highest-utilized GPU for the pod).
1818
5. Normalizes the value from 0-100 to [0.0, 1.0].
19-
6. Stores the result as a `GPUUtilization` attribute on the corresponding endpoint.
19+
6. Stores the result as `ScalarMetricValue` on the corresponding endpoint.
2020

2121
## Attributes produced
2222

23-
- `GPUUtilization` stored at attribute key `GPUUtilizationDataKey`
24-
(`GPUUtilization/dcgm-extractor`) on each endpoint.
23+
- **Type:** `ScalarMetricValue` (from `attribute/metrics`)
24+
- **Key string:** `GPUUtilization/dcgm-extractor`
2525

26-
```go
27-
key := attrgpu.GPUUtilizationDataKey.String()
28-
util, ok := attrgpu.ReadGPUUtilization(endpoint.GetAttributes(), key)
26+
Use this key string in `endpoint-attribute-filter` and `endpoint-attribute-scorer`
27+
configuration:
28+
29+
```yaml
30+
- type: endpoint-attribute-filter
31+
name: gpu-utilization-filter
32+
parameters:
33+
attribute: "GPUUtilization/dcgm-extractor"
34+
...
35+
36+
- type: endpoint-attribute-scorer
37+
name: gpu-utilization-scorer
38+
parameters:
39+
attributeKey: "GPUUtilization/dcgm-extractor"
40+
...
2941
```
3042

3143
## Configuration

pkg/epp/framework/plugins/datalayer/extractor/dcgm/extractor.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
fwkdl "github.com/llm-d/llm-d-router/pkg/epp/framework/interface/datalayer"
2727
fwkplugin "github.com/llm-d/llm-d-router/pkg/epp/framework/interface/plugin"
2828
attrgpu "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/datalayer/attribute/gpu"
29+
attrmetrics "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/datalayer/attribute/metrics"
2930
sourcemetrics "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/datalayer/source/metrics"
3031
)
3132

@@ -101,14 +102,14 @@ func (e *Extractor) Extract(_ context.Context, in fwkdl.PollInput[sourcemetrics.
101102
return fmt.Errorf("metric %q present but has no samples for pod %q", gpuUtilMetricName, podName)
102103
}
103104

104-
normalized := attrgpu.GPUUtilization(maxUtil / 100.0)
105+
normalized := attrmetrics.ScalarMetricValue(maxUtil / 100.0)
105106
in.Endpoint.GetAttributes().Put(e.dk.String(), normalized)
106107
return nil
107108
}
108109

109110
// Produces declares the data key this extractor publishes.
110111
func (e *Extractor) Produces() map[fwkplugin.DataKey]any {
111-
return map[fwkplugin.DataKey]any{e.dk: attrgpu.GPUUtilization(0)}
112+
return map[fwkplugin.DataKey]any{e.dk: attrmetrics.ScalarMetricValue(0)}
112113
}
113114

114115
// sampleBelongsToPod reports whether m should contribute to this endpoint's

pkg/epp/framework/plugins/datalayer/extractor/dcgm/extractor_test.go

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828

2929
fwkdl "github.com/llm-d/llm-d-router/pkg/epp/framework/interface/datalayer"
3030
attrgpu "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/datalayer/attribute/gpu"
31+
attrmetrics "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/datalayer/attribute/metrics"
3132
sourcemetrics "github.com/llm-d/llm-d-router/pkg/epp/framework/plugins/datalayer/source/metrics"
3233
)
3334

@@ -215,7 +216,7 @@ func TestExtractorExtract(t *testing.T) {
215216
if diff := cmp.Diff(before, after); diff == "" {
216217
t.Error("expected attribute to be updated, but no change detected")
217218
}
218-
val, ok := attrgpu.ReadGPUUtilization(attr, key)
219+
val, ok := attrmetrics.ReadScalarMetricValue(attr, key)
219220
if !ok {
220221
t.Fatal("GPU utilization not found in attributes after extract")
221222
}
@@ -247,7 +248,23 @@ func TestFactory_SetsName(t *testing.T) {
247248
func TestProduces_DeclaresGPUUtilization(t *testing.T) {
248249
ext := NewDCGMExtractor()
249250
produced := ext.Produces()
250-
if _, ok := produced[attrgpu.GPUUtilizationDataKey]; !ok {
251+
val, ok := produced[attrgpu.GPUUtilizationDataKey]
252+
if !ok {
251253
t.Error("Produces must declare GPUUtilizationDataKey")
252254
}
255+
if _, isScalar := val.(attrmetrics.ScalarMetricValue); !isScalar {
256+
t.Errorf("Produces value type = %T, want ScalarMetricValue", val)
257+
}
258+
}
259+
260+
// TestAttributeKeyContract verifies that the attribute key string stored by
261+
// the extractor matches the value that generic endpoint-attribute-filter and
262+
// endpoint-attribute-scorer expect in their YAML config. A mismatch means
263+
// the filter/scorer silently skip all endpoints (attribute not found).
264+
func TestAttributeKeyContract(t *testing.T) {
265+
const expectedKey = "GPUUtilization/dcgm-extractor"
266+
got := attrgpu.GPUUtilizationDataKey.String()
267+
if got != expectedKey {
268+
t.Errorf("GPUUtilizationDataKey.String() = %q, want %q (must match YAML attribute config)", got, expectedKey)
269+
}
253270
}

pkg/epp/framework/plugins/scheduling/filter/gpuutilization/README.md

Lines changed: 0 additions & 26 deletions
This file was deleted.

pkg/epp/framework/plugins/scheduling/filter/gpuutilization/plugin.go

Lines changed: 0 additions & 118 deletions
This file was deleted.

0 commit comments

Comments
 (0)