mjolnir-cli 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mjolnir_cli/__init__.py +8 -0
- mjolnir_cli/__main__.py +4 -0
- mjolnir_cli/accuracy.py +333 -0
- mjolnir_cli/autoresearch.py +539 -0
- mjolnir_cli/benchy.py +475 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4/config.yaml +78 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_DFLASH2/config.yaml +103 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_DSPARK/config.yaml +102 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_FA2/config.yaml +84 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_FA4hd256/config.yaml +104 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR/config.yaml +86 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3/config.yaml +93 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_DFLASH2/config.yaml +123 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_DSPARK/config.yaml +124 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8/.env +2 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8/config.yaml +98 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT32K/.env +4 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT32K/config.yaml +98 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT64K/.env +4 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT64K/config.yaml +102 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_VT32K/.env +3 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_VT32K/config.yaml +98 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/draft_vocab.json +1 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/kv_scales.json +35197 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8_chat_template.jinja +456 -0
- mjolnir_cli/bundled/docker/litellm/docker-compose.yaml +113 -0
- mjolnir_cli/bundled/docker/litellm/litellm.env.example +51 -0
- mjolnir_cli/bundled/docker/litellm/litellm_config.template.example.yaml +192 -0
- mjolnir_cli/bundled/docker/perses/README.md +89 -0
- mjolnir_cli/bundled/docker/perses/dashboards/global-datasource.yaml +17 -0
- mjolnir_cli/bundled/docker/perses/dashboards/performance_statistics.yaml +771 -0
- mjolnir_cli/bundled/docker/perses/dashboards/project.yaml +13 -0
- mjolnir_cli/bundled/docker/perses/dashboards/query_statistics.yaml +399 -0
- mjolnir_cli/bundled/docker/perses/docker-compose.yaml +51 -0
- mjolnir_cli/bundled/docker/perses/perses.yml +16 -0
- mjolnir_cli/bundled/docker/perses/prometheus.template.yaml +20 -0
- mjolnir_cli/bundled/scripts/hw/setup-thor.sh +1287 -0
- mjolnir_cli/cachectl.py +146 -0
- mjolnir_cli/charts.py +1687 -0
- mjolnir_cli/cli.py +1480 -0
- mjolnir_cli/clidoc.py +170 -0
- mjolnir_cli/config.py +346 -0
- mjolnir_cli/dockerctl.py +533 -0
- mjolnir_cli/drivers/fa2_driver.py +89 -0
- mjolnir_cli/drivers/fi_driver.py +134 -0
- mjolnir_cli/e2e.py +302 -0
- mjolnir_cli/fonts/InterDisplay-Bold.ttf +0 -0
- mjolnir_cli/fonts/InterDisplay-Medium.ttf +0 -0
- mjolnir_cli/fonts/InterDisplay-Regular.ttf +0 -0
- mjolnir_cli/fonts/InterDisplay-SemiBold.ttf +0 -0
- mjolnir_cli/fonts/OFL.txt +92 -0
- mjolnir_cli/gate.py +233 -0
- mjolnir_cli/history.py +159 -0
- mjolnir_cli/interactive.py +383 -0
- mjolnir_cli/legs.py +109 -0
- mjolnir_cli/litellm.py +254 -0
- mjolnir_cli/perses.py +214 -0
- mjolnir_cli/picker.py +70 -0
- mjolnir_cli/readme.py +1020 -0
- mjolnir_cli/stack.py +340 -0
- mjolnir_cli/tasks.py +122 -0
- mjolnir_cli/theme.py +281 -0
- mjolnir_cli/thor.py +108 -0
- mjolnir_cli/verify/__init__.py +2 -0
- mjolnir_cli/verify/cli.py +816 -0
- mjolnir_cli/verify/docker.py +334 -0
- mjolnir_cli/verify/kvcache.py +180 -0
- mjolnir_cli/verify/legs.py +134 -0
- mjolnir_cli/verify/ncu.py +141 -0
- mjolnir_cli/verify/profile.py +312 -0
- mjolnir_cli/verify/report.py +177 -0
- mjolnir_cli/verify/results.py +157 -0
- mjolnir_cli/verify/spec.py +279 -0
- mjolnir_cli/verify/stages.py +817 -0
- mjolnir_cli-0.2.0.dist-info/METADATA +87 -0
- mjolnir_cli-0.2.0.dist-info/RECORD +80 -0
- mjolnir_cli-0.2.0.dist-info/WHEEL +4 -0
- mjolnir_cli-0.2.0.dist-info/entry_points.txt +2 -0
- mjolnir_cli-0.2.0.dist-info/licenses/LICENSE +202 -0
- mjolnir_cli-0.2.0.dist-info/licenses/NOTICE +64 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# The single Perses project the vLLM dashboards live in.
|
|
2
|
+
#
|
|
3
|
+
# Standalone Perses is project-centric: the UI only renders a dashboard if a
|
|
4
|
+
# Project with a matching metadata.name exists (it groups dashboards by
|
|
5
|
+
# project and drops any that don't match a known project). The upstream vLLM
|
|
6
|
+
# dashboards ship with `project: ""`, which is invisible in the UI — so we
|
|
7
|
+
# provision a named project here and point the two dashboards at it.
|
|
8
|
+
kind: Project
|
|
9
|
+
metadata:
|
|
10
|
+
name: vllm
|
|
11
|
+
spec:
|
|
12
|
+
display:
|
|
13
|
+
name: vLLM
|
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
# Vendored from vllm-project/vllm (examples/observability/dashboards/perses/query_statistics.yaml),
|
|
2
|
+
# fetched 2026-09-30. One adaptation for standalone Perses: `kind:
|
|
3
|
+
# PersesDashboard` (the k8s-operator CRD form) -> `kind: Dashboard` (the
|
|
4
|
+
# form the standalone API / provisioning accepts). Second adaptation:
|
|
5
|
+
# `project: ""` -> `project: vllm` (standalone Perses only renders dashboards
|
|
6
|
+
# whose project exists as a Project resource — see project.yaml). Everything
|
|
7
|
+
# else verbatim.
|
|
8
|
+
kind: Dashboard
|
|
9
|
+
metadata:
|
|
10
|
+
name: query-statistics
|
|
11
|
+
createdAt: 0001-01-01T00:00:00Z
|
|
12
|
+
updatedAt: 0001-01-01T00:00:00Z
|
|
13
|
+
version: 0
|
|
14
|
+
project: vllm
|
|
15
|
+
spec:
|
|
16
|
+
display:
|
|
17
|
+
name: Query Statistics_New
|
|
18
|
+
|
|
19
|
+
variables:
|
|
20
|
+
- kind: ListVariable
|
|
21
|
+
spec:
|
|
22
|
+
name: NS
|
|
23
|
+
display: { name: Namespace }
|
|
24
|
+
allowMultiple: false
|
|
25
|
+
defaultValue: llm-d
|
|
26
|
+
plugin:
|
|
27
|
+
kind: PrometheusLabelValuesVariable
|
|
28
|
+
spec:
|
|
29
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
30
|
+
labelName: namespace
|
|
31
|
+
matchers:
|
|
32
|
+
- up{service=~".*vllm.*"}
|
|
33
|
+
|
|
34
|
+
- kind: ListVariable
|
|
35
|
+
spec:
|
|
36
|
+
name: SVC
|
|
37
|
+
display: { name: Service }
|
|
38
|
+
allowMultiple: false
|
|
39
|
+
defaultValue: vllm-qwen2-0-5b-sim
|
|
40
|
+
plugin:
|
|
41
|
+
kind: PrometheusLabelValuesVariable
|
|
42
|
+
spec:
|
|
43
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
44
|
+
labelName: service
|
|
45
|
+
matchers:
|
|
46
|
+
- up{namespace="$NS",service=~".*vllm.*"}
|
|
47
|
+
|
|
48
|
+
- kind: ListVariable
|
|
49
|
+
spec:
|
|
50
|
+
name: MODEL
|
|
51
|
+
display: { name: Model (real vLLM) }
|
|
52
|
+
allowAllValue: true
|
|
53
|
+
allowMultiple: true
|
|
54
|
+
defaultValue: ["$__all"]
|
|
55
|
+
plugin:
|
|
56
|
+
kind: PrometheusLabelValuesVariable
|
|
57
|
+
spec:
|
|
58
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
59
|
+
labelName: model_name
|
|
60
|
+
matchers:
|
|
61
|
+
- vllm:request_success_total{namespace="$NS",service="$SVC"}
|
|
62
|
+
|
|
63
|
+
panels:
|
|
64
|
+
|
|
65
|
+
# --- Core (works on Simulator & Real) ---
|
|
66
|
+
core_running_now:
|
|
67
|
+
kind: Panel
|
|
68
|
+
spec:
|
|
69
|
+
display: { name: Running Requests (now) }
|
|
70
|
+
plugin: { kind: StatChart, spec: { calculation: last-number } }
|
|
71
|
+
queries:
|
|
72
|
+
- kind: TimeSeriesQuery
|
|
73
|
+
spec:
|
|
74
|
+
plugin:
|
|
75
|
+
kind: PrometheusTimeSeriesQuery
|
|
76
|
+
spec:
|
|
77
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
78
|
+
query: sum(vllm:num_requests_running{namespace="$NS",service="$SVC"}) or vector(0)
|
|
79
|
+
minStep: "15s"
|
|
80
|
+
|
|
81
|
+
core_waiting_now:
|
|
82
|
+
kind: Panel
|
|
83
|
+
spec:
|
|
84
|
+
display: { name: Waiting Requests (now) }
|
|
85
|
+
plugin: { kind: StatChart, spec: { calculation: last-number } }
|
|
86
|
+
queries:
|
|
87
|
+
- kind: TimeSeriesQuery
|
|
88
|
+
spec:
|
|
89
|
+
plugin:
|
|
90
|
+
kind: PrometheusTimeSeriesQuery
|
|
91
|
+
spec:
|
|
92
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
93
|
+
query: sum(vllm:num_requests_waiting{namespace="$NS",service="$SVC"}) or vector(0)
|
|
94
|
+
minStep: "15s"
|
|
95
|
+
|
|
96
|
+
core_kv_usage_now:
|
|
97
|
+
kind: Panel
|
|
98
|
+
spec:
|
|
99
|
+
display: { name: KV Cache Usage (0–1) }
|
|
100
|
+
plugin: { kind: StatChart, spec: { calculation: last-number } }
|
|
101
|
+
queries:
|
|
102
|
+
- kind: TimeSeriesQuery
|
|
103
|
+
spec:
|
|
104
|
+
plugin:
|
|
105
|
+
kind: PrometheusTimeSeriesQuery
|
|
106
|
+
spec:
|
|
107
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
108
|
+
query: avg(vllm:kv_cache_usage_perc{namespace="$NS",service="$SVC"}) or vector(0)
|
|
109
|
+
minStep: "15s"
|
|
110
|
+
|
|
111
|
+
core_running_ts:
|
|
112
|
+
kind: Panel
|
|
113
|
+
spec:
|
|
114
|
+
display: { name: Running Over Time }
|
|
115
|
+
plugin:
|
|
116
|
+
kind: TimeSeriesChart
|
|
117
|
+
spec:
|
|
118
|
+
legend: { mode: table, position: bottom }
|
|
119
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
120
|
+
queries:
|
|
121
|
+
- kind: TimeSeriesQuery
|
|
122
|
+
spec:
|
|
123
|
+
plugin:
|
|
124
|
+
kind: PrometheusTimeSeriesQuery
|
|
125
|
+
spec:
|
|
126
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
127
|
+
query: sum by (service) (vllm:num_requests_running{namespace="$NS",service="$SVC"}) or vector(0)
|
|
128
|
+
minStep: "15s"
|
|
129
|
+
|
|
130
|
+
core_waiting_ts:
|
|
131
|
+
kind: Panel
|
|
132
|
+
spec:
|
|
133
|
+
display: { name: Waiting Over Time }
|
|
134
|
+
plugin:
|
|
135
|
+
kind: TimeSeriesChart
|
|
136
|
+
spec:
|
|
137
|
+
legend: { mode: table, position: bottom }
|
|
138
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
139
|
+
queries:
|
|
140
|
+
- kind: TimeSeriesQuery
|
|
141
|
+
spec:
|
|
142
|
+
plugin:
|
|
143
|
+
kind: PrometheusTimeSeriesQuery
|
|
144
|
+
spec:
|
|
145
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
146
|
+
query: sum by (service) (vllm:num_requests_waiting{namespace="$NS",service="$SVC"}) or vector(0)
|
|
147
|
+
minStep: "15s"
|
|
148
|
+
|
|
149
|
+
core_targets_up:
|
|
150
|
+
kind: Panel
|
|
151
|
+
spec:
|
|
152
|
+
display: { name: Scrape Targets Up }
|
|
153
|
+
plugin: { kind: StatChart, spec: { calculation: last-number } }
|
|
154
|
+
queries:
|
|
155
|
+
- kind: TimeSeriesQuery
|
|
156
|
+
spec:
|
|
157
|
+
plugin:
|
|
158
|
+
kind: PrometheusTimeSeriesQuery
|
|
159
|
+
spec:
|
|
160
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
161
|
+
query: count(up{namespace="$NS",service="$SVC"} == 1) or vector(0)
|
|
162
|
+
minStep: "15s"
|
|
163
|
+
|
|
164
|
+
# --- KV Cache as Percent (works on Simulator & Real) ---
|
|
165
|
+
core_kv_usage_pct_now:
|
|
166
|
+
kind: Panel
|
|
167
|
+
spec:
|
|
168
|
+
display: { name: KV Cache Usage (%) – now }
|
|
169
|
+
plugin: { kind: StatChart, spec: { calculation: last-number } }
|
|
170
|
+
queries:
|
|
171
|
+
- kind: TimeSeriesQuery
|
|
172
|
+
spec:
|
|
173
|
+
plugin:
|
|
174
|
+
kind: PrometheusTimeSeriesQuery
|
|
175
|
+
spec:
|
|
176
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
177
|
+
# multiply by 100 to present percentage; omit format.unit to avoid schema conflicts
|
|
178
|
+
query: (avg(vllm:kv_cache_usage_perc{namespace="$NS",service="$SVC"}) * 100) or vector(0)
|
|
179
|
+
minStep: "15s"
|
|
180
|
+
|
|
181
|
+
core_kv_usage_pct_ts:
|
|
182
|
+
kind: Panel
|
|
183
|
+
spec:
|
|
184
|
+
display: { name: KV Cache Usage (%) – over time }
|
|
185
|
+
plugin:
|
|
186
|
+
kind: TimeSeriesChart
|
|
187
|
+
spec:
|
|
188
|
+
legend: { mode: table, position: bottom }
|
|
189
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
190
|
+
queries:
|
|
191
|
+
- kind: TimeSeriesQuery
|
|
192
|
+
spec:
|
|
193
|
+
plugin:
|
|
194
|
+
kind: PrometheusTimeSeriesQuery
|
|
195
|
+
spec:
|
|
196
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
197
|
+
query: (avg by (service) (vllm:kv_cache_usage_perc{namespace="$NS",service="$SVC"}) * 100) or vector(0)
|
|
198
|
+
minStep: "15s"
|
|
199
|
+
|
|
200
|
+
# --- Per-Pod breakdowns (works on Simulator & Real) ---
|
|
201
|
+
per_pod_running_ts:
|
|
202
|
+
kind: Panel
|
|
203
|
+
spec:
|
|
204
|
+
display: { name: Running by Pod }
|
|
205
|
+
plugin:
|
|
206
|
+
kind: TimeSeriesChart
|
|
207
|
+
spec:
|
|
208
|
+
legend: { mode: table, position: bottom }
|
|
209
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
210
|
+
queries:
|
|
211
|
+
- kind: TimeSeriesQuery
|
|
212
|
+
spec:
|
|
213
|
+
plugin:
|
|
214
|
+
kind: PrometheusTimeSeriesQuery
|
|
215
|
+
spec:
|
|
216
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
217
|
+
query: sum by (pod) (vllm:num_requests_running{namespace="$NS",service="$SVC"}) or vector(0)
|
|
218
|
+
minStep: "15s"
|
|
219
|
+
|
|
220
|
+
per_pod_waiting_ts:
|
|
221
|
+
kind: Panel
|
|
222
|
+
spec:
|
|
223
|
+
display: { name: Waiting by Pod }
|
|
224
|
+
plugin:
|
|
225
|
+
kind: TimeSeriesChart
|
|
226
|
+
spec:
|
|
227
|
+
legend: { mode: table, position: bottom }
|
|
228
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
229
|
+
queries:
|
|
230
|
+
- kind: TimeSeriesQuery
|
|
231
|
+
spec:
|
|
232
|
+
plugin:
|
|
233
|
+
kind: PrometheusTimeSeriesQuery
|
|
234
|
+
spec:
|
|
235
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
236
|
+
query: sum by (pod) (vllm:num_requests_waiting{namespace="$NS",service="$SVC"}) or vector(0)
|
|
237
|
+
minStep: "15s"
|
|
238
|
+
|
|
239
|
+
per_pod_kv_pct_ts:
|
|
240
|
+
kind: Panel
|
|
241
|
+
spec:
|
|
242
|
+
display: { name: KV Cache (%) by Pod }
|
|
243
|
+
plugin:
|
|
244
|
+
kind: TimeSeriesChart
|
|
245
|
+
spec:
|
|
246
|
+
legend: { mode: table, position: bottom }
|
|
247
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
248
|
+
queries:
|
|
249
|
+
- kind: TimeSeriesQuery
|
|
250
|
+
spec:
|
|
251
|
+
plugin:
|
|
252
|
+
kind: PrometheusTimeSeriesQuery
|
|
253
|
+
spec:
|
|
254
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
255
|
+
# if your exporter labels kv metric with pod (the sim does), this works; otherwise it will just return empty
|
|
256
|
+
query: (avg by (pod) (vllm:kv_cache_usage_perc{namespace="$NS",service="$SVC"}) * 100) or vector(0)
|
|
257
|
+
minStep: "15s"
|
|
258
|
+
|
|
259
|
+
# --- Real vLLM only (zeros on simulator) ---
|
|
260
|
+
real_req_rate_ts:
|
|
261
|
+
kind: Panel
|
|
262
|
+
spec:
|
|
263
|
+
display: { name: Request Rate (real vLLM) }
|
|
264
|
+
plugin:
|
|
265
|
+
kind: TimeSeriesChart
|
|
266
|
+
spec:
|
|
267
|
+
legend: { mode: table, position: bottom }
|
|
268
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
269
|
+
queries:
|
|
270
|
+
- kind: TimeSeriesQuery
|
|
271
|
+
spec:
|
|
272
|
+
plugin:
|
|
273
|
+
kind: PrometheusTimeSeriesQuery
|
|
274
|
+
spec:
|
|
275
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
276
|
+
query: sum by (model_name) (rate(vllm:request_success_total{namespace="$NS",service="$SVC",model_name=~"$MODEL"}[$__interval])) or vector(0)
|
|
277
|
+
minStep: "15s"
|
|
278
|
+
|
|
279
|
+
real_p50:
|
|
280
|
+
kind: Panel
|
|
281
|
+
spec:
|
|
282
|
+
display: { name: p50 Latency (real vLLM) }
|
|
283
|
+
plugin: { kind: StatChart, spec: { calculation: last-number } }
|
|
284
|
+
queries:
|
|
285
|
+
- kind: TimeSeriesQuery
|
|
286
|
+
spec:
|
|
287
|
+
plugin:
|
|
288
|
+
kind: PrometheusTimeSeriesQuery
|
|
289
|
+
spec:
|
|
290
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
291
|
+
query: histogram_quantile(0.50, sum by (le, model_name) (rate(vllm:e2e_request_latency_seconds_bucket{namespace="$NS",service="$SVC",model_name=~"$MODEL"}[$__interval]))) or vector(0)
|
|
292
|
+
minStep: "15s"
|
|
293
|
+
|
|
294
|
+
real_p90:
|
|
295
|
+
kind: Panel
|
|
296
|
+
spec:
|
|
297
|
+
display: { name: p90 Latency (real vLLM) }
|
|
298
|
+
plugin: { kind: StatChart, spec: { calculation: last-number } }
|
|
299
|
+
queries:
|
|
300
|
+
- kind: TimeSeriesQuery
|
|
301
|
+
spec:
|
|
302
|
+
plugin:
|
|
303
|
+
kind: PrometheusTimeSeriesQuery
|
|
304
|
+
spec:
|
|
305
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
306
|
+
query: histogram_quantile(0.90, sum by (le, model_name) (rate(vllm:e2e_request_latency_seconds_bucket{namespace="$NS",service="$SVC",model_name=~"$MODEL"}[$__interval]))) or vector(0)
|
|
307
|
+
minStep: "15s"
|
|
308
|
+
|
|
309
|
+
real_p99:
|
|
310
|
+
kind: Panel
|
|
311
|
+
spec:
|
|
312
|
+
display: { name: p99 Latency (real vLLM) }
|
|
313
|
+
plugin: { kind: StatChart, spec: { calculation: last-number } }
|
|
314
|
+
queries:
|
|
315
|
+
- kind: TimeSeriesQuery
|
|
316
|
+
spec:
|
|
317
|
+
plugin:
|
|
318
|
+
kind: PrometheusTimeSeriesQuery
|
|
319
|
+
spec:
|
|
320
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
321
|
+
query: histogram_quantile(0.99, sum by (le, model_name) (rate(vllm:e2e_request_latency_seconds_bucket{namespace="$NS",service="$SVC",model_name=~"$MODEL"}[$__interval]))) or vector(0)
|
|
322
|
+
minStep: "15s"
|
|
323
|
+
|
|
324
|
+
real_input_tokens_ts:
|
|
325
|
+
kind: Panel
|
|
326
|
+
spec:
|
|
327
|
+
display: { name: Input Tokens / sec (real vLLM) }
|
|
328
|
+
plugin:
|
|
329
|
+
kind: TimeSeriesChart
|
|
330
|
+
spec:
|
|
331
|
+
legend: { mode: table, position: bottom }
|
|
332
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
333
|
+
queries:
|
|
334
|
+
- kind: TimeSeriesQuery
|
|
335
|
+
spec:
|
|
336
|
+
plugin:
|
|
337
|
+
kind: PrometheusTimeSeriesQuery
|
|
338
|
+
spec:
|
|
339
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
340
|
+
query: sum by (model_name) (rate(vllm:prompt_tokens_total{namespace="$NS",service="$SVC",model_name=~"$MODEL"}[$__interval])) or vector(0)
|
|
341
|
+
minStep: "15s"
|
|
342
|
+
|
|
343
|
+
real_output_tokens_ts:
|
|
344
|
+
kind: Panel
|
|
345
|
+
spec:
|
|
346
|
+
display: { name: Output Tokens / sec (real vLLM) }
|
|
347
|
+
plugin:
|
|
348
|
+
kind: TimeSeriesChart
|
|
349
|
+
spec:
|
|
350
|
+
legend: { mode: table, position: bottom }
|
|
351
|
+
visual: { display: line, lineWidth: 1, areaOpacity: 0.3 }
|
|
352
|
+
queries:
|
|
353
|
+
- kind: TimeSeriesQuery
|
|
354
|
+
spec:
|
|
355
|
+
plugin:
|
|
356
|
+
kind: PrometheusTimeSeriesQuery
|
|
357
|
+
spec:
|
|
358
|
+
datasource: { kind: PrometheusDatasource, name: accelerators-thanos-querier-datasource }
|
|
359
|
+
query: sum by (model_name) (rate(vllm:generation_tokens_total{namespace="$NS",service="$SVC",model_name=~"$MODEL"}[$__interval])) or vector(0)
|
|
360
|
+
minStep: "15s"
|
|
361
|
+
|
|
362
|
+
layouts:
|
|
363
|
+
- kind: Grid
|
|
364
|
+
spec:
|
|
365
|
+
display: { title: Core (Sim & Real) }
|
|
366
|
+
items:
|
|
367
|
+
- { x: 0, y: 0, width: 6, height: 3, content: { $ref: '#/spec/panels/core_running_now' } }
|
|
368
|
+
- { x: 6, y: 0, width: 6, height: 3, content: { $ref: '#/spec/panels/core_waiting_now' } }
|
|
369
|
+
- { x: 12, y: 0, width: 6, height: 3, content: { $ref: '#/spec/panels/core_kv_usage_now' } }
|
|
370
|
+
- { x: 18, y: 0, width: 6, height: 3, content: { $ref: '#/spec/panels/core_targets_up' } }
|
|
371
|
+
- { x: 0, y: 3, width: 12, height: 6, content: { $ref: '#/spec/panels/core_running_ts' } }
|
|
372
|
+
- { x: 12, y: 3, width: 12, height: 6, content: { $ref: '#/spec/panels/core_waiting_ts' } }
|
|
373
|
+
|
|
374
|
+
- kind: Grid
|
|
375
|
+
spec:
|
|
376
|
+
display: { title: KV Cache (%) }
|
|
377
|
+
items:
|
|
378
|
+
- { x: 0, y: 9, width: 6, height: 3, content: { $ref: '#/spec/panels/core_kv_usage_pct_now' } }
|
|
379
|
+
- { x: 6, y: 9, width: 18, height: 6, content: { $ref: '#/spec/panels/core_kv_usage_pct_ts' } }
|
|
380
|
+
|
|
381
|
+
- kind: Grid
|
|
382
|
+
spec:
|
|
383
|
+
display: { title: Per-Pod breakdowns }
|
|
384
|
+
items:
|
|
385
|
+
- { x: 0, y: 15, width: 12, height: 6, content: { $ref: '#/spec/panels/per_pod_running_ts' } }
|
|
386
|
+
- { x: 12, y: 15, width: 12, height: 6, content: { $ref: '#/spec/panels/per_pod_waiting_ts' } }
|
|
387
|
+
- { x: 0, y: 21, width: 24, height: 6, content: { $ref: '#/spec/panels/per_pod_kv_pct_ts' } }
|
|
388
|
+
|
|
389
|
+
- kind: Grid
|
|
390
|
+
spec:
|
|
391
|
+
display: { title: Real vLLM only (shows 0 on simulator) }
|
|
392
|
+
items:
|
|
393
|
+
- { x: 0, y: 27, width: 12, height: 6, content: { $ref: '#/spec/panels/real_req_rate_ts' } }
|
|
394
|
+
- { x: 12, y: 27, width: 4, height: 3, content: { $ref: '#/spec/panels/real_p50' } }
|
|
395
|
+
- { x: 16, y: 27, width: 4, height: 3, content: { $ref: '#/spec/panels/real_p90' } }
|
|
396
|
+
- { x: 20, y: 27, width: 4, height: 3, content: { $ref: '#/spec/panels/real_p99' } }
|
|
397
|
+
- { x: 0, y: 33, width: 12, height: 6, content: { $ref: '#/spec/panels/real_input_tokens_ts' } }
|
|
398
|
+
- { x: 12, y: 33, width: 12, height: 6, content: { $ref: '#/spec/panels/real_output_tokens_ts' } }
|
|
399
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Perses + Prometheus observability stack for the vLLM server.
|
|
2
|
+
#
|
|
3
|
+
# Driven by the `mjolnir perses` CLI (docker compose under the hood), on the
|
|
4
|
+
# same terms as docker/litellm/:
|
|
5
|
+
#
|
|
6
|
+
# - INDEPENDENT of the vLLM server: prometheus scrapes the server's
|
|
7
|
+
# /metrics through host.docker.internal (the host-published port), so
|
|
8
|
+
# the stack works whether mjolnir's vLLM container is up or down, and
|
|
9
|
+
# never shares a network with it
|
|
10
|
+
# - the scrape target is rendered per-run by `mjolnir perses up` from
|
|
11
|
+
# prometheus.template.yaml -> ${PERSER_DATA_DIR}/prometheus.yml (the
|
|
12
|
+
# port = the resolved server port, same as `mjolnir serve`)
|
|
13
|
+
# - the vllm project, the two vLLM dashboards (vendored from
|
|
14
|
+
# vllm-project/vllm, dashboards/) + the Prometheus datasource are
|
|
15
|
+
# PROVISIONED from the read-only dashboards/ folder — Perses loads them
|
|
16
|
+
# at startup and re-syncs hourly; no manual import (percli) ever needed
|
|
17
|
+
# - data lives under ${PERSER_DATA_DIR} (default
|
|
18
|
+
# ~/.local/share/mjolnir/perses): db/ (Perses file DB) + prom/ (TSDB —
|
|
19
|
+
# scrape history survives restarts)
|
|
20
|
+
#
|
|
21
|
+
# All ${...} are interpolated at `docker compose` time; the values come from
|
|
22
|
+
# the env file ($MJOLNIR_PERSER_ENV, default
|
|
23
|
+
# ~/.local/share/mjolnir/perses/perses.env) with the :-defaults below as
|
|
24
|
+
# fallback.
|
|
25
|
+
|
|
26
|
+
services:
|
|
27
|
+
prometheus:
|
|
28
|
+
image: prom/prometheus:${PROMETHEUS_IMAGE_TAG:-v3.15.0}
|
|
29
|
+
restart: unless-stopped
|
|
30
|
+
ports:
|
|
31
|
+
- "${PROMETHEUS_PORT:-9090}:9090"
|
|
32
|
+
extra_hosts:
|
|
33
|
+
- "host.docker.internal:host-gateway"
|
|
34
|
+
volumes:
|
|
35
|
+
- ${PERSER_DATA_DIR}/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
|
36
|
+
- ${PERSER_DATA_DIR}/prom:/prometheus
|
|
37
|
+
|
|
38
|
+
perses:
|
|
39
|
+
image: persesdev/perses:${PERSER_IMAGE_TAG:-v0.54.0}
|
|
40
|
+
restart: unless-stopped
|
|
41
|
+
ports:
|
|
42
|
+
- "${PERSER_PORT:-8080}:8080"
|
|
43
|
+
volumes:
|
|
44
|
+
# over the image's bundled config (the entrypoint's --config path):
|
|
45
|
+
# file-backed DB + the provisioning folder
|
|
46
|
+
- ./perses.yml:/etc/perses/config.yaml:ro
|
|
47
|
+
- ${PERSER_DATA_DIR}/db:/perses
|
|
48
|
+
# the vLLM dashboards + the Prometheus datasource (repo, read-only):
|
|
49
|
+
- ./dashboards:/provisioning:ro
|
|
50
|
+
depends_on:
|
|
51
|
+
- prometheus
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Perses standalone config (static — mounted over the image's bundled
|
|
2
|
+
# /etc/perses/config.yaml, which is the entrypoint's --config path).
|
|
3
|
+
#
|
|
4
|
+
# - database.file: the dashboards/datasource live as JSON files in /perses
|
|
5
|
+
# (bind-mounted to the data dir's db/ — survives `perses down`)
|
|
6
|
+
# - provisioning: at startup (and re-synced hourly) Perses loads every
|
|
7
|
+
# known resource from /provisioning — the vllm project, the two vLLM
|
|
8
|
+
# dashboards + the Prometheus datasource from docker/perses/dashboards/.
|
|
9
|
+
# No percli import ever needed.
|
|
10
|
+
database:
|
|
11
|
+
file:
|
|
12
|
+
folder: /perses
|
|
13
|
+
extension: json
|
|
14
|
+
provisioning:
|
|
15
|
+
folders:
|
|
16
|
+
- /provisioning
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Rendered by `mjolnir perses up` into the perses data dir
|
|
2
|
+
# (${PERSER_DATA_DIR}/prometheus.yml) — the vLLM scrape target comes from the
|
|
3
|
+
# active model/config (the same port `mjolnir serve` exposes; override with
|
|
4
|
+
# PERSER_VLLM_TARGET in the perses env file), so the rendered file is user data,
|
|
5
|
+
# not a repo artifact.
|
|
6
|
+
global:
|
|
7
|
+
scrape_interval: 15s
|
|
8
|
+
scrape_configs:
|
|
9
|
+
- job_name: vllm
|
|
10
|
+
metrics_path: /metrics
|
|
11
|
+
static_configs:
|
|
12
|
+
- targets: ["${VLLM_METRICS_TARGET}"] # host:port — the path is
|
|
13
|
+
# given by metrics_path (a full URL is NOT a valid prom target)
|
|
14
|
+
# The upstream vLLM dashboards filter EVERY panel by
|
|
15
|
+
# namespace=<v>,service=<v> (k8s-shaped label matchers). Standalone,
|
|
16
|
+
# those values come from the target labels of this scrape job — this
|
|
17
|
+
# is what makes the dashboards work verbatim (see README.md).
|
|
18
|
+
labels:
|
|
19
|
+
namespace: mjolnir
|
|
20
|
+
service: mjolnir-vllm
|