Skip to content

[Performance] Chunk process-slot worker results in AsyncBatchedCollector - #4305

Merged
vmoens merged 6 commits into
mainfrom
async-collector-worker-owned-replay
Sep 9, 2026
Merged

[Performance] Chunk process-slot worker results in AsyncBatchedCollector#4305
vmoens merged 6 commits into
mainfrom
async-collector-worker-owned-replay

Conversation

@vmoens

@vmoens vmoens commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

Stack: #4305#4306#4307#4308 (base).

Batch worker transitions to reduce queue, unpickling, and replay-write overhead.

collector = AsyncBatchedCollector(
    ...,
    transition_chunk_size=64,  # ProcessSlotTransport only; default: 1
)

Chunks preserve stream order and frame budgets. Larger chunks increase latency and in-flight memory; batches become dense with tensor env_index.

Coverage: ordering/budgets, replay routing, trajectories, pause/shutdown. Reported CPU benchmark: ~6× less driver CPU/frame.

@pytorch-bot

pytorch-bot Bot commented Sep 8, 2026

Copy link
Copy Markdown

🔗 Helpful Links

🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/rl/4305

Note: Links to docs will display an error until the docs builds have been completed.

✅ No Failures

As of commit 6108be6 with merge base b7f348e (image):
💚 Looks good so far! There are no failures yet. 💚

This comment was automatically generated by Dr. CI and updates every 15 minutes.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 8, 2026
@github-actions github-actions Bot added Documentation Improvements or additions to documentation Benchmarks rl/benchmark changes Collectors Integrations/torch_geometric Integrations Performance Performance issue or suggestion for improvement labels Sep 8, 2026
@vmoens vmoens added the benchmarks/trigger Run the full benchmark suite on main right after this PR merges label Sep 8, 2026
@vmoens

vmoens commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator Author
Measured locally:     0.226 -> 0.037 ms/frame (~6x less driver CPU)
Projected collection: ~1.5x; ceiling ~370 -> ~1,000 steps/s

The collection estimates are unmeasured GPU projections. Reaching the ceiling requires sufficient learner throughput (#4307).

@vmoens

vmoens commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator Author

Measured on the target hardware (64-environment DreamerV3 run on a pixel task, one 4-GPU node, process-slot inference server with a static batch of 64, compiled and CUDA-graph learner step, bf16, train ratio 16), comparing the full stack #4305 + #4306 + #4307 + #4308 (with transition_chunk_size=64) against the same configuration without these four PRs, over the same elapsed window of the two runs (1,000 s to 4,428 s after training start):

environment steps/s learner updates/s (32x256)
without the stack 361 0.70
with the stack 1,249 2.44
speed-up 3.46x 3.46x

The unthrottled collection phase before training reached 1,254 steps/s (298 before), the learner GPU now shows sustained full-utilization bursts instead of about a quarter duty cycle, and the run had no errors over the measured 1.3 hours. The two rates move together because the train ratio couples them, so the stack lifted both the collection ceiling and the learner cadence past the previous limits. This measures the combined effect of the four PRs; per-PR attribution has not been measured.

@vmoens

vmoens commented Sep 9, 2026

Copy link
Copy Markdown
Collaborator Author

Learning check (09 Sep): on the 64-environment task the stack keeps its throughput without CUDA-graph inference batches (1,234 env steps/s and 2.41 updates/s with inference_static_batch_size=null, against 1,249 with them) and the learning curve then matches the previous example (episode score 3.9 / 4.2 / 4.4 at 3-4.5M environment steps). The collapse seen with static batches is explained and guarded in #4310 (the acting policy rewrites its state/belief input keys, which a captured CUDA graph cannot follow).

vmoens and others added 6 commits September 9, 2026 10:24
Add an opt-in transition_chunk_size argument for the ProcessSlotTransport
path. Each environment worker process accumulates that many consecutive
transitions and sends them to the driver as one dense message instead of
one message per transition. The driver receives one consolidated
TensorDict per chunk, keeps chunks as dense blocks that are split only
where a batch or the total frame budget ends (the remainder is carried
into the next batch in order), assembles each batch with torch.cat and
writes it to the replay buffer with the existing single routed extend.
The driver's per-transition Python is amortized over the chunk; one
result-capacity permit now covers a whole chunk.

Profiling a 64-environment DreamerV3 Minecraft run on a 4-GPU node with
inference served from the environment processes showed the driver main
thread spending about 1.1 ms per transition in _rollout_frames (queue
get and unpickling, the unpickler's filelock audit hook, replay extend)
while environment workers waited in result_capacity.acquire: the
bounded result queue back-pressured the environments at 371 steps/s.

The default (transition_chunk_size=1) keeps the previous behavior,
including lazy_stack batch assembly for every existing mode. Chunking
requires ProcessSlotTransport and raises otherwise. Chunked batches are
dense TensorDicts with a tensor env_index. pause(), shutdown(),
total_frames trimming, background collection and completed-trajectory
yielding work with chunks; partial chunks stay in the worker while
paused and are dropped, like queued results, when the collector stops.

Worker-owned replay streams were considered and not taken here: the
collected batch is still needed in the driver for postproc and
post_collect_hook, sampler window state, writer generation stamps and
conditional patches live in the learner process, and CUDA replay
storages would be excluded. Shipping chunks through shared-memory slots
instead of the queue is a possible follow-up.

Benchmarks: bench_collectors.py gains --transition-chunk-size and
replay-mode support for async-process-slot; test_collectors_benchmark.py
gains an async-process-slots-chunked series documented in
ASYNC_BENCHMARKS.md. Tests cover exact budgets and per-stream ordering
of dense chunked batches, routed writes into a StreamingSliceSampler
ensemble with contiguous sampled windows, backpressure with pause and
shutdown, trajectory yielding across chunk boundaries and validation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add a driver_cpu_ms_per_frame column: the benchmarked process's user
plus system CPU time over the measured window divided by the collected
frames. End-to-end frames per second only exposes the driver's
per-transition cost once the driver saturates; with process-backed
environments and inference this column isolates the driver's own
transition-path cost directly, which is what transition_chunk_size
targets. Thread backends include their coordinator and inference-server
threads in the same figure, as documented on the field.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@vmoens
vmoens force-pushed the async-collector-worker-owned-replay branch from d3e9b60 to 6108be6 Compare September 9, 2026 09:41
@vmoens
vmoens merged commit 5076ae1 into main Sep 9, 2026
128 checks passed
@vmoens
vmoens deleted the async-collector-worker-owned-replay branch September 9, 2026 11:21
vmoens added a commit that referenced this pull request Sep 9, 2026
…tor (#4305)

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

benchmarks/trigger Run the full benchmark suite on main right after this PR merges Benchmarks rl/benchmark changes CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Collectors Documentation Improvements or additions to documentation Integrations/torch_geometric Integrations Performance Performance issue or suggestion for improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant