跳到主要内容
TileLang 系统教程

tilelang-tutorial.huandu.me

第 05 章背景、设计思想与架构23 分钟15 习题7 自测题

横向对比:CUDA / Triton / CUTLASS-CuTe / TVM / cuTile / Ascend C / PTO-DSL

用「用户必须提供的硬件相关决策数量」这把尺子,把 CUDA、Triton、CUTLASS-CuTe、TVM、cuTile、Ascend C、PTO-DSL 放到同一条纵轴上,再用同一个带融合 epilogue 的 GEMM 逐层对照。

本章进度状态 未读完习题 0 / 15自测 未作答

学习目标

读完本章,你应当能够:

  1. 用「抽象层次」这把尺子把本章的七个对象放到同一张图上,并说出每一个层次 用户写什么、编译器替你做什么、谁来决定 tiling 与数据搬运。
  2. 拿一个统一的例子(带融合 epilogue 的 GEMM:C = relu(A @ B))说明它在 CUDA、 Triton、CUTLASS-CuTe、TileLang、Ascend C、PTO-DSL 里各要写多少东西,差别具体在哪。
  3. 说清 TVM 在 TileLang 里的角色:它是编译器底盘(IR、pass 基础设施、target/ device 抽象),不是 TileLang 的竞争者,也不是一个可以直接拿来写 AI kernel 的前端。
  4. 说清 Ascend C 与 PTO-DSL 作为「昇腾原生路线」的定位,以及它们和 TileLang@Ascend 的竞争/互补关系:谁提供 ISA,谁提供编译期调度。
  5. 面对「我该用哪个」的问题,用本章的决策表给出一个有理由的答案,而不是凭印象站队。
  6. 分清哪些结论有本地一手资料支撑,哪些只能标注「资料不足」,以及要补什么资料才能下结论。

前置知识

  • 第 03 章:TileLang 的设计哲学与编程模型(tile / dataflow / schedule 解耦、三层接口)。
  • 第 04 章:架构总览与一次编译的全流程(Python → TIR → pass → codegen → runtime)。
  • 会用 Python、写过 PyTorch(能读懂 A @ B、relu(x))。
  • 不需要 CUDA、Triton 或 Ascend C 的编程经验。本章出现的每个 C/C++/Python 片段都 会先说明它「属于哪一层」,再解释它在整个对比里的作用。

本章依赖的锁定版本见 版本锁定:TileLang v0.1.15、 TileLang-Ascend TileLang-ascend-v0.1.2.000-release。写作环境为 macOS (Apple Silicon)、Python 3.11,没有 NVIDIA GPU,也没有昇腾 NPU;因此本章不给出任何 本机实测的性能数字,任何引用的数字都必须带来源与测量条件。


1. 问题的由来:为什么需要一张坐标系

一个刚会用 PyTorch 的人,第一次想把算子写快时,会同时听到七八个名字:手写 CUDA、 Triton、CUTLASS、CuTe、cutlass-cute、cuTile、TileLang、Ascend C、PTO-DSL、TVM…… 它们看起来都能「写 kernel」,于是最常见的两个错误随之出现:

  • 把它们当成同一层的竞品:认为「Triton 是不是要取代 CUDA」「TileLang 就是另一个 Triton」,于是无法解释为什么 TileLang 还在用 TVM,为什么 CUTLASS 还在用 CuTe, 为什么昇腾上既有 Ascend C 又有 PTO-DSL。
  • 只比较语法长短:数谁的代码行数少,而不问「少掉的那些行由谁在什么时候补回来」—— 是编译器补、是库补、还是运行时补。代码短不等于事情被消灭,很多时候只是被搬到了编译期 或运行时里。

本章要做的事,是给出一把能反复使用的尺子:用「抽象层次」把每个对象放到它应该在的 位置上,然后用一个统一的例子把它们串起来。这样你在第 14、15 章真正动手写 GEMM / Attention 时,才知道自己站在哪一层、TileLang 帮你吃掉了哪一段、剩下的哪一段还得自己写。

一句话预告本文的结论:这七个对象不在同一层。它们大致分布在「线程/指令层」 (CUDA、Ascend C、PTO-DSL、CUTLASS-CuTe 的 C++ 与 DSL)与「tile 层」 (Triton、cuTile、TileLang)两级,而 TVM 根本不在这条纵轴的正中间——它是一条横穿 两级的地基。TileLang 的独特之处,是同时坐在 tile 层(前端)和底盘层(它自己写 pass)。


2. 概念与模型:三层抽象,七个对象

抽象层次纵轴与 TVM 底盘tile 级:用户给 tile,编译器管调度 / 布局 / 同步Triton(编译器选调度)· TileLang(数据流留在语言里)· cuTile(资料不足)高层线程 / 指令级:用户直接面对线程、存储层级与同步CUDA · CUTLASS / CuTe(含 CuTe DSL) · Ascend C · PTO-DSL低层硬件 ISAPTX / SASS · PTO-ISA / CCE最低TVM 底盘(横穿所有层)IR + pass 基础设施 + target/device 抽象横切
七个对象不在同一层:tile 级、线程/指令级,再加上横穿两级的 TVM 底盘。
  • TileLang 同时出现在 tile 层(前端)和底盘使用方(自己写 pass)。
  • CuTe DSL 虽然用 Python,仍在低层(R5/R27),不要把它归到 tile 级。
  • TVM 不是某一层的一员,而是横切面,见 §4。

2.1 抽象层次的定义

本书把「抽象层次」定义为:用户为表达一个算子所必须提供的、与硬件相关的决策数量。 数量越少,层次越高。三个关键决策是:

  1. 谁负责搬数据:用户显式写 copy / DataCopy / TMA,还是编译器从数据流反推;
  2. 谁负责切 tile:用户给 tile 尺寸,还是编译器 / 自动调优搜索;
  3. 谁负责同步:用户写 barrier / EnQue/DeQue / set_flag/wait_flag,还是编译器插入。

按这三个问题,本章的七个对象可以放在一条纵轴上(从低到高):

抽象层次纵轴:从图级到硬件 ISA图级 / 模型级torch.compile(不在本章范围,见第 02 章)高层tile 级Triton(编译器选调度)· cuTile · TileLang(用户显式数据流)高层线程 / 指令级CUDA · CUTLASS-CuTe(C++ 与 CuTe DSL) · Ascend C · PTO-DSL低层硬件 ISAPTX / SASS · PTO-ISA / CCE最低TVM 底盘(横穿所有层)IR + pass 基础设施 + target/device 抽象横切
七个对象不在同一层:图级、tile 级、线程 / 指令级与硬件 ISA,再加上横穿所有层的 TVM 底盘。
  • 层次越高,用户为表达一个算子必须提供的硬件相关决策越少(见正文 2.1 节给出的三个问题)。
  • CuTe 与 CuTe DSL 是一族,在抽象层次上和 CUDA 同级;Ascend C 与 PTO-DSL 同样在低层,但暴露的是昇腾的 L1 / L0A / L0B / L0C / UB 与 MTE 搬运流水。

注意三件事,它们后面会反复用到:

  • CuTe 与 CuTe DSL 是一族(CUTLASS 4 把 CuTe DSL 定义为「与 CuTe C++ 抽象完全一致的 低层编程模型」,来源 NVIDIA/cutlass 第 39–51 行), 所以在抽象层次上它们和 CUDA 是同一级,而不是和 Triton 同一级。
  • Ascend C 与 PTO-DSL 也在低层,但它们暴露的不是 NVIDIA 的 shared/register,而是 昇腾特有的 L1 / L0A / L0B / L0C / UB 与 MTE 搬运流水。
  • TVM 不在这条纵轴上。它既可以被 CUDA 一侧的代码使用,也可以被昇腾一侧使用;它是 横切面。第 4 节专门讲这一点。

2.2 七个对象一览

下表是本章的主索引。每一行对应一个对象,列就是本章要求你建立的坐标系要素。 「与 TileLang 的关系」一列里,竞争指两者在同一层抢同一件事,互补指两者在不同层 可以叠在一起用,底盘指它不是同类物。

对象 抽象层次 用户写什么 编译器替你做什么 适用场景 生态与成熟度 与 TileLang 的关系
CUDA 线程/指令级 grid/block/warp/thread 映射、__shared__、__syncthreads()、cp.async/TMA 把 SPMD C++ 编成 PTX/SASS;不做 tile 级推导 需要极限控制、非常规算子、教学 最成熟,CUDA 生态的底座(NVCC、cuBLAS、cuDNN、NCCL 都在其上) 互补:TileLang 的 NVIDIA 后端最终产出 CUDA C
Triton tile 级 Python 里的块级程序(tl.load/tl.dot/tl.store),块尺寸由 autotune 搜索 tile 级优化 pass:内存合并、共享内存分配与同步、流水 通用算子快速出好性能,尤其是内存受限与归约类 生态广泛(PyTorch/Inductor 侧大量使用);文档见 R4 竞争:最直接的对手,都在 tile 层
CUTLASS / CuTe 线程/指令级 C++ 模板:Layout、Tensor、MMA/Copy atom;CUTLASS 4 起还有 CuTe DSL CuTe 做 layout 代数与索引;CUTLASS 提供分层 GEMM 组件与 kernel 模板 生产级 GEMM/卷积,需要贴合每一代 tensor core NVIDIA 官方库,README 自列为 Volta→Blackwell(含 Ada);CuTe DSL 于 CUTLASS 4 发布、自述公测(R5) 互补:TileLang 的 T.gemm 在 NVIDIA 侧就落到 CuTe/MMA 上
TVM 编译器底盘(横切) 一般用户不直接写;研究者写 TE/TIR/TIRx 与 schedule IR、pass 基础设施、target/device 抽象、自动调优(Ansor/MetaSchedule) 做编译器、加后端、做自动调度研究 Apache 顶级项目,长期维护;TIRx 是其 tile 方向的新接口(R10) 底盘:TileLang 建在 TVM 之上
cuTile tile 级 Python 里的 tile 程序(据第三方描述,与 CuTe DSL / Triton 同级) 自述为「类似 cuTile 但原生 NPU」的反面参照;细节资料不足 NVIDIA 新一代 Python tile DSL 资料不足:本 corpus 只有指向 docs.nvidia.com/cuda/cutile-python/ 的链接(R17),PTX ISA 里出现 python-cutile 语言码(R9) 竞争:在 NVIDIA tile 层与 TileLang 正面重叠
Ascend C 线程/指令级 __global__ __aicore__ 核函数;TPipe/TQue;CopyIn/Compute/CopyOut;EnQue/DeQue 与 set_flag/wait_flag bisheng 编译器把 CCE C++ 编成 AI Core 指令;不替你做 tile 级推导与跨流水同步计划 昇腾算子的原生开发语言,CATLASS 等模板库建其上 华为官方主推,CANN 的一部分(R14、R15) 竞争 + 互补:TileLang@Ascend 的 Ascend C&PTO 路线最终产出 Ascend C;TileLang 替掉的正是它的同步(R3/R22)
PTO-DSL 线程/指令级 Python:pto.load/tile.matmul/pto.store,显式 L1/L0A/L0B/L0C/UB PTOAS 的 InsertSync 自动插同步;自动软件流水;编译到 PTO-ISA 想用 Python 写昇腾、又要贴硬件原语的场景 华为实验室开源,自述目标对标硬件 intrinsic 性能;2026/05 起并入 PTOAS 主仓(R17) 竞争 + 互补:与 TileLang@Ascend 抢同一批用户;TileLang 也可把 PTO-ISA 当 codegen 后端(R17)

表里每个「功能」级别的事实都能落到来源:CUDA 的同步与共享内存机制见 R7/R8;Triton 的 tile 语义与编译器 pass 见 R2;CUTLASS 的 CuTe DSL 定位见 R5;TVM 的 TIRx 见 R10; Ascend C 的 TPipe/TQue 范式见 R14;PTO-DSL 的定位见 R17。cuTile 一行的内容最少, 因为本地资料最少——这一点在第 5 节会单独交代。


3. 用法:同一个 GEMM,六种写法

统一例子选 带融合 epilogue 的 GEMM:C = relu(A @ B),A、B 为 fp16, 累加与输出为 fp32,形状 M = N = K = 1024,tile 取 128×128×32。这组参数不是随手取的: 它正是 TileLang 官方 quickstart 示例的默认配置(来源 _vendor/tilelang-v0.1.15/examples/quickstart.py:51-56),所以下面每一版都可以和 TileLang 这一版逐行对照。

选「融合 epilogue」而不是纯 GEMM 的原因:它同时考验三件事——(1) 能不能做 tensor core / Cube 上的矩阵乘;(2) 能不能把 relu 合进同一个 kernel,省掉一次 HBM 往返;(3) 能不能 在矩阵乘结束后让计算单元与搬运流水正确衔接。这三件事正好能把不同层次的差异暴露出来。

同一个 GEMM 的各个系统:每个系统内部的数据流顺序系统①②③④CUDA__shared__ aTile/bTilethread computes element__syncthreads()epilogue relu in same kernelTritontl.load blocktl.dottl.maximum(acc, 0)tl.store blockTileLangT.copy(GM→shared)T.gemmT.Parallel 里做 reluT.copy 写回Ascend CCopyIn(DataCopy)Compute / Cube手写 Vector 段CopyOutPTO-DSLpto.load GM→L1tile.extract L1→L0tile.matmul(_acc)pto.store L0C→GM
CUDA / Triton / TileLang / Ascend C / PTO-DSL 各自把 C = relu(A @ B) 走成一条流水线。
  • A、B、C 都在 Global memory:GM 是所有系统的共同起点。
  • 同一件事在不同系统里被切成不同的步数,步与步之间「谁等谁」也不同。
  • 「片上存储 / 多缓冲 / 同步 / 融合 ReLU 分别由谁负责」的逐项对照见下一张图。
「谁负责什么」:同一件事在五个系统里的归属AI 关注点CUDATritonTileLangAscend CPTO-DSL片上存储用户手写 __shared__编译器决定用户声明,pass 布局用户 TPipe.InitBuffer用户 pto.alloc_tile多缓冲用户手写编译器(流水 pass)num_stages用户 BUFFER_NUM自动 + 可选手写同步__syncthreads / mbarrier编译器插入编译器 pass用户 EnQue/DeQuePTOAS InsertSync融合 ReLU用户 epilogue块级一行fragment 上一行手写 Vector 段手写 Vector 段
行是用户要提供的东西,列越往右越自动化;自动化不等于更短,只是把决定权搬进了编译器。
  • 正文 §3.7 的文字表就是这张图的文字版。
  • 证据:CUDA=R7/R8;Triton=R2/R4;TileLang=S1/S10/S11;Ascend C=R14;PTO-DSL=R18/R19。
统一例子 C = relu(A @ B):五个系统的共同起点与终点Global memoryA、B、C(fp16 输入,fp32 累加与输出)CUDA手写 shared memory 与同步Tritontl.dot,让编译器管调度TileLangT.gemm + T.copy + T.PipelinedAscend CTPipe / TQue 三段流水PTO-DSLpto.load / tile.matmulC = relu(A @ B)融合 epilogue 省掉一次 HBM 往返
同一道题(M = N = K = 1024,tile 128×128×32)在五个系统里有不同的写法,但起点和终点相同。
  • 选「带融合 epilogue 的 GEMM」是为了同时暴露三件事:矩阵乘、融合、搬运与计算的衔接。
  • 每个系统内部的具体步骤见下一张图;逐项责任划分见 §3.7 的对照表。

3.1 CUDA:从线程写起

CUDA 是这一族的「汇编之上」的地板。用户自己回答第 2.1 节那三个问题:自己决定 block 的 二维划分,自己用 __shared__ 开 tile,自己在 for 循环里 __syncthreads(), epilogue 由自己写在线程里。NVIDIA 官方《CUDA C++ Best Practices Guide》给过一个用 共享内存做分块矩阵乘的示范,其核心是:

__shared__ float aTile[TILE_DIM][TILE_DIM]; —— 来源:CUDA C++ Best Practices Guide 第 1745–1830 行 ("Using shared memory to improve the global memory load efficiency in matrix multiplication",CUDA C++ Best Practices Guide)。

也就是说,在 CUDA 这一层,「把 tile 放进 shared memory」是用户动作,不是编译器的义务。 本 tilelang-book 的 code/01-unified-gemm-relu/cuda_gemm_relu_illustrative.cu 按这个结构 写出了带 ReLU epilogue 的版本,并明确标注为教学用伪代码:它演示层次,不是可直接 编译的生产代码。

需要强调:CUDA 本身没有 tile 概念。这正是 Triton 论文要解决的问题——见下一节。

3.2 Triton:把 tile 写进语言,让编译器选调度

2019 年的 Triton 原始论文把 tile 定义为「statically shaped multi-dimensional sub-arrays」(静态形状的多维子数组),来源 Triton: An Intermediate Language and Compiler for T… 第 37 行。用户写的是一个 「单线程、但会被自动并行化」的块级程序,编译器负责机器相关优化。

论文里那段矩阵乘是 Triton-C(一种 CUDA 风格的 C 方言),核心几行是(原文 Listing 1):

float C[TM, TN] = 0;
float A[TM, TK] = check_a ? *pa : 0;
float B[TN, TK] = check_b ? *pb : 0;
C += dot( A, trans( B ) );

—— 来源:Triton: An Intermediate Language and Compiler for T… 第 130–200 行 (Listing 1,"C = A×BT in Triton-C")。Triton-JIT 的机器相关 pass 恰好就是 CUDA 用户要 手写的那几件事,论文列得很清楚:(1) 分层 tiling、(2) 内存合并、(3) 共享内存分配、 (4) 共享内存同步(barrier 插入),来源 Triton: An Intermediate Language and Compiler for T… 第 583–720 行。

必须注明一个版本事实:2019 年的 Triton 语言比今天小得多。论文自己在结论里写, 未来的工作包括「support for tensor cores」和「implementation of quantized kernels」, 来源 Triton: An Intermediate Language and Compiler for T… 第 943–946 行——也就是 说,当年的 Triton-C 还没有张量核支持。今天 Triton 的张量核/tl.dot、FP8、以及 更低的 Gluon 层都远远超出了这篇论文(今天的文档索引里能看到 triton.language 与 Gluon,来源 Triton documentation 第 11–35 行)。 所以引用 2019 论文时只能说清「tile 抽象与编译器分工的设计来源」,不能拿它当今天 Triton 的能力清单。

今天的 Triton 用 Python 写,形如(本书示意,按论文与官方文档的语义重写,非 corpus 内原文):

# 示意伪代码:Triton 的 tile 级 GEMM + 融合 ReLU
a = tl.load(A_ptrs)                # 块级 load,编译器决定合并/共享内存
b = tl.load(B_ptrs)
acc = tl.dot(a, b, acc)            # 块级矩阵乘,落到 tensor core
acc = tl.maximum(acc, 0.0)         # 融合 ReLU,仍在块级
tl.store(C_ptrs, acc)

关键差异在决策权:Triton 里你写「块大小」,但共享内存怎么用、什么时候插 barrier、 要不要多缓冲,基本交给编译器(论文把这个思路讲得很明确:单线程程序 + 自动并行化 + 编译器负责同步)。TileLang 反过来,把这些决策部分留在语言里。

3.3 CUTLASS / CuTe:在低层把生产 GEMM 拆成可复用组件

CUTLASS 的定位是「在 CUDA 里实现高性能 GEMM 及其相关计算的全套抽象」,把 GEMM 拆成 可在不同并行层次上专门化、调优的组件(来源 NVIDIA/cutlass 第 19–33 行)。CUTLASS 4 起 加上了 CUTLASS DSLs,第一个就是 CuTe DSL:一个「与 CuTe C++ 抽象完全一致的低层 编程模型,暴露 layout、tensor、hardware atom,以及对硬件线程与数据层级(hierarchy) 的完全控制」,来源 NVIDIA/cutlass 第 39–51 行。

CuTe 的核心抽象是「hierarchically multidimensional layouts of threads and data」: 用 Layout 与 Tensor 同时描述数据和线程的多维布局,并做 layout 代数与索引推导, 来源 CuTe: C++ template abstractions for layout algebra 第 10–12 行。

这意味着 CuTe DSL 不是 tile 层。它是把 CuTe C++ 的布局代数搬到了 Python,但用户仍然 要自己写 tidx、自己调 cute.arch.barrier()、自己用 cute.autovec_copy 搬元素。 一个真实的 CuTe DSL 片段(TileFoundry 的 GEMV kernel)长这样:

@cute.jit
def _load_and_normalise(x, gamma, smem, scratch, tidx, k, eps, nt):
    nch = k // VEC
    xv = cute.tiled_divide(x, (VEC,))
    frag = cute.make_fragment(VEC, BF16)
    acc = F32(0.0)
    for i in cutlass.range_constexpr(cdiv(nch, nt)):
        j = i * nt + tidx
        if j < nch:
            cute.autovec_copy(xv[None, j], frag)
            ...
    total = _block_sum(acc, tidx, nt // 32, scratch)

—— 来源: TileFoundry/examples/minicpm3_4b-cutedsl/kernels/cute_gemv.py 第 36–113 行。

对照一下:这里出现的是 tidx、warp_reduction_sum、barrier、autovec_copy——全是 线程/指令级词汇。而 TileLang 的同一件事只需要 T.gemm + 一行 T.copy。所以 CUTLASS-CuTe 和 TileLang 在同一份程序里的不同层:TileLang 的 T.gemm 在 NVIDIA 侧 正是落到 CuTe/MMA 上的(quickstart 注释原文:「Currently we dispatch to the cute/hip on Nvidia/AMD GPUs」,来源 _vendor/tilelang-v0.1.15/examples/quickstart.py:38)。

资料不足:CUTLASS 里「融合 epilogue 的 GEMM」在 C++ 与 CuTe DSL 两侧的完整、 可运行写法,本 corpus 没有收录(只有 README 介绍与 CuTe 教程目录链接)。要给出可 对照的真实 epilogue 代码,需要 CUTLASS 仓库 examples/ 下的完整源文件,或 media/docs/cpp/cute/0x_gemm_tutorial 的全文。

3.4 TileLang:把数据流留在语言里,把调度交给 pass

回到统一例子。TileLang 的这一版就是官方 quickstart(来源 _vendor/tilelang-v0.1.15/examples/quickstart.py:1-46),去掉注释后的骨架是:

with T.Kernel(T.ceildiv(N, block_N), T.ceildiv(M, block_M), threads=128) as (bx, by):
    A_shared = T.alloc_shared((block_M, block_K), dtype)
    B_shared = T.alloc_shared((block_K, block_N), dtype)
    C_local = T.alloc_fragment((block_M, block_N), accum_dtype)
    T.clear(C_local)
    for ko in T.Pipelined(T.ceildiv(K, block_K), num_stages=3):
        T.copy(A[by * block_M, ko * block_K], A_shared)
        T.copy(B[ko * block_K, bx * block_N], B_shared)
        T.gemm(A_shared, B_shared, C_local)
    for i, j in T.Parallel(block_M, block_N):
        C_local[i, j] = T.max(C_local[i, j], 0)   # 融合 ReLU
    T.copy(C_local, C[by * block_M, bx * block_N])

逐点对照第 2.1 节那三个问题:

  • 谁搬数据:用户写 T.copy(_vendor/tilelang-v0.1.15/tilelang/language/copy_op.py:59), 但「搬成什么指令」(cp.async / TMA / 向量访问)由 codegen 决定;
  • 谁切 tile:用户给 block_M/block_N/block_K 与 num_stages,也就是用户决定 tile 形状,编译器负责把它变成 thread binding 与多缓冲;
  • 谁同步:都不写。TileLang 的 CUDA pipeline 里由 PipelinePlanning → InjectSoftwarePipeline → LayoutInference → LowerTileOp → …… → ThreadSync 一串 pass 插入同步(_vendor/tilelang-v0.1.15/tilelang/cuda/pipeline.py:129-142、 :258-259)。

这就是 TileLang 相对 Triton 的取舍:Triton 把 tile 与调度都让编译器定,TileLang 把 数据流(每片数据从哪来、去哪、在哪一级算)写进语言,把剩下的布局/流水/同步交给 pass。 quickstart 里那行 ReLU 正好说明「融合 epilogue」在 tile 层有多便宜:它只是对 C_local(fragment)做一次元素级变换,再 T.copy 出去,不需要新开一个 kernel。

3.5 Ascend C:昇腾官方原生语言

Ascend C 是华为官方的算子开发语言,编译运行在昇腾 AI 处理器上(CANN 的一部分, 来源 hiascend.com · zh_developer_techArticles_20230830-1 第 29 行)。 它把算子实现拆成 CopyIn / Compute / CopyOut 三段,用 TPipe 管内存、用 TQue(EnQue/DeQue)连接三段做同步与多缓冲(来源同文件 :51-57)。

一个真实的 Ascend C 片段(官方的 LeakyReLU 样例):

__aicore__ inline void Init(GM_ADDR x, GM_ADDR y, uint32_t totalLength, ...) {
    xGm.SetGlobalBuffer((__gm__ half*)x + this->blockLength * get_block_idx(), this->blockLength);
    pipe.InitBuffer(inQueueX, BUFFER_NUM, this->tileLength * sizeof(half));
}
__aicore__ inline void CopyIn(int32_t progress) {
    LocalTensor<half> xLocal = inQueueX.AllocTensor<half>();
    DataCopy(xLocal, xGm[progress * tileLength], tileLength);
    inQueueX.EnQue(xLocal);
}
__aicore__ inline void Compute(int32_t progress) {
    LocalTensor<half> xLocal = inQueueX.DeQue<half>();
    LocalTensor<half> yLocal = outQueueY.AllocTensor<half>();
    LeakyRelu(yLocal, xLocal, scalar, tileLength);
    outQueueY.EnQue<half>(yLocal);
}

—— 来源: hiascend.com · zh_developer_techArticles_20230830-1 第 350–440 行。

注意 BUFFER_NUM:多缓冲在这里是用户显式声明的东西(loopCount = tileNum * BUFFER_NUM,:376-386)。这正是 TileLang@Ascend 想拿走的部分——它把缓冲与同步建模成 编译期调度问题。TileLang 官方 Ascend 文档有一张直接对照表:用户只写 T.alloc_*、 T.copy、T.dual_copy,而「Ascend C code you can skip」一栏列的就是 TPipe/TQue 与 DMA 调用、Set/Wait flag 与 flag ID 管理,Synchronization 一行的原文是 「None (Just write operations in order!)」(来源 _vendor/tilelang-v0.1.15/tilelang/ascend/README.md:141-151)。

资料不足:本 corpus 没有 Ascend C 版本的「GEMM + 融合 epilogue」完整样例(上面的 是逐元素算子)。要逐行对照 GEMM 的 Cube 指令与 epilogue,需要 CANN 官方 GEMM 样例或 CATLASS 的具体 kernel 源码(CATLASS README 只给了仓库入口,来源 cann/catlass — Ascend C template library)。

3.6 PTO-DSL:用 Python 写昇腾,但仍然贴硬件原语

PTO-DSL 自述是「类似 cuTile、但原生 NPU」的 Python 接口与 JIT 编译器,目标是提供 「低层、显式、NPU 原生的原语」,性能对标直接写硬件 intrinsic(来源 pto-dsl/README.md 第 4–7、46–48 行)。它和 TileLang@Ascend 的关系,PTO-DSL 自己说得很直接:tilelang 也可以把 PTO-ISA 当 codegen 后端,而 PTO-DSL 故意暴露更低层的控制——例如 L2 swizzling 在 tilelang 里是一行 T.use_swizzle,在 PTO-DSL 里要用户自己写(来源同上 :49)。

它的 matmul 教程给出了一条从零优化的路径,第一步是一段约 80 行的 Python,结构是 显式的三级循环(core 循环 → GM→L1 → L1→L0),核心 API 是:

for li in pto.range(bid, core_loop, num_blocks):   # persistent:每核迭代取 tile
    ...
    for k_idx in pto.range(c0, k_dtile_num, c1):
        for phase in range(8):                      # L1→L0 静态展开
            tile.extract(a_l1, c0, a_col, a_l0)     # TEXTRACT
            tile.extract(b_l1, b_row, c0, b_l0)
            tile.matmul_acc(c_l0, a_l0, b_l0, c_l0) # TMATMUL_ACC

—— 来源: pto-dsl/examples/aot/matmul_optimization_guide/step1_baseline.py 第 34–125 行 与 .../matmul_optim_guide_zh.md(说明 pto.load=TLOAD、tile.extract=TEXTRACT、 tile.matmul=TMATMUL,以及 GM→L1→L0A/L0B→Cube→L0C→GM 的搬运路径)。

PTO-DSL 的定位因此很清楚:它在 TileLang 之下——用户仍要显式写出 L1/L0 的搬运与 extract。它自述的卖点是「自动软件流水、无需手动同步」,由 PTOAS 的 InsertSync pass 实现(来源 pto-dsl/README.md 第 9–12 行)。 一个能说明「昇腾原生 FP 语义」的细节:PTO 规范把 64 个 Tile 寄存器、118 条 Direct Tile operation、execution mask 都形式化了(来源 pto-spec/README.md 第 15–40 行)。

3.7 一张对照表

把「带融合 ReLU 的 GEMM」这件事横着摊开:

你要提供的 CUDA Triton CUTLASS-CuTe TileLang Ascend C PTO-DSL
任务/块划分 grid + block 块尺寸(可 autotune) 分层 tile(可 policy 化) T.Kernel + tile 尺寸 核函数 + get_block_idx persistent pto.range
片上存储放置 __shared__ 手写 编译器决定 用户按 CuTe 层级放置 T.alloc_shared(声明,pass 决定布局) TPipe.InitBuffer 手写 pto.alloc_tile 手写
矩阵乘 手写 MMA/tensor core 序列 tl.dot CuTe atom / CUTLASS 组件 T.gemm Cube 指令 / 库 tile.matmul
多缓冲 手写 编译器(流水 pass) 用户/模板 T.Pipelined(num_stages=k) BUFFER_NUM 手写 自动 + 可选手写
同步 __syncthreads/mbarrier 编译器插入 用户/atom 编译器插入 EnQue/DeQue、Set/Wait PTOAS InsertSync 自动
融合 ReLU 手写 epilogue 块上再做一次 epilogue 组件 T.Parallel 里一行 手写 Vector 段 手写 Vector 段
抽象层次 低 高 低 高(但数据流显式) 低 低

一句话读法:行越往下的是「用户要提供的东西」,列越往右的越自动化。但「自动化」不等于 「更短」——自动化只是把决定权从你手里搬到了编译器里,代价是编译期复杂度(见第 4 节)。


4. 实现机制:TVM 是底盘,不是竞争者

4.1 TVM 提供什么

TVM 是一个端到端的深度学习编译器,暴露图级与算子级优化,为不同硬件后端提供性能可移植性, 并用学习式代价模型自动探索低级优化,来源 TVM: An Automated End-to-End Optimizing Compiler fo…(TVM,OSDI 2018 摘要)。 它带来的三样东西构成了 TileLang 的地基:

  1. IR:TensorIR 把「循环嵌套」升级成以张量计算为一等公民的 block/axis 表示,来源 TensorIR: An Abstraction for Automatic Tensorized P…(TensorIR, ASPLOS 2023)。 TileLang 的 IR 就是 TVM 的 TIR(v0.1.15 已迁到 TIRX 表示,见第 30 章)。
  2. pass 基础设施:一个 IRModule 上串起一长串 pass 的能力——这正是 TileLang 的 LowerTileOp / LayoutInference / ThreadSync 的落点。
  3. target / device 抽象:把「给哪个后端生成代码」与「用什么运行时加载」分开。 TileLang 在此基础上做了自己的 backend 化改造(见 4.3)。

TVM 自己也在往 tile 层演化:上游文档里已经出现 TIRx,包含「Tensor Layout」「Tile Primitives」「Tile Primitive Dispatch」等章节,来源 Apache TVM documentation(TIRx 小节)。但即便如此, TVM 的自我定位仍是编译基础设施——它提供的是一套能装各种前端/后端的骨架,而不是 「推荐你直接用 TVM 写大模型算子」的产品级前端。这就是本章把 TVM 标成「底盘」而不是 「竞争者」的依据。

4.2 为什么「TVM 是竞争者」是错的

如果 TVM 是竞争者,那么 TileLang 就应该自己写一套 IR 和 pass 框架。事实相反:TileLang 把几乎全部结构调整都表达成 TIR pass。举例来说,昇腾侧那条自动调度流水是这样的 (来源 _vendor/tilelang-v0.1.15/tilelang/ascend/pipeline.py:108-114):

EstimateLatency → AutoSchedule → PrepareMultiBuffer → InsertSync → MaterializeMultiBuffer

其中 AutoSchedule 背后是 Z3(SMT 求解器)——_vendor/tilelang-v0.1.15/tilelang/ascend/transform/z3_scheduler.py:1-26 开头就写着「Z3-based scheduler for auto-scheduling」。这些 pass 之所以能存在,是因为 TVM 先把 IR 与 pass 机制准备好了。换句话说:TileLang 的竞争力,很大程度上是「知道在 TVM 这条底盘上把哪些新 pass 装进去」。把它和 TVM 对立起来,等于否定它自己的实现方式。

4.3 TileLang 的 backend 化改造

v0.1.15 里的 TileLang 已经把自己讲成「multi-backend compiler (TileLang-X)」:每个 target backend 被视为一条「compiler vertical slice」,自己拥有语言方言、pass 流水、 host/device codegen,而 build/load/launch 交给可复用的 execution backend(来源 _vendor/tilelang-v0.1.15/tilelang/backend/README.md:1-27)。官方 README 的 Platform/Backend 表把后端分成 Primary / Supported / Experimental / Ecosystem 四档, 其中 NVIDIA CUDA 是 Primary,Huawei Ascend 950 是 Supported,NVIDIA CuTe DSL 是 Experimental(来源 _vendor/tilelang-v0.1.15/README.md:113-128)。

这张表恰好回扣本章的坐标系:

  • cutedsl 后端的存在,说明 TileLang 把 CuTe DSL 当成下层的可替换 codegen (_vendor/tilelang-v0.1.15/tilelang/cuda/cutedsl_backend.py:1-20 把 cutedsl 注册成 复用 CUDA pipeline 的 backend;tilelang/contrib/cutedsl/gemm_tcgen05.py:1-13 提供 Blackwell 的 tcgen05 MMA 原语)。也就是说 TileLang 与 CUTLASS-CuTe 的关系是 互补,不是二选一。
  • ascend 后端对应的是昇腾主线(950),而 A2/A3 的 ascendc/pto/npuir 是 Ecosystem 档(在独立仓库 tilelang-ascend / tilelang-mlir-ascend 里,来源 _vendor/tilelang-v0.1.15/README.md:129-132)。

4.4 cuTile 与 CuTe DSL:NVIDIA 自己的新 tile 层

TileLang 在 NVIDIA 侧最需要警惕的对手,是 NVIDIA 自己在推的 Python tile DSL。 本地能确证的事实只有三条:

  1. CUTLASS 4 引入了 CUTLASS DSLs,第一个是 CuTe DSL,自述为「与 CuTe C++ 抽象完全一致 的低层编程模型」(R5),它并不是 tile 层;
  2. TileLang 有一个 [RoadMap] CuteDSL Backend issue,把 CuTe DSL 称作 「NVIDIA's newer Python tile DSL (cuTile/CuTe DSL),which is the most serious competitor on the NVIDIA side」(来源 [RoadMap] CuteDSL Backend);
  3. PTO-DSL 的 README 反复把 cuTile 当作参照物,并给出链接 https://docs.nvidia.com/cuda/cutile-python/(R17);PTX ISA 的语言码表里出现了 8 | "python-cutile"(来源 Parallel Thread Execution ISA 第 38645–38658 行),说明 「python-cutile」是被 PTX 工具链识别的源语言之一。

资料不足(cuTile):本 corpus 没有 cuTile 的官方文档快照,也没有任何 cuTile 代码样例。上面三条只够说明「cuTile 作为 NVIDIA 新一代 Python tile DSL 存在,且与 CuTe DSL 被并列讨论」。要给出 cuTile 的「用户写什么 / 编译器替你做什么」,必须补齐 docs.nvidia.com/cuda/cutile-python/ 的正文与至少两个官方样例。在此之前,任何关于 cuTile 语言细节的陈述都只能是猜测,本章不予给出。


5. 什么时候该选谁:决策表

把前面所有内容压成一张可以照着做的表。使用顺序:先确定硬件,再确定你要写的是 普通算子、还是要在编译器/后端里做事,最后看你愿意让出多少控制权。

你的处境 首选 理由(可回溯到本文哪节/哪条来源) 不要用它来做
想快速给一个具体算子拿到接近库的性能,规模通用 Triton(GPU)/ TileLang(要更细的数据流控制或要跨 NVIDIA+昇腾) 两者都在 tile 层;Triton 让编译器定调度(R2/R4),TileLang 把数据流留在语言里(S1、quickstart.py) 需要手写非常规同步协议的实验
要在 NVIDIA 上对齐 cuBLAS/CUTLASS 级别的 GEMM/卷积,且要跟着每一代 tensor core 走 CUTLASS / CuTe(含 CuTe DSL) CuTe 的 layout 代数与分层组件是官方路线(R5/R6) 想要「几十行写一个算子」
要写 TileLang 之外、但比 CUDA 高一层的东西,且愿意让编译器插同步 TileLang T.gemm/T.copy/T.Pipelined + 编译器插同步(S1、cuda/pipeline.py) 需要直接控制每条 PTX/mbarrier 时序
要改编译器、加 pass、做自动调度研究 TVM(作为底盘)+ TileLang(作为上层) TVM 提供 TIR/pass/target(R10/R11/R12),TileLang 在其上装 pass(S10/S11/S12) 直接用 TVM 当「大模型算子前端」
在昇腾上要贴硬件、要极致控制 Ascend C 或 PTO-DSL 两者都暴露 L1/L0/UB 与 MTE(R14/R17/R18) 想自动调度
在昇腾上要自动调度、自动同步,愿意用 tile 前端 TileLang@Ascend 自动 layout/schedule/sync(资料库索引、ascend/pipeline.py) 需要访问后端暂不支持的非常规指令
要把 kernel 融进 PyTorch 训练/推理 TileLang / Triton / CUTLASS 都可能,取决于图的哪一部分 图级融合仍归 torch.compile/Inductor(第 02 章) 用 kernel DSL 去做图级优化

两条使用建议:

  • 不要用「代码行数」选工具。本节引用的社区文章(R22)确实说过 TileLang@Ascend「代码 行数差了好几倍」、性能「和主线 Ascend C 打得有来有回」,但作者自己也承认没有公开基线 与测量口径,本书只把它当定性描述。(R22 是社区一手文章,非厂商文档。)
  • 不要跨层比较「谁更强」。比较 CUDA 和 Triton 的「性能」,就像比较汇编和 C 的性能—— 只有在同一目标、同一优化预算、同一测量口径下才有意义。

什么时候该选谁:从硬件到控制权的判定树NVIDIA昇腾其他 / 跨厂商写编译器写算子要完全控制要自动调度写编译器写算子贴硬件要自动调度要写一段 kernel目标硬件?NVIDIA:改编译器还是写算子?昇腾:改编译器还是写算子?其他 / 跨厂商TileLang:一个前端,多后端 lowering改编译器 → TVM 底盘 + 写 passR10/R11/R12、S10/S11让出多少控制权?CUTLASS-CuTe完全控制 epilogue / 对齐库Triton 或 TileLang自动调度、tile 级让出多少控制权?Ascend C 或 PTO-DSL贴硬件、显式 L1/L0/UBTileLang@Ascend自动 layout / schedule / sync
判定顺序是「硬件 → 目标是算子还是编译器 → 愿意让出多少控制权」,不要从语法长短开始比。
  • 判定要点一:先选硬件,决定可选项集合。
  • 判定要点二:改编译器走 TVM 底盘(§4),写算子走 tile 层或低层。
  • 判定要点三:不要用代码行数决定——社区文章说的「差几倍」没有公开基线(R22)。
  • 注意:NVIDIA 的 cuTile 与 CuTe DSL 是两个不同的东西,CuTe DSL 在低层(R5/R27)。

6. 进阶与陷阱

  1. 「2019 年的 Triton」不是「今天的 Triton」。 引用原始论文时,注意它的贡献是 Triton-C + LLVM 式 IR + tile 级 pass + autotuner,而张量核支持是论文里写明 「未来的工作」(R2:943-946)。用 2019 论文评价今天 Triton 的能力是时代错位。
  2. 「没有同步」不等于「没有代价」。 TileLang 的 T.Pipelined 在昇腾侧背后是 EstimateLatency → AutoSchedule(Z3) → PrepareMultiBuffer → InsertSync → Materialize 一整条流水(S11)。代码里看不到 set_flag/wait_flag,是因为它们被生成出来了,而不是 不存在。
  3. 不要把 CuTe DSL 当成「NVIDIA 的 Triton」。 CuTe DSL 自述与 CuTe C++ 抽象一致、 暴露 hardware atom 与线程/数据层级(R5);从真实片段看,它是要写 tidx 和 cute.arch.barrier() 的(R27)。它和 cuTile 是两回事。
  4. 昇腾有两条 950 路线,选哪条要问维护者。 issue #3317 就是用户问「PR3308 和 PR3310 两个 Ascend 950 后端该用哪个」——但本 corpus 抓到的快照里只有提问、没有回答, 所以本章不臆测官方建议;见「待补资料」。
  5. 判据优先级:先看硬件(NVIDIA / 昇腾 / 其他)→ 再看你要改的是算子还是编译器 → 最后才看语法。跳过前两步直接比语法,得到的结论通常不可靠。

7. 本章小结

  • 本章用「用户必须提供的硬件相关决策数量」定义抽象层次,把七个对象放到一条纵轴上: 线程/指令级(CUDA、CUTLASS-CuTe、Ascend C、PTO-DSL)↔ tile 级(Triton、 cuTile、TileLang);TVM 是横穿两级的底盘。
  • 统一例子(C = relu(A @ B)):CUDA 要手写 shared memory 与同步;Triton 用 tl.dot 让编译器管调度;CUTLASS-CuTe 仍在低层,但给你可复用的布局与组件;TileLang 用 T.gemm + T.copy + T.Pipelined 把数据流写出来、把布局/流水/同步交给 pass; Ascend C 用 TPipe/TQue 手写三段流水;PTO-DSL 用 Python 但仍显式写 L1/L0 搬运。
  • TVM 不是竞争者,是底盘:TIR/pass/target 都来自 TVM,TileLang 的全部魔法都是装进 这条底盘的 pass(layout inference、autoschedule、sync insertion)。
  • Ascend C 与 PTO-DSL 是昇腾原生路线:TileLang@Ascend 与它们竞争用户、互补层次—— TileLang 可以产出 Ascend C,也可以把 PTO-ISA 当 codegen 后端。
  • 决策表:先硬件、再「算子还是编译器」、最后「让出多少控制权」。
  • 证据边界:cuTile 与 CUTLASS epilogue 细节本地资料不足(见 references.md 的 「待补资料」);社区文章的「性能打平」说法没有公开基线,只作定性引用。

延伸阅读

  • TileLang 的 tile 抽象与三层接口:第 03 章;论文摘要见 R1。
  • TVM/TensorIR 的 IR 与 pass 基础:第 20 章;资料见 R10、R11、R12。
  • NVIDIA 后端(CuTe/MMA/TMA):第 24 章。
  • 昇腾后端(Ascend C & PTO vs AscendNPU IR):第 25 章;资料见 R14、R17、R18、R20。
  • 本章所有引用的完整清单与核验状态:见 本章引用。

习题

15 题 · 答案在提交后展开

先在纸上或输入框里写下你的答案,再展开参考答案对照。客观判断请自己打勾:这三颗按钮 只影响本机保存的学习进度。

E1综合难度 ★无需硬件抽象层次

用本章的「三个决策」(谁搬数据、谁切 tile、谁同步)填空:

对象 谁搬数据 谁切 tile 谁插同步
CUDA ? ? ?
Triton ? ? ?
TileLang(NVIDIA 后端) ? ? ?

并回答:为什么说 TVM 不在这张表的任何一行里?

(硬件:否)


E2综合难度 ★无需硬件tile 的定义

写出 Triton 2019 论文对 tile 的定义原文(英文),并注明来源文件与行号。 然后说明:为什么「tile」这个定义同时适用于 Triton 和 TileLang,却不适用于 CUDA。

(硬件:否)


E3综合难度 ★★无需硬件2019 Triton 的能力边界

有人读完 Triton 的 2019 论文后说「Triton 原生支持张量核,所以写 GEMM 比 CUDA 容易」。 请用论文原文指出这句话里哪一部分至少对 2019 年的 Triton 不成立,并给出出处。

(硬件:否)


E4综合难度 ★★无需硬件读 TileLang 源码:谁在插同步

打开 _vendor/tilelang-v0.1.15/tilelang/cuda/pipeline.py,找出 NVIDIA 后端 pass 顺序里 与「流水」和「同步」有关的两处(提示:一个在 129 行附近,一个在 258 行附近)。 写出这两段的 pass 名,并解释为什么 TileLang 的用户不需要写 __syncthreads()。

(硬件:否)


E5综合难度 ★★★无需硬件TVM 的角色

本章说「TVM 是底盘,不是竞争者」。请给出至少两条源码级证据支持这个说法,并解释 如果把 TVM 换成「TileLang 自己写的 IR 框架」,TileLang 会失去什么。

(硬件:否)


E6综合难度 ★★无需硬件Ascend C 与 TileLang@Ascend 的分工

依据 _vendor/tilelang-v0.1.15/tilelang/ascend/README.md 里的对照表,列出至少三件 「用 TileLang 写时可以跳过、但用 Ascend C 写时必须自己做」的事,并指出这张表在文件里的 行号范围。

(硬件:否)


E7综合难度 ★★无需硬件PTO-DSL 与 TileLang@Ascend 的关系

PTO-DSL 的 README 自己说明了它和 tilelang-ascend 的关系。请引用原文,说明: (1) 谁更「低层」;(2) 举出一个「在 tilelang 里一行、在 PTO-DSL 里要自己写」的例子。

(硬件:否)


E8综合难度 ★★无需硬件统一例子:融合 epilogue 的位置

在本章的统一例子(C = relu(A @ B))里,TileLang 用 T.Parallel 对 C_local 做 ReLU。 请回答:

  1. 为什么在 CUDA 里这个 ReLU 通常是「另一个 kernel」或「GEMM 的 epilogue stage」, 而在 TileLang 里可以就是同一个 kernel 里的几行?
  2. 查 _vendor/tilelang-v0.1.15/examples/quickstart.py,写出这段融合 ReLU 的行号区间。

(硬件:否)


E9综合难度 ★★无需硬件昇腾上的 persistent kernel

PTO-DSL 的 matmul 教程指出:NPU 算子的 grid 通常等于硬件核数(persistent),而不像 普通 CUDA/Triton kernel 那样随输入规模增长。请引用该教程的说法,并说明 TileLang@Ascend 示例里对应的是哪个原语(提示:_vendor/tilelang-v0.1.15/tilelang/ascend/README.md)。

(硬件:否)


E10综合难度 ★★★无需硬件决策:该选谁

下面三个场景,各选一个工具并给出理由(必须引用本章的证据,不许只凭印象):

  1. 你在一台昇腾 950 上要把一个自定义 attention 前向写到接近 CANN 算子库的水平, 并且希望自动处理多缓冲与同步。
  2. 你要在 NVIDIA H100 上把 GEMM 的 fp8 blockscaled 路径对齐 CUTLASS,并保留对 epilogue 的完全控制。
  3. 你要给 TileLang 加一个新的 pass,改善某个 layout 推导的结果。

(硬件:否)


E11综合难度 ★★无需硬件资料缺口

本章明确标注了「资料不足」的地方。请列举至少三处,每处说明:缺什么资料、为什么缺了 就无法下结论、建议从哪里补。(不要求你补齐资料,只要求写清缺口。)

(硬件:否)


E12代码阅读难度 ★★★无需硬件代码阅读:CuTe DSL 与 TileLang 的区别

读 TileFoundry/examples/minicpm3_4b-cutedsl/kernels/cute_gemv.py 第 36–113 行。 找出其中属于「线程/指令级」的三个 API(例如带 tidx 的参数),并说明:如果同样一件事 用 TileLang 写,哪几个概念会从代码里消失。为什么这不意味着 CuTe DSL「更差」?

(硬件:否)


E13综合难度 ★★无需硬件社区数字的引用规范

有一位社区作者写道「TileLang 性能已经和主线 Ascend C 打得有来有回,代码行数差了好几倍」。 请按本章的引用规则改写这句话,使其成为一句可被审计的表述(要写清:来源是什么性质、 是否厂商材料、有没有测量口径、本书如何使用它)。

(硬件:否)


E14动手难度 ★★★无需硬件动手:画坐标系

用 Mermaid 或 ASCII 画一张图,把本章七个对象分别放到「线程/指令级」「tile 级」 「编译器底盘」三层,并标出 TileLang 与每一个对象的连线类型(竞争 / 互补 / 底盘)。 图里每个连线上写一个本章用过的证据编号(如 R2、S1、S11)。

(硬件:否)


E15综合难度 ★★无需硬件读源码:Z3 在昇腾调度里的位置

打开 _vendor/tilelang-v0.1.15/tilelang/ascend/transform/z3_scheduler.py, 说明这个文件开头为什么强调 Z3「not thread-safe」,以及它在整个昇腾调度流水里对应 _vendor/tilelang-v0.1.15/tilelang/ascend/pipeline.py 的哪个 pass。

(硬件:否)

章节自测

7 题 · 提交后本地评分

单选题。提交后立即给出分数与逐题解析;重做会清空选择,但会保留上一次的成绩记录。

  1. 1. 本章用「抽象层次」这把尺子给七个对象排序,它衡量的到底是什么?

  2. 2. 按本章的层次划分,CUTLASS 4 引入的 CuTe DSL 应该放在哪一层,为什么?

  3. 3. 本章为什么说「TVM 是 TileLang 的底盘,不是竞争者」?

  4. 4. 在 TileLang 里写带融合 ReLU 的 GEMM,多缓冲(软件流水)由谁负责?

  5. 5. 「越自动化就越短、越省事」,本章是怎么纠正这个说法的?

  6. 6. 引用 2019 年那篇 Triton 论文时,本章提醒要注意什么?

  7. 7. 按本章的决策表,面对「我该用哪个」的问题,正确的判据顺序是什么?

本章代码

10 个文件

正文里提到的每个示例都能在这里直接阅读(带语法高亮),也可以整章浏览。

浏览本章全部代码 →

本章引用

源码链接指向锁定 tag

本章写到的每个源码位置与外部资料都在下面列出:源码链接指向锁定 tag 的 GitHub 文件, 资料链接指向原文。查看全部资料索引 →

展开引用清单

第 05 章 参考资料

本章所有结论都基于下表的本地资料或锁定版本源码。版本以 版本锁定 为准:TileLang v0.1.15 (commit a35f8ddf45eba16c21211ec8822d56ce5363036f)、TileLang-Ascend TileLang-ascend-v0.1.2.000-release(commit 89a9364e47a341fffdd65ed94786b1d4f9b6a78c)。 文中不出现「最新版」这类表述;讨论 main/未合入的能力时一律显式标注。

写作环境:macOS (Apple Silicon)、Python 3.11;没有 NVIDIA GPU,也没有昇腾 NPU。 因此本章所有代码示例的最高验证级别是「仅静态核对」(API 存在性与签名逐个在 _vendor/ 中比对过),没有任何一条性能数字来自本机实测。

引用路径约定:源码相对书籍根目录写 _vendor/...;corpus 资料写 资料库索引。


锁定的源码引用(_vendor/tilelang-v0.1.15/)

id 引用位置 用途 核验方式与状态
S1 _vendor/tilelang-v0.1.15/examples/quickstart.py:1-46、:51-56、:38、:41-43 统一例子(GEMM+ReLU)的 TileLang 版;默认 tile 参数;T.gemm 落到 cute/hip 的注释;融合 ReLU 已核验(2026-10-01):grep -n/sed -n 定位逐行比对;未运行(无 GPU)
S2 _vendor/tilelang-v0.1.15/README.md:113-132 Platform/Backend 支持表:CUDA=Primary、Ascend 950=Supported、CuTe DSL=Experimental、A2/A3=Ecosystem 已核验(2026-10-01):表格逐行阅读
S3 _vendor/tilelang-v0.1.15/tilelang/ascend/README.md:74-124、:141-151 昇腾 GEMM+ReLU quickstart(含 :124「single kernel, without a separate launch for the epilogue」);「Compared with writing Ascend C directly」对照表(用户写什么 / 可跳过什么) 已核验(2026-10-01);未在 NPU 上运行
S4 _vendor/tilelang-v0.1.15/tilelang/language/gemm_op.py:160 T.gemm(...) 定义行 已核验(2026-10-01):grep -n "^def gemm" → 160
S5 _vendor/tilelang-v0.1.15/tilelang/language/copy_op.py:59 T.copy(...) 定义行 已核验(2026-10-01)
S6 _vendor/tilelang-v0.1.15/tilelang/language/kernel.py:431 T.Kernel(...) 定义行 已核验(2026-10-01)
S7 _vendor/tilelang-v0.1.15/tilelang/ascend/language/allocate.py:26,37,46,55 alloc_l1 / alloc_l0a / alloc_l0b / alloc_l0c 的 scope 默认值 已核验(2026-10-01)
S8 _vendor/tilelang-v0.1.15/tilelang/ascend/language/copy_op.py:53 T.dual_copy 定义行 已核验(2026-10-01)
S9 _vendor/tilelang-v0.1.15/tilelang/ascend/language/frame.py:107,179 T.SimtVF(threads=128, latency=0)、T.SimdVF(latency=0) 已核验(2026-10-01)
S10 _vendor/tilelang-v0.1.15/tilelang/cuda/pipeline.py:129-142,258-259 NVIDIA 后端 pass 顺序:PipelinePlanning→InjectSoftwarePipeline→LayoutInference→LowerTileOp;ThreadSync("shared"/"shared.dyn") 已核验(2026-10-01):逐行阅读
S11 _vendor/tilelang-v0.1.15/tilelang/ascend/pipeline.py:108-114 昇腾侧 EstimateLatency→AutoSchedule→PrepareMultiBuffer→InsertSync→MaterializeMultiBuffer 已核验(2026-10-01)
S12 _vendor/tilelang-v0.1.15/tilelang/ascend/transform/z3_scheduler.py:1-26,67 昇腾自动调度使用 Z3(SMT);文件头注明 Z3 非线程安全 已核验(2026-10-01):文件头与函数定义阅读
S13 _vendor/tilelang-v0.1.15/tilelang/backend/README.md:1-27 backend 抽象:target backend = compiler vertical slice;execution backend 可复用 已核验(2026-10-01)
S14 _vendor/tilelang-v0.1.15/tilelang/cuda/cutedsl_backend.py:1-20 cutedsl 后端注册(复用 CUDA pipeline) 已核验(2026-10-01)
S15 _vendor/tilelang-v0.1.15/tilelang/contrib/cutedsl/gemm_tcgen05.py:1-13 CuTe DSL 侧的 tcgen05(Blackwell)MMA 原语清单 已核验(2026-10-01)
S16 _vendor/tilelang-v0.1.15/tilelang/ascend/README.md:58-98 昇腾版示例使用 T.Persistent(:88)、T.dual_copy(:94)、T.SimtVF+T.Parallel(:95-97) 已核验(2026-10-01)

「已核验」的含义:在锁定版本工作树上用 grep -n / sed -n 定位到定义行,并阅读了完整 签名与 docstring;行号区间与文件内容一致。这不是运行验证。


corpus 资料引用(资料库索引)

抓取日期:2026-09-30(Asia/Shanghai),见 corpus 的 资料库索引。

id 本地路径 上游链接 用途 核验状态
R1 TileLang: A Composable Tiled Programming Model for … https://arxiv.org/abs/2504.17577 TileLang 论文摘要:tile 数据流、调度空间与数据流解耦、composable 已核验(2026-10-01):本地为摘要全文
R2 Triton: An Intermediate Language and Compiler for T…(:37 tile 定义;:130-200 Listing 1;:583-720 机器相关 pass;:943-946 未来工作含 tensor cores) https://www.eecs.harvard.edu/~htk/publication/2019-mapl-tillet-kung-cox.pdf ;DOI 10.1145/3315508.3329973 Triton 原始论文全文(PDF 同目录 triton-mapl-2019.pdf) 已核验(2026-10-01):本地为逐页文本提取,逐行阅读
R3 triton-lang/triton https://github.com/triton-lang/triton Triton 当前实现仓库自述;确认 MAPL2019 为其奠基论文 已核验(2026-10-01)
R4 Triton documentation https://triton-lang.org/main/index.html 当前 Triton 文档索引:triton.language、Gluon 层 已核验(2026-10-01):本地为索引页
R5 NVIDIA/cutlass(:19-51 概览与 DSL;:28-37 支持的数据类型与架构) https://github.com/NVIDIA/cutlass CUTLASS 4.x 定位、CuTe DSL 自述(低层、与 CuTe C++ 一致、公测) 已核验(2026-10-01):本地为 README 快照
R6 CuTe: C++ template abstractions for layout algebra 第 10–12 行 https://docs.nvidia.com/cutlass/latest/media/docs/cpp/cute/00_quickstart.html CuTe 核心抽象:hierarchically multidimensional layouts、Layout/Tensor 已核验(2026-10-01):本地为 quickstart 页
R7 CUDA C++ Programming Guide https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html CUDA 编程模型总览(本地为节选,用于层次定位) 已核验(2026-10-01);本地为节选,未用于任何具体数字
R8 CUDA C++ Best Practices Guide 第 1745–1830 行 https://docs.nvidia.com/cuda/cuda-c-best-practices-guide/index.html 共享内存分块矩阵乘示例(__shared__ float aTile[TILE_DIM][TILE_DIM]) 已核验(2026-10-01):本地为全文;引用处为示例段
R9 Parallel Thread Execution ISA 第 38645–38659 行 https://docs.nvidia.com/cuda/parallel-thread-execution/ PTX 语言码表含 `8 "python-cutile"`(PTX ISA 9.3 引入)
R10 Apache TVM documentation https://tvm.apache.org/docs/ TVM 文档索引;TIRx(Tensor Layout / Tile Primitives)小节 已核验(2026-10-01):本地为索引页
R11 TVM: An Automated End-to-End Optimizing Compiler fo… https://arxiv.org/abs/1802.04799 TVM(OSDI 2018)摘要:图级+算子级优化、自动代价模型 已核验(2026-10-01):本地为摘要
R12 TensorIR: An Abstraction for Automatic Tensorized P… https://arxiv.org/abs/2207.04296 TensorIR(ASPLOS 2023)摘要:张量为 first-class 的 block/axis IR 已核验(2026-10-01):本地为摘要
R13 MLIR documentation https://mlir.llvm.org/docs/ MLIR dialect/pass 基础设施(昇腾 AscendNPU IR 路线的共同语言) 已核验(2026-10-01):本地为索引页
R14 hiascend.com · zh_developer_techArticles_20230830-1(:29 定位;:51-57 编程范式与队列;:350-440 代码) https://www.hiascend.com/developer/techArticles Ascend C 官方技术文章:CopyIn/Compute/CopyOut、TPipe/TQue/EnQue/DeQue、LeakyReLU 样例 已核验(2026-10-01):本地为官方文章镜像
R15 CANN 异构计算架构总览 https://www.hiascend.com/cann CANN 定位(Ascend C 属 CANN 软件栈) 部分核验:本地为站点抓取,正文含较多导航噪声;本章仅用于「Ascend C 属 CANN」这一定位,并改用 R14 支撑细节
R16 cann/catlass — Ascend C template library https://gitcode.com/cann/catlass CATLASS:昇腾算子模板库(GEMM 及融合类算子模板),提供仓库入口与 v2.1.0 概述 已核验(2026-10-01):本地为仓库页快照;未取得具体 kernel 源码
R17 pto-dsl/README.md(:4-7 类比 cuTile;:9-12 自动软件流水;:46-52 框架对比,含 :49 与 tilelang 的关系) https://github.com/huawei-csl/pto-dsl PTO-DSL 定位、与 tilelang-ascend 的关系、目标对标硬件 intrinsic 已核验(2026-10-01):本地为仓库 README 快照
R18 pto-dsl/examples/aot/matmul_optimization_guide/matmul_optim_guide_zh.md 同仓库文件 昇腾 matmul 逐步优化指南:persistent kernel 行为、GM→L1→L0→Cube→L0C→GM 路径、自动同步 已核验(2026-10-01):本地为仓库快照
R19 pto-dsl/examples/aot/matmul_optimization_guide/step1_baseline.py 第 27–125 行 同仓库文件 PTO-DSL matmul 基线实现(pto.load/tile.extract/tile.matmul(_acc)/pto.store) 已核验(2026-10-01):本地为仓库快照;未在 NPU 上运行
R20 pto-spec/README.md 第 15–40 行 https://github.com/PTO-ISA/pto-spec PTO ISA 形式规范概览:64 个 T/U/M/N Tile 寄存器、118 条 Direct Tile operation、execution mask 已核验(2026-10-01):本地为工作树快照,架构标识 0.58.7(开发分支,非发布版)
R21 PTO-Gym/README.md https://github.com/PTO-ISA/pto-gym PTO 教学资源:kernel.pto/launch.cpp/golden.py 结构与 Tile 指令 SPEC 已核验(2026-10-01):本地为仓库快照
R22 DeepSeek 开源昇腾基础组件将会带来哪些影响? https://www.zhihu.com/question/2088578683623814216/answer/2088624284100999121 昇腾 950 后端的中文一手叙述:NV/昇腾逐项对照、为什么同步最难、Z3 调度、latency 与 issue interval 部分核验:本地为登录态抓取的全文;链接需登录;属社区一手文章,非厂商官方文档;其性能说法(「打得有来有回」「代码行数差好几倍」)无公开基线与测量口径,本章只作定性引用
R23 tilelang-ascend/README.md https://github.com/tile-ai/tilelang-ascend TileLang-Ascend 适配器定位:两条技术路线(Ascend C & PTO / AscendNPU IR) 已核验(2026-10-01):本地为仓库 README 快照
R24 [RoadMap] CuteDSL Backend https://github.com/tile-ai/tilelang/issues/1454 CuteDSL Backend roadmap;把 CuTe DSL 称为 NVIDIA tile DSL 侧最有力的竞争者 已核验(2026-10-01):本地为 issue 快照
R25 [Question] It seems there are two Ascend 950 backen… https://github.com/tile-ai/tilelang/issues/3317 用户提问「Ascend 950 的两个后端该用哪个」 快照不完整:抓到的正文只有提问,没有维护者回答;本章据此不给出「官方推荐哪条路线」的结论
R26 [Ascend] Add PTO backend for Ascend950 https://github.com/tile-ai/tilelang/pull/3310 给 Ascend950 增加 PTO 后端:注册 pto target、生成 PTO 设备码、ptoas+Bisheng 编译 已核验(2026-10-01):本地为 PR 快照(bot 生成的摘要)
R27 TileFoundry/examples/minicpm3_4b-cutedsl/kernels/cute_gemv.py 第 29–113 行 https://github.com/tile-ai/TileFoundry 真实 CuTe DSL kernel(GEMV + RMSNorm):@cute.jit、tidx、cute.arch.barrier、cute.autovec_copy 已核验(2026-10-01):本地为仓库快照;未运行

上游链接核验状态

  • https://docs.nvidia.com/cuda/cutile-python/:未核验。本 corpus 只有 PTO-DSL README 指向它的链接,没有正文快照;未联网核验其内容(写作环境不依赖实时网络)。这是本章 cuTile 一节标注「资料不足」的直接原因。
  • https://docs.nvidia.com/cutlass/latest/media/docs/pythonDSL/overview.html:未核验。 同上,只在 PTO-DSL / CUTLASS README 中作为链接出现。
  • https://github.com/tile-ai/tilelang/issues/3317:本地快照只有提问,未包含回答。
  • 其余上游链接均以 corpus 本地快照为准,已核验 指「本地文件存在且内容与引用一致」, 不代表已联网复核上游当日页面。

待补资料

以下缺口会直接影响本章(以及第 24、25 章)能否给出可复核的结论,按优先级列出。

  1. cuTile 官方资料(高优先级)。缺:docs.nvidia.com/cuda/cutile-python/ 的正文, 以及至少两个官方样例(一个 GEMM、一个带 epilogue 的算子)。需要它才能写出 cuTile 的 「用户写什么 / 编译器替你做什么」,并判断它与 TileLang 在 NVIDIA 侧的重叠边界。
  2. CUTLASS 融合 epilogue 的完整源文件(高优先级)。缺:CUTLASS examples/ 下与 media/docs/cpp/cute/0x_gemm_tutorial 的全文。需要它才能把本章的统一例子在 CUTLASS-CuTe 一侧写到「可对照」的粒度。
  3. Ascend C 的 GEMM + 融合 epilogue 样例(中优先级)。缺:CANN 官方 GEMM 样例或 CATLASS 的具体 kernel 源码。现在只有逐元素(LeakyReLU)样例,无法逐行对照 Cube 侧。
  4. Ascend 950 两条后端路线的官方取舍建议(中优先级)。缺:issue #3317 的维护者回答 或官方文档中的选型说明。现在只有提问,不能给出「该用 ascendc/pto 还是 npuir」。
  5. 带条件的性能对比报告(中优先级)。缺:明确写出昇腾型号、CANN 版本、矩阵形状、 基准口径的 benchmark。现在社区文章的「打平 / 差几倍」不可审计,只能定性引用。
  6. PTO-ISA 发布版规范(低优先级)。本 corpus 的 pto-spec 为开发分支快照 (架构标识 0.58.7),不是发布版;若要引用具体指令语义,应换用其 GitHub Releases 中某个已发布的 release 身份。

本章共 10 个二级小节;右上角目录在桌面端会跟随滚动高亮。