已关闭
feat(pypto_pro):Provide R3 design document #588
xuxinlei321创建于 24 天前关闭于 7 天前
feat(pypto_pro):Provide R3 design document #588
已关闭
xuxinlei321创建于 24 天前关闭于 7 天前
2 个文件变更+203-25
@@ -121,34 +121,17 @@ EXPLORE_REPORT.md §3只用于提供候选映射。逐项核对API参考页后
121 121 
122**核心问题**:每块 tile 放在哪个内存空间的哪个地址?如何分配管理?122**核心问题**:每块 tile 放在哪个内存空间的哪个地址?如何分配管理?
123 123 
124-**内存空间**:tile 按 R2 确定的 `target_memory` 落到不同片上空间,**每个空间独立寻址、独立限**——地址各自从 `0x00000` 起算,同一 addr 值在不同空间是不同物理位置124+> 📌 **权威依据(必读)**:读取[片上空间布局](references/onchip_memory_layout.md)。按其流程展开全部物理槽位空间检查地区间对齐、量和地址复用证明;当前平台容量仍以`EXPLORE_REPORT.md` §7为准
125 125 
126-- `Vec`(UB)vector 计算用;纯 vector 算子只涉及此空间(`TileType.md` 参数范围表:`Vec` 对应 UB)126+**执行要点**
127-- `Mat`(L1)、`Left`(L0A)、`Right`(L0B)、`Acc`(L0C):含 cube/matmul 的算子涉及。`matmul` 的操作数内存空间是**硬性约束**——`lhs` 只能 `Left`(L0A)、`rhs` 只能 `Right`(L0B)、`dst` 只能 `Acc`(L0C),放错空间即报错
128-- 典型数据流:`GM --load--> L1(Mat) --move--> L0A/L0B --matmul--> L0C(Acc)`,结果既可从 Acc 直接 `store` 回 GM,也可先 `move` 到 UB 再后处理/store
129 127 
130-**流程**:128+1. 按`target_memory`分组,依据当前前端规则计算每个物理槽位的字节数和左闭右开地址区间。
129+2. 展开TileGroup的所有槽位,逐槽位检查首地址对齐;单基地址和离散地址列表的语义以`make_tile_group.md`和当前实现为准。
130+3. 同一空间内的并存区间不得重叠;逻辑Tile复用物理区间时,记录生命周期和同步证明。
131+4. 容量按MemorySpace独立校验,使用当次`EXPLORE_REPORT.md` §7的探测值和该空间的最高地址上界;地址空洞也计入上界。
132+5. MX路径额外检查`ScaleLeft`/`ScaleRight`与配对`Left`/`Right`的地址映射;计划并行访问的Mat Tile额外做L1 Bank冲突检查。
131 133 
132-1. 按 `target_memory` 把 R2 的 tile 分组,**每个内存空间各自从 `0x00000` 开始**连续排列地址,不重叠UB/L1 首地址须 32 字节对齐;L0A/L0B/L0C 的对齐以对应 API 文档 / 官方指定算子为准134+**输出**:DESIGN.md §3。[片上空间布局](references/onchip_memory_layout.md)给出逐物理槽位的地址表、逐空间容量计算以及所有地址复用的证明表若超限,带着空间名、最高地址上界、容量和字节差额回退R2,必要时再回退R1
133-2. 标注同地址不同 layout 的 tile 对(如有)
134-3. 分配方式应使用 `make_tile_group` + `auto_mutex`,由框架自动管理 buffer 切换与同步(见上方「实现约束」)。
135-4. **逐空间**验证该空间上的 tile 总大小不超过其容量上限。容量值以 EXPLORE_REPORT §7 探测记录为准——§7 必含 UB 容量;含 cube 时须补探 L1/L0 各空间容量(§7 未记录则回退 material-explore 补测,不得在此臆测数值)
136-5. **double buffer 地址规划**`make_tile_group` 的 buffer 数 > 1 时地址占用按倍数放大,须在地址表中显式反映(buffer 数、受影响 tile、是否需 PONG 地址)。buffer 数取值参照官方指定算子中相似算子的实际配置
137- 
138-**输出**:片上地址映射表(**按内存空间分节**,纯 vector 算子只有 UB 一节):
139- 
140-| 内存空间 | 用途 | 变量名 | shape | dtype | layout | 地址 | 大小 | 备注 |
141-|---------|------|--------|-------|-------|--------|------|------|------|
142-| UB(Vec) | 输入暂存 | `tile_a` | `[64,128]` | FP32 | `—` | `0x00000` | 32768 | ... |
143-| L1(Mat) | A 矩阵暂存 | `a_l1` | `[128,128]` | FP16 | `—` | `0x00000` | 32768 | ... |
144-| L0C(Acc) | 累加结果 | `acc` | `[128,128]` | FP32 | `—` | `0x00000` | 65536 | Acc FP32 自动 fractal |
145-| ... | ... | ... | ... | ... | ... | ... | ... | ... |
146- 
147-> `—` 表示 layout 列留空即用该内存空间的默认布局(Vec 无约束;其余空间见 `TileType.md` 默认布局表);非默认布局显式写出,具体值以 API 文档为准。
148- 
149-**各空间总用量**(逐空间列出,无对应 tile 的空间可省略):
150-- UB(Vec): {∑ 大小} / {§7 UB 容量} = {百分比}
151-- L1(Mat) / L0A / L0B / L0C(如有 cube): {∑ 大小} / {§7 对应容量} = {百分比}——各空间容量来自 §7 探测记录
152 135 
153---136---
154 137 
@@ -0,0 +1,195 @@
1+# 片上空间布局
2+ 
3+R3将R2确定的每个Tile落到具体的片上地址,并证明地址对齐、空间容量和地址复用均正确。R3不重新选择Tile shape、dtype、layout或缓冲深度;若无法布局,应带着明确的超限空间和字节差额回退R2,必要时再回退R1更换API链。
4+ 
5+本文与[API映射与Tile规划](api_mapping_and_tile_planning.md)配套使用。接口的当前行为以`$PYPTO_DEVKIT_DIR/docs/pypto_pro/api/SIMD-API/`中的`make_tile.md``make_tile_group.md``TileType.md``MemorySpace.md`为准;平台容量以`EXPLORE_REPORT.md` §7的当次探测结果为准。
6+ 
7+## R3的输入与输出
8+ 
9+R3开始前,R2必须已给出:
10+ 
11+- 全部Tile及其`shape``dtype``target_memory``layout``fractal``pad``compact`
12+- 每个Tile使用`make_tile`还是`make_tile_group`
13+- TileGroup的`depth`、逐槽位`mutex_ids`和访问方式;
14+- 各Tile的生命周期,包括首次写入、最后一次读取和是否跨循环保留;
15+- API要求的额外物理空间,例如分形向上对齐或RowPlusOne的额外行。
16+ 
17+R3的交付物是DESIGN.md §3中的片上地址表、逐空间容量计算和地址复用依据。表中必须展开TileGroup的所有物理槽位,不能只记基地址。
18+ 
19+## 1. 按MemorySpace分组
20+ 
21+`target_memory`决定Tile的物理空间和可用API。不同空间独立寻址:例如Vec的`0x00000`与Mat的`0x00000`不是同一块物理存储。地址重叠和容量必须在每个MemorySpace内分别检查,不能跨空间求和或比较地址。
22+ 
23+| MemorySpace | 物理位置 | 主要用途 |
24+|---|---|---|
25+| `Vec` | UB | Vector Tile的输入、输出和中间量 |
26+| `Mat` | L1 | GM与L0A/L0B之间的矩阵暂存 |
27+| `Left` | L0A | Cube左操作数 |
28+| `Right` | L0B | Cube右操作数 |
29+| `Acc` | L0C | Cube累加结果 |
30+| `Scaling` | FBuffer | 部分量化、反量化路径的参数 |
31+| `ScaleLeft` | L0A的MX scale独立地址域 | `matmul_mx`的A矩阵E8M0 scale |
32+| `ScaleRight` | L0B的MX scale独立地址域 | `matmul_mx`的B矩阵E8M0 scale |
33+ 
34+`Bias`当前没有CCE Tile codegen映射,不能规划为`make_tile``make_tile_group`的片上Tile。`Scaling``ScaleLeft`/`ScaleRight`是不同空间,不能混用。
35+ 
36+Cube矩阵乘的常见数据路径为:
37+ 
38+```text
39+GM --load--> Mat(L1) --move--> Left(L0A) / Right(L0B)
40+Left × Right --matmul/matmul_acc--> Acc(L0C)
41+Acc --store--> GM,或 Acc --move--> Vec(UB) --Vector后处理
42+```
43+ 
44+这个路径只用于检查是否漏掉Tile,不代替`load``move``matmul``store`的单接口约束。
45+ 
46+## 2. 计算每个物理槽位的地址区间
47+ 
48+地址表统一使用左闭右开区间`[addr, addr + size)`。因此,前一区间的结束地址等于后一区间的起始地址时不构成重叠。
49+ 
50+### `make_tile_group`
51+ 
52+`addrs`是单个基地址时,当前前端将第`i`个槽位展开为:
53+ 
54+```text
55+slot_size = prod(static_shape) × max(1, ceil(dtype_bits / 8))
56+slot[i].addr = base + i × slot_size
57+slot[i].range = [slot[i].addr, slot[i].addr + slot_size)
58+```
59+ 
60+shape的每一维必须是正的编译期整数。对INT4等亚字节dtype,当前实现按每元素至少1字节预留,不能直接用`dtype_bits / 8`得到半字节步长。
61+ 
62+`addrs`是地址列表时,列表长度必须等于`depth`,每个元素分别指定一个槽位的起始地址。离散地址不会改变`slot_size`
63+ 
64+`make_tile_group`当前没有`size`参数,每个槽位的预留大小就是上述`slot_size`。layout、fractal、pad或compact要求更大物理边界时,必须在R2将需求落实到能表示该占用的Tile规格,并用对应API文档或官方样例复核。不能假设TileGroup会因为layout自动扩大槽位。
65+ 
66+### `make_tile`
67+ 
68+`make_tile`缺省`size`时使用与TileGroup相同的计算公式。仅当单次scratch Tile的实际预留范围大于该缺省值时,才显式填写经API证实的`size``size`必须是正的编译期字节数。
69+ 
70+`valid_shape`只描述当前有效区域,不缩小物理预留范围。容量和地址区间始终按物理shape和实际预留大小计算。
71+ 
72+## 3. 满足首地址对齐
73+ 
74+当前`pypto_cann` Pro前端对编译期已知的Tile首地址执行以下对齐检查:
75+ 
76+| MemorySpace | 首地址对齐 |
77+|---|---:|
78+| `Vec` | 32B |
79+| `Mat` | 32B |
80+| `Left` | 512B |
81+| `Right` | 512B |
82+| `Acc` | 64B |
83+| `ScaleLeft` | 32B |
84+| `ScaleRight` | 32B |
85+ 
86+`Scaling`当前没有在该前端映射中强制对齐,不等于硬件或具体API没有要求。使用`Scaling`时必须查对应API参考页和官方样例,不在R3自行推断对齐。
87+ 
88+单个基地址展开TileGroup时,不仅要检查`base`,还要检查每个`base + i × slot_size`是否符合该MemorySpace的对齐。若`slot_size`不是所需对齐的整数倍,应调整R2物理shape或使用显式地址列表,不能只把基地址对齐。
89+ 
90+## 4. 分配地址与判定复用
91+ 
92+先为同一MemorySpace内同时存活的物理槽位分配不重叠区间。一个`depth=N`的TileGroup是N个可同时在途的物理Tile,所有槽位都要单独占地址,不能把它当成一份Tile计算。
93+ 
94+不同逻辑Tile可以复用同一物理区间,但必须同时满足以下条件:
95+ 
96+1. 两者位于同一MemorySpace,且被复用区间能容纳两者各自的完整物理占用;
97+2. 生命周期不重叠,或者已有明确的同步保证新写入不会覆盖未完成的读取;
98+3. 需要`auto_mutex`保护的核内跨Pipe依赖通过共享的`mutex_id`关系表达;未配置mutex元数据时,设计中必须给出对应的手工核内同步;
99+4. 跨Cube/Vector Section的复用由R6的cross-core READY/RELEASE协议保护,`mutex_id`不能替代`event_id`
100+ 
101+不能证明上述条件时,地址必须分开。不同layout的Tile共用地址不是一种自动转换;只有对应API确实以新layout解释同一物理数据,且字节范围与生命周期均安全时,才能在设计中明示为别名复用。
102+ 
103+### `mutex_id`与地址的关系
104+ 
105+`mutex_ids`是Tile的同步元数据,不是内存分配器。它不决定Tile的地址、大小或槽位数,也不会检测容量超限。
106+ 
107+当前实现要求`mutex_id`位于`[0, 31]`;同一Tile内的多个ID不能重复,同一TileGroup中每个Tile携带的ID数量必须相同。不同Tile之间允许复用ID,因此不能写成“kernel内必须全局唯一”。是否共享ID应由真实互斥关系决定。
108+ 
109+## 5. 逐空间检查容量
110+ 
111+对每个MemorySpace,将地址表中的物理区间合并后计算峰值占用。对于从0开始的连续排布,占用上界就是最大区间终点;存在地址空洞时,同时记录“有效字节数”和“最高地址上界”。容量校验使用最高地址上界,不能只把各Tile大小相加后忽略空洞。
112+ 
113+以当前`pypto_cann` A5仿真平台配置为例,950PR/950DT的主要容量快照如下。这些数值用于理解和交叉检查,设计仍必须使用`EXPLORE_REPORT.md` §7中与当前产品和环境一致的探测值。
114+ 
115+| MemorySpace | A5配置快照 | 字节数 |
116+|---|---:|---:|
117+| `Vec` | 248 KiB | 253952 |
118+| `Mat` | 512 KiB | 524288 |
119+| `Left` | 64 KiB | 65536 |
120+| `Right` | 64 KiB | 65536 |
121+| `Acc` | 256 KiB | 262144 |
122+| `ScaleLeft` | 4 KiB逻辑地址域 | 4096 |
123+| `ScaleRight` | 4 KiB逻辑地址域 | 4096 |
124+ 
125+`Scaling`的可用容量和具体分区与产品/API路径有关,必须从当次平台探测和对应API文档取值,本文不给出通用常量。
126+ 
127+一个空间通过当且仅当:
128+ 
129+```text
130+0 <= 每个物理区间的起始地址
131+所有并存区间不冲突,或重叠处有完整的复用证明
132+max(addr + size) <= 该MemorySpace的当次探测容量
133+```
134+ 
135+超限时先清理不必要的地址空洞和重复预留,再依据生命周期寻找安全复用。仍然超限时回退R2调整Tile shape、缓冲深度或中间量保留时间;若主要占用来自API强制的临时空间,再回退R1更换API链。拆成多次kernel调用会改变整体方案,不应作为R3内的默认修复。
136+ 
137+## 6. MX scale地址映射
138+ 
139+`ScaleLeft``ScaleRight`虽然拥有独立的4 KiB逻辑地址域,但它们的起始地址不能独立选择。每个MX data/scale槽位必须逐项满足:
140+ 
141+```text
142+ScaleLeftAddr[i] = LeftAddr[i] >> 4
143+ScaleRightAddr[i] = RightAddr[i] >> 4
144+```
145+ 
146+例如`Left` group的两个地址为`[0x0000, 0x8000]`,对应`ScaleLeft` group必须为`[0x0000, 0x0800]`。该映射是硬件寻址约束,不是可选的bank优化。ScaleLeft/ScaleRight的4 KiB不从Left/Right的64 KiB数据空间中扣除。
147+ 
148+## 7. L1 Bank冲突检查
149+ 
150+容量、对齐和生命周期检查通过后,对Mat地址做L1 Bank检查。Ascend 950PR/950DT的L1为16个32 KiB Bank,组成8个Bank Group;地址位域和读写冲突规则见:
151+ 
152+`$PYPTO_DEVKIT_DIR/docs/pypto_pro/tutorials/operator_development/tile_based_python_programming/Cube_matrix_computation.md`
153+ 
154+R3只对计划并行访问的L1 Tile做这项检查。应根据实际`load`/`move`并行关系和地址位域判断,不能仅看两个Tile的基地址不同就宣称“无Bank冲突”。若官方指定样例与目标算子具有相同的Tile shape和访问方式,可借鉴其地址分组;仍需在本设计的地址表上重新验证。
155+ 
156+## 8. DESIGN.md记录格式
157+ 
158+每个物理槽位单独一行。单槽TileGroup也要标出`slot=0`,scratch Tile的槽位列写`—`
159+ 
160+| 空间 | 变量 | 槽位 | 用途 | shape | dtype | layout | 起始地址 | 大小(B) | 区间 | 生命周期/复用依据 |
161+|---|---|---:|---|---|---|---|---:|---:|---|---|
162+| Vec | `a_group` | 0 | 输入ping | `[64,128]` | FP16 | `—` | `0x00000` | 16384 | `[0x00000,0x04000)` | 迭代`2k` |
163+| Vec | `a_group` | 1 | 输入pong | `[64,128]` | FP16 | `—` | `0x04000` | 16384 | `[0x04000,0x08000)` | 迭代`2k+1` |
164+| Mat | `a_l1` | 0 | A矩阵暂存 | `[128,128]` | FP16 | NZ | `0x00000` | 32768 | `[0x00000,0x08000)` | K循环当前槽 |
165+| Acc | `acc` | 0 | 累加结果 | `[128,128]` | FP32 | NZ | `0x00000` | 65536 | `[0x00000,0x10000)` | 完整K循环 |
166+ 
167+`—`表示未显式设置layout,由`TileType`按当前平台和MemorySpace应用默认值;它不表示“没有layout语义”。非默认layout必须显式写出。
168+ 
169+地址表后按空间记录:
170+ 
171+```text
172+Vec: 有效预留 ... B;最高地址上界 ... B / 容量 ... B = ...%
173+Mat: 有效预留 ... B;最高地址上界 ... B / 容量 ... B = ...%
174+Left/Right/Acc/...: 同样逐空间记录
175+```
176+ 
177+若存在地址复用,再增加复用表:
178+ 
179+| 物理区间 | 逻辑Tile A | 逻辑Tile B | A最后读 | B首次写 | 保护机制 | 结论 |
180+|---|---|---|---|---|---|---|
181+| `Vec [0x...,0x...)` | `...` | `...` | `...` | `...` | 共享mutex / 手工核内sync / R6 cross-core事件 | 可复用/不可复用 |
182+ 
183+## R3完成检查
184+ 
185+提交R3前逐项确认:
186+ 
187+- R2的每个Tile都能在地址表中找到,TileGroup的所有槽位已展开。
188+- 每个地址和`size`均为编译期整数,区间统一按`[addr, addr + size)`记录。
189+- 每个槽位的首地址满足对应MemorySpace的对齐要求。
190+- 分形、RowPlusOne、显式`size`和亚字节dtype的物理占用没有套用错误的普通公式。
191+- 同一MemorySpace内的并存区间不重叠;每个有意复用都有生命周期和同步证明。
192+- 容量使用当次`EXPLORE_REPORT.md` §7的平台值,并以最高地址上界而非仅Tile大小之和校验。
193+- MX路径的data/scale地址按槽位满足`scale_addr = data_addr >> 4`
194+- 计划并行访问的L1 Tile已按官方L1 Bank位域和读写规则检查。
195+- `mutex_id`只表达核内跨Pipe互斥;cross-core `event_id`由R6单独设计。