人工智能指令集算子库CANNAscend【免费下载链接】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点击查看免费下载导读本文全面解析 CANN pto-isa 提供的Auto Mode自动模式编译能力编译器自动为Tile分配片上缓冲区地址、自动在昇腾硬件不同 pipeline 之间插入同步指令让 kernel 开发者免于手写TASSIGN与Event同步同时保持与专家手调 manual 模式相当的性能。读完本文你将掌握 auto mode 的抽象边界TF 层以上、三大核心特性liveness 分析、自动同步、Tile 内存分配、完整的 Ascend CANN 编译命令以及 kernel 开发者在 auto mode 下必须遵守的控制流与内存规则。一、什么是 PTO Auto ModePTOParallel Tile Operation是昇腾 CANN 定义的一种面向 tile 级运算的虚拟指令集架构而Auto Mode 是 PTO 的一种编译模式它把为 Tile 分配内存和跨 pipeline 插入同步指令这两件事全部交给编译器完成。与 manual 模式相比auto mode 下编程方式几乎不变但有以下两点关键差异不需要调用TASSIGN来为 Tile 手动绑定硬件缓冲区地址不需要显式的Event同步在 auto mode 下这些指令实际是 no-op写了也不起作用。这一表述在 auto 模式总览 中亦有明确说明并得到仓库演示工程的印证在 demos/auto_mode/baseline/add 的 README 中明确指出与 manual 模式不同kernel 中无需手动调用TASSIGN和同步指令编译器会代为处理。PTO AUTO 模式的定位是提供两大收益见 auto 模式 README简化开发在开发高效 PTO 代码的同时仍为 kernel 开发者保留实现优化所必需的机制跨架构兼容同一份 PTO 源码可针对不同代际的昇腾架构编译无需修改源码即可保持性能——尤其不需要关心不同架构之间 Cube 与 Vector 计算协同方式的差异。二、为什么使用 Auto Modeauto mode 的目标非常明确为使用者提供更高层的接口抽象以提升开发效率同时确保与专家手调代码相比仍具备有竞争力的性能。围绕这一目标它提供了两大抽象能力自动同步指令插入在昇腾硬件不同 pipeline如PIPE_MTE2、PIPE_V、PIPE_MTE3之间自动插入同步指令Tile 内存分配与管理对Tile抽象对象自动完成片上 buffer 的分配。这两大抽象正是本文后续第三、四节要展开的核心。三、抽象层级编译器工作的边界在 TF 层以上理解 auto mode 之前必须先理解 PTO 指令实现的分层抽象。按照 auto 模式总览 的说明每一个 PTO 指令的实现通常包含以下层级从高到低层级说明用户层 API公有、最高层级的接口由 kernel 开发者直接调用IMPL 层 API指令实现层接口TFTile Function层 APITile 抽象层级的最后一层CCE 实现层 API内部 CCE 实现如 VF、SIMT 函数等PTO 编译器工作在 Tile 这一抽象层级上。这意味着上文所述的所有 auto 特性只在 TF 层以上生效因为 TF 层接口是 Tile 抽象的最后一层一旦进入 tile function 内部就不再存在 tile 级抽象只剩裸指针和裸 CCE intrinsics——那是 CCE 编译器的领域。因此tile function 对 PTO 编译器而言是一个完全的黑盒子PTO 编译器的功能不会进入 tile function 内部运作。这个边界在库开发者规则中有更具体的体现库开发者规则文档 第 3 条指出auto-sync 不会穿透 tile function整个 auto 模式编译器都工作在 tile function 层级tile function 内部对编译器完全不可见因此 tile function 内部仍需要库开发者手动加入同步。源码层面这一向量化 Tile的设计可以从 include/pto/common/memory.hpp 得到佐证MemoryQualifierTileType::Vec, DType在__PTO_AUTO__宏下定义为__ubuf__ DType向量类型而在 manual 模式下定义为__ubuf__ DType*指针类型TileType::Mat、TileType::Left、TileType::Right、TileType::Acc等也有同样的区分。这正是 库开发者规则文档 第 1 条所说 .data()在 auto mode 下返回向量类型而非指针类型 的根源。四、Auto Mode 三大核心特性4.1 Tile 自动 liveness 分析核心基础在 auto mode 下PTO 编译会跟踪每一个 Tile 及其live-range活跃区间。这是 auto mode 的核心分析组件为后面两项特性自动同步、Tile 内存分配提供基础支撑只有知道每个 Tile 何时被写、何时最后一次被读编译器才能决定缓冲区的复用时机和同步的插入位置。这一点在 库开发者规则文档 第 4 条中也有印证auto mode 下整个内存分配完全基于每个 Tile 的 liveness 分析不依赖其他任何上下文——这正是TPUSH、TPOP当前无法在 auto mode 下工作的原因。4.2 自动同步Automatic Synchronization在 manual 模式下程序员必须时刻关注硬件异步执行的特点借助 PTO 的 事件模型Event Model 在代码的精确位置插入同步以同时保证功能正确与高性能。这既繁琐又极易出错。auto mode 编译则替程序员省去了这一负担编译器会在底层自动确定需要插入同步的位置保证功能正确的同时维持有竞争力的性能。为了直观感受两者的差距我们看 auto 模式示例文档 中的TADD向量加法对比。Auto mode 版本#include pto/pto-inst.hpp #include pto/common/constants.hpp using namespace pto; AICORE void runTAdd(__gm__ float __out__ *out, __gm__ float __in__ *src0, __gm__ float __in__ *src1) { using DynShapeDim5 Shape1, 1, 1, 64, 64; using DynStridDim5 Stride1, 1, 1, 64, 1; using GlobalData GlobalTensorfloat, DynShapeDim5, DynStridDim5; using TileData TileTileType::Vec, float, 64, 64, BLayout::RowMajor, 64, 64; TileData src0Tile(64, 64); TileData src1Tile(64, 64); TileData dstTile(64, 64); GlobalData src0Global(src0); GlobalData src1Global(src1); GlobalData dstGlobal(out); TLOAD(src0Tile, src0Global); TLOAD(src1Tile, src1Global); TADD(dstTile, src0Tile, src1Tile); TSTORE(dstGlobal, dstTile); }Manual mode 版本#include pto/pto-inst.hpp #include pto/common/constants.hpp using namespace pto; AICORE void runTAdd(__gm__ float __out__ *out, __gm__ float __in__ *src0, __gm__ float __in__ *src1) { using DynShapeDim5 Shape1, 1, 1, 64, 64; using DynStridDim5 Stride1, 1, 1, 64, 1; using GlobalData GlobalTensorfloat, DynShapeDim5, DynStridDim5; using TileData TileTileType::Vec, float, 64, 64, BLayout::RowMajor, 64, 64; TileData src0Tile(64, 64); TileData src1Tile(64, 64); TileData dstTile(64, 64); /* TAssign only in manual mode */ TASSIGN(src0Tile, 0x0); TASSIGN(src1Tile, 0x10000); TASSIGN(dstTile, 0x20000); GlobalData src0Global(src0); GlobalData src1Global(src1); GlobalData dstGlobal(out); /* event model only in manual mode */ EventOp::TLOAD, Op::TADD event0; EventOp::TADD, Op::TSTORE_VEC event1; TLOAD(src0Tile, src0Global); event0 TLOAD(src1Tile, src1Global); event1 TADD(dstTile, src0Tile, src1Tile, event0); TSTORE(dstGlobal, dstTile, event1); }对比可见manual 版本需要手写 3 条TASSIGN分配地址、声明 2 个Event对象并手工把事件 token 从TLOAD一路传递到TSTORE而 auto 版本只有纯粹的 load → compute → store 数据流其余全部交给编译器。4.3 Tile 内存分配Tile Memory Allocation在 PTO 默认manual编译模式下实例化Tile变量之后还需要用TASSIGN指令手动为它绑定一个专用的 buffer 地址。而 auto mode 下这一步被省略只要实例化Tile变量编译器就会自动在底层为它分配 buffer 地址。同样的差异也体现在矩阵乘TMATMUL的对比中完整代码见 auto 模式示例文档。下面分别给出 auto 与 manual 两个版本的核心片段Auto mode 版本TMATMULtemplate typename cType, typename aType, typename bType, typename fbType, typename l0cType, int M, int K, int N, int ValidM, int ValidK, int ValidN __global__ AICORE void runTMatMul(__gm__ cType *out, __gm__ aType *src0, __gm__ bType *src1, __gm__ fbType *src2) { using GlobalDataSrc0 GlobalTensoraType, pto::Shape1, 1, 1, ValidM, ValidK, pto::StrideValidM * ValidK, ValidM * ValidK, ValidM * ValidK, ValidK, 1; using GlobalDataSrc1 GlobalTensorbType, pto::Shape1, 1, 1, ValidK, ValidN, pto::StrideValidK * ValidN, ValidK * ValidN, ValidK * ValidN, ValidN, 1; using GlobalDataSrc2 GlobalTensorfbType, pto::Shape1, 1, 1, 1, ValidN, pto::StrideValidN, ValidN, ValidN, ValidN, 1; using GlobalDataOut GlobalTensorcType, pto::Shape1, 1, 1, ValidM, ValidN, pto::StrideValidM * ValidN, ValidM * ValidN, ValidM * ValidN, ValidN, 1; GlobalDataSrc0 src0Global(src0); GlobalDataSrc1 src1Global(src1); GlobalDataSrc2 src2Global(src2); GlobalDataOut dstGlobal(out); using TileMatAData TileTileType::Mat, aType, M, K, BLayout::ColMajor, ValidM, ValidK, SLayout::RowMajor, 512; using TileMatBData TileTileType::Mat, bType, K, N, BLayout::ColMajor, ValidK, ValidN, SLayout::RowMajor, 512; using TileMatFbData TileTileType::Mat, fbType, 1, N, BLayout::RowMajor, 1, ValidN, SLayout::NoneBox; using LeftTile TileLeftaType, M, K, ValidM, ValidK; using RightTile TileRightbType, K, N, ValidK, ValidN; using AccTile TileAccl0cType, M, N, ValidM, ValidN; using FbTile TileTileType::Scaling, fbType, 1, N, BLayout::RowMajor, 1, ValidN, SLayout::NoneBox; TileMatAData aMatTile; TileMatBData bMatTile; TileMatFbData fbMatTile; LeftTile aTile; RightTile bTile; AccTile cTile; FbTile fbTile; TLOAD(aMatTile, src0Global); TLOAD(bMatTile, src1Global); TLOAD(fbMatTile, src2Global); /**************************TMOV TMATMUL**************************/ TMOV(aTile, aMatTile); TMOV(bTile, bMatTile); TMATMUL(cTile, aTile, bTile); TMOV(fbTile, fbMatTile); /********************************TSTORE****************************/ TSTORE_FPAccTile, GlobalDataOut, FbTile(dstGlobal, cTile, fbTile); }Manual mode 版本TMATMUL 差异部分/* TAssign only in manual mode */ TASSIGN(aMatTile, 0x0); TASSIGN(bMatTile, 0x10000); TASSIGN(fbMatTile, 0x20000); LeftTile aTile; RightTile bTile; AccTile cTile; FbTile fbTile; /* TAssign only in manual mode */ TASSIGN(aTile, 0x0); TASSIGN(bTile, 0x0); TASSIGN(cTile, 0x0); TASSIGN(fbTile, 0x0); /* event model only in manual mode */ EventOp::TLOAD, Op::TMOV_M2L evtLoad_Mov; EventOp::TMOV_M2B, Op::TMATMUL evtMov_Matmul; EventOp::TMATMUL, Op::TMOV_M2S evtMatmul_MovM2s; TLOAD(aMatTile, src0Global); TLOAD(bMatTile, src1Global); evtLoad_Mov TLOAD(fbMatTile, src2Global); /**************************TMOV TMATMUL**************************/ TMOV(aTile, aMatTile, evtLoad_Mov); evtMov_Matmul TMOV(bTile, bMatTile); evtMatmul_MovM2s TMATMUL(cTile, aTile, bTile, evtMov_Matmul); TMOV(fbTile, fbMatTile, evtMatmul_MovM2s); /********************************TSTORE****************************/ TSTORE_FPAccTile, GlobalDataOut, FbTile(dstGlobal, cTile, fbTile);可以看到矩阵乘这类横跨 L1TileMatA/B/Fb、L0LeftTile/RightTile/AccTile/FbTile多个缓冲区的复杂 kernelmanual 模式需要多达 7 条TASSIGN和 3 个跨 pipeline 的Eventauto 模式则全部消解。五、使用 Ascend CANN 编译 Auto Mode 代码5.1 编译选项要用 auto mode 编译 kernel只需在 Bisheng CCE 工具链中使能 PTO auto mode 编译 pass即追加两个编译选项--cce-pto-enable --cce-pto-auto-enable此外有两个需要牢记的限制见 auto 模式 README 与 demos 说明auto mode 目前只支持-O2优化选项需要根据目标 SoC 指定--cce-aicore-arch本仓库示例中使用的取值包括dav-c220-vec、dav-c310-vec等。5.2 Device 侧编译示例编译单个 CCE kernel 源文件为 object 文件source /usr/local/Ascend/ascend-toolkit/latest/bin/setenv.bash bisheng -c -x cce -O2 --cce-aicore-only \ --cce-aicore-archdav-c310-vec \ -stdc17 \ --cce-pto-enable \ --cce-pto-auto-enable \ kernel.cpp -o kernel.o参数说明-c -x cce将输入视为 CCE 源码并只编译不链接-O2auto mode 当前支持的唯一优化级别必须使用--cce-aicore-only仅生成 AI Core 侧代码--cce-aicore-archdav-c310-vec指定目标 SoC 的 AI Core 架构-stdc17按 C17 标准编译--cce-pto-enable使能 PTO 编译通道--cce-pto-auto-enable在 PTO 通道上叠加 auto mode 编译。5.3 在工程构建CMake中使能除了直接调用 bishengauto mode 也可以集成进ascendc_library工程。仓库中的 demos/auto_mode/baseline/add/CMakeLists.txt 展示了标准做法ascendc_library(no_workspace_kernel STATIC csrc/kernel/add_custom.cpp ) ascendc_compile_options(no_workspace_kernel PRIVATE --cce-pto-enable --cce-pto-auto-enable -O2)同样需要注意-O2必须显式带上否则不满足 auto mode 的编译前提。5.4 一个可运行的最小例子TMULauto 模式 README 给出了元素级乘法TMUL的最小对比。Auto mode 版本如下去掉全部手动同步与地址分配template typename T, int kGRows_, int kGCols_, int kTRows_, int kTCols_ __global__ AICORE void runTMul(__gm__ T __out__ *out, __gm__ T __in__ *src0, __gm__ T __in__ *src1) { using DynShapeDim5 Shape1, 1, 1, kGRows_, kGCols_; using DynStridDim5 Stride1, 1, 1, kGCols_, 1; using GlobalData GlobalTensorT, DynShapeDim5, DynStridDim5; using TileData TileTileType::Vec, T, kTRows_, kTCols_, BLayout::RowMajor, -1, -1; TileData src0Tile(kGRows_, kGCols_); TileData src1Tile(kGRows_, kGCols_); TileData dstTile(kGRows_, kGCols_); int offset (block_idx / 4) * (64 * 16) (block_idx % 4) * 16; GlobalData src0Global(src0 offset); GlobalData src1Global(src1 offset); GlobalData dstGlobal(out offset); TLOAD(src0Tile, src0Global); TLOAD(src1Tile, src1Global); TMUL(dstTile, src0Tile, src1Tile); TSTORE(dstGlobal, dstTile); out dstGlobal.data(); }而manual 版本则需要显式的TASSIGN和set_flag/wait_flag同步template typename T, int kGRows_, int kGCols_, int kTRows_, int kTCols_ __global__ AICORE void runTMul(__gm__ T __out__ *out, __gm__ T __in__ *src0, __gm__ T __in__ *src1) { using DynShapeDim5 Shape1, 1, 1, kGRows_, kGCols_; using DynStridDim5 Stride1, 1, 1, kGCols_, 1; using GlobalData GlobalTensorT, DynShapeDim5, DynStridDim5; using TileData TileTileType::Vec, T, kTRows_, kTCols_, BLayout::RowMajor, -1, -1; TileData src0Tile(kGRows_, kGCols_); TileData src1Tile(kGRows_, kGCols_); TileData dstTile(kGRows_, kGCols_); TASSIGN(src0Tile, 0x0 0x400 * block_idx); TASSIGN(src1Tile, 0x4000 0x400 * block_idx); TASSIGN(dstTile, 0x8000 0x400 * block_idx); int offset (block_idx / 4) * (64 * 16) (block_idx % 4) * 16; GlobalData src0Global(src0 offset); GlobalData src1Global(src1 offset); GlobalData dstGlobal(out offset); TLOAD(src0Tile, src0Global); TLOAD(src1Tile, src1Global); set_flag(PIPE_MTE2, PIPE_V, EVENT_ID0); wait_flag(PIPE_MTE2, PIPE_V, EVENT_ID0); TMUL(dstTile, src0Tile, src1Tile); set_flag(PIPE_V, PIPE_MTE3, EVENT_ID0); wait_flag(PIPE_V, PIPE_MTE3, EVENT_ID0); TSTORE(dstGlobal, dstTile); out dstGlobal.data(); }manual 版本中程序员必须手工计算并硬编码 buffer 地址0x0 0x400 * block_idx等还需显式插入两组set_flag/wait_flag来保证TLOAD → TMUL → TSTORE的 pipeline 顺序——这些在 auto 模式下全部由编译器接管。六、Auto Mode 下的开发规则与限制实战要点auto mode 能自动完成同步与分配的前提是代码的可分析性。违反以下规则可能导致编译失败、功能错误如精度问题或性能退化。这些规则完整收录于 kernel 开发者规则与限制 与 库开发者规则与限制。6.1 控制流规则复杂的控制流尤其是循环内部会让编译器难以进行精确的跨 pipeline 并行与双缓冲优化。由于编译器必须保证程序正确性它可能生成更保守的同步操作从而带来性能损失。具体建议1首末迭代的守卫条件应可静态求值。把循环首、末迭代的守卫写成能被编译器静态评估的形式编译器就能自动对首末迭代做 peel从而大幅简化自动同步。例如for (int tile_id 0; tile_id total_tiles; tile_id) { if (tile_id 0) { TLOAD(srcTile, globalSrc); } ... if (tile_id total_tiles-1) { TSTORE(globalDst, dstTile); } }2循环嵌套中的循环不变量控制流应留在内层。不依赖内层循环归纳变量的 if 语句应保留在内层循环内部而非提到外层// 推荐把 if 保留在内层循环里 for (int tile_id 0; tile_id total_tiles; tile_id) { int next_tile tile_id total_tiles-1 ? tile_id 1 : -1; ... for (int subtile_id 0; subtile_id total_subtiles; subtile_id) { if (next_tile ! -1) { ... // computation here } } }3if 语句中的复杂逻辑表达式应预先求值。守卫 PTO 指令的复杂逻辑表达式强烈建议先求值成 bool 变量再使用bool cond (srcTile.GetValidRow() 16 || srcTile.GetValidCol() 16) srcTile.GetKAligned(); if (cond) { TLOAD(srcTile, globalSrc1); } else { TLOAD(srcTile, globalSrc0); }4当前阶段强烈建议不要使用双/多缓冲double/multi buffering。一旦 kernel 变复杂双缓冲几乎必然引入复杂控制流给编译器的自动同步带来巨大挑战。auto mode 团队正在设计带约束的专用抽象/接口来支持双缓冲但在那之前应避免使用。6.2 内存分配规则1用TRESHAPE表达两个 Tile 同基地址别名。auto mode 下直接对两个 Tile 写TASSIGN(tileA, 0x0); TASSIGN(tileB, 0x0);是无效的正确做法是// Invalid in auto mode TASSIGN(tileA, 0x0); TASSIGN(tileB, 0x0); // Correct in auto mode TRESHAPE(tileB, tileA);2用 sub-tile aliasing 表达Tile B 是 Tile A 的子视图。用于表达addr(tileB) addr(tileA) 偏移且偏移可以是运行时变量uint16_t rowOffset, colOffset; // can be runtime variable // addr(tileB) addr(tileA) offsets TileData tileA(...); TileData tileB(...); // Invalid in auto mode TASSIGN(tileA, 0x0); TASSIGN(tileB, 0x0 rowOffset * TileData::Col colOffset * 1 sizeof(T)); // Correct for auto mode sub-tile aliasing(tileB, tileA, rowOffset, colOffset);3auto mode 下 Tile 的内存地址在运行时不可改变。编译器会给每个声明的 Tile 变量分配恒定地址无法像 manual 模式那样在循环里通过TASSIGN(tile, 0x100 * i)动态改址。auto mode 下每个 Tile 只会被分配一次内存。这里有一个关键心智模型把 Tile 想象成 C 引用——一旦声明其内存地址就已确定不能再改变。4正确理解TRESHAPE与 sub-tile aliasing 在 auto mode 下的语义。manual 模式下它们都是真正重新赋址的指令而 auto mode 下它们只是向编译器提供两个 Tile 如何别名alias的提示TRESHAPEauto mode 下把源、目标 Tile 绑定到同一地址绑定在整个作用域内有效manual 模式则是在指令执行点赋址sub-tile aliasing编译器计算子 Tile 的相对偏移并加到基 Tile 的自动分配地址上。由于 auto mode 下 Tile 地址在其作用域内不可变一个 Tile 不能作为多条TRESHAPE/sub-tile aliasing 的目标行为未定义。好的实践是把TRESHAPE/sub-tile aliasing 紧跟在目标 Tile 的声明之后。6.3 通用规则1不要在目标输出Tile 上调用TLOAD。如果一个 Tile 仅作输出、不需要从 GM 拷贝数据就绝不应对它TLOAD。原因auto mode 下编译器基于 liveness 复用内存——若dstTile与srcTile的活跃区间不重叠编译器可能给它们分配同一地址此时两个并发TLOAD会互相覆盖产生数据竞争。2不要直接调用 CCE intrinsics。原因有二一是 CCE intrinsics 接收裸指针参数而 auto mode 下 Tile 以向量类型而非指针类型表示无法编译二是自动内存分配与同步只建立在 PTO 指令分析之上编译器无法识别其他指令。因此不要在 kernel 里直接调用 Tile 的.data()成员函数——它本质上是给库开发者用的接口。若确实没有对应的 PTO 指令可用应向 pto-isa 提交新增 PTO 指令的请求。3优先使用PtoSetWaitFlag或 Event 同步而不是裸的set_flag/wait_flag。PtoSetWaitFlag与 Event 同步在内部已对 manual/auto 两种模式做了防护auto mode 编译时该接口是 no-op不会与编译器的自动同步冲突。直接调用set_flag/wait_flag则必须手动用__PTO_AUTO__宏包起来繁琐且易错。6.4 库开发者规则要点对于 pto-isa 库的维护者实现 PTO 指令/库的人库开发者规则与限制 还提出了额外的实现约束.data()的返回类型在 auto mode 下是向量类型而非指针pto::(Conv)Tile::data()返回TileDType在 auto mode 下定义为向量类型不能当作裸指针使用避免对结构体/类成员做默认初始化默认初始化会让编译器的 SROA pass 无法消除AllocaInst及关联的 load/store建议用#ifdef __PTO_AUTO__区分写法并尽量采用兼容 C 语言的 POD 聚合编程tile function 及其调用链内部仍需显式同步使用set_flag、wait_flag或pipe_barriertile function 之外使用PtoSetWaitFlag在 auto mode 下为 no-op实现中避免使用TASSIGN某些指令实现直接用了TASSIGN_IMPL它在 auto mode 下是 no-op若只是表达别名应改用TRESHAPE*_IMPL函数约束函数签名需带PTO_INTERNAL宏实现内直接调用 tile function除非内联否则不调用非 tile 函数通过.data()传参或对.data()的返回值按引用返回auto src srcTile.data();正确auto dst dstTile.data();错误tile function 参数规则参数类型用typename ...::TileDType而非DType *按值传递正确附加__in__/__out__属性用__cce_get_tile_ptr获取底层 buffer 指针返回值必须为void其余返回值改为按值传出参数避免在 tile function 前出现运行时控制流如TROWEXPANDDIV_IMPL、TMULS_IMPL所示运行时条件会严重干扰自动同步应尽量移除或移入 tile function 内部。七、动手实践完整的 Auto Mode 工程示例仓库的 demos/auto_mode/baseline/add 提供了一个开箱即用的 auto mode PyTorch 自定义算子torch_npuKERNEL_LAUNCH示例。其 kernel 源码 add_custom.cpp 正是 auto 模式写法的完整示范——定义Tile、TLOAD、TADD、TSTORE全程无TASSIGN、无显式同步using TileData TileTileType::Vec, T, bTileRows, bTileCols, BLayout::RowMajor, -1, -1; TileData xTile(bTileRows, bTileCols), yTile(bTileRows, bTileCols), zTile(bTileRows, bTileCols); TLOAD(xTile, xGlobal); TLOAD(yTile, yGlobal); TADD(zTile, xTile, yTile); TSTORE(zGlobal, zTile);该 kernel 通过extern C __global__ AICORE void add_custom(...)作为算子入口host 侧在 csrc/host/my_add.cpp 中用TORCH_LIBRARY_FRAGMENT(npu, m)声明my_add算子、通过ACLRT_LAUNCH_KERNEL示例封装为EXEC_KERNEL_CMD下发执行。构建与运行流程详见 示例 README# 1. 设置环境与 PTO 库路径 export ASCEND_HOME_PATH/usr/local/Ascend/ source /usr/local/Ascend/ascend-toolkit/set_env.sh export PTO_LIB_PATH[YOUR_PATH]/pto-isa # 2. 构建 wheel rm -rf build op_extension.egg-info python3 setup.py bdist_wheel # 3. 安装 wheel cd dist pip uninstall *.whl pip install *.whl # 4. 运行测试 cd test python3 test.py注意需要在 CMakeLists.txt 中把SOC_VERSION设置为目标 SoC示例注释提到 A2A3 对应Ascend910B1可用npu_smi info查询芯片名后以Ascend芯片名形式填写编译选项务必包含--cce-pto-enable --cce-pto-auto-enable -O2。该示例当前不使用双缓冲也再次印证了auto mode 下暂不建议使用双缓冲的约束。八、总结PTO Auto Mode 是 CANN pto-isa 面向生产力的一次关键抽象它以 Tile liveness 分析为核心在 TF 抽象层之上自动完成跨 pipeline 同步与 Tile 片上内存分配使 kernel 开发者得以用声明 Tile → 数据流计算 → 存储的纯数据流方式编写 kernel同时保持与 manual 模式接近的性能并天然获得跨昇腾架构代际的源码级兼容。使用上只需记住三个要点编译时追加--cce-pto-enable --cce-pto-auto-enable、必须使用-O2、按目标 SoC 指定--cce-aicore-arch编码时遵循本文第六节的规则——可静态分析的控制流、用TRESHAPE/sub-tile aliasing 表达别名、不在输出 Tile 上调TLOAD、不直接调用 CCE intrinsics、tile function 内部仍手动同步。如果你想进一步深入推荐按顺序阅读本仓库的以下材料auto 模式与 manual 模式的完整代码对照见 Examples.mdkernel 开发者约束见 Kernel_Developer_Rules_And_Limitations.md库开发者约束见 Library_Developer_Rules_And_Limitations.mdmanual 模式下的事件同步模型见 Event 文档可直接运行的最小示例见 demos/auto_mode/baseline/add。赞分享人工智能指令集算子库CANNAscend【免费下载链接】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点击查看免费下载相关推荐PTO AUTO Mode 编译模式完全指南CANN pto-isa 自动内存分配与自动同步编程详解PTO AUTO Mode 编译模式完全指南CANN pto isa 自动内存分配与自动同步编程详解 导读 PTO AUTO自动模式是 CANN pto人工智能指令集算子库CANNAscendpto-isa 的 PTO AUTO 模式让编译器接管 Tile 内存分配与 Pipe 间自动同步pto isa 的 PTO AUTO 模式让编译器接管 Tile 内存分配与 Pipe 间自动同步 本文基于 pto isa 仓库中 Auto_Mode_Ov人工智能指令集算子库CANNAscendPTO AUTO 模式昇腾 Tile 编程中免除手动同步与内存分配的编译器自动化路径PTO AUTO 模式昇腾 Tile 编程中免除手动同步与内存分配的编译器自动化路径 PTO AUTO 是 pto isa 提供的编译模式编译器会自动为 T人工智能指令集算子库CANNAscend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考