Skip to content

[None][feat] Expose host/GPU per-iter time and clarify iter labeling in /metrics#14127

Merged
eopXD merged 3 commits into
NVIDIA:mainfrom
eopXD:investigation/v1-kv-cache-manager-stats
May 28, 2026
Merged

[None][feat] Expose host/GPU per-iter time and clarify iter labeling in /metrics#14127
eopXD merged 3 commits into
NVIDIA:mainfrom
eopXD:investigation/v1-kv-cache-manager-stats

Conversation

@eopXD

@eopXD eopXD commented May 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

Add three new JSON keys to each /metrics IterationStats record and fix a
labeling artifact in the iter field. All changes are Python-only and ride
the existing serializer-injection pattern used for kvCacheIterationStats
(PR #12413) — no C++ rebuild required.

New JSON keys

Key Type Meaning
hostStepTimeMS float, ms Clean per-loop CPU wall captured by profile_step(). Mirrors the log line's host_step_time. Always single-loop, unlike iterLatencyMS which spans ~2 loops under the overlap scheduler.
prevDeviceStepTimeMS float, ms GPU forward time read via the ping-pong CUDA event pair in profile_step(). The "prev_" prefix reflects that under steady state the value lags hostStepTimeMS on the same record by 1 loop.
schedulerMode "overlap" | "non_overlap" Per-record indicator so consumers can interpret iterLatencyMS without inspecting server config. PP (pp_size > 1) always reports "overlap" since _executor_loop_pp is structurally overlap-style (BatchStatePP is queued in iter N and consumed in a later loop), regardless of disable_overlap_scheduler.

iter field relabel

stats.iter is now stamped at batch construction time in
_get_init_iter_stats (the loop that BUILT the batch) instead of at
consumption time in _update_iter_stats. Under the overlap and PP
schedulers _process_iter_stats runs in a later loop than the one that
built the batch, so the live iter_counter mislabeled records by 1+ iters.

Note: this changes how /metrics jsonl aligns with server_runtime.log.
Under overlap mode the two streams are now off by 1 iter (the log line still
stamps from the live counter at print time, which is intentional and
unchanged here).

Why

These changes address three concrete pain points users hit when joining
/metrics data against batch composition for performance benchmarking:

  1. numCtxTokens (and other inflightBatchingStats) appeared to lag the
    iter label by 1+ iterations under overlap — actually the iter label
    itself was wrong; the batch composition was correctly attributed.
  2. iterLatencyMS is misleading for absolute per-loop CPU cost under
    overlap (spans ~2 loops, sum ≈ 2 × wall_time). hostStepTimeMS gives
    the clean per-loop value, and schedulerMode lets consumers branch.
  3. GPU per-iter time was only available in the text log (prev_device_step_time),
    not in the JSON. prevDeviceStepTimeMS exposes it directly to /metrics
    consumers.

Implementation summary

  • tensorrt_llm/_torch/pyexecutor/py_executor.py:
    • _profiler.profile_step(): split timing capture from log emission so
      timing is stashed on self._latest_host_step_time_ms /
      self._latest_prev_device_step_time_ms whenever
      enable_iter_perf_stats or print_iter_log is on.
    • _get_init_iter_stats: stamp stats.iter at construction.
    • _update_iter_stats: removed the consumption-time stats.iter overwrite
      (replaced with a comment).
    • _process_iter_stats: snapshot per-loop timings and pass through the
      append/queue path; documented iterLatencyMS semantics under both
      schedulers.
    • _append_iter_stats: extended with host_step_time_ms /
      prev_device_step_time_ms kwargs; computes schedulerMode with the
      PP-as-overlap rule; injects new keys into the gather_all_ranks
      per-rank dict and into the legacy tuple (now 7 entries, defensive
      len() > N access in the serializer keeps older shapes readable).
  • tensorrt_llm/_torch/pyexecutor/adp_iter_stats.py: ADPIterStatsRecord
    carries the new timing fields; queue / finalize / _discard updated
    to preserve them across the ADP fanout delay. Rank-0 values are broadcast
    to all rank rows (true per-rank timing would require widening the
    rank-state allgather payload — left for a future PR).
  • tensorrt_llm/executor/base_worker.py: _stats_serializer reads tuple
    slots [4]/[5]/[6] defensively and injects the new JSON keys with
    field-level comments explaining the semantics.

Test plan

  • Build wheel and serve a model with enable_iter_perf_stats=true + enable_block_reuse=true
  • Verify GET /metrics JSON contains hostStepTimeMS, prevDeviceStepTimeMS, and schedulerMode on each record
  • Verify iter field matches construction-time iter (numbers are 1 lower under overlap mode than before)
  • Validate that a PP run (pp_size > 1) reports schedulerMode = "overlap" in /metrics even when disable_overlap_scheduler=True.
  • Confirm log emission still works when print_iter_log=true (gated condition was widened to also fire when enable_iter_perf_stats=true)
  • Confirm legacy 4-/3-tuple stat consumers (e.g. the TRT-engine path returning 3-tuples) still serialize OK
  • Run unit tests under tests/unittest/
  • Validate ADP fanout path (multi-rank attention-DP run) still emits records

[x] Write code carefully and responsibly.

@eopXD
eopXD requested review from a team as code owners May 14, 2026 07:51
@eopXD
eopXD requested review from hchings and lancelly May 14, 2026 07:51
@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR extends iteration statistics capture to include per-loop CPU timing, GPU forward timing from the preceding loop, and scheduler mode (overlap vs non-overlap), propagating these values through ADP fanout and metrics output with backward-compatible tuple deserialization.

Changes

Iteration Stats Timing Extension

Layer / File(s) Summary
ADP iteration stats schema and buffer management
tensorrt_llm/_torch/pyexecutor/adp_iter_stats.py
ADPIterStatsRecord adds two optional float fields for timing. ADPIterStatsBuffer maintains rank-0-only dictionaries keyed by iteration ID, stores timing in queue() when is_rank0 is true, includes timing in finalize() output, and clears entries in _discard().
PyExecutor timing capture and stats initialization
tensorrt_llm/_torch/pyexecutor/py_executor.py (lines 578–586, 1046–1091, 1132–1137, 1234–1238)
Executor stores latest host and ping-pong GPU timings from profiler in new instance fields. Profiler computation is gated by timing-capture condition and writes values to executor. Iteration stats initialization stamps stats.iter from iter_counter at construction time; updates guard against re-stamping.
Stats buffer format and iteration latency computation
tensorrt_llm/_torch/pyexecutor/py_executor.py (lines 1569–1618)
Stats tuple layout extended with host timing, device timing, and scheduler mode. _process_iter_stats computes iter_latency_ms according to scheduler mode semantics and snapshots latest profiled timings for downstream propagation.
Iteration stats append with timing and scheduler mode
tensorrt_llm/_torch/pyexecutor/py_executor.py (lines 1459–1503, 1543–1547)
_append_iter_stats accepts external timing parameters and derives scheduler mode from disable_overlap_scheduler. Metrics JSON now includes hostStepTimeMS, prevDeviceStepTimeMS, and schedulerMode per rank.
Stats processing and ADP/metrics propagation
tensorrt_llm/_torch/pyexecutor/py_executor.py (lines 1630–1642, 3237–3240)
_process_iter_stats passes timing fields to both ADP queuing and direct metrics append. ADP finalize-to-append wiring forwards timing from record objects into _append_iter_stats.
BaseWorker stats deserialization
tensorrt_llm/executor/base_worker.py
_stats_serializer uses len() checks for backward compatibility, conditionally extracting and injecting host timing, device timing, and scheduler mode into the serialized stats dictionary.

🎯 3 (Moderate) | ⏱️ ~25 minutes


Possibly Related PRs

  • NVIDIA/TensorRT-LLM#13649: Introduces the ADP iter-stats queuing and fanout pipeline that this PR extends with timing field propagation.

Suggested Reviewers

  • zhenhuaw-me
  • Tabrizian
  • achartier
  • pcastonguay
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: exposing per-iteration host and GPU timing metrics while fixing iter labeling in /metrics output.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The PR description is comprehensive and follows the template structure with clear sections covering Summary, New JSON keys, Implementation details, and Test plan.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tensorrt_llm/_torch/pyexecutor/py_executor.py`:
- Around line 1498-1503: The scheduler_mode calculation can mislabel PP runs
because _executor_loop_pp yields overlap-style iterLatencyMS even when
self.disable_overlap_scheduler is True; update the logic that sets
scheduler_mode so that if self.dist.pp_size > 1 it is always "overlap",
otherwise keep the existing check (use "non_overlap" only when no pipeline
parallelism and disable_overlap_scheduler is True), and leave hostStepTimeMS
comment unchanged; update the assignment that defines scheduler_mode to
reference self.dist.pp_size and self.disable_overlap_scheduler accordingly so PP
executions report "overlap".
- Around line 1611-1617: The IterationStats emitted in _executor_loop is
snapshotting _latest_host_step_time_ms and _latest_prev_device_step_time_ms too
early (profile_step() updates them at the start of the next loop), so iter N
gets stale timings; modify _executor_loop to buffer the produced IterationStats
(e.g., pending_iteration_stats) and only attach and emit timing fields when the
next loop starts and profile_step() has populated
_latest_host_step_time_ms/_latest_prev_device_step_time_ms, then flush the
pending record; apply the same pending-buffer/delayed-flush change to the other
occurrence that snapshots timings (around the block at lines referenced
1638-1642) so all non-overlap exports wait one iteration for correct timing
values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 08f5c3aa-7be5-4cfb-ae8c-d428a84c5b47

📥 Commits

Reviewing files that changed from the base of the PR and between 9a9d73d and 7e672eb.

📒 Files selected for processing (3)
  • tensorrt_llm/_torch/pyexecutor/adp_iter_stats.py
  • tensorrt_llm/_torch/pyexecutor/py_executor.py
  • tensorrt_llm/executor/base_worker.py

Comment thread tensorrt_llm/_torch/pyexecutor/py_executor.py Outdated
Comment thread tensorrt_llm/_torch/pyexecutor/py_executor.py
@eopXD
eopXD force-pushed the investigation/v1-kv-cache-manager-stats branch from 7e672eb to 0441ea8 Compare May 18, 2026 08:10
@eopXD

eopXD commented May 18, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #48869 [ run ] triggered by Bot. Commit: 0441ea8 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #48869 [ run ] completed with state SUCCESS. Commit: 0441ea8
/LLM/main/L0_MergeRequest_PR pipeline #38622 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@eopXD
eopXD force-pushed the investigation/v1-kv-cache-manager-stats branch from 0441ea8 to d1e7d9f Compare May 19, 2026 03:50
@eopXD

eopXD commented May 19, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49075 [ run ] triggered by Bot. Commit: d1e7d9f Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49075 [ run ] completed with state SUCCESS. Commit: d1e7d9f
/LLM/main/L0_MergeRequest_PR pipeline #38801 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

…in /metrics

Add three new JSON keys to each /metrics IterationStats record and fix a
labeling artifact in the `iter` field. All changes are Python-only and ride
the existing serializer-injection pattern used for kvCacheIterationStats —
no C++ rebuild required.

New JSON keys:
- hostStepTimeMS: clean per-loop CPU wall captured by profile_step().
  Mirrors the log line's `host_step_time`. Always a single-loop measurement,
  unlike iterLatencyMS which spans ~2 loops under the overlap scheduler.
- prevDeviceStepTimeMS: GPU forward time read via the ping-pong CUDA event
  pair in profile_step(). The "prev_" prefix reflects that under steady
  state the value lags hostStepTimeMS on the same record by one loop (see
  the ping-pong design comment in _profiler).
- schedulerMode: "overlap" or "non_overlap". Per-record indicator so
  consumers can interpret iterLatencyMS without inspecting server config.

iter relabel:
- stats.iter is now stamped at batch construction time in
  _get_init_iter_stats (the loop that BUILT the batch), instead of at
  consumption time in _update_iter_stats. Under the overlap and PP
  schedulers _process_iter_stats runs in a later loop than the one that
  built the batch, so the live iter_counter mislabeled records by 1+ iters.
- Note: this changes /metrics jsonl alignment with server_runtime.log.
  Under overlap mode the two streams are now off by 1 iter (the log still
  stamps from the live counter at print time).

Signed-off-by: Yueh-Ting Chen <yuehtingc@nvidia.com>
Signed-off-by: Yueh-Ting Chen <yueh.ting.chen@gmail.com>
@eopXD
eopXD force-pushed the investigation/v1-kv-cache-manager-stats branch from d1e7d9f to 1e3acc5 Compare May 21, 2026 03:39
@eopXD

eopXD commented May 21, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49575 [ run ] triggered by Bot. Commit: 1e3acc5 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49575 [ run ] completed with state SUCCESS. Commit: 1e3acc5
/LLM/main/L0_MergeRequest_PR pipeline #39201 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

Link to invocation

@eopXD

eopXD commented May 22, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49838 [ run ] triggered by Bot. Commit: 1e3acc5 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #49838 [ run ] completed with state SUCCESS. Commit: 1e3acc5
/LLM/main/L0_MergeRequest_PR pipeline #39422 completed with status: 'SUCCESS'

CI Report

Link to invocation

@Superjomn Superjomn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there any tests to protect this feature? Or it will be broken easily in the following iterations.

Add two focused tests for the changes in 1e3acc5 (Expose host/GPU
per-iter time and clarify iter labeling in /metrics):

1. test_update_iter_stats_does_not_overwrite_construction_iter
   Regression guard: _update_iter_stats must not re-stamp stats.iter from
   the live self.iter_counter. Before the fix, under overlap and PP
   schedulers the consuming loop ran 1+ iters after the loop that built
   the batch, so re-stamping mislabeled records. The test passes a batch
   stamped at iter=17, advances iter_counter to 999, and confirms the
   construction-time stamp survives.

2. test_serializer_7_tuple_emits_new_timing_and_scheduler_mode
   Verifies the three new JSON keys (hostStepTimeMS, prevDeviceStepTimeMS,
   schedulerMode) emitted from the 7-tuple slots in BaseWorker._stats_serializer.
   Also confirms a None timing slot omits the key (not null) so consumers
   can distinguish "first iter / unavailable" from a real zero.

Signed-off-by: Yueh-Ting Chen <yueh.ting.chen@gmail.com>
Signed-off-by: Yueh-Ting Chen <yuehtingc@nvidia.com>
@eopXD

eopXD commented May 25, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50168 [ run ] triggered by Bot. Commit: 7b7dc05 Link to invocation

@Superjomn Superjomn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50168 [ run ] completed with state SUCCESS. Commit: 7b7dc05
/LLM/main/L0_MergeRequest_PR pipeline #39712 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@eopXD

eopXD commented May 26, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50283 [ run ] triggered by Bot. Commit: 7b7dc05 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50283 [ run ] completed with state SUCCESS. Commit: 7b7dc05
/LLM/main/L0_MergeRequest_PR pipeline #39814 completed with status: 'SUCCESS'

CI Report

Link to invocation

Comment thread tensorrt_llm/_torch/pyexecutor/py_executor.py

@lancelly lancelly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM~ Thanks!

@eopXD

eopXD commented May 27, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50550 [ run ] triggered by Bot. Commit: 720abd2 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50550 [ run ] completed with state FAILURE. Commit: 720abd2
/LLM/main/L0_MergeRequest_PR pipeline #40054 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@eopXD

eopXD commented May 28, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50645 [ run ] triggered by Bot. Commit: 720abd2 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50645 [ run ] completed with state SUCCESS. Commit: 720abd2
/LLM/main/L0_MergeRequest_PR pipeline #40139 completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@eopXD

eopXD commented May 28, 2026

Copy link
Copy Markdown
Collaborator Author

/bot skip --comment "Given that this MR has earned pre-merge CI success before. The latest merge is only on resolving conflict to the print calls. The failing pipeline is un-related to the change introduced in this MR. Skipping the CI now."

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50733 [ skip ] triggered by Bot. Commit: 720abd2 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #50733 [ skip ] completed with state SUCCESS. Commit: 720abd2
Skipping testing for commit 720abd2

Link to invocation

@eopXD
eopXD merged commit fe07957 into NVIDIA:main May 28, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants