☰
NCCL Device API 之 GIN:GPU 发起网络的单向传输、信号与屏障编程指南
2026/10/14 19:54:18 网站建设 项目流程
  • 高性能计算
  • 通信
  • 深度学习
  • 分布式训练

【免费下载链接】nccl

Optimized primitives for collective multi-GPU communication

项目地址:https://gitcode.com/gh_mirrors/nc/nccl
点击查看免费下载

GIN(GPU-Initiated Networking)是 NCCL Device API 中用于跨节点网络通信的核心模块,它允许设备(GPU)内核直接发起网络数据传输,而无需 CPU 介入。本文以仓库中 GIN 设备 API 参考文档 为主体,结合 Device API 使用指南 与仓库源码(gin.h、gin_device_common.h、gin_barrier.h)以及 纯 GIN AlltoAll 示例,系统讲解ncclGin对象、单向put/get传输、信号(Signal)与计数器(Counter)完成机制、以及ncclGinBarrierSession网络屏障的完整用法。读完本文,你将能够在自己的 CUDA 内核中编写纯 GIN 的单向通信与跨节点同步逻辑。

GIN 是什么:从 Device API 到 GPU 发起网络

NCCL 自 2.28 版本起提供设备端通信 API(Device API),使通信原语可以直接在用户 CUDA 内核中使用;而 GIN 自NCCL 2.28.7起成为其中负责"跨网络通信"的模块(见 deviceapi.rst)。与 LSA(Load/Store Accessible,面向 NVLink/PCIe P2P 的直访通信)和 Multimem(NVLink SHARP 硬件多播)不同,GIN 的所有数据传输都通过网卡完成,适用于:

  • 不同节点之间、无法使用 LSA 直访的 rank 之间的通信;
  • 纯网络路径的集体通信(如跨节点 AlltoAll);
  • 需要计算与通信重叠、以信号驱动异步完成检测的场景。

从源码结构看,GIN 在设备侧由 gin.h 中的ncclGin类型与 gin_device_common.h 中的后端分发机制支撑,支持三种后端(见NCCL_GIN_BACKEND_MASK_ALL宏与 device_setup.rst 中ncclGinType_t的说明):

  • Host Proxy(NCCL_GIN_TYPE_PROXY):由主机代理转发的 GIN 类型;
  • GDAKI(NCCL_GIN_TYPE_GDAKI):GPUDirect Async Kernel-Initiated,内核直接发起;
  • GPI(NCCL_GIN_TYPE_GPI):GPU-Push Interface,需要 SpectrumX,自 NCCL 2.30.6 起作为实验特性加入。

使用 GIN 的软硬件要求

根据 deviceapi.rst 的"Requirements"一节,使用 GIN 需要满足:

  • 编译 GPU 代码需 CUDA 12.2 或更高;
  • GPU 需 Volta 及以上,驱动 >= 510.40.3;
  • 网卡需 CX4 及以上,rdma-core >= 44.0;
  • 主机代理 GIN 需要 DMA-BUF 或 nvidia-peermem;GDAKI 需要 DMA-BUF(内核 >= 6.1)或 nvidia-peermem;
  • 网络拓扑要求全 NIC 连通,不支持跨 rail 无法通信的拓扑,也不支持NCCL_CROSS_NIC=0;
  • 不支持融合网卡(Fused NIC);双口网卡需设置NCCL_IB_MERGE_NICS=0;
  • 使用由多个 cuMem 段支撑的缓冲区时需要 DMA-BUF。

此外,跨版本兼容性方面:LSA/Multimem 内核自 NCCL 2.29 起支持向后兼容,而GIN 内核目前不做向后兼容,NCCL 升级后需要重新编译。

ncclGin:一个对象对应一条 GIN 上下文

ncclGin是 GIN 支持的"主类",封装了 GIN 的关键元素(文档中定义为"A class encompassing major elements of the GIN support")。它只在设备(GPU)代码中可调用,构造方式如下:

ncclGin(ncclDevComm const& comm, int contextIndex)
  • comm:通过ncclDevCommCreate创建的设备通信器(参见 device_setup.rst);
  • contextIndex:GIN 上下文(网络通信通道)的索引。

多个 GIN 上下文可以将流量分散到多条连接上,避免锁竞争和瓶颈,因此面向性能的内核应当在不同上下文间轮转使用,以提高资源利用率。可用上下文数量通过设备通信器的ginContextCount字段查询(该字段在 device_setup.rst 中注明自 NCCL 2.28.7 起提供)。在 core.h 中可以看到,ncclGinSignal_t与ncclGinCounter_t均为 32 位无符号整数句柄,而ncclGinRequest_t是一个 16 字节(两个uint64_t)的不透明请求对象,用于异步flushAsync/wait。

ncclGin的一个实例总是代表某一个特定上下文。当需要执行一个栅栏(barrier),且该栅栏的 fence 需要覆盖通信器上的所有GIN 上下文时(例如操作被切分到多个上下文、多网卡场景),可以在ncclGinBarrier的位置上传入ncclGinAllContexts(comm)而非某个ncclGin。ncclGinAllContexts在 gin_barrier.h 中定义,其注释明确说明:传给它时,信号仍走上下文 0,而 fence 会遍历通信器上的每一个上下文。

从 gin.h 的实现看,ncclGin实际上是ncclGin_BackendMask<...>的别名(using ncclGin = ncclGin_BackendMask<NCCL_GIN_BACKEND_MASK_ALL>),其中NCCL_GIN_BACKEND_MASK_ALL按编译期宏NCCL_GIN_PROXY_ENABLE、NCCL_GIN_GDAKI_ENABLE、NCCL_GIN_GPI_ENABLE展开为后端位掩码(见 gin_device_common.h)。运行时通过ncclGinCall/ncclGinCallImpl按位掩码分发到对应后端的ncclGinApi_Put、ncclGinApi_Get、ncclGinApi_Flush等实现——这正是"一个 API、多后端"的设计。

单向数据传输:put 与 get

put:本地缓冲区 → 远端缓冲区

void put(ncclTeam team, int peer, ncclWindow_t dstWnd, size_t dstOffset, ncclWindow_t srcWnd, size_t srcOffset, size_t bytes, RemoteAction remoteAction, LocalAction localAction, Coop coop, DescriptorSmem descriptor, cuda::thread_scope alreadyReleased, cuda::thread_scope expected_scope, SegmentType bufType)

put调度一个由设备发起的单边(one-sided)数据传输操作:把本地缓冲区的内容写到 peer 的远端缓冲区。参数要点:

  • peer是team内的一个 rank(参见设备 API 的 Teams 概念:ncclTeamWorld()、ncclTeamLsa()、ncclTeamRail());它可以指向本地 rank 自身(即 loopback 回环);
  • 目的与源缓冲区各自由窗口(dstWnd/srcWnd)+ 字节偏移(dstOffset/srcOffset)描述;
  • bytes指定传输的字节数;
  • 若 GIN 以NCCL_GIN_CONNECTION_RAIL连接类型初始化,peer必须与本地 rank 处于同一个 rail team 内(rail team 是本地 LSA team 内 rank 编号相同的对等节点集合,见 deviceapi.rst 的 Teams 一节)。

前七个参数之外均为可选参数:

参数作用默认值
remoteAction载荷在目的端落定后,在目的 peer 上执行的动作ncclGin_None(无动作)
localAction输入被消费后,在本地 rank 上执行的动作ncclGin_None
coop参与本次操作的线程集合ncclCoopThread(单个设备线程,官方推荐模型)
descriptor可选的共享内存描述符空间ncclGin_None
alreadyReleased/expected_scope线程作用域(thread scope)控制thread_scope_thread/thread_scope_device
bufType源/目的缓冲区的物理内存组成ncclGin_SegmentDevice

remoteAction的常见取值是ncclGin_Signal{Inc|Add}(信号类动作),localAction的取值是ncclGin_CounterInc(计数器动作),详见下文"信号与计数器"一节。bufType的取值见 deviceapi.rst 的 Segment Types 一节:ncclGin_SegmentDevice(默认,纯设备显存段)、ncclGin_SegmentHostNuma(纯 CPU 侧HOST_NUMA段)、ncclGin_SegmentMixed(设备段与HOST_NUMA段混合)。

可见性语义:目的端 peer 上信号的可见性意味着它所附着的那次put数据也已可见。根据信号类型的不同(强/弱,见下文),信号的可见性还可能意味着同一上下文上、发往同一 peer 的所有此前 put 数据均已可见。

ncclGin还定义了两种便捷变体:

  • ncclSymPtr变体:用ncclSymPtr<T>类型描述缓冲区,且大小以元素个数(nElts)而非字节数表达;
  • putValue变体:一次传输单个元素(不超过 8 字节),按值传递,无需窗口偏移寻址。

get:远端缓冲区 → 本地缓冲区

void get(ncclTeam team, int peer, ncclWindow_t remoteWnd, size_t remoteOffset, ncclWindow_t localWnd, size_t localOffset, size_t bytes, Coop coop = ncclCoopThread{}, DescriptorSmem descriptor = ncclGin_None{}, uint32_t optFlags = ncclGinOptFlagsDefault, SegmentType bufType = ncclGin_SegmentDevice{})

get调度与put方向相反的单边传输:把远端缓冲区读到本地缓冲区,自 NCCL 2.30.3 起可用。参数语义与put对称:peer是team内 rank(可指向本地回环);远端与本地缓冲区用窗口 + 字节偏移描述;bufType默认ncclGin_SegmentDevice。与put不同的是get携带一个optFlags参数,默认ncclGinOptFlagsDefault(0),可选的标志位在 gin_device_common.h 中定义:

  • ncclGinOptFlagsMaySkipCreditCheck(1 << 0):允许跳过信用检查;
  • ncclGinOptFlagsAggregateRequests(1 << 1):聚合请求。

完成管理:flush、flushAsync 与 wait

void flush(Coop coop, cuda::memory_order ord = cuda::memory_order_acquire)

flush确保coop中任意线程调度的所有挂起传输操作在本地被消费完毕:

  • 对put而言,意味着源缓冲区可以安全复用;它不保证远端 peer 上的完成状态;
  • 对get而言,意味着数据对本地 rank 可见。
void flushAsync(ncclTeam team, uint32_t peer, ncclGinRequest_t* request, Coop coop = ncclCoopThread{}, uint32_t optFlags = ncclGinOptFlagsDefault, DescriptorSmem descriptor = ncclGin_None{})

flushAsync发起针对单个 peer的非阻塞 flush(自 NCCL 2.30.3 起可用)。request由调用方提供、由flushAsync初始化,调用方随后可用它判断 flush 是否完成:

void wait(ncclGinRequest_t& request, Coop coop = ncclCoopThread{}, DescriptorSmem descriptor = ncclGin_None{}, cuda::memory_order ord = cuda::memory_order_acquire)

wait阻塞直到request完成(自 NCCL 2.30.3 起可用)。这一"异步发起 + 请求对象轮询/等待"的模式,为计算与通信重叠提供了非阻塞的完成跟踪手段。

信号(Signals)与计数器(Counters)

信号与计数器是 GIN 异步完成语义的两大支柱。信号(Signal)用于触发远端 peer 上的动作,最常见的是在put完成时通知对端;计数器(Counter)用于触发本地 rank 上的动作,与信号互补。两者都关联一个可被原子操作的 64 位整数值,并采用"滚动比较"(rolling comparison)逻辑:即使无符号溢出,仍保持x < x + 1的性质(该算法在 gin.h 的注释中以rolling_less_equal伪代码给出,等待条件为"给定值滚动小于等于内部值")。

强信号与弱信号(NCCL 2.30.5 起)

自 NCCL 2.30.5 起,信号分为**强(strong)与弱(weak)**两种:

  • 强信号:其可见性意味着同一上下文上、发往同一 peer 的所有此前 put均已落定;
  • 弱信号:只保证其所附着的这一次 put 数据已落定。

两类信号各有 Inc/Add 两种对象(定义见 gin.h):

类型结构体成员
强 IncncclGin_StrongSignalIncncclGinSignal_t signal
强 AddncclGin_StrongSignalAddsignal+uint64_t value
弱 IncncclGin_WeakSignalIncncclGinSignal_t signal
弱 AddncclGin_WeakSignalAddsignal+uint64_t value

这些对象可作为put、signal等方法的remoteAction参数传入,表示"收到载荷后把指定signal的值增加若干"。其中SignalInc{signalIdx}功能上等价于SignalAdd{signalIdx, 1};但Inc 不能与其他修改信号的操作混用,除非中间插入一次信号重置(resetSignal)。

VA 信号:任意虚拟地址上的信号

除了预分配的信号索引,GIN 还支持VA 信号:信号位于任意的 VA(窗口 + 偏移对),而非预分配的信号槽。对应对象为ncclGin_StrongVASignalInc、ncclGin_StrongVASignalAdd、ncclGin_WeakVASignalInc、ncclGin_WeakVASignalAdd,均包含ncclWindow_t signalWindow与size_t signalOffset成员(Add 变体另有uint64_t value)。使用 VA 信号的前提:

  • 该窗口必须以NCCL_WIN_STRICT_ORDERING标志注册;
  • 一旦某地址被用作信号,对该地址的所有读写都必须经由 GIN 发起(即通过RemoteAction或 GIN 信号方法),不能由普通 load/store 访问。

自 NCCL 2.30.5 起,以下旧信号类型被弃用,官方建议显式选用强/弱信号对象:

  • ncclGin_VASignalInc、ncclGin_VASignalAdd→ 改用ncclGin_{Strong|Weak}VASignal{Inc|Add};
  • ncclGin_SignalInc、ncclGin_SignalAdd→ 改用ncclGin_{Strong|Weak}Signal{Inc|Add}。

对于这些被弃用的信号,其强弱由创建设备通信器时ginStrongSignalsRequired字段的值决定(该字段在 device_setup.rst 中说明,默认true)。若将ginStrongSignalsRequired设为false而内核仍使用强信号操作,则行为未定义。

信号方法

ncclGin提供四类信号相关方法:

void signal(ncclTeam team, int peer, RemoteAction remoteAction, Coop coop, DescriptorSmem descriptor, cuda::thread_scope alreadyReleased, cuda::thread_scope expected_scope)

signal实现不带数据传输的显式信号通知,参数是put的参数子集——即"只发信号、不搬数据"。

uint64_t readSignal(ncclGinSignal_t signal, int bits = 64, cuda::memory_order ord = cuda::memory_order_acquire) void waitSignal(Coop coop, ncclGinSignal_t signal, uint64_t least, int bits = 64, cuda::memory_order ord = cuda::memory_order_acquire) void resetSignal(ncclGinSignal_t signal)
  • readSignal返回signal数值的低bits位;
  • waitSignal等待signal数值的低bits位达到或超过least;
  • resetSignal将信号值重置为0(注意:该方法不能与对信号的其他并发修改竞争)。

针对 VA 信号还有一组同名重载,参数由ncclGinSignal_t换成ncclWindow_t signalWindow, size_t signalOffset。此外,gin.h 中还提供了信号"影子值"(shadow)相关的高级方法(getSignalShadowPtr、increaseSignalShadow、waitSignalMeetShadow、waitSignalFollowShadow),每个信号都有专属的影子副本,用户可自由操作,供复杂的按序消费场景使用。

计数器方法

计数器使用与信号完全对称的 API,但有两个关键差异:

  • 计数器用于本地动作(localAction),唯一的动作对象是ncclGin_CounterInc(成员为ncclGinCounter_t counter);
  • 计数器最多只能存储 56 位(bits默认56),少于uint64_t的完整位宽。
uint64_t readCounter(ncclGinCounter_t counter, int bits = 56, cuda::memory_order ord = cuda::memory_order_acquire) void waitCounter(Coop coop, ncclGinCounter_t counter, uint64_t least, int bits = 56, cuda::memory_order ord = cuda::memory_order_acquire) void resetCounter(ncclGinCounter_t counter)

这三个方法分别对应readSignal/waitSignal/resetSignal的语义(读低 bits 位、等待达到阈值、重置为 0)。在 gin.h 中,ncclGin_CounterInc被标记为弃用,建议改用ncclGin_WeakCounterInc(弱计数器递增,只保证所附着的 put 在本地完成)。

网络屏障:ncclGinBarrierSession

跨节点的内核协作需要网络级屏障,ncclGinBarrierSession即代表一个网络屏障会话(gin_barrier.h 中同时定义了对应的宿主端创建函数ncclGinBarrierCreateRequirement)。

构造:rail 专用变体与通用变体

ncclGinBarrierSession(Coop coop, ncclGin gin, ncclTeamTagRail tag, uint32_t index)

这是 rail 专用的构造变体:coop表示协作线程组(ncclCoopThread/ncclCoopWarp/ncclCoopCta,见 deviceapi.rst 的 Thread Groups 一节);gin是先前初始化的ncclGin对象;ncclTeamTagRail表示屏障作用于与本地 rank 同一 rail 的所有 peer;index标识底层使用的屏障槽位——每个coop应当使用不同的 index,通常设为blockIdx.x以保证 CTA 之间唯一。

ncclGinBarrierSession(Coop coop, ncclGin gin, ncclTeam team, ncclGinBarrierHandle handle, uint32_t index)

这是通用变体:用于与 world team 等(而非 rail team)的 rank 通信。它要求显式传入team,并额外接受handle参数,指明底层屏障的位置(通常设为设备通信器的railGinBarrier字段)。从 gin_barrier.h 可以看出,ncclGinBarrierSession还提供绑定ncclGinAllContexts(fence 覆盖所有上下文)的构造重载,且会话对象不可拷贝(Sessions are not copyable),并支持带timeoutCycles的sync重载用于超时控制。

sync 与 fence 级别

void sync(Coop coop, cuda::memory_order order, ncclGinFenceLevel fence = ncclGinFenceLevel::Put | ncclGinFenceLevel::Get)

sync同步参与屏障会话的所有 team 成员的所有线程。fence是位标志枚举,选择屏障返回后必须完成的先前的网络操作;省略时默认Put | Get,即调用方未显式选择也能获得最强保证。各取值定义在 gin_barrier.h 的ncclGinFenceLevel枚举中:

取值含义
ncclGinFenceLevel::None纯同步,不做任何 drain(排空)
ncclGinFenceLevel::Put屏障返回后,其他 team 成员在屏障前发出的、以调用方 rank 为目标的 put,在调用方内存中可见
ncclGinFenceLevel::Get屏障返回后,调用方 rank 在屏障前发出的 get 已落入其本地内存
ncclGinFenceLevel::Relaxed已弃用的None别名,仅为源码级向后兼容保留;新代码应使用None

fence是位标志,可通过按位或组合:同时请求 Put 与 Get 语义就传ncclGinFenceLevel::Put | ncclGinFenceLevel::Get。在 gin_barrier.h 中可以看到为operator|/operator&提供的组合运算符实现。屏障的实现细节见 gin_barrier__funcs.h,其中syncInternal会根据fence是否包含Put来决定参与的 peer 信号数量,并处理Get的落地检查——这也是"默认最强保证"在实现层面的体现。

实战:纯 GIN AlltoAll 内核

仓库的 02_alltoall_gin 示例(配套说明见 README.md)把上述 API 完整串起来:所有 peer 数据都走网络,正是 GIN 跨节点场景的基线用法。

宿主端:创建带 GIN 资源的设备通信器

#define NCCL_DEVICE_CTA_COUNT 16 #define NCCL_DEVICE_THREADS_PER_CTA 512 ncclDevCommRequirements reqs = NCCL_DEV_COMM_REQUIREMENTS_INITIALIZER; reqs.worldGinBarrierCount = NCCL_DEVICE_CTA_COUNT; // ncclGinBarrierSession(world team)槽位 reqs.ginSignalCount = NCCL_DEVICE_CTA_COUNT; // 每个 CTA(blockIdx.x)一个信号索引 reqs.ginConnectionType = NCCL_GIN_CONNECTION_FULL; // 全连接:每个 rank 连到所有 peer NCCLCHECK(ncclDevCommCreate(comm, &reqs, &devComm));

要点(与 device_setup.rst 的ncclDevCommRequirements字段一一对应):

  • worldGinBarrierCount为ncclGinBarrierSession(world team 网络屏障)预留槽位,自 NCCL 2.30.3 起可用;
  • ginSignalCount为完成信号预留槽位,保证从 id=0 开始编号;
  • 二者都应等于内核发射网格的gridDim.x(这里都是 16),使每个线程块用blockIdx.x作为自己的屏障索引与信号索引;
  • ginConnectionType = NCCL_GIN_CONNECTION_FULL建立全连接;若无法提供 GIN,ncclDevCommCreate会失败。连接类型枚举(NCCL_GIN_CONNECTION_NONE/FULL/RAIL)见 device_setup.rst 的ncclGinConnectionType_t。

创建前还应通过ncclCommQueryProperties查询props.deviceApiSupport与props.ginType(若ginType == NCCL_GIN_TYPE_NONE则无法创建 GIN 通信器),示例中对此做了显式检查。缓冲区必须用ncclMemAlloc分配并通过ncclCommWindowRegister注册为对称窗口(NCCL_WIN_COLL_SYMMETRIC),这是 Device API 数据搬移的前提。

内核端:ncclGin + 信号 + 屏障 + put

template <typename T> __global__ void PureGinAlltoAllKernel(ncclWindow_t sendwin, size_t sendoffset, ncclWindow_t recvwin, size_t recvoffset, size_t count, struct ncclDevComm devComm) { int ginContext = 0; // 单上下文 unsigned int signalIndex = blockIdx.x; ncclGin gin { devComm, ginContext }; uint64_t signalValue = gin.readSignal(signalIndex); ncclGinBarrierSession<ncclCoopCta> bar { ncclCoopCta(), gin, ncclTeamTagWorld(), blockIdx.x }; bar.sync(ncclCoopCta(), cuda::memory_order_acquire, ncclGinFenceLevel::None); int tid = threadIdx.x + blockIdx.x * blockDim.x; int nthreads = blockDim.x * gridDim.x; const size_t size = count * sizeof(T); for (int r = tid; r < devComm.nRanks; r += nthreads) { gin.put(ncclTeamWorld(devComm), r, recvwin, recvoffset + devComm.rank * size, sendwin, sendoffset + r * size, size, ncclGin_WeakSignalInc{signalIndex}); } int receivingCta = (devComm.rank % nthreads) / blockDim.x; if (blockIdx.x == receivingCta) gin.waitSignal(ncclCoopCta(), signalIndex, signalValue + devComm.nRanks); gin.flush(ncclCoopCta()); bar.sync(ncclCoopCta(), cuda::memory_order_release, ncclGinFenceLevel::None); }

逐段解读其与文档 API 的对应关系:

  1. 构造ncclGin:ncclGin gin { devComm, ginContext }使用上下文 0。生产代码可轮转多个上下文(devComm.ginContextCount)提升吞吐。
  2. 入口屏障:ncclGinBarrierSession<ncclCoopCta>以ncclTeamTagWorld()+blockIdx.x构造,bar.sync在所有 rank 就绪后才放行数据交换;此处 fence 显式传ncclGinFenceLevel::None(纯同步、不做 drain),因为真正的完成保证由后面的信号与 flush 承担。
  3. 逐 peer 发 put:循环内每个线程为不同目的 rank 发一次gin.put,remoteAction传ncclGin_WeakSignalInc{signalIndex}——数据落定后,目的 rank 上该信号槽位自增 1。AlltoAll 的"每个线程索引只需在本 rank 内唯一"(tid步进nthreads)即可,随后用该索引选出目的 peer。
  4. 信号化完成等待:所有 peer 发往本 rank 的 put 都会使signalIndex == blockIdx.x那个槽位自增一次,共需nRanks次。因此只让一个"接收 CTA"(receivingCta,由(devComm.rank % nthreads) / blockDim.x计算)执行gin.waitSignal(..., signalValue + devComm.nRanks),等待所有入站 put 落定;其余 CTA 只发 put 和 flush。
  5. flush 收尾:gin.flush(ncclCoopCta())保证本地发送缓冲区可安全复用(不保证远端完全落定,远端完成由waitSignal保证);随后再次bar.sync(release),确保所有 rank 完成集体操作后才退出内核。

示例还在main.cu中完成了数据初始化(my_rank * 1000 + dest_rank * 100 + element_idx的可验证模式)、cudaStreamSynchronize后回拷校验("PASSED/FAILED"),以及ncclDevCommDestroy、ncclCommWindowDeregister、ncclMemFree等清理流程——完整可运行的代码可直接参考该文件。

版本兼容与迁移提示

若目标 NCCL 版本早于 2.30,文档(deviceapi.rst 的 Compatibility adjustments 一节)给出如下调整建议:

  • NCCL 2.28.7 基线:GIN 自该版本起可用;
  • 早于 2.30(无worldGinBarrierCount):ncclGinBarrierSession仅可用于 rail 连通,对应字段为railGinBarrierCount;若要 world team 的 GIN 屏障,将barrierCount设为 CTA 数(等于gridDim.x),内核中改用混合ncclBarrierSession+ncclTeamTagWorld();
  • 早于 2.29.7(无ginConnectionType):将弃用的ginForceEnable设为true以启用全连接(等价于NCCL_GIN_CONNECTION_FULL);ginConnectionType自 NCCL 2.29.7 起可用,ginForceEnable自 2.29.7 起弃用。

另外注意ncclGin::get、flushAsync、wait自NCCL 2.30.3起可用,强/弱信号、VA 信号语义自NCCL 2.30.5起可用,GPI 后端自NCCL 2.30.6起作为实验特性加入——编写内核前请核对所用 NCCL 版本与 device_gin.rst 中各 API 标注的引入版本。

小结

GIN 把网络通信的发起权从 CPU 移交给了 GPU 内核:ncclGin封装 GIN 上下文与多后端分发,put/get提供单边传输,信号/计数器提供远端/本地的异步完成语义(含 2.30.5 起的强/弱之分与 VA 信号),ncclGinBarrierSession提供带 fence 级别的跨节点屏障。结合仓库中的 API 参考、使用指南 与 完整示例,你可以直接以此为基础编写自己的纯 GIN 内核,或将其与 LSA、Multimem 结合构建面向多节点、拓扑感知的混合通信方案。

  • 高性能计算
  • 通信
  • 深度学习
  • 分布式训练

【免费下载链接】nccl

Optimized primitives for collective multi-GPU communication

项目地址:https://gitcode.com/gh_mirrors/nc/nccl
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询