Repository navigation
fix(metrics): make per-request context gauges opt-in via CLI - #2836
Conversation
Signed-off-by: ZhangLirong <219599949+ZhangLirong-amd@users.noreply.github.com>
🏷️ CI GuideRuns automatically on every eligible PR before approval:
Heavy model tests:
|
There was a problem hiding this comment.
🟢 Approval recommended
No active review issues remain for the change making per-request context gauges opt-in.
No open issues 🎉
What changed in this PR
Makes ATOM’s per-request context gauges opt-in, preventing request-history growth in default Prometheus series and native multiprocess storage while preserving aggregate metrics.
Changes:
- Adds
ATOM_ENABLE_METRICS_REQUEST_CONTEXT, disabled by default, to gate gauge registration and per-request observations. - Adds 10,000-request cardinality and storage regression checks; explicitly enables gauges in existing diagnostic tests.
- Documents bounded diagnostic use and safe cleanup of retained samples.
| File | Description |
|---|---|
tests/test_scheduler_metrics.py |
Enables request-context gauges for existing observation tests. |
tests/test_scheduler_metrics_cardinality.py |
Checks stable series and mmap storage with gauges disabled. |
tests/test_multiprocess_metrics.py |
Enables diagnostic gauges in multiprocess export tests. |
docs/metrics_guide.md |
Explains opt-in behavior, retention, and cleanup. |
docs/environment_variables.md |
Documents the new flag and its default. |
atom/utils/envs.py |
Registers the request-context metrics flag. |
atom/metrics/scheduler.py |
Gates gauge creation and skips disabled observations. |
Review effort: Balanced
Signed-off-by: ZhangLirong <219599949+ZhangLirong-amd@users.noreply.github.com>
| capture, pass `--enable-request-context-metrics` when starting the server. | ||
| For PD deployments, pass it separately to each P/D service to be diagnosed. | ||
| The option is disabled by default for both roles and standalone serving. | ||
| Python callers can set `enable_request_context_metrics=True` on `LLM(...)`. |
Jasen2201
left a comment
There was a problem hiding this comment.
Making the two per-request context gauges opt-in is appropriate: it bounds default metric cardinality while preserving aggregate observations. I found no blocking issue in the scheduler configuration propagation or recording paths.
Locally verified all four 10,000-request cardinality probes (ordinary/mmap storage, default/explicitly disabled), opt-in first-dispatch observations with unchanged aggregate values, and three related report tests. GPU end-to-end tests were not run locally.
Non-blocking documentation nits: update the Agentic report instructions to explain how to opt in for request-context panels, and use LLMEngine(...) rather than LLM(...) in the Python example, as already noted in the existing review comment.
Under AgentX load, both API processes of an ATOM PD deployment spent ~45% of the wall clock in stop-the-world gen-2 GC passes, and each pass grew with the requests served (~0.65 s per pass after an hour). A pass freezes the event loop, so admission, the prefill hand-back and SSE delivery all wait on it. CoreManager.outputs_queue grew with every completed request. The output thread put every batch of finished sequences on it, but only LLMEngine.step()/generate() and asyncio mode read it; the OpenAI server and the atomesh standalone service deliver through the per-sequence stream callbacks. So every finished Sequence stayed reachable for the life of the process, as RequestOutputs did on stream_outputs_queue before. Whether the queue has a reader is now declared: consumes_outputs_queue starts True in _init_shared_state, both callback-only entrypoints clear it as they wire up, and the output thread queues only while it is set. get_output()/get_output_async() raise when it is cleared instead of waiting on a queue nothing fills. _asyncio_mode is set only in _init_shared_state, and both managers derive async_output_queue from it. The per-request context gauges were the other source of growth; ROCm#2836 made them opt-in with --enable-request-context-metrics. The metrics guide's table rows for them now say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Long-running serving and PD benchmarks accumulate Prometheus time series in two per-request context gauges:
atom:prefill_request_context_tokensatom:decode_request_context_tokensTheir labels include
request_id,sequence_id, andstarted_at, so each newly observed request sequence creates a distinct series for that phase. Samples are intentionally retained after completion so periodic scrapes can capture short requests and reports can show exact per-request context lengths. There is no automatic expiry. As a result, series count grows with request history rather than active concurrency; in native multiprocess mode, the retained samples also grow the Prometheus mmap files and scrape payloads.This change makes both diagnostic gauges disabled by default for standalone serving, Prefill services, and Decode services. When disabled, the gauges are not registered and their per-request samples are not allocated or written.
To collect these diagnostics, add the server CLI flag:
For PD deployments, pass the flag separately to each P or D service whose diagnostics are needed. Python callers can set
enable_request_context_metrics=TrueonLLM(...). The setting is propagated throughEngineArgsandConfigto the schedulers; it does not introduce an environment-variable switch.Aggregate metrics remain enabled, including queue and batch metrics, context and latency histograms, and cache counters. These retain the observability needed to diagnose queueing, latency, and cache behavior without allocating a series per request. The independent GPU timing option is unchanged.
Opting in preserves the existing retention behavior, so use it for short diagnostic captures rather than sustained throughput runs. Disabling the option does not purge samples already stored in an existing metrics directory; restart with a fresh metrics directory when a clean capture is needed, without deleting storage used by live workers.
Validation on main
124c3b0plus this change:git diff --checkpassed.