feat(observability): llama.cpp metrics PodMonitor and pinned contract (#1186) - #1754
Open
joryirving wants to merge 1 commit into
Open
feat(observability): llama.cpp metrics PodMonitor and pinned contract (#1186)#1754joryirving wants to merge 1 commit into
joryirving wants to merge 1 commit into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
joryirving
force-pushed
the
feat/llamacpp-metrics-podmonitor
branch
from
September 3, 2026 12:47
326390d to
a2ad11f
Compare
Slice 2 of defilantech#700 (defilantech#1186). Adds a PodMonitor that scrapes llama.cpp /metrics from every InferenceService the operator creates, selecting on the operator's own inference.llmkube.dev/service label so a new server needs no monitoring change, and relabelling each series with service, model, runtime and namespace so a panel can break down per model without naming a target. Pins the contract in docs/observability/llamacpp-metrics.md, read from live servers rather than from documentation. Two names defilantech#1186 originally pinned do not exist: llama.cpp emits no tokens_per_second (throughput is split into predicted_tokens_seconds and prompt_tokens_seconds) and exposes nothing for KV-cache occupancy. The split is worth keeping — prefill and decode degrade independently, and a combined figure hides one collapsing while the other holds. requests_deferred is added as the queueing signal. The static scrape_configs remain the right shape for an external Prometheus; this is the default for a cluster running prometheus-operator. Signed-off-by: Jory Irving <jory@jory.dev>
joryirving
force-pushed
the
feat/llamacpp-metrics-podmonitor
branch
from
September 3, 2026 14:10
a2ad11f to
76192cd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds the producer half of the inference tier:
config/monitoring/llamacpp-podmonitor.yaml— scrapes llama.cpp/metricsfrom every InferenceService the operator creates.docs/observability/llamacpp-metrics.md— the pinned metric contract, in the same shape asamd-gpu-metrics.md.Why
Fixes #1186
Slice 2 of #700. Per the discussion on #1186, two of the three metric names pinned there do not exist in llama.cpp's
/metrics, so #1187 would build panel queries against metrics that never arrive:llamacpp:requests_processingllamacpp:tokens_per_secondllamacpp:kv_cache_usage_ratiokv_cacheis exposedHow
Scraping. The PodMonitor selects on the operator's own
inference.llmkube.dev/servicelabel rather than naming servers, so a new InferenceService is picked up with no monitoring change. Each series is relabelled withservice,model,runtimeandnamespace, so #1187's panel can break down per model without hardcoding a target.The static
scrape_configsinprometheus-scrape-config.yamlare left as-is. They remain the right shape for an external Prometheus that cannot do service discovery in this cluster; the PodMonitor is the default for a cluster running prometheus-operator.Contract. Throughput is pinned as two metrics rather than one —
llamacpp:predicted_tokens_seconds(decode) andllamacpp:prompt_tokens_seconds(prefill). They bottleneck on different resources and degrade independently, so a combined figure hides one collapsing while the other holds. I watched a server fall from 56 to 5 tokens/s of decode with prefill unchanged; an averaged number would have read as a mild dip rather than a 10x regression.llamacpp:requests_deferredis added as the queueing signal. It rises only once every parallel slot is occupied, which is what separates "busy" from "oversubscribed" — better than inferring queueing from latency.KV-cache occupancy is documented as a known gap rather than substituted.
llamacpp:n_busy_slots_per_decodeis a reasonable saturation proxy but measures slot occupancy, not cache residency, and renaming it would put the same drift back into the contract that pinning it was meant to prevent.Scope. Deliberately does not touch
charts/llmkube/dashboards/amd-gpu-observability.json— that is #1187, and it should build against this contract once pinned. The inference stanza inamd-gpu-metrics.mdnow points at the new contract and gainsrequests_deferred; itsmetrics-contractmarkers are preserved.Assisted-by: Claude Code (drafted the manifest, the contract doc and this description; I verified every metric name, type and description against my own running servers, confirmed the PodMonitor live, and checked the kustomize render).
Checklist
kubectl kustomize config/monitoringrendering the PodMonitor, and by reading every documented metric, type and help string from live servers' own metric metadata (a Strix Halo gfx1151 node plus four other InferenceServices, scraped through this PodMonitor for 15 days).make testpasses locally — unaffected, no Go changesmake lintpasses locally — unaffected, no Go changesgit commit -s) per DCO