Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
98bc9ce
feat(data-plane): default the mooncake_cpu transport to RDMA
ZhiyuLi-Nvidia Aug 7, 2026
a53d55b
fix(data-plane): drop the TQ actor runtime_env injection
ZhiyuLi-Nvidia Aug 11, 2026
d7d46cf
test: add DeepSeek-V3 mooncake_cpu TQ coverage recipe
ZhiyuLi-Nvidia Aug 11, 2026
063c815
refactor(data-plane): tidy up after the runtime_env removal
ZhiyuLi-Nvidia Aug 11, 2026
128ec55
fix(data-plane): bound mooncake sizing to a fraction of host RAM
ZhiyuLi-Nvidia Aug 11, 2026
7a6f086
refactor(data-plane): derive the mooncake memory bound from cluster.g…
ZhiyuLi-Nvidia Aug 11, 2026
2236342
docs(data-plane): correct the mooncake segment residency comment
ZhiyuLi-Nvidia Aug 11, 2026
41c36e0
fix(data-plane): default mooncake sizing to 64/4 GiB per client
ZhiyuLi-Nvidia Aug 11, 2026
1b661c5
fix(data-plane): register the DSv3 TQ recipe and sync sizing docs
ZhiyuLi-Nvidia Aug 11, 2026
e69748d
test: drop the DSv3 TQ recipe and pin mooncake coverage to RDMA
ZhiyuLi-Nvidia Aug 11, 2026
d45aa48
docs(data-plane): trim the mooncake sizing note
ZhiyuLi-Nvidia Aug 11, 2026
59855dc
fix(data-plane): stop silently downgrading mooncake_cpu to TCP
ZhiyuLi-Nvidia Aug 11, 2026
e6be8bd
test: opt TCP-only mooncake tests into the TCP transport
ZhiyuLi-Nvidia Aug 11, 2026
6dad0f7
fix(data-plane): make mooncake_cpu RDMA-only
ZhiyuLi-Nvidia Aug 11, 2026
b985ff7
fix(data-plane): restore required data_plane keys and gate RDMA on ve…
ZhiyuLi-Nvidia Aug 12, 2026
5ae26a5
ci: expose host RDMA devices to GPU test containers
ZhiyuLi-Nvidia Aug 12, 2026
640647f
ci: make RDMA coverage self-verifying and match it locally
ZhiyuLi-Nvidia Aug 12, 2026
7864f96
feat(data-plane): prefer InfiniBand over RoCE for the mooncake transport
ZhiyuLi-Nvidia Aug 12, 2026
a10ac77
feat(data-plane): use all IB rails and reuse RDMA-registered buffers
ZhiyuLi-Nvidia Aug 14, 2026
f296a3f
fix(data-plane): scale num_storage_units with the cluster
ZhiyuLi-Nvidia Aug 14, 2026
ad46f26
style: apply ruff-format to the mooncake staging patch
ZhiyuLi-Nvidia Aug 14, 2026
fd4a662
fix(data-plane): update schema-warmup test for the skip guard
ZhiyuLi-Nvidia Aug 14, 2026
4afbd19
fix(data-plane): harden the mooncake staging pool and check registrat…
ZhiyuLi-Nvidia Aug 15, 2026
ff4a8cf
fix(data-plane): nest data_plane sizing under the backend that reads it
ZhiyuLi-Nvidia Aug 16, 2026
7c043fc
fix(data-plane): pin each mooncake transfer's peer rail to the local one
ZhiyuLi-Nvidia Aug 16, 2026
dcf7f9c
test: dump RDMA rail/NUMA mapping in the mooncake functional test
ZhiyuLi-Nvidia Aug 17, 2026
2ae8e95
fix(data-plane): pin the RoCE GID index in every process, not just th…
ZhiyuLi-Nvidia Aug 17, 2026
ba61440
test: surface mooncake_master's log when the store fails to come up
ZhiyuLi-Nvidia Aug 17, 2026
39fd0f2
test: honour MC_MOONCAKE_DEVICE in the temporary device_name dump
ZhiyuLi-Nvidia Aug 17, 2026
49a69a7
test: surface TransferQueue's bootstrap log and mooncake_master state
ZhiyuLi-Nvidia Aug 17, 2026
9d9b169
fix(data-plane): apply mooncake engine env before Ray snapshots it
ZhiyuLi-Nvidia Aug 17, 2026
fcbb403
refactor(data-plane): trim the engine-env docstrings to what they decide
ZhiyuLi-Nvidia Aug 17, 2026
b19408f
test: add multi-node mooncake coverage on 4-GPU nodes
ZhiyuLi-Nvidia Aug 17, 2026
cbc36a7
refactor(data-plane): read sizing only from the nested block
ZhiyuLi-Nvidia Aug 17, 2026
943798a
feat(data-plane): expose the staging pool's per-slot size
ZhiyuLi-Nvidia Aug 17, 2026
9c302f9
docs(data-plane): say what staging_buffer_size actually bounds
ZhiyuLi-Nvidia Aug 17, 2026
9de0d3c
fix(data-plane): require num_storage_units instead of defaulting to 2
ZhiyuLi-Nvidia Aug 18, 2026
6ceac41
fix(data-plane): mark schema fields warmed only after the write lands
ZhiyuLi-Nvidia Aug 18, 2026
c770635
test(data-plane): pin literals in the mooncake defaults-fallback test
ZhiyuLi-Nvidia Aug 18, 2026
5fe5b7b
docs(data-plane): fix docs claiming legacy flat keys are rejected
ZhiyuLi-Nvidia Aug 18, 2026
9b4a38c
fix(data-plane): fix two test arity mismatches from the max_bytes plu…
ZhiyuLi-Nvidia Aug 18, 2026
a842b94
ci: gate RDMA passthrough on uverbs*, matching rdma_devices()
ZhiyuLi-Nvidia Aug 18, 2026
d79fc30
fix(data-plane): supply num_storage_units for the async-gym SC functi…
ZhiyuLi-Nvidia Aug 18, 2026
04694f7
test(data-plane): cover init_ray threading mooncake env into runtime_env
ZhiyuLi-Nvidia Aug 18, 2026
a63b604
refactor(data-plane): revert init_ray's data_plane_cfg parameter
ZhiyuLi-Nvidia Aug 18, 2026
0c3e007
style: ruff-format _staging_pool's constructor call
ZhiyuLi-Nvidia Aug 18, 2026
3eca93a
refactor(data-plane): apply /simplify team review to the mooncake diff
ZhiyuLi-Nvidia Aug 18, 2026
815f32c
fix(data-plane): fix pyrefly type error from the n_slots bail-clean fix
ZhiyuLi-Nvidia Aug 18, 2026
59c51a9
fix(data-plane): fix growth-vs-outlier size in the staging-pool growt…
ZhiyuLi-Nvidia Aug 18, 2026
a3057fc
fix(data-plane): restore _MAX headroom instead of shrinking the growt…
ZhiyuLi-Nvidia Aug 18, 2026
60de859
fix(single-controller): complete the test fixture's data_plane config
ZhiyuLi-Nvidia Aug 18, 2026
f4444af
fix(data-plane): make TransferQueue's mooncake retry count configurable
ZhiyuLi-Nvidia Aug 18, 2026
9f92de4
Revert "fix(data-plane): make TransferQueue's mooncake retry count co…
ZhiyuLi-Nvidia Aug 18, 2026
7a55031
fix(data-plane): dedupe redundant same-domain rails in rdma_devices()
ZhiyuLi-Nvidia Aug 19, 2026
69956c9
feat(data-plane): make per-NUMA-domain rail dedup configurable
ZhiyuLi-Nvidia Aug 19, 2026
277bcbf
fix(data-plane): scope rail dedup to RoCE only, never InfiniBand
ZhiyuLi-Nvidia Aug 19, 2026
d31a0a9
docs(data-plane): correct MC_ENABLE_DEST_DEVICE_AFFINITY=0 override c…
ZhiyuLi-Nvidia Aug 19, 2026
07f8699
feat(data-plane): log kept/dropped RoCE rails on dedup
ZhiyuLi-Nvidia Aug 19, 2026
e830bbd
refactor(data-plane): rename dedupe_rails_per_numa_domain to dedupe_r…
ZhiyuLi-Nvidia Aug 19, 2026
e871567
refactor(data-plane): dedupe RDMA-detection bash logic, trim repeated…
ZhiyuLi-Nvidia Aug 19, 2026
d76c499
fix(data-plane): add dedupe_roce_rails_per_numa_domain to the grpo_ma…
ZhiyuLi-Nvidia Aug 19, 2026
a887282
refactor(ci): dedupe the CI action's RDMA-detection copy into detect_…
ZhiyuLi-Nvidia Aug 19, 2026
da3a8ee
fix(data-plane): export MC_ENABLE_DEST_DEVICE_AFFINITY, drop RoCE rai…
ZhiyuLi-Nvidia Aug 20, 2026
d507518
fix(data-plane): configure mooncake MC_* before the engine snapshots …
ZhiyuLi-Nvidia Aug 20, 2026
68b587a
refactor(data-plane): scope the staging-pool lock to a registry object
ZhiyuLi-Nvidia Aug 20, 2026
3d1b7fa
Update nemo_rl/data_plane/README.md
ZhiyuLi-Nvidia Aug 22, 2026
779c38b
Update nemo_rl/data_plane/README.md
ZhiyuLi-Nvidia Aug 22, 2026
e665dc3
Update nemo_rl/data_plane/adapters/transfer_queue_env.py
ZhiyuLi-Nvidia Aug 22, 2026
c2bd346
Update nemo_rl/data_plane/adapters/transfer_queue.py
ZhiyuLi-Nvidia Aug 22, 2026
a92eb15
Update nemo_rl/data_plane/interfaces.py
ZhiyuLi-Nvidia Aug 22, 2026
9eb27c2
fix(data-plane): fail loud on TQ shape drift, fix router-failover fla…
ZhiyuLi-Nvidia Aug 22, 2026
2def95b
style(data-plane): satisfy ruff-format on the shape-drift error message
ZhiyuLi-Nvidia Aug 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/actions/test-template/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,41 @@ runs:
echo -e "\033[1;34m│ script : ${{ inputs.script }}\033[0m"
echo -e "\033[1;34m│ runner : ${{ inputs.runner }}\033[0m"
echo -e "\033[1;34m│ container : ${{ inputs.registry }}/${{ inputs.image }}:${{ inputs.image-tag || github.run_id }}\033[0m"
# Expose the host's RDMA devices so mooncake_cpu tests exercise the real
# transport instead of finding no verbs device and skipping. A container
# sees the host's /sys/class/infiniband but does NOT inherit
# /dev/infiniband/uverbs*, which is what libibverbs actually opens;
# ibv_reg_mr additionally needs IPC_LOCK and an unlimited memlock rlimit
# to pin its registrations.
#
# Requires an mlx5 device on the host, either fabric — rdma_devices()
# prefers InfiniBand and falls back to RoCE. When the host has one,
# NEMO_RL_REQUIRE_MOONCAKE promotes the tests' skip into a failure, so
# losing this passthrough surfaces as a red job rather than silently
# dropping mooncake coverage.
#
# --device against a missing path makes docker run itself fail, which
# would break every test rather than only the RDMA ones — hence the
# host-side check (see detect_rdma.sh for what it gates on).
source "${{ github.workspace }}/${{ github.run_id }}/${{ steps.uuid.outputs.id }}/nemo-rl/tests/scripts/detect_rdma.sh"
RDMA_FLAGS=()
# MC_ENABLE_DEST_DEVICE_AFFINITY is normally decided by
# configure_engine_env in nemo_rl/data_plane/adapters/transfer_queue_env.py,
# which sets it only on a RoCE-only fabric. Passing it here overrides that
# gate (an already-set value is left alone) and also covers processes that
# never run the data-plane factory, e.g. a bare pytest invocation.
if [[ "${{ inputs.is_doc_test }}" != "true" ]] && rdma_device_available; then
RDMA_FLAGS=(--device=/dev/infiniband --cap-add=IPC_LOCK --ulimit memlock=-1
--env NEMO_RL_REQUIRE_MOONCAKE=1
--env MC_ENABLE_DEST_DEVICE_AFFINITY=1)
fi
echo -e "\033[1;34m│ rdma : ${RDMA_FLAGS[*]:-none}\033[0m"
echo -e "\033[1;34m└──────────────────────────────────────────────────────────────────────────┘\033[0m"

echo "::group::Logs"
docker run --rm -u root --runtime=nvidia --gpus all \
--shm-size=64g \
"${RDMA_FLAGS[@]}" \
--env TRANSFORMERS_OFFLINE=0 \
--env GHA_RUNNER=${{ inputs.runner }} \
--env HYDRA_FULL_ERROR=1 \
Expand Down
16 changes: 12 additions & 4 deletions examples/configs/grpo_math_1B.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -534,11 +534,19 @@ data_plane:
enabled: false
impl: transfer_queue
backend: "simple" # TQ storage backend ('simple' or 'mooncake_cpu')
storage_capacity: 1000000 # max samples retained per partition
num_storage_units: 2 # storage shards
claim_meta_poll_interval_s: 0.5 # blocking-claim poll cadence
global_segment_size: 549755813888 # 512 GiB — used when backend == "mooncake_cpu"
local_buffer_size: 68719476736 # 64 GiB — used when backend == "mooncake_cpu"
# Backend-specific blocks: only the one named by `backend` is read, and an
# absent block means that backend's defaults (see SimpleStorageConfig /
# MooncakeCpuConfig in nemo_rl/data_plane/interfaces.py).
simple:
storage_capacity: 1000000 # max samples retained per partition
num_storage_units: ${mul:2, ${cluster.num_nodes}} # TQ wants >= 2 per node
mooncake_cpu:
# Per client process — see MooncakeCpuConfig before raising these.
global_segment_size: 68719476736 # 64 GiB/process
local_buffer_size: 4294967296 # 4 GiB/process
reuse_registered_buffers: true # reuse RDMA-registered buffers
staging_buffer_size: 268435456 # 256 MiB/pool slot; bigger transfers bypass the pool
# observability: # NotRequired
# enabled: false

Expand Down
3 changes: 3 additions & 0 deletions examples/nemo_gym/run_grpo_nemo_gym.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
)
from nemo_rl.algorithms.utils import get_tokenizer
from nemo_rl.data.utils import setup_response_data
from nemo_rl.data_plane.factory import maybe_configure_data_plane_env
from nemo_rl.distributed.virtual_cluster import init_ray
from nemo_rl.environments.nemo_gym import (
setup_nemo_gym_config,
Expand Down Expand Up @@ -224,6 +225,8 @@ def main() -> None:
pprint.pprint(config)

with rl_init_timer.time("ray_connect"):
# Must precede init_ray() — see maybe_configure_data_plane_env's docstring.
maybe_configure_data_plane_env(config.data_plane)
init_ray()

# `is_trajectory_collection` is a NeMo-RL-side control-flow knob; pop it
Expand Down
3 changes: 3 additions & 0 deletions examples/run_grpo.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
)
from nemo_rl.algorithms.utils import get_tokenizer
from nemo_rl.data.utils import setup_response_data
from nemo_rl.data_plane.factory import maybe_configure_data_plane_env
from nemo_rl.distributed.virtual_cluster import init_ray
from nemo_rl.models.generation import configure_generation_config
from nemo_rl.utils.config import (
Expand Down Expand Up @@ -108,6 +109,8 @@ def main() -> None:
)

with rl_init_timer.time("ray_connect"):
# Must precede init_ray() — see maybe_configure_data_plane_env's docstring.
maybe_configure_data_plane_env(config.data_plane)
init_ray()

# setup tokenizer
Expand Down
3 changes: 3 additions & 0 deletions examples/run_grpo_single_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
setup_single_controller,
)
from nemo_rl.algorithms.utils import get_tokenizer
from nemo_rl.data_plane.factory import maybe_configure_data_plane_env
from nemo_rl.distributed.virtual_cluster import init_ray
from nemo_rl.environments.nemo_gym import setup_nemo_gym_config
from nemo_rl.models.generation import configure_generation_config
Expand Down Expand Up @@ -115,6 +116,8 @@ def main() -> None:
f"📊 Using checkpoint directory: {config.checkpointing['checkpoint_dir']}"
)

# Must precede init_ray() — see maybe_configure_data_plane_env's docstring.
maybe_configure_data_plane_env(config.data_plane)
init_ray()

tokenizer = get_tokenizer(config.policy["tokenizer"])
Expand Down
3 changes: 3 additions & 0 deletions examples/run_grpo_sliding_puzzle.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
from nemo_rl.algorithms.grpo import MasterConfig, grpo_train, setup
from nemo_rl.algorithms.utils import get_tokenizer, set_seed
from nemo_rl.data.interfaces import DatumSpec, LLMMessageLogType
from nemo_rl.data_plane.factory import maybe_configure_data_plane_env
from nemo_rl.distributed.virtual_cluster import init_ray
from nemo_rl.environments.games.sliding_puzzle import (
SlidingPuzzleConfig,
Expand Down Expand Up @@ -232,6 +233,8 @@ def main():
)

with rl_init_timer.time("ray_connect"):
# Must precede init_ray() — see maybe_configure_data_plane_env's docstring.
maybe_configure_data_plane_env(config.data_plane)
init_ray()

set_seed(config.grpo.seed)
Expand Down
3 changes: 3 additions & 0 deletions examples/run_vlm_grpo.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from nemo_rl.algorithms.grpo import MasterConfig, async_grpo_train, grpo_train, setup
from nemo_rl.algorithms.utils import get_tokenizer
from nemo_rl.data.utils import setup_response_data
from nemo_rl.data_plane.factory import maybe_configure_data_plane_env
from nemo_rl.distributed.virtual_cluster import init_ray
from nemo_rl.models.generation import configure_generation_config
from nemo_rl.utils.config import (
Expand Down Expand Up @@ -83,6 +84,8 @@ def main() -> None:
)

with rl_init_timer.time("ray_connect"):
# Must precede init_ray() — see maybe_configure_data_plane_env's docstring.
maybe_configure_data_plane_env(config.data_plane)
init_ray()

with rl_init_timer.time("tokenizer"):
Expand Down
35 changes: 25 additions & 10 deletions nemo_rl/data_plane/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,29 +409,44 @@ global_forward_pad_seqlen = round_up(1320, 64) = 1344
## Configuration

The data plane is configured via a `data_plane:` block in the master
YAML (`examples/configs/...`). **YAML is the single source of truth
for defaults** — the adapter has no hidden `cfg.get(key, default)`
fallbacks. The canonical exemplar is
YAML (`examples/configs/...`). The canonical exemplar is
`examples/configs/grpo_math_1B.yaml`.

All eight keys below are **required** when `enabled=true`. Recipes
under `examples/configs/recipes/**/*.yaml` inherit them via
`defaults:` from the exemplar.
`enabled`, `impl`, `backend` and `claim_meta_poll_interval_s` are
**required** when `enabled=true`. Backend sizing lives in a block named
for the backend that reads it; only the block named by `backend` is
consulted. An absent `mooncake_cpu:` block means that backend's
defaults, declared on `MooncakeCpuConfig` in
`nemo_rl/data_plane/interfaces.py`. `simple:` is **not** optional —
`num_storage_units` has no static default, since no single value is
right across cluster sizes, so a `simple` run without the block fails
validation. Recipes under `examples/configs/recipes/**/*.yaml` inherit
all of it via `defaults:`.

```yaml
data_plane:
enabled: false # flip to true to engage grpo_train_sync
impl: transfer_queue # only one impl today
backend: "simple" # "simple" or "mooncake_cpu"
storage_capacity: 1000000 # max samples retained per partition
num_storage_units: 2 # storage shards
claim_meta_poll_interval_s: 0.5 # blocking-claim poll cadence
global_segment_size: 549755813888 # 512 GiB — used when backend == "mooncake_cpu"
local_buffer_size: 68719476736 # 64 GiB — used when backend == "mooncake_cpu"
simple:
storage_capacity: 1000000 # max samples retained per partition
num_storage_units: ${mul:2, ${cluster.num_nodes}} # TQ wants >= 2 per node
mooncake_cpu:
global_segment_size: 68719476736 # 64 GiB/process
local_buffer_size: 4294967296 # 4 GiB/process
reuse_registered_buffers: true # reuse RDMA-registered buffers
Comment thread
ZhiyuLi-Nvidia marked this conversation as resolved.
staging_buffer_size: 268435456 # 256 MiB/pool slot; bigger transfers bypass the pool
# observability: # NotRequired
# enabled: false
```

These keys used to sit directly under `data_plane:`. That spelling is not
rejected — it is simply never read. A config still using it silently gets
this backend's defaults instead of its own values: an inherited config
supplies the nested block, so a surviving flat key always loses the merge,
with no warning either way.

Backend choice:
- **`simple`** — ZMQ-backed; lowest setup overhead. Default for tests
and small runs.
Expand Down
4 changes: 4 additions & 0 deletions nemo_rl/data_plane/adapters/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Keep this file import-free. ``transfer_queue_env`` is importable only because
# reaching it does not load ``transfer_queue`` (and therefore mooncake, which
# snapshots MC_* on the way in); re-exporting an adapter here would break that.
Loading
Loading