已关闭
[RFC]: reduction autotune 方案 #3464
AllenGuan创建于  7月29日关闭于  8月13日
AllenGuan成员
7月29日 创建

Reduction Autotune 候选集拟合报告

状态(Status): Draft
作者(Authors): @Your_community
创建日期(Created): 2026-07-29
更新日期(Updated): 2026-07-29
相关 Issue/PR: #(待关联 Issue/PR 以便追踪背景)

说明:本文为原《Reduction Autotune 候选集拟合报告》按 RFC 模板改写格式,内容不变、来源单一(仅原报告)。原文中的内部章节交叉引用已随新结构重指(如原 §2 理论依据 → §3.1、原 §3.4 grid → §3.3)。


1. 概述

1.1 简介

本报告给出 reduction kernel 的 autotune 候选集规律与公式驱动的候选生成算法 select_reduction_final,并以 dense 最优为参考,对比 npu-inductor 生产启发式与本文算法的性能与编译成本。每个 kernel 的流程为:候选集生成 → autotuner 编译并 benchmark 每个候选、取最快 → 与 dense 全局最优对比。

本文算法实现 95% 无损 / 0% 严重,全面优于生产启发式(73% / 7%);真实编译数 20,比生产启发式 59 少 66%、比 dense 79 少 75%——候选更少、质量更高。机理:按 reduction 轴长 rnumel 把搜索空间精确切三段(条件剪枝),每段只发命中带内的锚点,不再撒大网——故编译数下降而非膨胀。

1.2 动机

使用场景 / 数据底座:面向 Ascend NPU(硬件:Ascend910B3,UB=192KB,40 个 AIV 向量核)上 reduction kernel 的 autotune。数据底座为 153 个 reduction kernel(存量 57 = generated 49 + torchbench 8;backward 96 = resnet18/50 bw bf16 66 + fp32 30),全部 dense mspti 实测(每个 kernel 在完整 tile 格点上 bench,winner = dense 全局最优 = min ms_mspti)。out/generated_reduction{,_torchbench,_torchbench_bw_dense_bf16,_torchbench_bw_dense_fp32}.csv

当前痛点:npu-inductor 生产启发式(autotune_enhance)在 snap=2.0 口径下仅 73% 无损、7% 严重(snap=1.0 严格口径 63% / 11%),且真实编译数达 59;dense lattice 虽 100% 无损但需 79 候选、编译成本高。

必要性与用户价值:候选集是 autotune 编译耗时的近似线性决定因素(autotuner 逐候选编译 + mspti bench)。更少且更准的候选既降低 autotune 编译时间,又消除严重性能回退(0% severe)。不做此提案则维持 7% 严重回退 kernel 与约 3× 的冗余编译。

1.3 目标

目标

  • 给出公式驱动的候选生成算法 select_reduction_final(drop-in 替换 reduction() 候选生成步骤)。
  • 选中-best / dense 全局最优:95% ≤5% 无损、0% >30% 严重(snap=2.0 生产代理口径)。
  • 真实编译数降至 20(≈3× 少于生产启发式 59、≈4× 少于 dense 79)。

非目标(边界)

  • 不改变运行期性能:候选是 winner 模式的超集,autotuner 取 min,多余候选只增编译、不损运行性能。
  • 不改 compile→mspti-bench→argmin 管线;不改 reduction grid(固定 40 程序、与 tile 无关)。
  • 不覆盖其他 kernel 类型(仅 reduction)。

2. 用例分析

场景:Ascend NPU reduction kernel 的 autotune 候选生成。

功能点:按 reduction 轴长 rnumel 把搜索空间精确切三段(HOLE / SMALL/FILL / MID,条件剪枝),每段只发命中带内的锚点,不再撒大网。

关键性能指标

  • 选中-best / dense 全局最优的分层占比(≤5% 无损 / 5-10% / 10-30% / >30% 严重)。
  • 真实编译数 n_pred(候选/kernel)。

DFX(兼容性、可维护性、可测试性、可靠性)要求:兼容性(参数名与 npu_inductor autotune 源码一致,drop-in);可维护性(单调并集、优雅退化);可测试性(dense mspti 双 snap 口径可复现);可靠性(0% severe,HOLE/SMALL 阈值落宽死区中央、鲁棒)。

使用限制 / 约束:前置条件 xnumel/rnumel/num_load/num_reduction 均为 ≥1 整数;硬件 Ascend910B3(UB=192KB、40 AIV)。


3. 方案设计

3.1 总体方案

select_reduction_final.select_candidates纯候选生成器——输入 (xnumel, rnumel, dtype, num_load, num_reduction, min_ptr_elem_bytes),输出 (XBLOCK, R0_BLOCK) 元组列表。参数名与 npu_inductor autotune 源码一致——生产中每个值都从 kernel 的 size_hints / inductor_meta / triton_meta 签名读出,故与生产 reduction() 启发式产出的 Config 二元组同形,是候选生成步骤的 drop-in 替换。整体设计思路:按 rnumel 三分支(HOLE / SMALL / MID)精确切搜索空间,每段只发命中带内的锚点。

reduction 真正被 autotuner 扫的旋钮只有 (XBLOCK, R0_BLOCK)(源码坐实,npu_inductor/npu_triton_heuristics.py)——输出轴 / reduction 轴的 tile 尺寸。其余全 pin 或派生:

旋钮 类别
XBLOCK, R0_BLOCK free(扫) 输出轴 / reduction 轴 tile
num_warps 派生(非自由) next_pow2((X·R0)//128)
num_stages pinned 1(无软件流水)
launch grid pinned 40 核 group-dispatch(见 §3.3)
因子 含义 物理作用
xnumel 输出轴长度 XBLOCK 上限 pow2_floor(xnumel)
rnumel reduction 轴长度 决定物理 regime(三段分割的唯一预判量)
dtype 元素类型 _dt_bytes → 元素字节 d,决定 tile 乘积 P*(见下)
num_load, num_reduction 读 / reduction buffer 数 buffers = num_load+num_reduction+1,决定 UB 预算
min_ptr_elem_bytes 最严指针元素字节 覆盖 dtype 推导(混合 dtype kernel)

理论依据(153 kernel dense 数据坐实)

① rnumel 的三段"死区"分割 —— 剪枝的预判条件。 reduction 轴长 rnumel 把 153 个 winner 干净切成三段,两段空隙里 0 个 kernel

空隙 范围 kernel 数 含义
死区 ① 64 < rnumel < 128 0 SMALL 与 MID 天然分界
死区 ② 25088 < rnumel < 50176 0 MID(max 25088)与 HOLE(min 50176)天然分界

→ 阈值 rnumel=64rnumel=50000 落在宽真空带中央,不是过拟合。三段 winner 的 R0 行为完全不同:

条件 n winner R0 行为
HOLE rnumel≥50K 28 R0 被 UB 饱和与 rnumel 无关(corr(log2 rnumel, log2 wR)=−0.08≈0),恒落 {512,1024,2048,4096}
SMALL/FILL rnumel≤64 36 R0=rnumel(fill 整轴),甚至过 tile(rnumel=49→R0=56/64)
MID 64<rnumel<50K 89 R0≈rnumel/24..32(reduction-split 因子)

② tile 乘积 P=X·R0 是 2 的幂。 93% 的 winner P 是精确 pow2,88% 落在 {1024,2048,4096,8192},众数 4096(36%)。winner 贴 UB 墙(P·d·buffers·_NPU_UB_OVERHEAD_FACTOR / _NPU_UB_CAPACITY_BYTES 中位=1.0)。但 P 与 buffers 几乎无关(corr(log2 P, log2 buffers)=−0.04)、dtype 影响弱(bf16 仅 1.10× fp32)——故 P* 取 dtype 决定的常数P* = 2048 if d≤2 else 4096d = 元素字节)。

③ X 轴与 regime 无关。 pow2 阶梯封顶 pow2_floor(xnumel) 单独即覆盖 97%。wX>32 只在短 rnumel 出现(HOLE 强制 wX≤8,28/28)。→ X 侧不需 regime 分支,x_cap 自动适配。候选数瓶颈全在 R0 侧。

3.2 技术选型

考虑过但放弃的其他方案,优劣对比与不选择理由:

方案 候选/kernel(真实编译 n_pred) ≤5% 无损 / >30% 严重(snap=2.0) 不选择理由
dense lattice(全局最优源,参考) 79 100% / 0% 全 tile 格点穷举,编译成本最高(本文 ≈4× 少)
npu-inductor 生产启发式(autotune_enhance) 59 73% / 7% 非定向撒网 _full_r_range(8,16384),质量低且候选多
本文 select_reduction_final 20 95% / 0%

dense 质量上限最高但编译成本不可承受;生产启发式候选多且 7% 严重;本文以定向发射兼顾质量与编译成本。

3.3 功能与性能设计

算法公式(select_reduction_final.select_candidates

给定 (xnumel, rnumel, dtype, num_load, num_reduction, min_ptr_elem_bytes),按 rnumel 三分支输出 (XBLOCK, R0_BLOCK) 候选(变量名与源码完全一致):

d        = _dt_bytes(dtype, min_ptr_elem_bytes)              # 元素字节
x_cap    = pow2_floor(xnumel)                                # XBLOCK 上限
P        = 2048 if d <= 2 else 4096                          # tile 乘积目标(即 §3.1 的 P*)
buffers  = num_load + num_reduction + 1
ub_cap   = _NPU_UB_CAPACITY_BYTES / (d * buffers * _NPU_UB_OVERHEAD_FACTOR)   # UB 软上限(loose)
rmax     = pow2_floor(min(rnumel, max(ub_cap, 1)))            # max(.,1) 兜超大 buffers(非冗余)
r_cap    = pow2_ceil(rnumel)                                 # 允许 rnumel=49→64 过 tile

if rnumel >= 50000:             # B1 HOLE: UB 饱和、与 rnumel 无关
    emit {1,2,4,8} × {512,1024,2048,4096}                    # 固定 4×4 格

elif rnumel <= 64:              # B2 SMALL/FILL: R0=rnumel,搜索坍缩到 X
    R0 ∈ {rnumel, pow2_ceil(rnumel)};  X ∈ {1, pX/4, pX/2, pX, 2pX, 4pX}   (pX=pow2_round(P/rnumel))

else:                           # B3 MID (64<rnumel<50000): 预测锚点 + 定向格
    split = 2^(-2.06 + 0.59·log2(xnumel/rnumel))   # OLS: log2(X/R0)~log2(xnumel/rnumel), R²=0.62
    pX = pow2_round(sqrt(P·split));  pR = pow2_round(sqrt(P/split))
    emit {1, pX/2, pX, 2pX, x_cap} × {pR/2, pR, 2pR}        # 核心定向格
    + (pX × {pR/4, pR/8, 16, 32})                            # 小-R0 列(P 在小输出轴上过估 R0)
    + ({1,2,4,...,min(x_cap,128)} × rnumel)  if rnumel <= ub_cap   # FILL 列(兜住 wR==rnumel)
    + (x_cap, 2), (x_cap, min(rnumel,8))                     # hugex 病态锚点
约束:X ≤ x_cap;R0 ≤ r_cap(仅允许小过 tile)。去重。中位 ~14 snapped / 20 emitted。
注:前提 `xnumel/rnumel/num_load/num_reduction` 均为 ≥1 整数,故相关冗余守卫(`int(x or 0)`/`or 1`/`max(1,·)`/`x and`)已去;保留的**非冗余**守卫——`max(ub_cap,1)`(兜超大 buffers)、B3 的 `max(1,pX//2)` 与 `1≤x≤x_cap` 过滤(派生 pX/pR 可能为 1)。

逐项通俗解释

  • rnumel 三分支:唯一预判量。HOLE 固定格代替撒网(最大收益——生产启发式用 _full_r_range(8,16384) 蹭到 4K-8K 故 HOLE 只 4% severe,但非定向;本文固定格精确命中 → HOLE 100% 无损)。SMALL fill 把搜索坍缩到 X。MID 预测锚点 (pX,pR) 再发定向小格。
  • P*(tile 乘积目标):winner 的 X·R0 跨 kernel 落在 {1024,2048,4096,8192},dtype 决定中心。MID 把 P* 拆成 (pX,pR)。
  • split(OLS):给定 P*,X 与 R0 怎么分?由 xnumel/rnumel 长宽比决定(log2(X/R0)=−2.06+0.59·log2(xnumel/rnumel))。R²=0.62 偏松,故配小-R0 列 + hugex + FILL 列做安全网。
  • 单调并集:候选是 winner 模式的超集 → 多候选只增编译、不损运行性能(autotuner 取 min)。

源码(即 report/reduction final report/select_reduction_final.py 的核心,贴近可用)

"""Reduction autotune candidate GENERATOR (drop-in for npu-inductor reduction())."""
import math

_NPU_UB_CAPACITY_BYTES = 192 * 1024   # :1711  Ascend910B3 Unified Buffer
NPU_CU_COUNT           = 40           # :218   AIV vector cores
_NPU_UB_OVERHEAD_FACTOR = 2.0         # :1716  double-buffer + scratch

# B1 HOLE 固定格:此段 winner R0 与 rnumel 无关(UB 饱和)
HOLE_X = (1, 2, 4, 8)
HOLE_R = (512, 1024, 2048, 4096)
# rnumel 三段阈值——均落在宽死区中央(无 kernel 落在 64<rnumel<128 / 25088<rnumel<50176)
RN_HOLE   = 50000            # >= : UB 饱和段(语料 min 50176)
RN_SMALL  = 64               # <= : fill / 过 tile 段
POW2 = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
        32768, 65536, 131072, 262144, 524288, 1048576]

def _p2floor(n): return None if (n is None or n < 1) else 1 << int(math.floor(math.log2(n)))        # 最大 2 幂 ≤ n
def _p2ceil(n):  return None if (n is None or n < 1) else 1 << int(math.ceil(math.log2(max(1, n))))  # 最小 2 幂 ≥ n
def _p2round(n): return 1 if (n is None or n < 1) else 1 << int(round(math.log2(max(1, n))))         # 最近 2 幂
def _dt_bytes(dtype, min_ptr_elem_bytes):
    if min_ptr_elem_bytes: return min_ptr_elem_bytes
    return 2 if dtype in ("bf16", "fp16", "f16") else 4     # i1 走父计算 dtype


def select_candidates(xnumel, rnumel, dtype, num_load, num_reduction, min_ptr_elem_bytes=None):
    """生成 reduction kernel 的 autotune 候选 (XBLOCK, R0_BLOCK)。理论依据见 §3.1。
    前提:xnumel/rnumel/num_load/num_reduction 均为 ≥1 的整数(故相关冗余守卫已去)。"""
    d       = _dt_bytes(dtype, min_ptr_elem_bytes)
    x_cap   = _p2floor(xnumel)                                            # ① XBLOCK 上限 = 最大 2 幂 ≤ xnumel(唯一硬 X 约束)
    P       = 2048 if d <= 2 else 4096                                     # ② tile 乘积目标 P*(dtype 决定,与 buffers 无关)
    buffers = num_load + num_reduction + 1                                # :1749
    ub_cap  = _NPU_UB_CAPACITY_BYTES / (d * buffers * _NPU_UB_OVERHEAD_FACTOR)   # ③ UB 软上限(loose,真 UB 由编译失败剪枝)
    rmax    = _p2floor(min(rnumel, max(ub_cap, 1)))                       # UB-bounded R0 上限;max(.,1) 兜超大 buffers
    r_cap   = _p2ceil(rnumel)                                             # ④ R0 过-tile 上限(rnumel=49 → 64)
    cands = set()
    def add(X, R):
        if X > xnumel: return                                             # XBLOCK ≤ xnumel(B1 固定格在 xnumel<8 时裁剪)
        if R > r_cap: return                                              # 仅允许小过 tile
        cands.add((X, R))

    # ---- B1 HOLE:UB 饱和、与 rnumel 无关 → 固定 4×4 格 ----
    if rnumel >= RN_HOLE:
        for X in HOLE_X:
            for R in HOLE_R: add(X, R)
        return sorted(cands)

    # ---- B2 SMALL/FILL:R0=rnumel(含过 tile),搜索坍缩到 X ----
    if rnumel <= RN_SMALL:
        rset = {rnumel, _p2ceil(rnumel)}
        pX = _p2round(P / rnumel)
        for X in {1, pX // 4, pX // 2, pX, pX * 2, pX * 4}:
            if X <= x_cap:
                for R in rset: add(X, R)
        return sorted(cands)

    # ---- B3 MID (64<rnumel<50000):预测锚点 (pX,pR) + 定向格 + 安全列 ----
    ratio = xnumel / rnumel
    # ⑤ OLS split: log2(X/R0)~log2(xnumel/rnumel), R²=0.62 (degrades gracefully if off)
    logsplit = -2.06 + 0.59 * math.log2(ratio)
    split = 2.0 ** logsplit
    pX = min(_p2round(math.sqrt(P * split)), x_cap)
    pR = min(_p2round(math.sqrt(P / split)), rmax)
    xs = [x for x in sorted(set([1, max(1, pX // 2), pX, min(pX * 2, x_cap), x_cap])) if 1 <= x <= x_cap]   # 核心 X 阶梯(恒含 1 与 cap)
    rs = [r for r in sorted(set([max(1, pR // 2), pR, min(pR * 2, rmax)])) if 1 <= r <= rmax]            # 核心 R0 ±一档
    for X in xs:
        for R in rs: add(X, R)
    for R in (pR // 4, pR // 8, 16, 32):                    # 小-R0 列(P* 在小输出轴上过估 R0)
        if 1 <= R < pR and R <= rmax: add(pX, R)
    if rnumel <= ub_cap:                                    # FILL 列:兜住漏进 MID 的 wR==rnumel winner
        for X in [p for p in POW2 if p <= min(x_cap, 128)]: add(X, rnumel)
    add(x_cap, 2); add(x_cap, min(rnumel, 8))              # hugex 病态锚点
    return sorted(cands)

逐行解释

  • x_cap:X 唯一硬约束(wX ≤ pow2_floor(xnumel),153/153 命中)。X 阶梯封顶它即自动适配 regime——小 xnumel 给少而小的 X(含全部 HOLE / 小 wX),大 xnumel 给完整上阶梯。X 不是候选数瓶颈,故无 X 侧 regime 分支。
  • P*:winner 的 X·R0 跨 kernel 落在 {1024,2048,4096,8192},dtype 决定中心(fp32→4096、bf16→2048),与 buffer 数无关(见 §3.1 理论依据 ②)。B3 把 P* 拆成 (pX,pR)。
  • ub_cap/rmax:UB 软上限,给 R0 一个合理上界;真 UB 由 autotuner 编译失败剪枝(静态 UB 是 loose 上限,故不拿它硬拒候选)。
  • r_cap:仅允许"ceil 一档"过 tile(实测 rnumel=49 → winner R0=56/64),不放大成任意过 tile。
  • B1 HOLE 固定格:rnumel≥50K 时 winner R0 被 UB 钉死在 512–4096、与 rnumel 多大无关(corr≈0)。固定 4×4 格命中 28/28、且只 16 候选——比生产启发式 _full_r_range(8,16384)(≈59 候选)更少更准。
  • B2 SMALL fill:轴短到一次 trip 跑完,R0=rnumel/ceil;搜索坍缩到 X 轴。
  • split(OLS):给定 P*,X:R0 的分劈由 xnumel/rnumel 长宽比决定。R²=0.62 偏松,故配小-R0 列 + FILL 列 + hugex 做安全网(系数扰动 ±50% 仍 86-90% 无损,优雅退化)。
  • FILL 列:MID 里混入若干 wR==rnumel 的 winner(与 PARTIAL 在输入上不可静态区分),靠 R0=rnumel 精确兜住。
  • 单调并集:候选是 winner 模式的超集 → 多候选只增编译、不损运行(autotuner 取 min)。

接入点(drop-in):本函数经 inject.install_injectioninject.py:46)patch 唯一 chokepoint NPUCachingAutotuner._precompile_workernpu_triton_heuristics.py:758self.configs:771 被读)替换 self.configs,随后走 compile→mspti-bench→argmin 管线(winner 仍由 min(timings) 决定)。reduction grid 固定 40 程序、与 tile 无关,候选只改 per-core trip count(输出 tile 数 = xnumel/XBLOCK、reduction trip 数 = rnumel/R0_BLOCK)——多余候选只增编译耗时,绝不拖累运行性能。

性能指标 / 收益(对比 heuristic 与 dense)

每个 kernel:候选集生成 → autotuner 编译并 benchmark 每个候选、取最快 → 与 dense 全局最优对比。下表为 选中-best / dense 全局最优 的分层占比(n=153,snap=2.0 生产代理口径):

候选集 ≤5% 无损 5-10% 10-30% >30% 严重 中位 候选/kernel(真实编译 n_pred)
dense lattice(全局最优源,参考) 100% 0% 79
npu-inductor 生产启发式(autotune_enhance) 73% 7% 12% 7% 0% 59
本文 select_reduction_final 95% 3% 3% 0% 0% 20
  • 本文算法 95% 无损 / 0% 严重,全面优于生产启发式(73% / 7%)。
  • 真实编译数 20,比生产启发式 59 少 66%、比 dense 79 少 75%——候选更少、质量更高。
  • 严格口径(snap=1.0,winner 必须被精确发射):本文 92% / 1%,生产启发式 63% / 11%。

候选数 / 编译成本

候选集 候选/kernel(真实编译 n_pred) 相对 dense 相对生产启发式
dense lattice 79
npu-inductor 生产启发式 59 0.75× 少
本文 select_reduction_final 20 ≈4× 少 ≈3× 少(−66%)

候选数 20 → 编译时间相应下降(autotuner 逐候选编译 + mspti bench,候选数近似线性决定 autotune 耗时)。

质量对比(双 snap 口径,n=153)

snap=2.0 生产代理口径(候选集含一个落在 winner 2× 邻域内的 tile):

候选集 ≤5% 无损 5-10% 10-30% >30% 严重 ≤10% 累计
dense(参考) 100% 100%
生产启发式 73% 7% 12% 7% 80%
本文 95% 3% 3% 0% 98%

snap=1.0 严格 exact-tile 口径(winner 必须被精确发射):

候选集 ≤5% 无损 5-10% 10-30% >30% 严重
生产启发式 63% 7% 19% 11%
本文 92% 3% 5% 1%
  • 双口径下本文均显著优于生产启发式:snap=2.0 无损 +22pp、严重 −7pp;snap=1.0 无损 +29pp、严重 −10pp。
  • 距 dense 上限:snap=2.0 仅差 5pp(95% vs 100%),且 0% 严重。

3.4 安全隐私与DFX设计

安全隐私:本提案为编译器 autotune 候选生成优化,不涉及用户数据、网络与权限,无安全隐私影响(不适用)

DFX(兼容性、可维护性、可测试性、可靠性)

  • 兼容性:参数名与 npu_inductor autotune 源码一致;产出的 Config 二元组与生产 reduction() 同形,drop-in 替换候选生成步骤,不动 compile→mspti-bench→argmin 管线。
  • 可维护性:候选是 winner 模式的单调超集(多候选只增编译、不损运行);MID 的 OLS 系数扰动 ±50% 仍 86-90% 无损(优雅退化)。
  • 可测试性:dense mspti 全格点 bench + 双 snap 口径可复现;提供 eval harness(见 §4)。
  • 可靠性:0% severe(snap=2.0);HOLE/SMALL 阈值落在宽死区中央,鲁棒。

3.5 编程与调用设计

本算法以纯 Python 函数提供,供 npu_inductor autotune 集成调用(二次开发)。

3.5.1 编程模型基本设计

开发环境:Ascend910B3(UB=192KB、40 AIV);Python;相关常量 _NPU_UB_CAPACITY_BYTES(=192×1024)、_NPU_UB_OVERHEAD_FACTOR(=2.0)、NPU_CU_COUNT(=40)。

开发约束:前置条件 xnumel/rnumel/num_load/num_reduction 均为 ≥1 整数;min_ptr_elem_bytes 缺省时由 dtype_dt_bytes 推导 d

可验收设计:n=153 kernel dense mspti 基线;验收指标为 ≤5% 无损占比 / >30% 严重占比 / 真实编译数 n_pred(见 §4、§3.3)。

3.5.2 接口定义与设计

参数 / 常量的源码出处(均在 npu_inductor/npu_triton_heuristics.py,已逐条核对):

算法变量 源码同名变量 源码出处 含义
xnumel xnumel size_hints["x"]reduction():2372 输出轴长度
rnumel rnumel size_hints["r0_"]reduction():2373 reduction 轴长度(剪枝预判量)
dtype dtype triton_meta 指针签名派生(reduction() 不读 inductor_meta["dtype"]);fallback:min_ptr_elem_bytes 缺省时 _dt_bytes 据此推 d 元素类型
num_load num_load inductor_meta["num_load"]:1765 读 buffer 数
num_reduction num_reduction inductor_meta["num_reduction"]:1766 reduction buffer 数
min_ptr_elem_bytes min_ptr_elem_bytes _min_ptr_elem_bytes(triton_meta["signature"]):2459 定义,:2474 调用) 最严指针元素字节 → d
buffers(局部) buffers max(1, num_load+num_reduction+1):1749,pointwise UB helper 同式) UB 占用 buffer 数
x_cap(局部) x_cap reduction():2521 XBLOCK 上限
r_cap(局部) r_cap reduction():2588 R0 上限 = next_pow2(rnumel)
_NPU_UB_CAPACITY_BYTES _NPU_UB_CAPACITY_BYTES :1711(= 192×1024) UB 容量
_NPU_UB_OVERHEAD_FACTOR _NPU_UB_OVERHEAD_FACTOR :1716(= 2.0) UB double-buffer 系数
NPU_CU_COUNT NPU_CU_COUNT :218(= get_npu_vector_core_count() = 40) AIV 向量核数

P / pX / pR / split / rmax / ub_cap 是本文拟合专用变量,源码无对应(见 §3.1 理论依据)。

3.5.2.1 select_candidates
  • 接口描述:生成 reduction kernel 的 autotune 候选 (XBLOCK, R0_BLOCK),作为 npu-inductor reduction() 候选生成步骤的 drop-in 替换。
  • 接口原型select_candidates(xnumel, rnumel, dtype, num_load, num_reduction, min_ptr_elem_bytes=None) -> list[tuple[int, int]]
  • 输入/输出参数:
参数名称 输入/输出 类型 描述 取值范围
xnumel 输入 int 输出轴长度 ≥1 整数
rnumel 输入 int reduction 轴长度(剪枝预判量) ≥1 整数
dtype 输入 str 元素类型 "bf16"/"fp16"/"f16"/"fp32"/…
num_load 输入 int 读 buffer 数 ≥1 整数
num_reduction 输入 int reduction buffer 数 ≥1 整数
min_ptr_elem_bytes 输入 int / None 最严指针元素字节;缺省由 dtype 经 _dt_bytes 推导 None 或 ≥1
  • 返回参数:
参数名称 类型 描述 取值范围
(返回值) list[tuple[int, int]] (XBLOCK, R0_BLOCK) 候选元组列表(已去重、排序) X ≤ pow2_floor(xnumel);R0 ≤ pow2_ceil(rnumel)
  • 异常处理:本提案未定义专用异常(不适用)。
  • 约束说明:前置条件 xnumel/rnumel/num_load/num_reduction 均为 ≥1 整数;候选为 winner 模式超集,多余候选只增编译、不损运行。
  • 变更说明:无(新提案)。
  • 调用参考代码:
select_candidates(xnumel=64,    rnumel=401408, dtype="fp32", num_load=6, num_reduction=2)   # B1 HOLE  -> 16 档 {1,2,4,8}×{512,1024,2048,4096}
select_candidates(xnumel=65536, rnumel=49,    dtype="fp32", num_load=2, num_reduction=1)    # B2 SMALL -> 12 档(R0∈{49,64},含过 tile)
select_candidates(xnumel=2048,  rnumel=768,   dtype="fp32", num_load=6, num_reduction=2)    # B3 MID   -> 27 档(预测锚 + 定向格 + FILL 列)
3.5.3 编程手册设计

本提案未规划独立《编程手册》(不适用)。集成参考以 select_reduction_final.py 源码注释为准。


4. 测试设计

方法:每个 kernel 在完整 tile 格点上 dense mspti bench,winner = dense 全局最优 = min ms_mspti;候选集选中最快 ÷ dense 全局最优,按损失分层(≤5% / 5-10% / 10-30% / >30%)。双 snap 口径:snap=2.0(候选集含一个落在 winner 2× 邻域内的 tile)/ snap=1.0(winner 必须被精确发射)。

语料:153 个 reduction kernel(generated 49 + torchbench 8 + backward 96)。

图 1:选中-best / dense 全局最优(n=153)

final_perf_vs_rnumel.pngfinal_perf_vs_rnumel.png

每个点是一个 kernel:纵轴 = 候选集选中最快 ÷ dense 全局最优(>1=变慢),按损失分层着色、按 regime 分标记。本文算法 95% 落在 ≤5% 无损带、0% 超 1.3×(snap=2.0);两条蓝虚线 = 死区分界 rnumel=64 / rnumel=50000——三 regime 沿 rnumel 轴的视觉证据。

图 2:winner 分布 vs 公式覆盖

final_winners_XR0.pngfinal_winners_XR0.png

winner 在 (XBLOCK, R0_BLOCK) log-log 空间:HOLE(红■)聚集在左上红框(X∈{1,2,4,8} × R0∈{512..4096},正是 B1 固定格);灰对角线 = tile 乘积 P=X·R0(众数 4096)。三 regime 在该空间清晰可分,公式覆盖精准。

分 regime 对比(snap=2.0,参考=dense 100%)

regime n 生产启发式 ≤5% / >30% 本文 ≤5% / >30%
FILL 36 89% / 0% 100% / 0%
HOLE 28 79% / 4% 100% / 0%
PARTIAL 89 65% / 11% 91% / 0%

本文在所有 regime 都不退化、且把生产启发式的 severe 全部清零;HOLE 灾区从 79%/4% 提到 100%/0%。

工具red_eval.py(snap-eval harness)+ eval_heuristic.py生产启发式 vs dense,monkeypatch 真 cached_autotune 取候选)+ select_reduction_final.py 自评 main(双 snap)+ make_final_figures.py(出图)。数据:kernels.json(153 kernel 紧凑表,由 red_data.py 从 4 dense CSV 导出)。


5. 缺点和风险


6. 现有技术

npu-inductor 生产启发式(autotune_enhance):非定向 _full_r_range(8,16384) 撒网,HOLE 段蹭到 4K-8K 故仅 4% severe 但非定向;候选 59、73% 无损(snap=2.0)。本文以定向固定格(HOLE 4×4)精确命中,候选 20、95% 无损。

dense lattice:全 tile 格点穷举,100% 无损但 79 候选、编译成本最高。本文为逼近其质量上限的低成本方案(snap=2.0 距 dense 仅差 5pp)。

注:本报告仅在内部基线(生产启发式 / dense)间对比,未引用外部项目/社区设计。


7. 未解决问题

待社区讨论/决策的开放问题(详见 §5 风险/未来工作):


附录

参考资料链接 / 产物

  • 生成算法:select_reduction_final.pyselect_candidates,可直接接入 npu-inductor reduction 启发式)。
  • 评估:red_eval.py(snap-eval harness)+ eval_heuristic.py生产启发式 vs dense,monkeypatch 真 cached_autotune 取候选)+ select_reduction_final.py 自评 main(双 snap)。
  • 图:make_final_figures.pyfinal_perf_vs_rnumel.pngfinal_winners_XR0.png
  • 数据:kernels.json(153 kernel 紧凑表,由 red_data.py 从 4 dense CSV 导出)。
  • 规律过程件:规律探索记录.md

术语表:UB(Unified Buffer,192KB)· AIV(向量核,40)· mspti(实测计时)· regime(HOLE / SMALL / MID 三段)· tile(XBLOCK / R0_BLOCK 分块)· snap(候选覆盖 winner 的口径,2.0 / 1.0)· winner(dense 全局最优 = min ms_mspti)· n_pred(真实编译数 / 候选数 per kernel)。

文档更新计划:随 MID 重拟合 / selector 形状接入进展更新。


欢迎加入社区,感谢您对社区的贡献 🎉!

likedislike
ascend-robotascend-robot成员
7月29日 添加了label:rfc
AAllenGuan成员
7月29日 修改了issue 的描述
AAllenGuan成员
7月29日 修改了issue 的描述
姚小白姚小白成员
7月30日 关联了看板:@yao-xiaobai的看板 20260730
TorchNPU-BotTorchNPU-Bot成员
8月10日 添加了label:bot-triaged
TorchNPU-Bot
TorchNPU-Bot成员
8月10日 评论:

检测到当前 issue 已关联 PR,自动添加标签:bot-triaged

likedislike
ascend-robotascend-robot成员
8月13日 关闭了 issue
ascend-robotascend-robot成员
8月13日 添加了label:resolved