
UB 缓冲区管理指南【免费下载链接】cannbot-skillsCANNBot 是面向 CANN 开发的用于提升开发效率的系列智能体本仓库为其提供可复用的 Skills 模块。项目地址: https://gitcode.com/cann/cannbot-skillsTBuf/TQue 选择、Double Buffer 流水线并行、批量搬运模式。目录TBuf vs TQue 选择TQue 详解TBuf 详解Double Buffer 流水线并行批量搬运 逐行计算模式TBuf vs TQue 选择场景推荐类型说明MTE2/MTE3 搬运缓冲区TQueVECIN/VECOUT需要与 Vector 并行需要 EnQue/DeQue纯 Vector 计算缓冲区TBufVECCALC不涉及 MTE 搬运用GetT()获取Double BufferTQueInitBuffer(que, 2, size)在 InitBuffer 中设置 num2 开启TQue 详解模板参数template TPosition pos, int32_t depth, auto mask 0 class TQue;参数说明pos队列逻辑位置VECIN,VECOUT,A1,A2,B1,B2,CO1,CO2depth队列深度表示可连续 EnQue/DeQue 的次数mask数据格式转换ND↔NZ或编译期优化参数depth 参数关键说明depth 值适用场景说明depth1默认推荐非 Tensor 原地操作编译器有特殊优化性能更好depth0Tensor 原地操作需要设置depth2连续 2 次 EnQue 场景与 InitBuffer 的 num 参数独立注意depth与 Double Buffer 无关。Double Buffer 由InitBuffer的num参数控制。// ✅ 非连续入队普通场景depth1 即可 AscendC::TQueAscendC::TPosition::VECIN, 1 que; pipe-InitBuffer(que, 1, size); auto tensor que.AllocTensorT(); que.EnQue(tensor); tensor que.DeQueT(); que.FreeTensor(tensor);Double Buffer 配置Double Buffer 是在InitBuffer的num参数中设置与模板参数depth无关。InitBuffer 参数作用说明InitBuffer(que, num, size)num控制 Double Buffernum1单 Buffernum2开启 Double Buffer模板参数depth队列深度表示可连续 EnQue 的次数// ✅ 开启 Double Buffer在 InitBuffer 中设置 num2 AscendC::TQueAscendC::TPosition::VECIN, 1 que; // 模板 depth1 即可 pipe-InitBuffer(que, 2, size); // num2 开启 Double Buffer // ✅ 关闭 Double Buffer AscendC::TQueAscendC::TPosition::VECIN, 1 que; pipe-InitBuffer(que, 1, size); // num1 单 BufferTQue Buffer 数量限制产品系列eventID 数量最大 TQue 数量Atlas 训练系列44Atlas 推理系列 AI Core88Atlas 推理系列 Vector Core88Atlas A2/A3 系列88注意不开启 Double Buffernum1最多可申请 8 个 TQue开启 Double Buffernum2每个 TQue 占用 2 个 buffer最多只能申请 4 个 TQue// 开启 Double Buffer 时最多只能申请 4 个 TQue pipe-InitBuffer(que0, 2, size); // ✅ pipe-InitBuffer(que1, 2, size); // ✅ pipe-InitBuffer(que2, 2, size); // ✅ pipe-InitBuffer(que3, 2, size); // ✅ pipe-InitBuffer(que4, 2, size); // ❌ 超过限制TQue 正确用法// TQue需要队列管理MTE 搬运相关 // 模板 depth1 即可Double Buffer 在 InitBuffer 的 num 参数中设置 AscendC::TQueAscendC::TPosition::VECIN, 1 inQueueX; pipe-InitBuffer(inQueueX, 2, bufferSize); // num2 开启 Double Buffer AscendC::LocalTensorhalf x inQueueX.AllocTensorhalf(); AscendC::DataCopyPad(x, xGm, {1, size * sizeof(half), 0, 0}, {false, 0, 0, 0}); inQueueX.EnQue(x); // ... AscendC::LocalTensorhalf xLocal inQueueX.DeQuehalf(); inQueueX.FreeTensor(xLocal);TBuf 详解特性特性说明内存用途只能参与计算无法执行 EnQue/DeQue内存分配每次 InitBuffer 只分配一块内存Tensor 释放无需手动释放// TBuf纯计算缓冲区 AscendC::TBufAscendC::TPosition::VECCALC workBuf; pipe-InitBuffer(workBuf, bufferSize); // ✅ 使用 GetT() 获取 Tensor无需释放 AscendC::LocalTensorfloat work workBuf.Getfloat(); // ... 计算逻辑 ... // 无需 FreeTensorDouble Buffer 流水线并行核心认知Double Buffer 不是用2块内存计算而是用2块内存做搬入/搬出使 MTE2/MTE3 与 Vector 计算并行。本质内存搬运与计算并行掩盖搬运延迟。硬件原理MTE2搬运工GM → UBVector加工员计算MTE3搬运工UB → GM时间线对比无 Double Buffer串行Row 0: [MTE2][Vector][MTE3] Row 1: [MTE2][Vector][MTE3]有 Double Buffer并行Row 0: [MTE2-B0][Vector-B0][MTE3-B0] Row 1: [MTE2-B1][Vector-B1][MTE3-B1] ↑ MTE2与Vector并行实现原则Buffer 类型InitBuffer num说明TQueVECIN(MTE2 搬运)2num2 开启 Double Buffer与 Vector 并行TQueVECOUT(MTE3 搬运)2num2 开启 Double Buffer与 Vector 并行TBufVECCALC(纯计算)-TBuf 不涉及 MTE 搬运正确用法// 1. Init: num2 开启 Double Buffer pipe-InitBuffer(inQueueX, 2, tileSize * sizeof(T)); pipe-InitBuffer(outQueueY, 2, tileSize * sizeof(T)); pipe-InitBuffer(workBuf, workSize * sizeof(T)); // 2. Process: 单循环结构TQue 自动轮转 for (int i 0; i totalTiles; i) { CopyIn(i); // MTE2 异步搬运 Compute(i); // Vector 计算 CopyOut(i); // MTE3 异步搬出 } // 3. CopyIn void CopyIn(int i) { LocalTensorT x inQueueX.AllocTensorT(); DataCopyPad(x, xGm[i * tileSize], {1, (uint32_t)(tileSize * sizeof(T)), 0, 0}, {false, 0, 0, 0}); inQueueX.EnQue(x); } // 4. Compute void Compute(int i) { LocalTensorT x inQueueX.DeQueT(); LocalTensorT y outQueueY.AllocTensorT(); Add(y, x, constTensor, tileSize); outQueueY.EnQue(y); inQueueX.FreeTensor(x); } // 5. CopyOut void CopyOut(int i) { LocalTensorT y outQueueY.DeQueT(); DataCopyPad(yGm[i * tileSize], y, {1, (uint32_t)(tileSize * sizeof(T)), 0, 0}); outQueueY.FreeTensor(y); }为什么能并行操作特性DataCopy异步 DMA立即返回EnQue非阻塞标记就绪DeQue阻塞等待就绪常见误区误区正确理解需要手动拆成 Ping/Pong 两套代码单循环 InitBuffer(que, 2, size)自动管理depth 模板参数控制 Double BufferDouble Buffer 由InitBuffer的num参数控制depth 越大越好模板 depth 通常设为 1性价比最高所有 buffer 都要 num2只有涉及 MTE 搬运的才需要 Double Buffer批量搬运 逐行计算模式适用场景处理多行数据时批量搬运减少 MTE2/MTE3 调用次数充分利用带宽。模式结构CopyInBatch(N行) → 逐行计算(N次) → CopyOutBatch(N行)代码模板__aicore__ inline void ProcessBatch() { uint32_t totalRowsToProcess endRow - startRow; if (totalRowsToProcess 0) return; for (uint32_t tile 0; tile tilesPerCore; tile) { uint32_t startLocalRow tile * tileRows; // 边界检查防止 uint32_t 下溢 if (startLocalRow totalRowsToProcess) break; uint32_t remaining totalRowsToProcess - startLocalRow; uint32_t rowsThisTile (remaining tileRows) ? remaining : tileRows; CopyInBatch(startLocalRow, rowsThisTile); ComputeBatch(rowsThisTile); CopyOutBatch(startLocalRow, rowsThisTile); } }Host 侧 Tiling 计算// A2/A3 UB 192KB constexpr uint64_t UB_SIZE 192 * 1024; constexpr uint32_t MAX_BLOCK_COUNT 4095; // DataCopyPad blockCount 限制 // bytesPerTileRow: double buffer (in*2 out*2) uint32_t bytesPerTileRow paddedColsT * typeSizeBytes * 4; // tileRows uint32_t tileRows (UB_SIZE - overheadBytes) / bytesPerTileRow; tileRows std::max(1u, std::min(tileRows, MAX_BLOCK_COUNT));注意事项tileRows 限制DataCopyPad 的blockCount最大 4095尾核处理startLocalRow totalRowsToProcess时提前退出stride 计算UB 侧 stride 单位是 32 字节块GM 侧是字节【免费下载链接】cannbot-skillsCANNBot 是面向 CANN 开发的用于提升开发效率的系列智能体本仓库为其提供可复用的 Skills 模块。项目地址: https://gitcode.com/cann/cannbot-skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考