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.
Files changed (80) hide show
  1. mjolnir_cli/__init__.py +8 -0
  2. mjolnir_cli/__main__.py +4 -0
  3. mjolnir_cli/accuracy.py +333 -0
  4. mjolnir_cli/autoresearch.py +539 -0
  5. mjolnir_cli/benchy.py +475 -0
  6. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4/config.yaml +78 -0
  7. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_DFLASH2/config.yaml +103 -0
  8. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_DSPARK/config.yaml +102 -0
  9. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_FA2/config.yaml +84 -0
  10. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_FA4hd256/config.yaml +104 -0
  11. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR/config.yaml +86 -0
  12. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3/config.yaml +93 -0
  13. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_DFLASH2/config.yaml +123 -0
  14. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_DSPARK/config.yaml +124 -0
  15. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8/.env +2 -0
  16. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8/config.yaml +98 -0
  17. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT32K/.env +4 -0
  18. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT32K/config.yaml +98 -0
  19. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT64K/.env +4 -0
  20. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT64K/config.yaml +102 -0
  21. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_VT32K/.env +3 -0
  22. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_VT32K/config.yaml +98 -0
  23. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/draft_vocab.json +1 -0
  24. mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/kv_scales.json +35197 -0
  25. mjolnir_cli/bundled/configs/Qwen/Qwen3.8_chat_template.jinja +456 -0
  26. mjolnir_cli/bundled/docker/litellm/docker-compose.yaml +113 -0
  27. mjolnir_cli/bundled/docker/litellm/litellm.env.example +51 -0
  28. mjolnir_cli/bundled/docker/litellm/litellm_config.template.example.yaml +192 -0
  29. mjolnir_cli/bundled/docker/perses/README.md +89 -0
  30. mjolnir_cli/bundled/docker/perses/dashboards/global-datasource.yaml +17 -0
  31. mjolnir_cli/bundled/docker/perses/dashboards/performance_statistics.yaml +771 -0
  32. mjolnir_cli/bundled/docker/perses/dashboards/project.yaml +13 -0
  33. mjolnir_cli/bundled/docker/perses/dashboards/query_statistics.yaml +399 -0
  34. mjolnir_cli/bundled/docker/perses/docker-compose.yaml +51 -0
  35. mjolnir_cli/bundled/docker/perses/perses.yml +16 -0
  36. mjolnir_cli/bundled/docker/perses/prometheus.template.yaml +20 -0
  37. mjolnir_cli/bundled/scripts/hw/setup-thor.sh +1287 -0
  38. mjolnir_cli/cachectl.py +146 -0
  39. mjolnir_cli/charts.py +1687 -0
  40. mjolnir_cli/cli.py +1480 -0
  41. mjolnir_cli/clidoc.py +170 -0
  42. mjolnir_cli/config.py +346 -0
  43. mjolnir_cli/dockerctl.py +533 -0
  44. mjolnir_cli/drivers/fa2_driver.py +89 -0
  45. mjolnir_cli/drivers/fi_driver.py +134 -0
  46. mjolnir_cli/e2e.py +302 -0
  47. mjolnir_cli/fonts/InterDisplay-Bold.ttf +0 -0
  48. mjolnir_cli/fonts/InterDisplay-Medium.ttf +0 -0
  49. mjolnir_cli/fonts/InterDisplay-Regular.ttf +0 -0
  50. mjolnir_cli/fonts/InterDisplay-SemiBold.ttf +0 -0
  51. mjolnir_cli/fonts/OFL.txt +92 -0
  52. mjolnir_cli/gate.py +233 -0
  53. mjolnir_cli/history.py +159 -0
  54. mjolnir_cli/interactive.py +383 -0
  55. mjolnir_cli/legs.py +109 -0
  56. mjolnir_cli/litellm.py +254 -0
  57. mjolnir_cli/perses.py +214 -0
  58. mjolnir_cli/picker.py +70 -0
  59. mjolnir_cli/readme.py +1020 -0
  60. mjolnir_cli/stack.py +340 -0
  61. mjolnir_cli/tasks.py +122 -0
  62. mjolnir_cli/theme.py +281 -0
  63. mjolnir_cli/thor.py +108 -0
  64. mjolnir_cli/verify/__init__.py +2 -0
  65. mjolnir_cli/verify/cli.py +816 -0
  66. mjolnir_cli/verify/docker.py +334 -0
  67. mjolnir_cli/verify/kvcache.py +180 -0
  68. mjolnir_cli/verify/legs.py +134 -0
  69. mjolnir_cli/verify/ncu.py +141 -0
  70. mjolnir_cli/verify/profile.py +312 -0
  71. mjolnir_cli/verify/report.py +177 -0
  72. mjolnir_cli/verify/results.py +157 -0
  73. mjolnir_cli/verify/spec.py +279 -0
  74. mjolnir_cli/verify/stages.py +817 -0
  75. mjolnir_cli-0.2.0.dist-info/METADATA +87 -0
  76. mjolnir_cli-0.2.0.dist-info/RECORD +80 -0
  77. mjolnir_cli-0.2.0.dist-info/WHEEL +4 -0
  78. mjolnir_cli-0.2.0.dist-info/entry_points.txt +2 -0
  79. mjolnir_cli-0.2.0.dist-info/licenses/LICENSE +202 -0
  80. 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