跳到主要内容
TileLang 系统教程

tilelang-tutorial.huandu.me

第 18 章 端到端 II:推理与部署

/code/18-e2e-inference-serving/

08-ascend-aclgraph/README.md3103 字节
# 示例 08:昇腾侧的 torch_npu 与 ACLGraph 入图

## 目的

把「TileLang 算子如何在昇腾上被反复执行而不被 host 侧下发拖死」讲清楚:

1. TileLang 的昇腾 kernel 怎么与 `torch_npu` 的算子落在同一条 stream 上;
2. ACLGraph 的 capture / replay 两阶段模型;
3. 入图对形状的要求,以及「为什么 vLLM-Ascend 只对 decode 入图」。

`aclgraph_decode_block.py` 里是 RMSNorm + 一步 decode 的最小骨架,
结构对照 corpus 里的
`07-tilelang-ascend-adapter/raw/tilelang-ascend/examples/aclgraph/rms_rope_aclgraph.py`。

## 版本归属(重要)

本文件用的是**适配器仓库** `_vendor/tilelang-ascend-v0.1.2.000` 的语言面:

* `T.Kernel(m_num, is_npu=True) as (cid, vid)`
  ——`tilelang/language/kernel.py:220,247`;
* `tilelang.PassConfigKey.TL_ASCEND_AUTO_SYNC` 等四个开关
  ——`tilelang/transform/pass_config.py:38-50`;
* `T.tile.mul/add/div/sqrt`——`tilelang/language/ascend_tile.py:1026,1048,1059,1241`
  经 `tilelang/language/__init__.py:86` 暴露成 `T.tile`;
* `T.reduce_sum(buffer, out, dim, clear)`——`tilelang/language/reduce.py:79`。

**主干 v0.1.15 的昇腾方言不是这套 API。** 在
`_vendor/tilelang-v0.1.15/tilelang/ascend/language/` 里 kernel 写成
`with T.Kernel(N_CORES) as core_id`(没有 `is_npu` 参数),auto-schedule 由
pass context 开关控制(`tilelang/ascend/pipeline.py` 里的 `allow_autoschedule`),
而且 `TL_ASCEND_AUTO_SYNC` 这类键在 v0.1.15 里**不存在**
(在 `tilelang/transform/pass_config.py` 里检索 `ASCEND` 无结果)。
参考 v0.1.15 的写法请看 `examples/ascend/example_rmsnorm.py`。

## 运行前提

* 昇腾 NPU(文档与示例针对 Ascend 950;适配器示例在 910 系列上也可运行)
  + CANN(含 `bisheng`、`ld.lld`、Ascend runtime)+ PyTorch + `torch_npu`;
  `torch.npu.is_available()` 必须为 `True`。
* TileLang-Ascend **适配器** `_vendor/tilelang-ascend-v0.1.2.000`。
* **本机没有 NPU、没有 CANN、没有 torch_npu**,因此本文件从未运行。

## 运行命令

```bash
# 0) 先确认设备可见
python3 -c "import torch, torch_npu; print(torch.npu.is_available())"

# 1) 跑本示例
python3 aclgraph_decode_block.py

# 2) 想看 ACLGraph 是否真的生效:打开 host 日志,搜 capture model
export ASCEND_HOST_LOG_FILE_NUM=1000
export ASCEND_PROCESS_LOG_PATH=logs
export ASCEND_GLOBAL_LOG_LEVEL=1
python3 aclgraph_decode_block.py
grep -r "capture model" logs | head

# 3) 用 msProf 看上板性能(不改变代码)
msprof op --kernel-name="main_rms" python3 aclgraph_decode_block.py
```

## 期望输出

**正确性判据**(本节未实际执行):

* `torch.testing.assert_close(out, reference(q, eps), rtol=1e-2, atol=1e-2)`
  通过,最后打印 `Kernel Output Match!`(与 corpus 里那份 ACLGraph 示例
  的收尾断言一致);
* 再跑一遍不带 `torch.npu.graph` 的 eager 版本,两次结果一致——
  这是「入图没有改变语义」的判据。

**性能口径**:

* 用 `msprof op` 或 `msprof op simulator` 采(见适配器编程指南第 6 章),
  或在 TileLang 里用 `do_bench(..., backend="msprof")`
  (`tilelang/profiler/bench.py:39,260-263`,它会用一个昇腾专用的
  cache-flush kernel 把 L2 冲掉);
* 要区分三种口径:eager 的 kernel 时间、graph replay 的 kernel 时间、
  以及端到端(含 host 下发)时间。ACLGraph 的收益主要在第三种。
* 必须一起报的变量:NPU 型号、CANN 版本、`torch_npu` 版本、
  batch / heads / hidden、是否开图、是否开 `TL_ASCEND_AUTO_CV_COMBINE`。

## 作者实际做到的验证级别

**仅静态核对。** `python3 -m py_compile aclgraph_decode_block.py` 通过;
上面列的每个 API 名都在 `_vendor/tilelang-ascend-v0.1.2.000/` 里定位到了
定义行。**没有在 NPU 上编译或运行过,也没有任何实测数字。**

## 已知局限

* 只覆盖「capture 一次 + replay 多次」这一条路径,没有覆盖动态形状、
  多流、以及 vLLM-Ascend 里把图路径限制在 decode 的调度层逻辑。
* corpus 里的 ACLGraph 示例使用 `T.tile.*` 做逐元素运算;主干 v0.1.15 的
  昇腾方言改用 `T.SimtVF` + `T.Parallel`,两者写法不同(见第 19 章)。
* `--soc-version` 的具体取值取决于你的 CANN 与硬件,本文件不写死。

← 浏览本章全部代码