Files
matmul-analysis/BMM/BMM_Theory/bmm_theory/hardware/ascend950pr.py
admin ec4fee99b8 Fix #40: 切换 Cube 算力为白皮书 Cube-only 口径 (单核统一 13.5T)
用户裁决: cube_peak_tflops 取白皮书表3-1 "Cube算力" 单行 (不含 Vector)。

- 数值: 950PR 486->432, 950PR_C28 425->378, 950DT 547->486,
  950DT_C32 486->432, 950DT_C28 425->378; 单核全系列精确 13.5T
  (16^3 MAC/拍 x 1.65GHz), 28 核档 0.06% 取整偏差随之消失
- 传导 (无结构改动, 全部经 q16/q_cube/r16 派生):
  MMAD 时延 x486/432 (+12.5%); R16 607.5->540 (MergeBatch 条件5/b0 上限);
  StreamK θ_c 12.24->10.9; ASW 面积/周长分界 93.5->83.1, MMAD/FIX 304->270
- 文档同步: README, docs/00 (R16 公式), 04 (607.5 实例), 05 (硬件事实/复核算例),
  06/07 (翻出阈值 187->166), 05_StreamK (θ_c 及 K 阈值 396->360);
  理论归档 (BMM算子优化分析_Release/) 与历史测评报告不动
- 验证: 单测 88/88; examples 重生成 —— recommend 27/44 行变化
  (计算Bound 行精确 +12.5%; b8_m32768_n2048_k512 瓶颈 MTE2->MMAD 翻转;
  17 行访存主导不变), plans.csv 仅 merge_demo_k_trunc note 的算存比上限
  23.7->21.1 一处文案; 压力回归 10000 例干净, MergeBatch 386->392 /
  IterBatch 2389->2384 (R16 下移致 b0 上限收小, 边界 case 换边, 预期行为)
2026-09-09 11:05:21 +08:00

188 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Ascend950PR (DAV_3510) 硬件规格参数.
数值来源: 《BMM算子优化分析 v0.98》§二 + 昇腾950 NPU架构白皮书 (表3-1 SKU 规格 /
表4-2 Memory 层次). 换芯片时逻辑结构不变, 只需新增一份同结构参数表
(系列其他 SKU 见文末 ASCEND950PR_C28 与 hardware/ascend950dt.py, issue#38).
单位约定: 算力 FLOP/s, 带宽 Byte/s, 容量 Byte, 时延 秒.
dtype 感知算力 (issue#28, 设计文档 docs/05 §2):
Cube 算力按输入 dtype 分档, 基准 = BF16 (fp16 同速); 白皮书: FP8/MXFP8/HiF8
提供 2x FP16 张量 TFLOPS, MXFP4 提供 4x FP16; FP32/TF32 同代比值为假设值
(按 DaVinci 惯例 = 1/2, 白皮书未给同代比值), int8 假设同 FP8, 均待实测标定.
AIV 逐元素通量按 lane 位宽等比假设 (16bit x2 / 8bit x4 / 4bit x8, 待标定).
口径 (issue#40 用户裁决): cube_peak_tflops 采用白皮书表3-1 **"Cube算力"单行**
(Cube-only, 不含 Vector): 950PR 32核 = 432, 单核 13.5T = 16³ MAC/拍 × 1.65GHz;
全系列 SKU 单核精确统一 13.5T (432/32 = 378/28 = 486/36)。2026-09 前曾沿用
v0.98 的 "Cube+Vector 总算力" 口径 (486, 单核 15.1875T), 切换后全模型 MMAD
时延 ×486/432 (+12.5%), R16 607.5→540, StreamK θ_c 12.24→10.9,
ASW 面积/周长分界 93.5→83.1。
"""
from __future__ import annotations
from dataclasses import dataclass
# Cube 精度因子 (相对 BF16/FP16 基准档; A/B 不一致时取较慢一侧 = min 因子)
CUBE_DTYPE_FACTOR = {
"fp32": 0.5, "f32": 0.5, "tf32": 0.5, # 假设 = 1/2, 待实测标定
"fp16": 1.0, "f16": 1.0, "bf16": 1.0,
"fp8": 2.0, "fp8_e4m3": 2.0, "fp8_e5m2": 2.0, "int8": 2.0, # 白皮书 FP8=2xFP16; int8 假设同 FP8
"fp4": 4.0, "fp4_e2m1": 4.0, # 白皮书 MXFP4=4xFP16; 普通 fp4 假设同 MXFP4
}
# AIV 逐元素通量因子 (相对 fp32 128 lane/拍/核; 位宽等比假设, 待实测标定)
AIV_DTYPE_FACTOR = {
"fp32": 1.0, "f32": 1.0, "tf32": 1.0,
"fp16": 2.0, "f16": 2.0, "bf16": 2.0,
"fp8": 4.0, "fp8_e4m3": 4.0, "fp8_e5m2": 4.0, "int8": 4.0,
"fp4": 8.0, "fp4_e2m1": 8.0,
}
_RATE_FALLBACK = 1.0 # 未知 dtype 按基准档 (models.dtype_bytes 已先行校验, 正常不会到达)
@dataclass(frozen=True)
class NpuSpec:
name: str = "Ascend950PR"
# ---- 核数与算力 ----
aic_num: int = 32 # C: AIC (Cube) 核数
aiv_num: int = 64 # AIV (Vector) 核数
cube_peak_tflops: float = 432.0 # 全芯片 Cube BF16 标称算力 (乘加各计一次,
# 白皮书表3-1 Cube 单行, issue#40)
aiv_freq_ghz: float = 1.65
aiv_fp32_per_cycle: int = 128 # 单 AIV 每拍 fp32 求和吞吐
# ---- 片上存储 (每核) ----
l1_bytes: int = 512 * 1024 # L1 Buffer 512KB
l0a_bytes: int = 64 * 1024 # L0A 64KB
l0b_bytes: int = 64 * 1024 # L0B 64KB
l0c_bytes: int = 256 * 1024 # L0C 256KB (fp32 累加, 4B/元素)
# ---- L2 / GM ----
l2_bytes: int = 128 * 1024 * 1024 # L2 Cache 128MB
bw_l2: float = 5.2e12 # L2 读写带宽 5.2TB/s (白皮书未给, 用户澄清口径)
bw_gm: float = 1.6e12 # GM(HBM) 带宽 1.6TB/s (读写共享)
gm_capacity_gb: float = 128.0 # GM(HBM) 容量 GB (信息项, 模型暂不消费)
# ---- 搬移效率经验约束 (950PR 实测总结) ----
dvalue_recommend: int = 512 # dValue 推荐值 (Byte), 更大无额外收益
dvalue_min: int = 128 # dValue 下限 (Byte)
dvalue_hw_min: int = 256 # DMA 硬件突发下限 (Byte) —— 尾轮文档 §2.3
min_tile_size: int = 16 * 1024 # min_TileSize: 单块搬移最小量 16KB
min_datamount_per_core: int = 480 * 1024 # min_DatamountPerCore: 单核搬移总量下限 480KB
min_core_num_ratio: float = 0.8 # minCoreNum ≈ 0.8 * C (经验: 约 3/4 核并发才达 90%+ 带宽利用率)
# ---- DMA 固定开销 ----
t_cmd_ns: float = 0.0 # T_cmd: 单次 GM->L1 DMA 命令固定开销 (ns)。
# 未标定, 按 0 处理 (issue#36 用户澄清):
# MergeBatch 的合并收益由搬移效率模型
# (move_eff: 单块 tile=nValue*dValue*dt
# 放大 b0 倍) 刻画, 不依赖 T_cmd 估计值.
# ---- 带宽模型假设 (issue#26) ----
# GM 1.6TB/s 为读写共享总线 (读+写累加计时); L2 带宽读写各自独享 5.2TB/s;
# active_cores < C 时按"每核份额线性配平"为模型假设 (如 1 核也给 50GB/s),
# 真实低核数带宽利用率低于线性, 需 msProf 实测曲线标定后替换该假设.
# ---- Cube 计算粒度 ----
fractal: int = 16 # 16x16x16 基本块
# ---- 派生量 (属性) ----
@property
def q16(self) -> float:
"""单核 Cube BF16/FP16 峰值算力 (FLOP/s) = 13.5T (issue#40 Cube-only)."""
return self.cube_peak_tflops * 1e12 / self.aic_num
@staticmethod
def _dtype_key(dtype) -> str:
return str(dtype).strip().lower()
def cube_factor(self, dtype_a, dtype_b=None) -> float:
"""按输入 dtype 取 Cube 精度因子 (issue#28).
A/B 不一致时取**较慢一侧** (因子较小者, 等价字节较大者);
Cube 乘法两侧的实际吞吐受较慢精度限制.
"""
keys = [self._dtype_key(dtype_a)]
if dtype_b is not None:
keys.append(self._dtype_key(dtype_b))
factors = [CUBE_DTYPE_FACTOR.get(k, _RATE_FALLBACK) for k in keys]
return min(factors)
def q_cube(self, dtype_a, dtype_b=None) -> float:
"""单核 Cube 峰值算力 (FLOP/s), 按输入 dtype 分档 (issue#28)."""
return self.q16 * self.cube_factor(dtype_a, dtype_b)
def aiv_elem_factor(self, dtype) -> float:
"""按 dtype 取 AIV 逐元素通量因子 (相对 fp32 基准)."""
return AIV_DTYPE_FACTOR.get(self._dtype_key(dtype), _RATE_FALLBACK)
@property
def aiv_elem_rate_fp32(self) -> float:
"""AIV fp32 逐元素吞吐 (元素/s), 64 核合计."""
return self.aiv_num * self.aiv_fp32_per_cycle * self.aiv_freq_ghz * 1e9
def aiv_elem_rate(self, dtype) -> float:
"""AIV 逐元素吞吐 (元素/s, 64 核合计), 按 dtype 分档 (issue#28)."""
return self.aiv_elem_rate_fp32 * self.aiv_elem_factor(dtype)
@property
def q_aiv(self) -> float:
"""AIV fp32 逐元素吞吐 (元素/s, 64 核合计) = aiv_elem_rate_fp32.
注意: 该值只适用于 fp32 数据 (如 StreamK 对 fp32 部分和求和);
逐元素运算按输入 dtype 用 aiv_elem_rate(dtype) (issue#28).
"""
return self.aiv_elem_rate_fp32
@property
def bw_pc(self) -> float:
"""单核 GM 带宽份额 (Byte/s) = W_GM / C = 50GB/s."""
return self.bw_gm / self.aic_num
@property
def bw_l2_pc(self) -> float:
"""单核 L2 带宽份额 (Byte/s) = W_L2 / C ≈ 162.5GB/s."""
return self.bw_l2 / self.aic_num
@property
def r16(self) -> float:
"""16bit 位宽平衡点算存比 R_16 = Cube峰值 / (GM带宽/2B) = 540 FLOP/元素.
按 issue#28 速率表该比值对全 dtype 不变 (Cube 因子与元素字节数互成反比),
故入口条件沿用单一 R_16. (issue#40 Cube-only 口径: 607.5 -> 540)
"""
return self.cube_peak_tflops * 1e12 / (self.bw_gm / 2)
@property
def min_core_num(self) -> int:
"""确保高带宽利用率的并行搬移核数下限."""
return round(self.min_core_num_ratio * self.aic_num)
@property
def t_cmd(self) -> float:
"""T_cmd (秒)."""
return self.t_cmd_ns * 1e-9
@property
def l0c_elems(self) -> int:
"""L0C 容量 (fp32 元素数) = 65536."""
return self.l0c_bytes // 4
ASCEND950PR = NpuSpec()
# 950PR 28 核衍生版 (白皮书表3-1: 28 AIC / 56 AIV, HBM 1.4TB/s 112GB,
# L2 112MB; L2 带宽未分档, 沿用 5.2TB/s 待标定)
ASCEND950PR_C28 = NpuSpec(
name="Ascend950PR_C28",
aic_num=28, aiv_num=56,
cube_peak_tflops=378.0,
l2_bytes=112 * 1024 * 1024,
bw_gm=1.4e12,
gm_capacity_gb=112.0,
)