Files
TheRock/rocm-systems/projects/rccl/docs/how-to/rccl-usage-tips.rst
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

371 lines
15 KiB
ReStructuredText

.. meta::
:description: Usage tips for the RCCL library of collective communication primitives
:keywords: RCCL, ROCm, library, API, peer-to-peer, transport
.. _rccl-usage-tips:
*****************************************
RCCL usage tips
*****************************************
This topic describes common RCCL configuration options and usage tips.
Profiling
=========
For fine-grained profiling of collective operations, use the RCCL **profiler plugin** API and related tooling rather than legacy in-tree profilers.
MSCCL and MSCCL++ integration has been removed from RCCL. The legacy API symbols ``mscclLoadAlgo``,
``mscclRunAlgo``, and ``mscclUnloadAlgo`` remain as no-ops for link compatibility.
Enabling peer-to-peer transport
===============================
To enable peer-to-peer access on machines with PCIe-connected GPUs,
set the HSA environment variable as follows:
.. code-block:: shell
HSA_FORCE_FINE_GRAIN_PCIE=1
This feature requires GPUs that support peer-to-peer access along with
proper large BAR addressing support.
Symmetric memory and ``NCCL_P2P_LEVEL``
=======================================
RCCL can accelerate some collectives (for example, allreduce, allgather, and
reduce-scatter) through a *symmetric memory* path. This path uses
:doc:`Virtual Memory Management <../api-reference/api-library>`-backed
buffers that are registered as symmetric windows
(``ncclCommWindowRegister`` with the ``NCCL_WIN_COLL_SYMMETRIC`` flag, or
buffers allocated with ``ncclMemAlloc``) so that every participating rank can
address the buffer directly.
Whether a communicator can use symmetric memory is decided once at
``ncclCommInitRank`` time. The prerequisites are:
- All local ranks are **peer-to-peer capable** with each other (on AMD
GPUs this means they are on the same host over PCIe or XGMI,
or are reachable through a Multi-Node Infinity Fabric clique).
- Virtual Memory Management is enabled (``NCCL_CUMEM_ENABLE=1``).
- Symmetric windows are enabled (``NCCL_WIN_ENABLE=1``, the default).
- Either GPU-Initiated Networking (GIN) is available, or the communicator is a
single locality (one-LSA) team.
.. note::
Symmetric-memory availability does **not** depend on the
``NCCL_P2P_LEVEL`` distance setting. This matches the behavior introduced in
upstream NCCL 2.28.7, which removed the topology-distance check from the
symmetric-memory decision. Restricting peer-to-peer reach with a value such
as ``NCCL_P2P_LEVEL=PHB`` (or even disabling distance-based P2P entirely with
``NCCL_P2P_DISABLE=1``) changes how the *flat* P2P transport schedule is
built, but it does **not** by itself turn off the symmetric path: as long as
the GPUs are CUDA peer-to-peer capable, symmetric memory remains eligible.
To confirm whether symmetric memory was enabled for a run, inspect the init
logs:
.. code-block:: shell
NCCL_DEBUG=INFO NCCL_DEBUG_SUBSYS=INIT ./your_app
When symmetric memory is **not** available, RCCL logs a line that begins with
``Symmetric memory is not supported`` and reports which prerequisite was
missing (for example, ``cuMemEnable`` or ``globalGinSupport``). If you expect
the symmetric path but it is disabled, check those prerequisites rather than
``NCCL_P2P_LEVEL``.
Ignoring CPU affinity with multi-node
=====================================
Depending on the job launcher and the requirements of your workload, performance as the communication workload scales
can be improved by setting ``NCCL_IGNORE_CPU_AFFINITY``. This allows the RCCL communication library to
ignore the job's supplied CPU affinity and use the GPU affinity only.
.. code-block:: shell
NCCL_IGNORE_CPU_AFFINITY=1
For general usage, this environment variable is not set so it doesn't interfere with the user or launcher
supplied preferences.
Improving performance on the MI200 series
=========================================
On MI200 series (gfx90a) systems, such as MI210, MI250, and MI250X, running
ROCm 7.13 or later, set ``HSA_NO_SCRATCH_RECLAIM=1`` when running RCCL:
.. code-block:: shell
export HSA_NO_SCRATCH_RECLAIM=1
Without this setting, per-launch scratch-memory reclaim in the runtime adds a
fixed overhead to every collective launch. This overhead dominates
small-message (under 16 MB) latency and can degrade it by roughly
5-10x compared to earlier ROCm releases. Setting ``HSA_NO_SCRATCH_RECLAIM=1``
removes the overhead and restores the expected small-message latency.
Improving performance on the MI300X
===================================
This section outlines ways to improve RCCL performance on MI300X systems,
including guidelines for systems with fewer than eight GPUs and the most efficient
GPU partition modes.
Configuration with fewer than eight GPUs
----------------------------------------
On a system with eight MI300X accelerators, each pair of accelerators is
connected with dedicated Infinity Fabric™ links in a fully connected topology.
For collective operations, this can achieve good performance when all eight
accelerators (and all Infinity Fabric links) are used. When fewer than eight
GPUs are used, however, this can only achieve a fraction of the potential
bandwidth on the system. However, if your workload warrants using fewer than
eight MI300X accelerators on a system, you can set the run-time variable
``NCCL_MIN_NCHANNELS`` to increase the number of channels. For example:
.. code-block:: shell
export NCCL_MIN_NCHANNELS=32
Increasing the number of channels can benefit performance, but it also increases
GPU utilization for collective operations.
Additionally, RCCL pre-defines a higher number of channels when only two or four
accelerators are in use on a 8\*MI300X system. In this situation, RCCL uses 32
channels with two MI300X accelerators and 24 channels for four MI300X
accelerators.
.. _nps4_cpx_mi300_rccl:
NPS4 and CPX partition modes
----------------------------
The term compute partitioning modes, or Modular Chiplet Platform (MCP), refers to the
logical partitioning of XCDs into devices in the ROCm stack. The names are
derived from the number of logical partitions that are created out of the eight
XCDs. In the default mode, SPX (Single Partition X-celerator), all eight XCDs are
viewed as a single logical compute element, meaning that the :doc:`amd-smi <amdsmi:index>`
utility will show a single MI300X device. In CPX (Core Partitioned X-celerator)
mode, each XCD appears as a separate logical GPU, for example, as eight separate
GPUs in :doc:`amd-smi <amdsmi:index>` per MI300X. CPX mode can be viewed as
having explicit scheduling privileges for each individual compute element (XCD).
While compute partitioning modes change the space on which you can assign work
to compute units, the memory partitioning modes (known as Non-Uniform Memory
Access (NUMA) Per Socket (NPS)) change the number of NUMA domains that a device
exposes. In other words, it changes the number of HBM stacks which are
accessible to a compute unit, and therefore the size of its memory space. However,
for the MI300X, the number of memory partitions must be less than or equal to
the number of compute partitions. NPS4 (viewing pairs of HBM stacks as a
disparate element), for example, is only enabled when in CPX mode (viewing each
XCD as a disparate element).
- Compute partition modes
- In SPX mode, workgroups launched to the device are distributed
round-robin to the XCDs in the device, meaning that the programmer cannot
have explicit control over which XCD a workgroup is assigned to.
- In CPX mode, workgroups are launched to a single XCD, meaning the
programmer has explicit control over work placement onto the XCDs.
- Memory partition modes
- In NPS1 mode (compatible with CPX and SPX), the entire memory is accessible
to all XCDs.
- In NPS4 mode (compatible with CPX), each memory quadrant of the memory is
directly visible to the logical devices in its quadrant. An XCD can still
access all portions of memory through multi-GPU programming techniques.
The MI300 CPX mode can be accessed using the following :doc:`amdsmi:index`
commands.
.. code-block:: shell
amd-smi set --gpu all --compute-partition CPX
amd-smi set --gpu all --memory-partition NPS4
RCCL performance with CPX and NPS4
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To run RCCL allreduce on 64 GPUs with CPX+NPS4 mode on the MI300X, use this
example:
.. code-block:: shell
mpirun -np 64 --bind-to numa rccl-tests/build/all_reduce_perf -b 8 -e 1G -f 2 -g 1
To run RCCL allreduce on 8 GPUs in the same OAM with CPX+NPS4 mode on the
MI300X, use this example:
.. code-block:: shell
export ROCR_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
mpirun -np 8 --bind-to numa rccl-tests/build/all_reduce_perf -b 8 -e 1G -f 2 -g 1
RCCL delivers improved allreduce performance in CPX mode for TP=8 (8 GPUs in
the same OAM) on the MI300X.
.. code-block:: shell
export HIP_FORCE_DEV_KERNARG=1
export ROCR_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
mpirun -np 8 --bind-to numa rccl-tests/build/all_reduce_perf -b 32 -e 1G -f 2 -g 1 -G 2 -w 20 -n 50
Here are the benchmark results for in-place (where the output buffer is used as
the input buffer) and out-of-place allreduce bus bandwidth.
.. figure:: ../data/how-to/rccl-usage-tips/in-place_allreduce.png
:alt: In-place allreduce benchmark results
:align: center
.. figure:: ../data/how-to/rccl-usage-tips/out-of-place_allreduce.png
:alt: Out-of-place allreduce benchmark results
:align: center
A significant performance improvement is achievable with optimized CPX mode,
which peaks at ~340 GB/s with a single OAM. The difference in bus bandwidth
between the unoptimized and optimized modes increases as the buffer size grows.
Using RCCL and CPX in PyTorch
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The PyTorch all_reduce benchmark is used to reproduce the performance reported
by RCCL-Tests with the RCCL and CPX optimizations.
.. note::
To use RCCL with CPX mode in PyTorch, check the RCCL version used by PyTorch.
For a virtualenv with a .whl-based PyTorch setup (such as nightly/rocm6.2),
this would be in
``<path-to-your-venv>/lib/<python-version>/site-packages/torch/lib/librccl.so``
This is the version of RCCL that is packaged as part of ROCm version 6.2.
RCCL for CPX mode was enabled in ROCm 6.3.0. To use the CPX features, replace
the existing ``librccl.so`` with one from ROCm 6.3.0 or newer or from a local
build of the RCCL develop branch.
To test the effects of RCCL on PyTorch, the `stas00 all reduce benchmark <https://github.com/stas00/ml-engineering/blob/master/network/benchmarks/all_reduce_bench.py>`_
was used. The following command is used to run a single OAM allreduce
benchmark:
.. code-block:: shell
export ROCR_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
python -u -m torch.distributed.run --nproc_per_node=8 --rdzv_endpoint localhost:6000 --rdzv_backend c10d all_reduce_bench.py
For better performance, the ``HIP_FORCE_DEV_KERNARG`` and
``TORCH_NCCL_USE_TENSOR_REGISTER_ALLOCATOR_HOOK`` environment variables are
set during the benchmark in the following manner:
.. code-block:: shell
export TORCH_NCCL_USE_TENSOR_REGISTER_ALLOCATOR_HOOK=1
export HIP_FORCE_DEV_KERNARG=1
export ROCR_VISIBLE_DEVICES=0,1,2,3,4,5,6,7
python -u -m torch.distributed.run --nproc_per_node=8 --rdzv_endpoint localhost:6000 --rdzv_backend c10d all_reduce_bench.py
The default allreduce PyTorch benchmark peak bus bandwidth performance is
~170 GB/s on a single OAM with ROCm 6.2.4, while the optimized run for CPX on a
single OAM peaks at ~315 GB/s.
Context tracking on GPUs
----------------------------------------
Context tracking is disabled by default for optimal performance. However, enabling of context tracking can significantly improve performance
in certain scenarios. To enable context tracking, set the following environment variable:
.. code-block:: shell
export RCCL_ENABLE_CONTEXT_TRACKING=1
.. _suspend-resume:
Suspending and resuming a communicator
======================================
A long-lived application can hold several RCCL communicators that are only used
during specific phases. While a communicator is idle, the GPU memory it holds
for channel buffers, transport FIFOs, and similar resources stays reserved and
is unavailable to the rest of the application. RCCL provides an API to release
those resources while a communicator is idle and to reacquire them later
without destroying and recreating the communicator.
The relevant functions, declared in ``rccl.h``, are described in full in
:ref:`communicator-suspend-resume`:
- ``ncclCommSuspend`` releases the resources selected by its ``flags``
argument. Pass ``NCCL_SUSPEND_MEM`` to release dynamic GPU memory
allocations. After this call, the communicator can't be used until it's
resumed.
- ``ncclCommResume`` reacquires every resource that the matching
``ncclCommSuspend`` call released, after which the communicator can run
collectives again.
- ``ncclCommMemStats`` reports per-communicator memory counters, such as the
amount of GPU memory that can be suspended and whether the communicator is
currently suspended.
Requirements
------------
Releasing the physical backing of a suspended communicator while keeping its
GPU virtual address space requires cuMem virtual memory management (VMM)
support. VMM is available only when all of the following conditions are met:
- ``NCCL_CUMEM_ENABLE`` is set to ``1`` (or to ``-2`` to enable VMM
automatically when the platform supports it). It is ``0`` (disabled) by
default.
- The HIP/ROCm runtime provides the cuMem VMM APIs: ROCm 7.12 or later, or a
ROCm 7.0.x build that includes the cuMem backport.
- The Linux kernel is version 6.8 or later.
- The GPU and driver report VMM support.
Without VMM support, ``ncclCommSuspend`` and ``ncclCommResume`` still succeed,
but they can't release the physical GPU memory, so the operation is
effectively a no-op.
Example
-------
The following example suspends an idle communicator, queries how much GPU
memory was freed, and later resumes it:
.. code-block:: cpp
// comm is an initialized ncclComm_t that is currently idle.
uint64_t suspendable = 0, suspended = 0;
NCCLCHECK(ncclCommMemStats(comm, ncclStatGpuMemSuspend, &suspendable));
// suspendable is bytes of GPU memory Suspend can release; 0 means none right
// now. This query is informational; Suspend does not require suspendable > 0
// Release dynamic GPU memory held by the communicator.
NCCLCHECK(ncclCommSuspend(comm, NCCL_SUSPEND_MEM));
NCCLCHECK(ncclCommMemStats(comm, ncclStatGpuMemSuspended, &suspended));
// suspended == 1 while the communicator is suspended.
// ... run other work that needs the freed GPU memory ...
// Reacquire the resources before using the communicator again.
NCCLCHECK(ncclCommResume(comm));
To suspend or resume several communicators together, wrap the calls in
``ncclGroupStart`` and ``ncclGroupEnd``
(see :ref:`communicator-suspend-resume`):
.. code-block:: cpp
NCCLCHECK(ncclGroupStart());
NCCLCHECK(ncclCommSuspend(commA, NCCL_SUSPEND_MEM));
NCCLCHECK(ncclCommSuspend(commB, NCCL_SUSPEND_MEM));
NCCLCHECK(ncclGroupEnd());