Skip to content

perf(data-plane): avoid local batch copies - #4091

Open
rohitrango wants to merge 4 commits into
NVIDIA-NeMo:rohit/packedtensor_paddingfrom
rohitrango:rohit/packedtensor_opt
Open

perf(data-plane): avoid local batch copies#4091
rohitrango wants to merge 4 commits into
NVIDIA-NeMo:rohit/packedtensor_paddingfrom
rohitrango:rohit/packedtensor_opt

Conversation

@rohitrango

@rohitrango rohitrango commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

What does this PR do ?

Avoids unnecessary copies when fetching full or subset batches from the local data plane. It also preserves PackedTensor physical-segment sharing across replica broadcasts when that sharing reaches the worker intact, including the local data-plane path. The TQ storage codec remains unchanged.

Packed payloads are coalesced and moved to the collective device one field at a time, which bounds GPU staging memory for large multimodal batches.

Adds coverage that verifies full local fetches share tensor storage and replica broadcasts preserve PackedTensor row mappings, sharing metadata, preprocessing configuration, and physical tensors. A two-rank NCCL test covers CPU-to-GPU staging, CPU restoration, and int16 transport.

This PR is stacked on #4082 via rohit/packedtensor_padding.

Issues

None.

Usage

No user-facing API changes.

Before your PR is "Ready for review"

Pre checks:

  • Make sure you read and followed Contributor guidelines
  • Did you write any new necessary tests?
  • Did you run the unit tests and functional tests locally? Visit our Testing Guide for how to run tests
  • Did you add or update any necessary documentation? The replica-broadcast scope is documented above.

Additional Information

Validated on Slurm job 18295320 (pool0-01445, 8xH100):

uv run --frozen --group test pytest --confcutdir=tests/unit/data_plane -q tests/unit/data_plane/test_leader_broadcast.py tests/unit/data_plane/test_local_sft.py
uv run --frozen --group test pytest --confcutdir=tests/unit/data -m "not mcore" -q tests/unit/data/test_multimodal_dict.py

Results: 17 data-plane tests passed, including the two-rank NCCL test; 59 PackedTensor tests passed. Ruff and Pyrefly passed for the changed implementation files.

Signed-off-by: rohitrango <rohit.rango@gmail.com>
@rohitrango
rohitrango requested review from a team as code owners September 10, 2026 22:12
@copy-pr-bot

copy-pr-bot Bot commented Sep 10, 2026

Copy link
Copy Markdown

Auto-sync is disabled for ready for review pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@rohitrango

Copy link
Copy Markdown
Contributor Author

/ok to test 33d6b8e

Signed-off-by: rohitrango <rohit.rango@gmail.com>
@rohitrango

Copy link
Copy Markdown
Contributor Author

/ok to test b7663d1

@rohitrango
rohitrango requested a review from a team as a code owner September 10, 2026 22:40
Signed-off-by: rohitrango <rohit.rango@gmail.com>
@rohitrango

Copy link
Copy Markdown
Contributor Author

/ok to test 696bd95

@rohitrango rohitrango left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Review of the three commits on this branch (33d6b8e6b7663d13696bd95c)

No functional correctness bug found. I specifically cleared: leader/follower symmetry of the if tensor.numel(): guard, the dtype/device string round-trips, torch.Size(shape).numel() vs the numel *= dimension loop (they agree, including 0-d and 0-size shapes), narrow().view() contiguity, and the all-None segment case. The inline comments cover one perf regression, one over-broad comment, one maintainability footgun, and one test gap.

Two things these commits quietly fix — worth adding to the commit messages

  • 696bd95c removes a follower-only crash. The old empty_packed branch built PackedTensor([None] * n_rows, ...), and for a zero-logical-row field (minted by PackedTensor.empty_rows_like(v, 0) at batched_data_dict.py:840, giving tensors=[]) to_wire() returns (None, []) — so the descriptor carried n_rows=0 and every follower hit AssertionError: Input tensors to PackedTensor must be a non-empty list while the leader sailed through. The new path bypasses __init__ and reproduces len() == 0 correctly.
  • It also removes a leader/follower layout divergence. from_wire always sets _row_offsets / _segment_indices, so for a legacy-layout value the leader had _row_offsets is None and len(.tensors) == 3 while followers got _row_offsets=[0,1,2,2] and len(.tensors) == 2. len(), as_tensor() and logical_segment_counts_by_row() all agreed — which is all the existing test checks — but .tensors[i] indexing diverged. All ranks now carry the leader's exact layout.

One candidate I chased and dropped

33d6b8e6's identity short-circuit means the local adapter hands out the same PackedTensor object the partition holds, and both PackedTensor.to() and as_tensor(device=...) mutate self.tensors in place — so training looked like it could silently move the stored partition to GPU.

The chain breaks at the consumer. SFTv2 is the only local-data-plane user and is Megatron-only (sft_v2.py:400), and the Megatron worker never device-moves the full fetched batch — the only .to("cuda") is on microbatches (megatron/data.py:144), which always come from PackedTensor.slice and are therefore fresh wrappers. Not a bug today.

The residual is worth a line of comment somewhere: the invariant "never device-move the fetched batch in place" is now load-bearing, undocumented, and untested. Wiring the local plane to a DTensor worker (which does data.to("cuda") on the full batch) would make it bite.


Caveat: reviewed by reading only — I could not execute the test suite in this environment.

Comment thread nemo_rl/data_plane/worker_mixin.py Outdated
Comment thread nemo_rl/data_plane/worker_mixin.py Outdated
Comment thread nemo_rl/data/multimodal_utils.py
Comment thread tests/unit/data_plane/test_leader_broadcast.py
Signed-off-by: rohitrango <rohit.rango@gmail.com>
@rohitrango

Copy link
Copy Markdown
Contributor Author

/ok to test a609bff

@rohitrango
rohitrango force-pushed the rohit/packedtensor_opt branch from a609bff to 0bff7dc Compare September 11, 2026 00:44
@rohitrango
rohitrango requested review from a team as code owners September 11, 2026 00:44
@rohitrango
rohitrango force-pushed the rohit/packedtensor_opt branch from 0bff7dc to a609bff Compare September 11, 2026 00:47
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