Skip to content

perf(metadata): scrub the padded input tail in one launch - #1218

Open
nperrin-fr wants to merge 3 commits into
mainfrom
perf/prep-tape-input-tail
Open

perf(metadata): scrub the padded input tail in one launch#1218
nperrin-fr wants to merge 3 commits into
mainfrom
perf/prep-tape-input-tail

Conversation

@nperrin-fr

Copy link
Copy Markdown
Collaborator

Every step refreshes the padding tail of six persistent graph input buffers, because a larger prior iteration leaves stale token ids, cache locations and request-pool slots where the captured graph still reads. As six torch fills that is six launches on the pre-replay critical path for a few kilobytes; in a profiled decode the six are the largest remaining block of elementwise work there, and none of it overlaps other streams.

PrepTape already exists for exactly this and already spells the operation (filltail), so the scrub becomes one recorded tape replayed per step. It is recorded against the persistent buffers in the constructor, so no model supplies a kernel of its own; every model's input prep gets it.

Three of the six buffers index a request pool and are int64, which the tape could not address, so filltail now carries its destination width in the descriptor's spare stride field and the interpreter stores through a 64-bit pointer for those rows. Mixed widths coexist in one stage. A non-CUDA InputBuffers keeps the torch spelling, which the backends' CPU tests need.

Summary

Test Plan

Every step refreshes the padding tail of six persistent graph input buffers,
because a larger prior iteration leaves stale token ids, cache locations and
request-pool slots where the captured graph still reads. As six torch fills
that is six launches on the pre-replay critical path for a few kilobytes; in a
profiled decode the six are the largest remaining block of elementwise work
there, and none of it overlaps other streams.

PrepTape already exists for exactly this and already spells the operation
(filltail), so the scrub becomes one recorded tape replayed per step. It is
recorded against the persistent buffers in the constructor, so no model
supplies a kernel of its own; every model's input prep gets it.

Three of the six buffers index a request pool and are int64, which the tape
could not address, so filltail now carries its destination width in the
descriptor's spare stride field and the interpreter stores through a 64-bit
pointer for those rows. Mixed widths coexist in one stage. A non-CUDA
InputBuffers keeps the torch spelling, which the backends' CPU tests need.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxaFPVQF6L13TGgrbwnDdh
Signed-off-by: Nicolas Perrin <nperrin.ai@gmail.com>
@nperrin-fr
nperrin-fr requested review from a team as code owners August 23, 2026 15:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c044aeabc7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread python/tokenspeed/runtime/execution/input_buffer.py
@nperrin-fr
nperrin-fr marked this pull request as draft August 23, 2026 17:13
nperrin-fr and others added 2 commits August 23, 2026 19:06
PrepTape wrote each step's register values straight into one persistent pinned
buffer and uploaded it asynchronously. Callers dispatch step N+1 before step N
commits (event_loop's in-flight depth), so the CPU can reach the next step's
write while the previous upload is still queued, and the in-flight tape then
reads the newer registers -- a row count that no longer matches its buffers, or
a pointer slot naming a table its own step never owned. input_buffer's bulk
pinned staging avoids exactly this and says why.

Values now live in a plain host tensor and each run copies them into a freshly
allocated pinned block, which the caching host allocator does not hand back
until that copy's stream event has completed. Measured on GB200, a run costs
46.8us of dispatch against 38.0us before, still well under the 67.4us of the
six torch fills it replaces on the input path.

Rewriting the pinned buffer under a queued upload does change what the tape
reads -- a probe that mutates it between run() and the sync flips the filled
range. Two ordinary consecutive run() calls did not reproduce that, so this is
a hazard closed by construction rather than a reproduced failure, and it comes
with no test that fails without it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DxaFPVQF6L13TGgrbwnDdh
Signed-off-by: Nicolas Perrin <nperrin.ai@gmail.com>
@nperrin-fr
nperrin-fr marked this pull request as ready for review August 24, 2026 07:54
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.

1 participant