跳转至

性能

单卡算子调优:先把执行过程看见,再逐个走过时间真正花掉的地方。

前置任务与定序作用域与放置

问题的形状

一个 PyPTO kernel 的墙上时间花在三台不同的机器上,而它们的失效方式各不相同:

host              编排                  AICore
 │                  │                     │
 ├─ 拷贝            ├─ 任务派发           ├─ kernel 本身
 │  (06-host)       │  (01, 02, 03)       │  (04-incore)
 │                  │                     │
 └────────────── 内存:片上缓冲 + 运行时 ring (05-memory) ──────┘

第一次调优大多直奔第三列——kernel 里的算术——然后发现问题出在前两列。本章的顺序就是按它们通常咬人的顺序排的。

目录

页面 内容
读泳道图 采集并打开 L2 泳道图 —— 唯一能显示时间去哪了的视图
任务粒度 派发不是免费的;如何放大与合并 InCore 函数而不饿死核
运行时开销 mix kernel、SPMD、allow_early_resolve、kernel 内 syncall
管理任务依赖 运行时为何把本可并行的活串起来,以及怎么告诉它不用
InCore 函数调优 double buffer、算法切分、L0 指令级 trace、硬件粒度、外部 kernel
内存 四层 scope-depth ring、scope 放置与 ring 尺寸
Host 让常驻的数据真的常驻

怎么用

下面每一项手段都用同样的四个字段来写,因为一个说不出代价的加速不算结果:

字段 回答什么
何时适用 什么症状说明该用这一招
怎么做 那一处代码改动
代价 它花掉了什么 —— 内存、通用性,或一份从此归你的正确性义务
怎么确认 哪个产物能证明它起作用了,以及其中什么该发生变化

本章不给加速数字。 它取决于你的形状、平台与工具链版本,而一个过期的数字比没有更糟——因为你没法察觉它过期了。确认那一步才是可迁移的部分:在你自己的 kernel 上跑一遍,你就得到属于你的数字。

动手之前

有两件更便宜的事排在这一切之前,而且都已经替你做好了:

  • 构建输出里的 report/perf_hints.log 编译器把它在编译期注意到的东西写在这里 —— 过小的搬运、它没能 tile 的 matmul、没放得下的流水深度。每次编译还会往 stderr 打一行摘要。
  • host / device 的分野。 run() 并不返回计时对象 —— 它的 execution_time 是整段墙上时间,含编译与 golden。要用 pypto.runtime.benchmark,它的 BenchmarkStats 分开给出 device_wall_ushost_wall_us。如果时间在 host 上,00–05 页里没有任何东西能动它 —— 直接去 Host

参见

  • 调度调优 —— 同样的内容,以动手教程的形式。
  • 精度 —— 对「结果错」的同类处理。