CANN PTO-ISA TGATHER 指令深度解析:跨 Rank 行拼接 Gather 的实现原理与开发指南

发布时间:2026/9/20 1:31:23
CANN PTO-ISA TGATHER 指令深度解析:跨 Rank 行拼接 Gather 的实现原理与开发指南
CANN PTO-ISA TGATHER 指令深度解析跨 Rank 行拼接 Gather 的实现原理与开发指南【免费下载链接】pto-isaParallel Tile Operation (PTO) is a virtual instruction set architecture designed by Ascend CANN, focusing on tile-level operations. This repository offers high-performance, cross-platform tile operations across Ascend platforms.项目地址: https://gitcode.com/cann/pto-isaTGATHER 是 CANN PTO-ISA 并行通信PTO-COMM指令集中的核心集合通信原语之一由根节点从并行组内所有 rank 收集数据并沿DIM_3行维度拼接至本地输出缓冲区。本文基于 docs/isa/comm/TGATHER_zh.md 展开并结合仓库内 A2/A3、A5CCU与 CPU_SIM 三套后端实现及 NPU 测试用例系统讲解 TGATHER 的数学语义、汇编与 C 内建接口、引擎选择、约束条件与实战代码。读完本文你将能够正确调用comm::TGATHER完成多 rank 数据汇聚理解其二维滑动分块与大 Tile 支持机制并能针对静态/动态 ValidRow/ValidCol 选择正确的 Tile 类型。一、指令概述TGATHER 完成一次Gather 集合操作调用方 NPU即根节点 root从并行组ParallelGroup中所有 rank 收集数据并沿DIM_3行维度将各 rank 的数据块依次拼接写入本地输出缓冲区GM。其关键行为特征如下仅根节点执行只有根节点需要执行TGATHER指令。非根节点无需调用任何指令只需保证在 Gather 操作期间其源缓冲区数据已就绪且保持有效不被覆盖或释放。非根节点调用属于未定义行为在非根节点上调用TGATHER不在支持范围内结果不可预期。大 Tile 支持当每个 rank 的 GlobalTensor 在行和/或列方向超出 UB Tile 容量时传输会通过二维滑动2D sliding自动分块完成与其他 PTO-COMM 指令如 TSCATTER、TBROADCAST、TREDUCE采用完全相同的机制。在指令集中的定位上TGATHER 与 TSCATTER根节点分发数据到各 rank互为逆操作同属以根节点为中心的汇聚/分发类通信原语可参考 docs/isa/comm/README_zh.md 了解完整的 PTO-COMM 指令家族。二、数学语义假设并行组中共有 $N$ 个 rank每个 rank $r$ 的源数据形状为 $(D_0, D_1, D_2, H, W)$。TGATHER 沿 DIM_3 维度拼接所有 $N$ 个 rank 的数据其数学定义如下$$\mathrm{dst}{d_0, d_1, d_2,; r \cdot H i,; j} \mathrm{src}^{(r)}{d_0, d_1, d_2,; i,; j} \quad \forall, r \in [0, N),; i \in [0, H),; j \in [0, W)$$也就是说每个 rank 的 $H$ 行数据在目标 tensor 中占据连续的 $H$ 行区间rank $r$ 的数据被写入目标 tensor 的 $[r \cdot H, (r1) \cdot H)$ 行目标 tensor 的形状为 $(D_0, D_1, D_2, N \times H, W)$除 DIM_3 外的其余维度DIM_0、DIM_1、DIM_2、DIM_4在源与目标之间保持不变。从实现源码看include/pto/comm/a2a3/TGather.hpp 中的TGATHER_IMPL正是按照这一语义工作它从parallelGroup[0]读取各维度形状gShape0..gShape4并以perRankRows gShape3计算每个 rank 在目标中的行偏移r * perRankRows * dstStride3。三、汇编语法与数据路径TGATHER 的同步形式汇编语法为tgather %group, %dst : (!pto.group..., !pto.memref...)其中%group为并行组!pto.group...类型操作数%dst为目标全局内存!pto.memref...操作数。降级时的数据路径为 GM → UB → GM由于源数据位于各远端 rank 的全局内存GM、目标位于根节点本地 GM二者之间无法直接拷贝编译器在降级过程中会自动为这一数据通路引入 UB 暂存 Tile通过TLOADMTE2将某 rank 的一块数据从 GM 读入 UB 暂存 Tile通过TSTOREMTE3将 UB 暂存 Tile 写回根节点本地 GM 的目标行区间。正因如此C 内建接口需要显式传入暂存 Tile 操作数——即stagingTileData单缓冲或pingTile/pongTile乒乓双缓冲编译器不会自动分配。这也是编写 TGATHER kernel 时最容易遗漏的关键参数。四、模板参数引擎选择TGATHER 以模板参数engine选择底层执行引擎引擎默认值适用平台说明CollEngine::AIV✅ 默认通用基于 TLOAD/TSTORE 的 Tile 级数据搬运路径A2/A3 与 A5 均支持CollEngine::CCU—Ascend950仅 NPU_ARCH 3510AIV kernel 触发 CKE gate实际 Gather 数据路径由 CCU 引擎执行CCUCollective Communication Unit是 Ascend950 芯片上专用于集合通信的硬件引擎。在 CCU 模式下TGATHER本体仍运行于 AIV通过触发 CKECCU Kernel Enginegate 将数据搬运任务卸载到 CCU由于 CCU 的调用语义与 AIV 不同所有 rank 都必须通过宿主侧HcclCcuKernelRegister/HcclCcuKernelLaunch注册并启动 CCU kernel而 AIV 路径只有根节点调用TGATHER。完整示例可参考 tests/npu/a5/comm/st/testcase/tgather_ccu/ 目录。五、C 内建接口TGATHER 的 C 内建接口声明于 include/pto/comm/pto_comm_inst.hpp命名空间为pto::comm包含两个重载// 基础 gather单暂存 Tile template CollEngine engine CollEngine::AIV, typename ParallelGroupType, typename GlobalDstData, typename TileData, typename... Args PTO_INST RecordEvent TGATHER(ParallelGroupType parallelGroup, GlobalDstData dstGlobalData, TileData stagingTileData, Args... args); // 乒乓 gather使用两个暂存 Tile 实现双缓冲 template CollEngine engine CollEngine::AIV, typename ParallelGroupType, typename GlobalDstData, typename TileData, typename... Args PTO_INST RecordEvent TGATHER(ParallelGroupType parallelGroup, GlobalDstData dstGlobalData, TileData pingTile, TileData pongTile, Args... args);参数说明parallelGroupParallelGroupGlobalData类型封装并行组内所有 rank 的源 GlobalTensor从根节点视角看到的各 rank 远端 GM以及根节点索引dstGlobalData根节点本地 GM 上的目标 GlobalTensor形状为 $(D_0, D_1, D_2, N \times H, W)$stagingTileData或pingTile/pongTileUB 中预先分配的暂存 TileArgs...当engine CollEngine::CCU时可变参数的第一个参数必须是包含 CKE slot 虚拟地址和 gate mask 的CcuTriggerContext。AIV kernel 触发 CKE gate实际的 Gather 数据路径在 CCU 引擎上执行。两个重载的返回值均为RecordEvent可配合事件机制参与流水编排。从 include/pto/comm/pto_comm_inst.hpp 的实现可以看到接口内部依据engine在编译期分派CollEngine::AIV先WaitAllEvents(args...)等待依赖事件再调用TGATHER_IMPL(parallelGroup, dstGlobalData, stagingTileData)或乒乓版本CollEngine::CCU通过static_assert(sizeof...(Args) 1, TGATHERCCU requires CcuTriggerContext as first argument)在编译期强制要求传入CcuTriggerContext随后调用TGATHER_CCU_IMPLengine(...)。这一设计保证漏传CcuTriggerContext会在编译期直接报错而不是在设备侧产生难以排查的运行时失败。六、源码级实现解析6.1 A2/A3 后端三类执行路径include/pto/comm/a2a3/TGather.hpp 是 TGATHER 在 A2/A3 上的核心实现其TGATHER_IMPL首先通过一系列编译期断言与运行时断言建立前置条件详见第七节然后根据数据规模选择三条执行路径1. 简单路径TgatherSimple单 Tile 即可容纳每 rank 数据当totalRows tileValidRow gShape4 tileValidCol时其中totalRows D0 * D1 * D2 * H即单个 rank 的全部行数每 rank 数据可以一次装入 UB Tile。实现循环遍历所有 rankinclude/pto/comm/a2a3/TGather.hppfor (int r 0; r nranks; r) { TLOAD(stagingTileData, parallelGroup[r]); set_flag(PIPE_MTE2, PIPE_MTE3, EVENT_ID0); wait_flag(PIPE_MTE2, PIPE_MTE3, EVENT_ID0); int64_t dstOffset static_castint64_t(r) * perRankRows * dstStride3; DstViewT dstView(dstGlobalData.data() dstOffset, perRankShape, dstViewStride); TSTORE(dstView, stagingTileData); set_flag(PIPE_MTE3, PIPE_MTE2, EVENT_ID0); wait_flag(PIPE_MTE3, PIPE_MTE2, EVENT_ID0); }每个 rank 的搬运流程为TLOADMTE2→ pipe barrierMTE2→MTE3→ 以r * perRankRows * dstStride3计算目标偏移构造目标视图 → TSTOREMTE3→ 反向 barrier。这里的set_flag/wait_flag用于保证同一 Tile 上 MTE2 与 MTE3 的读写依赖顺序。2. 分块路径TgatherChunkedSingle二维滑动当每 rank 数据超出 UB Tile 容量时进入 2D 滑动分块模式include/pto/comm/a2a3/TGather.hpp外层维度 DIM_0、DIM_1、DIM_2 被显式循环迭代源与目标各自按 stride 计算基址偏移DIM_3行按tileValidRow大小切块DIM_4列按tileValidCol大小切块内层TgatherChunkedRowColLoopinclude/pto/comm/a2a3/TGather.hpp逐块执行 TLOAD → barrier → TSTORE → barrier。若 Tile 的ValidRow/ValidCol为DYNAMIC则每块通过RowMaskInternal/ColMaskInternal设置实际有效行/列数从而支持不足一整块的行或列。3. 乒乓路径TgatherChunkedPingPong双缓冲使用pingTile/pongTile两个暂存 Tile通过TgatherPingPongState状态机usePing、hasPending、pendingDstOffset、pendingRows、pendingCols将下一块的 TLOADMTE2与当前块的 TSTOREMTE3重叠执行include/pto/comm/a2a3/TGather.hpp。源码注释给出了直观的时间线对比无乒乓 [TLOAD chunk0] - [TSTORE chunk0] - [TLOAD chunk1] - [TSTORE chunk1] - ... 乒乓 [TLOAD chunk0] - [TSTORE chunk0 | TLOAD chunk1] - [TSTORE chunk1 | TLOAD chunk2] - ...乒乓模式下前一块的 TSTORE 与后一块的 TLOAD 同时进行可显著提升搬运吞吐。循环结束后由TgatherPingPongEpilogue冲刷最后一块待写的 TSTOREinclude/pto/comm/a2a3/TGather.hpp。6.2 A5 后端AIV 转发与 CCU 卸载include/pto/comm/a5/TGather.hpp 是 A5 上的实现文件开头定义PTO_COMM_A5_TGATHER_PROVIDED宏并#include pto/comm/a2a3/TGather.hpp——AIV 路径直接复用 A2/A3 实现避免代码重复CCU 路径的TGATHER_CCU_IMPL调用CcuStoreTriggerSelf(parallelGroup, stagingTileData, ctx, events...)即 AIV 触发 CKE gate、由 CCU 引擎实际执行数据搬运。乒乓重载同样只传pingTilepongTile被忽略。值得注意的细节是A2/A3 的TGATHER_CCU_IMPL是一个deferred-fail延迟失败stubinclude/pto/comm/a2a3/TGather.hpp其函数体仅包含static_assert(engine ! CollEngine::CCU, TGATHERCollEngine::CCU requires A5 hardware; CCU engine is not available on A2/A3.)。由于断言依赖模板参数engine只有在 CCU 调用被真正实例化时才会触发——普通 AIV 编译不受影响。A5 头文件通过PTO_COMM_A5_TGATHER_PROVIDED宏屏蔽该 stub防止其与真实实现重载产生歧义。6.3 CPU_SIM 后端include/pto/cpu/comm/TGather.hpp 提供 CPU 模拟实现TGATHER_IMPL通过模板化的Gather函数按元素拷贝完成语义等价实现并额外断言目标 DIM_3 等于源 DIM_3 × nranks 等形状关系include/pto/cpu/comm/TGather.hpp乒乓重载简单地转发到单缓冲版本CPU 模拟无需真实双缓冲CPU_SIM没有可用的CollEngine::CCU功能路径与 A2/A3 相同其 deferred-fail 重载会在编译期拒绝不支持的 CCU 调用。CCU 路径应使用 A5 NPU 后端。七、使用约束详解7.1 类型约束ParallelGroup::value_type::RawDType必须等于GlobalDstData::RawDTypeTileData::DType必须等于GlobalDstData::RawDType。对应实现中的static_assert位于 include/pto/comm/a2a3/TGather.hpp同时要求源与目标的layout一致GlobalSrcData::layout GlobalDstData::layout。7.2 内存约束dstGlobalData必须指向本地内存当前 NPU且足够容纳所有 rank 拼接后的结果dstGlobalData.GetShape(DIM_3)必须 $\geq N \times H$其中 $H$ 为每个 rank 的GetShape(DIM_3)若dstGlobalData.GetShape(DIM_3) N × H则只写入前N × H行其余行保持不变stagingTileData或pingTile/pongTile必须预先在 UB 中分配——接口本身不会分配 UB 空间。7.3 ParallelGroup 约束parallelGroup.tensors[r]必须指向 rankr的源缓冲区从根节点视角看到的远端 GMparallelGroup.GetRootIdx()标识调用方 NPU 为 gather 根节点所有源 tensor 假定具有相同的形状和步幅否则行为未定义。ParallelGroup定义于 include/pto/comm/comm_types.hpp提供value_type类型别名、GetRootIdx()与tensors[teamRank]下标访问。TGATHER_IMPL会通过PTO_ASSERT校验nranks 0与rootIdx ∈ [0, nranks)。7.4 分块模式约束源数据超出单个 UB Tile 时若TileData具有静态ValidRow则每个 rank 源数据的GetShape(DIM_3)必须能被ValidRow整除。如需支持不足一行的情况请使用DYNAMICValidRow 的 Tile若TileData具有静态ValidCol则GetShape(DIM_4)必须能被ValidCol整除。如需支持不足一列的情况请使用DYNAMICValidCol 的 Tile。实现中对应的PTO_ASSERT为include/pto/comm/a2a3/TGather.hppif constexpr (!isDynamicRow) { PTO_ASSERT(gShape3 % tileValidRow 0, TGATHER chunked: per-rank DIM_3 must be divisible by tile ValidRow when static. Use a Tile with DYNAMIC ValidRow for partial row chunk support.); } if constexpr (!isDynamicCol) { PTO_ASSERT(gShape4 % tileValidCol 0, TGATHER chunked: DIM_4 must be divisible by tile ValidCol when static. Use a Tile with DYNAMIC ValidCol for partial column chunk support.); }此外tileValidRow与tileValidCol必须大于 0当totalRows 0 || gShape4 0时空数据TGATHER_IMPL直接返回不做任何搬运。八、实战示例8.1 基础 Gather单暂存 Tile每个 rank 提供ROWS × COLS的数据根节点将其收集到NRANKS * ROWS行中。Tile 大小TILE_ROWS × TILE_COLS可以小于每 rank 的数据——此时实现会自动沿 DIM_3 和 DIM_4 通过二维滑动进行分块传输。#include pto/comm/pto_comm_inst.hpp using namespace pto; template typename T, int ROWS, int COLS, int TILE_ROWS, int TILE_COLS, int NRANKS void gather(__gm__ T* group_addrs[NRANKS], __gm__ T* result, int my_rank) { using TileT TileTileType::Vec, T, TILE_ROWS, TILE_COLS, BLayout::RowMajor, -1, -1; using GPerRank GlobalTensorT, Shape1,1,1,ROWS,COLS, BaseShape2DT, ROWS, COLS, Layout::ND, Layout::ND; using GResult GlobalTensorT, Shape1,1,1,NRANKS*ROWS,COLS, BaseShape2DT, NRANKS*ROWS, COLS, Layout::ND, Layout::ND; GPerRank tensors[NRANKS]; for (int i 0; i NRANKS; i) tensors[i] GPerRank(group_addrs[i]); comm::ParallelGroupGPerRank group(tensors, NRANKS, my_rank); GResult dstG(result); TileT stagingTile(TILE_ROWS, TILE_COLS); comm::TGATHER(group, dstG, stagingTile); }关键点解读Tile模板中-1, -1表示静态 ValidRow/ValidCol 取 Tile 本身的行列数即TILE_ROWS × TILE_COLSParallelGroup构造参数依次为tensor 数组、rank 总数、当前进程在组内的 rank 号根节点由GetRootIdx()标识每个 rank 都执行gather()但只有my_rank root的进程真正执行comm::TGATHER。8.2 乒乓 Gather双缓冲使用两个 UB Tile将下一块的 TLOADMTE2与当前块的 TSTOREMTE3重叠执行适合数据量较大、搬运带宽成为瓶颈的场景。#include pto/comm/pto_comm_inst.hpp using namespace pto; template typename T, int ROWS, int COLS, int TILE_ROWS, int TILE_COLS, int NRANKS void gather_pingpong(__gm__ T* group_addrs[NRANKS], __gm__ T* result, int my_rank) { using TileT TileTileType::Vec, T, TILE_ROWS, TILE_COLS, BLayout::RowMajor, -1, -1; using GPerRank GlobalTensorT, Shape1,1,1,ROWS,COLS, BaseShape2DT, ROWS, COLS, Layout::ND, Layout::ND; using GResult GlobalTensorT, Shape1,1,1,NRANKS*ROWS,COLS, BaseShape2DT, NRANKS*ROWS, COLS, Layout::ND, Layout::ND; GPerRank tensors[NRANKS]; for (int i 0; i NRANKS; i) tensors[i] GPerRank(group_addrs[i]); comm::ParallelGroupGPerRank group(tensors, NRANKS, my_rank); GResult dstG(result); TileT pingTile(TILE_ROWS, TILE_COLS); TileT pongTile(TILE_ROWS, TILE_COLS); // 乒乓模式将 TLOAD 与 TSTORE 重叠执行以提升吞吐量 comm::TGATHER(group, dstG, pingTile, pongTile); }需要额外注意乒乓模式使用两个 UB TileUB 占用是单缓冲的两倍需确保不超过 UB 容量测试代码中使用((tile_rows * cols * sizeof(T) 1023) / 1024) * 1024计算 Tile 字节数并放置于不同地址见 tests/npu/a5/comm/st/testcase/tgather/tgather_kernel.cpp。九、测试与验证仓库在tests/npu/a5/comm/st/testcase/tgather/与tests/npu/a5/comm/st/testcase/tgather_ccu/提供了完整的 NPU 系统测试覆盖了 TGATHER 的主要使用形态测试场景数据规模验证要点基础 Gatherfloat256 元素 /int32_t4096 /uint8_t512每 rank 形状[1,1,1,1,count]根节点按 rank 序拼接逐元素比对i rank_id * 10000指定根节点float256root 可配置RunGatherWithRoot验证非 0 根节点空数据DIM_3 0目标缓冲保持初始值-1不变验证空行早退路径大形状分块int32_t128×32tile 16 行、float256×64tile 32、int32_t512×32tile 64静态 Tile 下total_rows % tile_rows 0验证二维滑动分块乒乓双缓冲同上规模验证TGATHER(pg, dst, ping, pong)重载与 MTE2/MTE3 重叠以基础测试 kernel 为例tests/npu/a5/comm/st/testcase/tgather/tgather_kernel.cpp每个 rank 通过CommRemotePtr(hcclCtx, src, i)构造指向远端 rank 源缓冲的 GlobalTensor 并装入ParallelGroup随后仅根节点执行pto::comm::TGATHER(pg, dstG, ubTile)最终在宿主侧读回并逐元素校验。CCU 测试tests/npu/a5/comm/st/testcase/tgather_ccu/tgather_ccu_kernel.cpp则展示了 CCU 路径的调用形态pto::comm::CcuTriggerContext ctx{ckeVA, mask}; pto::comm::TGATHERpto::comm::CollEngine::CCU(group, dstGm, stagingTile, ctx);即显式指定引擎模板参数为CollEngine::CCU并传入包含 CKE slot 虚拟地址与 gate mask 的CcuTriggerContext。十、总结TGATHER 是 PTO-ISA 通信指令集中实现根节点汇聚的原语根节点沿 DIM_3 行维度拼接并行组所有 rank 的数据底层通过 GM→UB→GM 的 TLOAD/TSTORE 数据路径完成搬运并自动支持二维滑动分块以突破 UB Tile 容量限制。开发时需牢记四点只有根节点调用、必须显式传入 UB 暂存 Tile、源/目标/暂存 Tile 类型必须一致、静态 ValidRow/ValidCol 要求形状整除否则使用 DYNAMIC Tile。在需要更高吞吐的场景下可使用乒乓双缓冲重载让 TLOAD 与 TSTORE 重叠执行在 Ascend950NPU_ARCH 3510上还可通过CollEngine::CCU将数据搬运卸载至 CCU 引擎。结合 include/pto/comm/a2a3/TGather.hpp、include/pto/comm/a5/TGather.hpp 与 include/pto/cpu/comm/TGather.hpp 三份实现以及对应测试用例即可快速上手并验证自己的 TGATHER kernel。【免费下载链接】pto-isaParallel Tile Operation (PTO) is a virtual instruction set architecture designed by Ascend CANN, focusing on tile-level operations. This repository offers high-performance, cross-platform tile operations across Ascend platforms.项目地址: https://gitcode.com/cann/pto-isa创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考