CANN PTO-ISA ConvTile 编程模型:卷积算子的片上 Tile 计算单元与地址绑定实战
【免费下载链接】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
ConvTile 是 PTO(Parallel Tile Operation)指令集中面向卷积类算子的固定容量 2D~6D 片上缓冲对象,既是卷积计算的最小计算单元,也是TLOAD/TSTORE等数据搬运指令的主要操作对象。本文基于docs/coding/ConvTile_zh.md,并结合 pto_tile.hpp 源码与 TASSIGN 指令文档,完整讲解pto::ConvTile的类型定义、布局与形状约束、地址绑定机制,以及一段可直接编译运行的最小示例,帮助你用 PTO 编写第一个卷积类内核。
ConvTile 表示什么
从概念上说,ConvTile驻留在片上 Tile 存储中(类似寄存器文件或片上 SRAM),并通过TLOAD/TSTORE与全局内存(GM)之间搬运数据。与通用的二维Tile不同,ConvTile支持 2 到 6 个维度,专门服务于卷积类算子的多维度数据布局(如 batch、通道、高度、宽度等)。
一个ConvTile主要由五类属性定义:
| 属性 | 说明 | 示例 |
|---|---|---|
| 位置(Location) | Tile 所属的逻辑存储类别(矩阵/立方寄存器等) | TileType::Mat、TileType::Vec |
| 元素类型(Element type) | 标量元素类型 | float、half、int8_t等 |
| 缓冲区大小(Buffer size) | ConvTile的静态缓冲容量 | 4096(元素个数) |
| 布局(Layout) | 指导 lowering 与目标相关优化路径 | NCHW、NHWC、NC1HWC0等 |
| 形状(Shape) | pto::ConvTileShape<...>,支持最多 6 个维度 | ConvTileShape<1, 1, 16, 16, 16> |
这些属性的具体承载形式,就是下文的 C++ 模板类型pto::ConvTile,其定义位于 include/pto/common/pto_tile.hpp。
pto::ConvTile类型
ConvTile通过 C++ 模板类型声明,模板参数依次对应上述五类属性:
pto::ConvTile< pto::TileType Loc_, // 位置:Tile 的逻辑/物理存储类别 Element_, // 元素类型:标量类型 BufferSize_, // 静态容量 pto::Layout_ layout, // 布局枚举 pto::ConvTileShape Shape_ // 形状(最多 6 维) >;从源码看(pto_tile.hpp),ConvTile结构体将这些模板参数公开为编译期常量,供后续指令特化使用:
template <TileType Loc_, typename Element_, const int BufferSize_, Layout Layout_, typename Shape_> struct ConvTile { using DType = Element_; // 元素类型 using ShapeType = Shape_; // 形状类型 static constexpr TileType Loc = Loc_; // 位置 static constexpr int bufferSize = BufferSize_; // 静态容量 static constexpr Layout layout = Layout_; // 布局 ... };位置(TileType)
TileType表示 Tile 的逻辑/物理存储类别,同时参与指令重载选择和编译期检查。ConvTile常见的合法位置包括:
TileType::Vec:向量 Tile 存储(UB / 向量流水线)。TileType::Mat:通用矩阵 Tile 存储(矩阵 L1)。
每条指令允许使用哪些位置,应以 docs/isa/ 下对应指令文档为准。例如TLOAD指令文档会说明其源/目的 Tile 的合法TileType组合。
容量(BufferSize_)
BufferSize_定义了 Tile 对象的静态容量(以元素个数计)。多数指令要求 Tile 具备静态形状,以便在编译期进行特化和优化。ConvTile在声明时通过static_assert限制形状维数,见源码 pto_tile.hpp:
static constexpr int totalDimCount = ShapeType::totalDimCount; static_assert( totalDimCount >= 1 && totalDimCount <= ConvTileDetail::MAX_CONVTILE_DIM, "ConvTile only support 1D~6D Shapes!");即ConvTile仅支持 1D~6D 形状,越界会在编译期直接报错。
布局(pto::Layout)
ConvTile包含一个布局枚举。文档中列举了卷积场景最常用的几种:
NCHWNHWCNC1HWC0FRACTAL_ZFRACTAL_Z_S16S8
在源码 type.hpp 中可以看到完整的Layout枚举,除上述卷积布局外还包括ND(行主序)、DN(列主序)、NZ(cube 分形)、GNC1HWC0、GNCHW、NDC1HWC0、NCDHW、FRACTAL_Z_3D以及 MX/HIF4 系列的专用布局(MX_A_ZZ、MX_B_NN、HIF4_A_ZZ、HIF4_B_NN等)。布局信息会影响后端实现、lowering 路径以及特定目标上的快速路径选择。
形状(pto::ConvTileShape)
pto::ConvTileShape<...Shapes>支持 1 到 6 个整型模板参数。每个维度既可以是编译期常量,也可以是pto::DYNAMIC(即-1,定义见 pto_tile.hpp)。
- 静态维度保存在类型信息中,可通过
ConvTileShape::staticShape[dim]获取。 - 动态维度保存在运行时对象
ConvTileShape::shape[dim]中,并由ConvTileShape(...)构造函数赋值。
源码中ConvTileShape的实现(pto_tile.hpp)提供了staticShape(6 个维度的编译期数组)、dynamicDimCount(动态维度数量)以及 1~6 参数的构造函数。构造函数通过static_assert检查"运行时传入参数个数是否与动态维度数量一致",例如:
PTO_INTERNAL ConvTileShape(int64_t n) { static_assert( dynamicDimCount == 1, "1-parameter constructors is only applicable to Shape with 1 dynamic dimension."); ... }因此若构造参数不匹配(例如形状声明了 2 个动态维度却只传 1 个运行参数),会在编译期报错。
此外,ConvTile还提供了SetDynamicShape成员(pto_tile.hpp),用于在内核运行时按需设置动态维度,同样以static_assert校验参数个数与类型:
template <typename... Ints> PTO_INTERNAL void SetDynamicShape(Ints... vals) { static_assert(sizeof...(vals) == dynamicDimCount, "Number of dynamic values does not match dynamic dimension count!"); static_assert((std::is_same_v<Ints, int64_t> && ...), "Dynamic values must be int64_t type!"); ... }卷积元数据:ConvTile 的隐藏字段
除模板参数外,源码中的ConvTile结构体还携带一组运行时卷积元数据(pto_tile.hpp),用于在手动放置流程中描述卷积计算的窗口参数,是编写卷积内核时常用的配套接口:
| 字段 | 类型 | 默认值 | 含义 |
|---|---|---|---|
fmapH_/fmapW_ | uint16_t | 0 | 特征图(feature map)高/宽 |
padList_[4] | uint8_t | {0,0,0,0} | 四方向 padding |
filterH_/filterW_ | uint16_t | 1 | 卷积核高/宽 |
dilationH_/dilationW_ | uint16_t | 1 | 膨胀率 |
strideH_/strideW_ | uint16_t | 1 | 卷积步长 |
padValue_ | DType | 0 | padding 填充值 |
channelSize_ | uint16_t | 0 | 通道数 |
repeatStride_/repeatTime_/repeatMode_ | uint16_t/uint8_t | 0 / 1 / 0 | 指令 repeat 相关参数 |
dstStride_/dstMposition_ | uint16_t | 0 | 目标 stride / M 位置(A2A3 架构除外) |
transpose_ | bool | false | 是否转置 |
smallChannel_ | bool | false | 小通道模式 |
对应的GetXxx/SetXxx接口(如SetFmapH、SetPadList、SetFilterH、SetStrideH、SetPadValue、SetTranspose等)均已声明为PTO_INTERNAL,可直接在 PTO Lib 内核代码中调用。
地址绑定(TASSIGN)
在手动放置流程中,TASSIGN(tile, addr)用于把一个ConvTile对象绑定到实现定义的片上地址;在自动模式(定义了__PTO_AUTO__)下,TASSIGN(tile, addr)可能被处理为 no-op。具体约束参考 docs/isa/TASSIGN.md。
两种调用形式
形式一:运行时地址(不做编译期越界检查,地址值在编译期不可知):
template <typename T, typename AddrType> PTO_INST void TASSIGN(T& obj, AddrType addr);形式二:编译期地址(带静态越界检查,Addr是非类型模板参数,编译器通过static_assert执行检查):
template <std::size_t Addr, typename T> PTO_INST void TASSIGN(T& obj);编译期检查项
形式二会触发以下编译期检查(断言 ID 对应 docs/coding/debug_zh.md 中的修复配方FIX-A12):
| 检查 | 条件 | 断言 ID | 错误信息 |
|---|---|---|---|
| 内存空间存在 | capacity > 0 | SA-0351 | Memory space is not available on this architecture. |
| Tile 放得下 | tile_size <= capacity | SA-0352 | Tile storage size exceeds memory space capacity. |
| 地址不越界 | Addr + tile_size <= capacity | SA-0353 | addr + tile_size exceeds memory space capacity (out of bounds). |
| 地址对齐 | Addr % alignment == 0 | SA-0354 | addr is not properly aligned for the target memory space. |
内存空间、容量与对齐
内存空间、容量和对齐由 Tile 的TileType(即Loc模板参数)自动确定,各架构的默认容量见下表(A2A3 / A5 / Kirin9030 / KirinX90,对齐均为 32 B):
| TileType | 内存 | A2A3 | A5 | Kirin9030 | KirinX90 | 对齐 |
|---|---|---|---|---|---|---|
| Vec | UB | 192KB | 256KB | 128KB | 128KB | 32 B |
| Mat | L1 | 512KB | 512KB | 512KB | 1024KB | 32 B |
| Left | L0A | 64KB | 64KB | 32KB | 64KB | 32 B |
| Right | L0B | 64KB | 64KB | 32KB | 64KB | 32 B |
| Acc | L0C | 128KB | 256KB | 64KB | 128KB | 32 B |
| Bias | Bias | 1KB | 4KB | 1KB | 1KB | 32 B |
| Scaling | FBuffer | 2KB | 4KB | 7KB | 6KB | 32 B |
| ScaleLeft | L0A | N/A | 4KB | N/A | N/A | 32 B |
| ScaleRight | L0B | N/A | 4KB | N/A | N/A | 32 B |
容量可在构建时通过-D宏覆盖(例如-DPTO_UBUF_SIZE_BYTES=262144),参见 include/pto/common/buffer_limits.hpp。
注意:该编译期检查重载仅对Tile与ConvTile类型可用;对于GlobalTensor,应使用TASSIGN(obj, pointer)(形式一)。
约束
- 若
obj是 Tile(含ConvTile):- 手动模式(未定义
__PTO_AUTO__):addr必须是整型,并被重新解释为 Tile 的存储地址。 - 自动模式(定义了
__PTO_AUTO__):TASSIGN(tile, addr)为 no-op。
- 手动模式(未定义
- 若
obj是GlobalTensor:addr必须是指针类型,且指向的元素类型必须与GlobalTensor::DType匹配。
地址绑定示例
运行时地址(不做编译期检查):
#include <pto/pto-inst.hpp> using namespace pto; void example_runtime() { using TileT = Tile<TileType::Vec, float, 16, 16>; TileT a, b, c; TASSIGN(a, 0x1000); TASSIGN(b, 0x2000); TASSIGN(c, 0x3000); TADD(c, a, b); }编译期地址(带静态越界检查):
void example_checked() { using TileT = Tile<TileType::Vec, float, 16, 16>; TileT a, b, c; TASSIGN<0x0000>(a); // OK: 0x0000 + 1024 <= 192KB TASSIGN<0x0400>(b); // OK: 0x0400 + 1024 <= 192KB TASSIGN<0x0800>(c); // OK: 0x0800 + 1024 <= 192KB TADD(c, a, b); }越界示例(触发 SA-0352 / SA-0353):
// Tile<Vec, float, 256, 256> 占用 256*256*4 = 256KB using BigTile = Tile<TileType::Vec, float, 256, 256>; BigTile t; TASSIGN<0x0>(t); // 主要触发 [SA-0352]:tile_size(256KB) > UB 容量(192KB, A2A3)最小示例
下面是一个完整的 ConvTile 使用示例:声明一个NC1HWC0布局、形状为<1, 1, 16, 16, 16>的Mat位置half类型 ConvTile,构造对应的GlobalTensor视图,先TASSIGN绑定片上地址,再通过TLOAD从全局内存加载数据:
#include <pto/pto-inst.hpp> using namespace pto; void example(__gm__ half* in, __gm__ half* out) { using TileT = ConvTile<TileType::Mat, half, 4096, Layout::NC1HWC0, pto::ConvTileShape<1, 1, 16, 16, 16>>; using GShape = Shape<1, 1, 16, 16, 16>; using GStride = Stride<1 * 16* 16* 16, 16* 16* 16, 16 * 16, 16, 1>; using GT = GlobalTensor<half, GShape, GStride, Layout::NC1HWC0>; GT gin(in); TileT tile5d; TASSIGN(tile5d, 0x0); TLOAD(tile5d, gin); }几点说明:
TileT的BufferSize_(4096)对应形状1*1*16*16*16 = 4096个half元素,即该 Tile 的静态容量;bufferSize以元素个数计,最终占用的字节数需乘以sizeof(half)。GShape/GStride定义了全局内存视图的形状与各维 stride,GStride的第一个维度1*16*16*16表示 batch 维步长,逐维递减直至最内层1。GlobalTensor的详细语义参见 GlobalTensor_zh.md。TASSIGN(tile5d, 0x0)在手动模式下把 Tile 绑定到片上地址0x0(此处为演示,实际应结合上文容量表规划地址布局,避免越界与未对齐)。TLOAD(tile5d, gin)完成 GM 到片上 Tile 的数据搬运;TSTORE则负责反向写回。两个指令的完整语义见 TLOAD.md 与 TSTORE.md。
与相关概念的衔接
- 与
Tile的关系:ConvTile与通用二维Tile(见 Tile_zh.md)同属于 PTO 的片上缓冲抽象,共享TileType、TASSIGN等机制;区别在于ConvTile面向卷积场景,支持最多 6 维形状并携带卷积元数据字段。 - 与
GlobalTensor的关系:GlobalTensor是全局内存(GM)的轻量级视图,ConvTile通过TLOAD/TSTORE与GlobalTensor之间交换数据(见 GlobalTensor_zh.md)。 - 编程模型上下文:Auto/Manual 两种开发风格、SPMD/MPMD 执行模型等背景概念,可参考 ProgrammingModel_zh.md;抽象执行模型见 abstract-machine_zh.md。
进一步阅读
- ConvTile 英文原版
- PTO 卷积类指令总览:逐条指令的 TileType 合法性、布局要求与数据流语义
- TASSIGN 指令详解:含全部编译期检查项与各架构容量表
- include/pto/common/pto_tile.hpp:
ConvTile/ConvTileShape/Shape/Stride完整实现 - include/pto/common/type.hpp:
Layout枚举全集 - include/pto/common/constants.hpp:
C0_SIZE_BYTE、FRACTAL_NZ_ROW、MX_ROW_LEN等布局常量
【免费下载链接】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),仅供参考