BREAK LAYER 研究阅读室

跟着 Astra 查问题:它怎样发现瓶颈、检验猜测,再改写方案

按问题跳读 · 每节自带背景 · 12节先认清两道题和四个名词1. 为什么先算“权重能不能一直留在计算旁边”2. 搜索到底在求什么:先把一个小问题说完整3. 发现计算单元闲着,怎样想到拆分历史注意力4. 发现计算在等数据,最先想到的办法为何失败5. 为什么继续搜旧参数不够:连任务边界也要改6. 放慢查询、键、值的计算,功率为什么一位没变7. 沿着重复读取追查,怎样想到二维复用8. 权重只搬一次以后,为什么还要研究何时搬9. 最后117个周期:最高峰的位置会改变10. 怎样把这个过程变成人类下次能用的方法证据范围和阅读入口

这是一名 AI agent 为 Transformer 设计硬件配置和配套程序的研究复盘。它可以改变机器有多少计算资源,也可以改变每份数据放在哪里、谁负责计算、任务先后怎样安排。我们追踪的是它如何选择下一次实验,五万分只是这段工作的终点。

这里没有真实芯片测量。所有周期和功率来自同一套教学模拟器:周期越少,程序完成越快;任意连续1000周期的平均功率都不能超过20瓦。还必须通过输出数值和芯片面积检查,才能把候选保留为合格版本。

文章按问题整理了交错进行的实验,小节顺序不代表每次实验的严格时间顺序。涉及当时想法时引用对外进度说明;涉及记录没有交代的起因时,明确写为代码解释。每节开头补有独立背景,可以从目录任意一节进入。

先看一次很小、却很关键的转折。P1 是一次处理整段输入的任务,这个程序已经很快,但功率是 20.130 W,比允许的 20 W 多了一点。程序会先把输入变成注意力需要的查询、键和值,简称 Q/K/V。Astra 把这段计算的数据广播间隔拉大,想错开活动。程序确实变慢了,功率却几乎一位不差。

接下来它没有继续盲目加大间隔。它检查后面的 K/V 导出,发现数据被“写到临时区、再读回来、再写到最终地址”。删掉这次往返后,功率降到 18.398 W,配对得分通过了 42,737.81 的完整验证。

这段过程包含本轮值得学习的几个动作:看到具体异常 → 提出可被否定的怀疑 → 改一个相关环节 → 观察结果是否支持 → 把下一次实验移到新线索上。 后面的 RF 网格、注意力分片和搜索模型,也可以沿这个顺序读。

本文依据自己的分支 codex/radical-50k、提交 64cbe3e、保存的实验和当时对用户的进度说明重建过程。引用块会注明“当时说明”或“推导”。当时没说明的起因,本文用代码和数据解释其合理性,不将事后解释当成逐字记录。为便于阅读,先讲清一种问题再讲下一种;实际运行中 P1、D1 和硬件实验交错进行。

先认清两道题和四个名词

从这里开始读:这一节解释整场实验的任务。Transformer是处理序列的模型;一个token是序列中的一个位置。权重是已经训练好的矩阵,本题只改变执行方法,不改变模型要算出的结果。

P1 一次处理很多行。 同一份权重会被许多位置使用。如果每算一个小输出都重新搬相同的数据,重复搬运就会很多。P1 的重要机会是:一次搬来,多算几块。

D1 连续生成 8 步,每一步只有一行。 下一步输入要等到规定时刻才释放,不能把未来 8 行提前合成一个大矩阵。权重每步相同,历史位置的键K和值V也反复使用,所以可以跨步保留;一步内部还可以继续拆出并行任务。

名词 在这篇文章里怎么理解
SM / WG SM 是一个计算单元;WG 是交给它执行的任务组。本轮布局通常每 SM 放 4 个 WG。
RF / SH / HBM RF 是计算直接使用的小存储;SH 是可选的片上暂存;HBM 是大容量主存。经过任何一级都可能花搬运与排队时间。
面板 / 分块(tile) 把矩阵切出的一块。D1 的“权重面板”通常是一组输出列对应的权重;P1中常用32行×32列的小块。
M / N / K 矩阵乘法输出的行数、列数、求和长度。拆 M/N 可各自写一块;拆 K 得到部分和,最后还要相加。

W1→GELU→W2 是前馈网络里的“扩展维度→激活→压回原维度”。QKV 是 attention 的查询、键、值;新生成的 K/V 还要写到题目规定的地址。

两题共用一套硬件,都要数值正确,面积≤24 mm²,最热的 1000 周期平均功率≤20 W。这解释了为什么一个更快但超功率的候选会被放弃。共同评分随两题周期乘积下降而提高,单看 P1 最快还不够。

先看完整过程:agent的注意力怎样转移

下面按照保存的进度说明概括推进顺序;容量与求解模型属于这条路径的基础,后文单独展开。整段输入与逐步生成两项实验在实际运行中交错进行。

当时已有的证据由此选择的调查结果怎样改变下一步
矩阵读取落在少数内存通道;计算在等数据先试共享暂存,再改中间数据排列和任务分工暂存变慢、两种分工一快一慢,转而研究一次读取可复用多少次
逐步生成的每层注意力约990周期,只有少数计算单元参与把128个历史位置拆成多份,再正确合并完整生成任务缩短,继续保留分片方向,并随着布局改变重新测片数
局部计算变快,完整程序却多次超功率检查加载队列、同数据传输与最高功率窗口把“总共搬多少”细化成“何时搬、哪些请求重合”
放慢查询/键/值计算,最高功率仍完全相同查后面的输出导出,删除K/V多余往返完整评分合格,保留为可回退版本,再继续更激进的复用实验
二维复用让程序更快,最高功率又超限一边细分初始装载,一边定位结果写回窗口生成任务省下时间,整段输入任务可以付出少量等待以压低峰值
一次写回修改后,最热窗口移到了别处重新定位,再只调整新窗口附近的发射间隔增加117周期后合格,固定程序再做整套评分和额外随机输入检查

1. 为什么先算“权重能不能一直留在计算旁边”

从这里开始读:本节研究逐步生成任务:连续算8个新位置,每步使用相同权重。外部大内存HBM容量大,但访问需要搬运;每个任务组WG有64 KiB寄存器存储RF,计算直接使用这里的数据。SM是承载这些任务的计算单元。问题是:能否用这点小存储,换掉后7步的重复读取?

线索:相同权重要用八次

D1 每步输入不同,权重相同。假如第一步把权重搬入 RF,后面一直保留,就有机会省掉后续重复装载。这个方向延续了前期已有的 RF 驻留思路;本轮继续解决怎么放得下、怎么分给更多计算单元。

下面是依据生成器重算的容量账,用于解释为什么 SM 数、面板大小和放置位置会进入搜索。

容量单位采用二进制:1 KiB为1024字节,1 MiB为1024 KiB。每层有四类权重矩阵:QKV是把输入映射成查询、键、值的合并投影,Wo将注意力结果映射回模型宽度,W1/W2是前馈网络的两次变换。它们的尺寸分别为:QKV 128×384,Wo 128×128,W1 128×512,W2 512×128。共 196,608 个32位浮点数(FP32,每个4字节),乘 4 字节为 0.75 MiB;两层就是 1.5 MiB。

8 个 SM,每 SM 4 个 WG,每 WG 64 KiB RF,总计 2 MiB。但权重不能独占:

8-SM 模板里的 RF 用途 所需空间 为什么不能省略
32 个 WG 的临时区 32×16 KiB = 0.5 MiB 输入、中间结果和运算临时值需要活跃空间。
两层历史 K/V 0.25 MiB 这个模板希望历史也常驻。
两层权重 1.5 MiB 要覆盖所有投影。
合计 2.25 MiB 超过已有的 2 MiB。

因此在这个模板里,8 SM 全驻留先被容量否定了。减少每块的列数会让单块变小,却不会减少总权重字节;单靠切得更细填不平这 0.25 MiB 缺口。

12 SM 提供 3 MiB,临时区占 0.75 MiB,再扣 0.25 MiB 历史,留下 2 MiB 放权重,总量上有希望。但这还没有保证每个 WG 单独不超容量,需要真正分配一次。

为什么还要搜索面板宽度

假设每个面板负责连续 16 个输出列。W1 面板是 128×16×4=8 KiB;W2 面板是 512×16×4=32 KiB。相同列数,W2 的求和长度大四倍,空间也大四倍。

若统一加宽到 32 列,W2 的一个完整面板达到 64 KiB。一个普通 WG 扣掉 16 KiB 临时区,只剩 48 KiB;即使全芯片空间够,这块也装不进任何 WG。此时必须缩窄面板、沿 K 切开,或改掉整个模板。

所以这些变量各有具体作用:SM 数影响总容量与并行机会;面板宽度影响单块大小和任务数量;WG 归属决定实际能否装下、是否有 SM 忙而其他 SM 空闲。

求解器给出的分配长什么样

12 SM、16 列面板的保存结果中,前两个 WG 如下。层号在这里改为人习惯的第 1/2 层;源文件从 0 开始编号。

WG 拿到的权重 权重空间 历史 + 临时区 总计
g0 第2层 W1 的第0–15列和16–31列 16 KiB 32+16 KiB 64 KiB
g1 第2层 Wo、W1、W2 各一块 8+8+32=48 KiB 0+16 KiB 64 KiB

这就是“放置解”:把具体权重交给具体任务组,生成器再据此写汇编。它还没有告诉我们这些 WG 会怎样争用网络、启动装载需要多久、功率是否过线。那些问题必须继续测。

证据:早期放置模型、实际12-SM分配表。原交互工作台可以修改计算单元数和权重分块宽度,重算这笔账。

这一步改变了什么判断

容量账先排除了一个根本装不下的方向,也解释了为什么“把块切小”不能弥补总容量缺口。但agent仍要实际生成程序:总量够,不保证每个任务组都装得下,更不保证运行快。下一步因此分成两层:先解决分配合法性,再评估完整执行。这是根据保存代码重建出的逻辑,记录没有证明agent当时逐句进行过上面的推导。

2. 搜索到底在求什么:先把一个小问题说完整

从这里开始读:本节解释agent怎样筛选机器和分工。D1是逐个生成8个新位置的任务;权重被切成若干列组成的小块,叫面板。SM是计算单元,WG是分给它的任务组,每组有自己的小存储RF。求解工具要安排的是“哪块权重交给哪组”,工具自身并不知道完整程序最终会有多快。

外层选规格,内层放面板

先约定本节的符号:W1把向量变宽,W2将其压回原宽度;M是矩阵输出行数,N是输出列数,K是一列输出计算时需要相乘累加的项数;一块面板覆盖若干连续输出列。固定机器大小和面板宽度后,内层求解器的一个整数变量可以读成:

x[层, 投影, WG] = “这一层的这个投影,有几块权重面板放在这个 WG 上”。

例如 W1 共 512 个输出列,16 列一块,就是 32 块。所有 WG 分到的 W1 面板数量必须加起来等于 32;否则会有输出漏算或重复分配。W2 只有 128 列,所以有 8 块。

第二条规则是容量。向量通道数设为16(配置中记为VL16)时,64 KiB寄存器被划成16个物理分区,每区4 KiB:W1 的一个面板占 2 区,W2 占 8 区。每个 WG 的面板总占用不得超过“16 区减 4 区临时空间,再减它负责的历史空间”。例如,一个组保留4区临时值、不持有历史,就最多剩12区给权重;一块W2面板占8区,还可放两块各占2区的W1面板。

为什么目标函数看“最忙的 SM”

假设某阶段全部面板都分到 SM0,其他 SM 空闲;总工作量没变,但要等 SM0 做完才能进入依赖它的下一阶段。把面板摊开,最慢的那份有机会缩短。因此模型先估算每个 SM 在这一阶段的负载,取最大的那个,再将各阶段的最大值相加。

这里的“代理”是一种便宜的工作量估计,用来挑下一批值得模拟的候选。代码给每块面板的服务代理是 K/4 + 20×所占分区数。这是简化成本,不是完整模拟器周期。16 列时,W1 的代理为 128/4+20×2=72;W2 为 512/4+20×8=288。把一个 W2 面板分给某个 SM,会比一个 W1 面板占用更多代理服务。

推导:先要求“每块有人拿、每个 WG 装得下”;再在这些可行分配中,使“各阶段最忙 SM 的负载之和”尽量小。

数学写法只是在压缩上面的意思。令 u 为该投影每块所占 RF 分区数:覆盖约束是 ΣWG x=N/面板宽度;容量约束是 Σ层,投影 ux≤可用分区数;目标是最小化 Σ阶段 maxSM Σ该SM内WG x(K/4+20u)。

真正选择这些整数的是 CP-SAT,一种为离散选择寻找满足约束解的求解工具。它会搜索满足规则的分配,返回找到的解、目标值以及下界。下界是工具证明任何合法分配都不能低于的目标数值;当已有解的目标等于这个下界时,才表示这个限定模型内无需再找。这项求解只产生权重分配;完整程序还需要代码生成、模拟验证和后续结构修改。

搜到了什么,又没搜到什么

固定子问题 保存的状态 代理目标 / 下界 对生成程序测到的 D1 周期
8 SM / 16列 / 历史驻RF 无可行分配(INFEASIBLE) — 没有该模板的合法分配
12 SM / 16列 / 历史驻RF 在本模型内最优(OPTIMAL) 1440 / 1440 66,633
16 SM / 16列 / 历史驻RF 在本模型内最优(OPTIMAL) 1296 / 1296 77,231

“最优”的范围是这个放置模型。16 SM 的代理更低,完整程序却更慢;这组硬件配置也有区别,不能据此只归因于 SM 数。可以确定的是:代理排序不足以替代完整时延。

为什么会漏?目标没完整表达一次性权重预载、多个 WG 的请求竞争、跨 SM 结果传输,以及每 1000 周期的功率。它还固定了“各投影分别算”的任务边界。哪怕穷尽这些 x,也搜不出后面那种 W1→GELU→W2 合成一个任务的程序。

这决定了下一步工作:保留求解器做它能回答的容量和分配问题;遇到代理外的瓶颈,扩展变量、修改任务结构,再用完整程序验证。

在这些分配实验之前,怎样选硬件区域

首次硬件枚举(文件中称census)检查了 7,776 个硬件点,面积合法 2,480 个。下面列的是实际代码范围及其作用;“为什么值得变”是基于模型的解释。

变化轴 首次范围 它改变什么
SM 数 8、12、16、20、24、32 总 RF、可分配任务数、面积。
矩阵引擎 矩阵阵列有4×8、8×8或8×16个行列位置;沿求和方向并行处理1/2/4项;每个计算单元配1–4个阵列 小矩阵匹配、计算服务和面积;供数不足时未必获益。
寄存器读写端口、向量通道数 4读2写或8读4写端口;8或16个向量通道 读写寄存器的速度与分区;影响能用的矩阵分块和逐元素运算。
共享暂存SH、缓存Cache 共享暂存0/32/128 KiB;缓存0/2/8 MiB 容量提供保留数据的机会,也占芯片面积。即使缓存命中,后续搬运和读取仍然花时间。
软件矩阵分块的行数M、列数N、求和长度K M16/32/64;N和K16/32/64/128 单块容量、复用和任务数量;先删掉 RF 放不下的组合。

候选排序用两道题各自预测耗时的乘积(代码记作P1_proxy×D1_proxy)。整段输入任务P1的预测包含矩阵计算和寄存器读写的估计成本、搬运字节量除以名义带宽512字节/周期,以及固定20,000的补偿项;逐步生成任务D1则包含首次加载、固定10,000补偿项与面板计算成本。部分服务用官方公式,但这些项怎么相加、常数怎么取仍是启发式,不能当严格周期下界。

它保留预测排名前30个点,另按计算单元数、矩阵阵列形状、向量通道数、有无暂存等区域保留 113 个代表。代表集合是“从哪些不同方向选下一次实验”的目录,不能读成已把 113 个全部测完。

首次枚举还固定了一些资源,因而这轮结果只覆盖这些固定条件。配置中的DMA是搬运引擎,depth是每个引擎可并发的请求深度,HBM是外部内存通道,NoC是片内网络,REDUCE是专用求和/最大值归约单元,SFU是指数、开方等特殊函数单元,VL是向量通道数。该轮固定4个搬运引擎、每引擎深度2、8个外存通道、片内网络每周期512字节、不开组播、2个归约单元,特殊函数通道数等于向量通道数。后续遇到搬运调度检查异常,将深度改为1;其他资源也继续变化。最终机器采用2个搬运引擎、深度1、启用组播、无专用归约单元、8个特殊函数通道,已经越出首次固定范围。组播指符合同时发射、同地址等条件的相同数据请求可以共用一次传输。

这个事实比一次代理排名更重要:最初搜索空间只是一个可以被修订的工作假设。 源记录未说明每个离散取值为何恰好选这些数字,本文不替它补造推导;能核对的是范围、筛选规则、输出和后续越界探索。

证据:枚举与代理代码、census结果、12-SM解、16-SM解。

怎样使用一个预测失败

16个计算单元的代理目标更低,程序却更慢。这不足以锁定某个唯一原因,却足以否定“按代理排序就能直接决定成品”的用法。保留代理用于排除非法分配和挑代表候选,随后检查真实模拟中的启动、通信与等待;如果想试的程序结构不在变量里,就修改生成器。后面的融合正是这样越出了早期模型。

3. 发现计算单元闲着,怎样想到拆分历史注意力

从这里开始读:本节研究逐个生成新位置时的注意力计算:新位置要从128个历史位置中提取信息。四个head是四路独立的注意力;SM是可以并行工作的计算单元,WG是交给它执行的任务组。下面引用的前馈融合,指把先变宽、再激活、再变回原宽度的三道操作连续执行,中间结果留在小存储里。即使把权重放进了小存储,只有四份大任务仍可能让许多计算单元闲着。

线索:四个 head,只让少量 SM 忙

当时说明:

D1 每层 attention 约 990 周期,四个 head 只用了少量 SM。刚测的 W1→GELU→W2 融合只带来约千周期改善,暂不继续扩展。

这条观察同时给了两个信息:attention 在当前关键路径上花了可见时间;还有计算单元没有参与。只增加硬件算力可能用不上,于是更值得问:一个 head 内部能否再拆任务?

每个 head 要看 128 个历史位置。这些位置的打分和加权结果可以分别计算,再合并。将每 head 分成 8 片,每片16个位置,就从4份大任务变成32份小任务,有机会分到更多 SM。它不需要提前读取下一步输入。

为什么还要检查数学正确性:分片后的注意力不能直接平均

注意力先算各位置的相关程度,再用softmax把这些分数变成加起来为1的权重。指数运算容易产生极大值,所以每片为了数值稳定,要减去自己的最大分数。片 A 可能减了10,片 B 减了8;两片算出的指数处在不同缩放基准。直接把两片已经归一化的向量取平均,会丢掉它们在全局中应有的权重。

正确做法是每片保留三样东西:最大分数 m、减去 m 后的指数和 s、同基准的加权 V 向量 u。这里exp表示自然指数函数。合并时取所有片最大值 M,把每片的 s 和 u 都乘 exp(m−M),再用总 u 除总 s。

用一个纯说明用例:A 的 m=10、s=2,B 的 m=8、s=3。统一到 M=10 后,A 的分母贡献是2;B是3e⁻²≈0.406。最终分母约2.406。u也做同样缩放;两片对结果的影响显然不应各占一半。

这里V是每个历史位置携带的32维信息向量,u是尚未除以分母的加权向量。最终每片摘要只需32维 u 加 m、s,共34个32位浮点数(FP32,每个4字节)。第0片还纳入当前位置的键K和值V,确保注意力同时包含历史和当前信息。数学可合并,才有理由引入“历史片数”和“片到 WG 的映射”这两个搜索变量。

对照如何改变结论

8片版本功能通过,当时记录 D1 从65,151降到56,396周期,约少13.4%。4片初版失败;修正预留与映射后为55,950。后续融合模板最终用8片。

所以“4片曾更快”不能自动推出最终也该4片:后来的权重放置、任务边界、装载排程已经改变。片数既增加并行,也增加部分摘要传输与归约,必须在当前模板里重新比较。完整配对之间还夹有其他配置变化,本文不将全部差值归为纯片数收益。

证据:分片与合并代码、当时说明、D1实验记录。

agent如何决定继续,以及何时重测

拆分历史后,数值检查通过,整道逐步生成任务也缩短,足以支持继续采用分片这个方向。但4片与8片的比较只属于当时的机器和分工。后面融合前馈计算改变了任务占位和通信,最终重新采用8片。因此保留下来的知识是“历史可被正确拆分,并且能补足并行”,并非永久固定一个片数。

4. 发现计算在等数据,最先想到的办法为何失败

从这里开始读:本节研究一次处理整段输入的P1任务。前馈网络先用W1把向量变宽,经过GELU逐元素变换,再用W2压回原宽度。数据由外部大内存HBM搬入计算直接读取的小存储RF;SH是可选的片上共享暂存。agent要查的是:矩阵计算慢,究竟有多少时间花在等数据?

两条不同的线索

当时先指出 W2 的1024维输入按较窄的求和分块读取,每次访问之间又有较大地址间隔,HBM 请求集中在少数通道。后来资源报告又显示 RF 读写占用远高于矩阵引擎。前者指向地址和通道分布,后者指向数据能否及时供到计算。

它们都让“再加几个矩阵引擎”显得不够直接:计算单元若在等数据,增加同类算力不保证解决等待。但接下来也不能只说“提高带宽”,要分别验证造成供数损失的机制。

第一种尝试:先把更宽的输入搬到 SH 暂存,再从 SH 喂 RF,希望把这些零碎读取变得连续。单独评测这道W2矩阵操作,结果从44,721变成49,240周期,慢了10.1%。额外经过 SH 也要服务与排队,这个代表点不支持继续沿原方案扩展。

把试验改为布局和分工

另一条路径是改变自己控制的中间张量布局:把32×32计算块连续存储,生产者直接写成消费者需要的形式。这里HBM的数据按通道分担传输,地址分布偏在少数通道会造成排队。原始权重的接口布局(ABI,题目规定的地址和排列方式)保持题目要求;改布局必须同步改生产、消费两边地址,不能只改一端。

WG是交给计算单元的一组任务;接着让多个任务组交错执行,尝试填补等待空隙。局部 W1 的一组对照:

WG与行分工 W1局部操作周期 这条记录能告诉我们什么
16 WG / 2行分片 38,513 对照起点。
32 WG / 2行分片 30,596 这个映射下,增加独立任务有收益。
32 WG / 4行分片 51,239 更多行分片改变了复用与分工,反而更慢。

这些结果把问题收窄为“怎样组织所有权与复用”。单纯追求更多任务或更多存储,没有给出稳定方向。后来扩大一次保留的输出块,W1局部评测达到23,763周期,进一步支持继续检查每次装载能服务多少输出。

“小核”是只运行一个局部矩阵操作的测试,它在这里有明确用途:便宜地辨别一个机制。它不包含完整图的所有依赖,也不能自动变成整题加速。采用连续分块布局并经过共享暂存的完整P1曾达到479,303周期,但功率21.236 W,仍不合格。

证据:局部核搜索、布局实现、局部核记录。

失败后留下了哪条知识

加共享暂存变慢,说明这条具体搬运路径没有抵消新增开销;32组的两种行分工一快一慢,说明只记工作组数量会丢掉决定效果的条件。agent随后把关注点收窄到一次读取服务多少输出、相邻任务是否重复搬同一数据。这里的小实验负责筛方向,完整程序负责检验该方向是否真正可用。

5. 为什么继续搜旧参数不够:连任务边界也要改

从这里开始读:本节回到逐步生成的D1任务。它的前馈网络把128维输入经W1变成512维,经GELU变换,再经W2变回128维。SM是硬件计算单元,WG是持有权重并执行指令的任务组,RF是该组的小存储。问题从“权重交给谁”变成“一个组能否连续完成几道原本分开的计算”。

旧模型遇到了表达能力的上限

D1 的 W2 只有128个输出列。按16列一个面板,只有8份任务;16个 SM 中,一些在这个阶段拿不到面板。早期模型的变量只决定每组拿多少完整面板,无论怎样重新分配,也无法凭空增加任务数。

一种直接扩展是沿求和方向(K维)切开:同一输出由几个 WG 分别计算部分和,最后合并。split_placement() 允许每道矩阵变换分别选择输出列数N和求和长度K。W2可以沿求和方向拆开,产生需要相加的部分结果;每块按元素数计算占用的小存储分区,目标仍是减轻各阶段最忙计算单元的估计工作量。变量变多有具体原因:要表达早期完整输出面板表达不了的并行。

代价也随之出现:部分和要写出、读取、相加。一个 W2 K分片代表点 D1 为55,834周期,功率20.081 W;增加并行并未自动得到合格改善。

再换一个问题:W1 的输出能否立即被 W2 用掉

前馈网络里,W1 先产生512维中间向量,GELU处理后,W2再消费。若一个任务持有一小段 W1 列和对应的 W2 行,它可以在 RF 内连续做完这段贡献,无需先把整条中间向量交出去。

最终模板每层安排32个生产 WG,每个负责16个中间通道,连续计算 W1→GELU→W2,产生输出部分和;16个消费者按输出列并行归约,借助矩阵乘加指令(MMA)完成求和:把待加数据与全1权重相乘,就能沿求和方向累加。它需要的权重组合跨了两个投影。

这已经改变了“一个任务是什么”。早期表示独立矩阵变换面板数量的变量没有“融合生产者”这个选择,优化原目标无法找到它。因此代码新增 pipeline_plan(),直接构造布局,保存状态为 CONSTRUCTIVE(由代码直接构造)。D1融合初版到53,004周期,仍略超20 W,后面继续优化启动排程。

这里要区分两个动作:求解器在给定模板内挑分配;设计生成器可以改变模板。对人类更有用的检查是:当我怀疑一种中间搬运可以省掉时,现有变量里是否有任何取值能把它省掉? 如果没有,继续扩大旧参数网格也覆盖不到这个想法。

最终入口 radical_compile.build() 实际调用 PipelineDecode(**d1_pipeline)。配置里遗留的顶层 d1_nt=16 不决定这一条路径;最终的查询/键/值及注意力输出投影,每块算8个输出列、沿128项求和;前馈计算则每组负责16个中间通道。理解实现要追到实际调用,不能只读参数文件的字段名。

证据:扩展分片模型、融合构造、实际编译入口。

为什么没有在第一次超功率时直接放弃融合

融合后的数值计算通过,周期也较前一代表方案缩短,说明新任务结构值得继续评估;但超功率使它还不能替换合格版本。后续转向装载与写回节奏,是在保留这条计算结构的同时处理另一个限制。记录支持这个继续推进的过程,不能据此说当时已经知道最后一定能调到合格。

6. 放慢查询、键、值的计算,功率为什么一位没变

从这里开始读:本节研究整段输入任务P1的功率超限。Q、K、V分别是注意力用的查询、键和值;算出的新K/V除了被后续计算使用,还必须写到评分接口规定的输出地址。功率看任意1000周期窗口的平均值,因此删掉一次集中的搬运可能比单纯放慢计算更有效。

在同步组播等调整之后,P1为449,641周期,功率20.1301398 W。它只差一点资格;此时观察“哪里形成最高功率窗口”比追求任意一个局部加速更直接。

Astra把QKV广播排程参数从256改到1024。下面三条记录使用共同硬件,D1均为49,974周期:

P1尝试 周期 峰值功率 相对上一条的含义
原同步排程 449,641 20.1301398 W 超限对照。
QKV间隔加大 454,909 20.1301398 W 变慢5,268周期,最高峰没有降低。
直接K/V写回 442,153 18.3984097 W 删除搬运后进入预算。

当时说明:

P1 的峰值没有随 QKV 计算排程改变,线索指向后续的 K/V 导出:先写中间 QKV,再读出并写到接口规定的最终地址。

这里的逻辑要把握准确。峰值不变,说明这次干预没影响当前最高窗口;单凭这一点还不能宣布QKV计算永远不重要。结合后面的代码路径,才形成下一项可验证的怀疑。

原来投影得到Q/K/V后一起写入临时区。后续为了交付题目要求的 new_k/new_v,再读出 K/V,写到最终地址。同样的数据多跑了一次集中往返。

改动将 Q 继续写到后面需要的临时位置,把 K/V 从 RF 直接写到最终地址;后续注意力计算也同步调整读地址。这样既保留数学结果与接口要求的输出,又删掉中间写后读。

周期只减少约1.67%,却让整个配对通过预算并得到42,737.81完整评分。它说明“值得做”的判断要结合当时约束:跨过资格门槛可能比再快10%但仍超功率更有价值。

证据:直接写回生成器、双题记录中的broadcast-v2、qkv1024、direct-kv、完整评分摘录。

7. 沿着重复读取追查,怎样想到二维复用

从这里开始读:本节研究整段输入任务P1中的矩阵乘法A×B。A是输入,B是权重;输出按行和列分块。一个任务组WG只有64 KiB寄存器存储RF,要同时容纳输入、权重和尚未累加完成的输出。问题是:同一块数据搬进来后,能否多算几块输出再丢掉?

线索来自前面的供数试验

前面已观察到 RF 服务繁忙,多WG映射对结果影响很大,扩大一次保留的输出块的局部核又有收益。代码中还存在一个明确复用关系:同一个 A 行块能配多个 B 列块,同一个 B 列块也能配多个 A 行块。

当时没有逐字记录“网格想法第一次如何形成”。下面是依据代码的机制解释:要继续少搬数据,可以让一个 WG 同时保留多行、多列的输出累加器,让 A/B 的两种复用同时发生。

用2×4算一轮,就能看懂好处和代价

一个 WG 留住2行块×4列块,共8块输出。矩阵乘法沿求和方向分轮累加;这里每轮处理32项,代码记作K=32。每轮搬2块 A、4块 B,就能配出8次小矩阵乘。若8个输出各自独立搬 A/B,需要16次逻辑块装载;共享之后是6次。

这些输出不能立即扔掉,因为下一轮 K 还要继续累加。因此8个输出块必须同时留 RF。每块32×32个32位浮点数,每数4字节,共4 KiB,64 KiB RF只有16区:

活跃内容 占用分区
8块输出累加器 8
2块输入A,另备下一轮的2块(双缓冲) 4
4块权重B,用完再换下一轮(单缓冲) 4
合计 16 / 16

这也解释了为什么最终 W1 的 B 不用双缓冲:再加4区就放不下。更大的网格虽然复用更多,也会占更多累加器;“让所有东西都驻留、都双缓冲”没有满足容量的取值。

这里16→6是一个任务组的一轮求和分块的逻辑比较,不能推出整题快16/6倍。实际还包含其他WG复制、同数据请求的合并传输(组播)、偏置和激活等收尾操作、任务同步等成本。原交互工作台的寄存器容量演示可以直观看到哪些组合放不下。

W2为何还要另一种分工

W2是前馈网络把宽向量压回原宽度的矩阵变换。P1中的W2求和长度为1024,输出列相对少。最终将 K 分2片,使用2份输入行分工×4份输出列分工×2份求和方向分工,共16 WG;每 WG 维护2×2局部网格,之后归并部分和。这里沿K拆开的收益与额外归并成本共同存在。

完整网格初版 P1为380,668周期,比442,153少约13.9%,功率却升到20.397 W。继续调整网格、存储与排程后更快,但约束问题再次变为:活动重叠太集中,怎样平滑最高窗口?

这条过程可读成“复用减少搬运→更多有效活动能重叠→功率成为新限制”。前半段成功并不免除后半段的验证。

证据:网格与容量检查、双题候选。

8. 权重只搬一次以后,为什么还要研究何时搬

从这里开始读:本节研究逐步生成8个新位置的D1任务。权重保存在每组的小存储RF中,后续步骤可以复用,但第一次装入仍要从外部大内存HBM搬运。SM是计算单元,DMA是负责搬运的硬件。这里没有减少必需的数据量,agent尝试改变请求的发出时刻,避免它们集中争抢资源。

线索:同样的必要数据,发出的时刻影响结果

RF常驻避免了重复搬权重,但第一次装入1.5 MiB权重仍要付成本。多个SM一起发请求,会争用HBM、网络、DMA和RF写口,也会形成动态功率峰。

早期进度已提到“分批装载反而比全部同时装载快”,把启动竞争列为独立问题。后来一组 按计算单元分批放行的对照(配置中记作wave)显示另一种速度/资格权衡:16个SM同时装载为45,385周期、20.089 W;9个一批为49,084周期、18.876 W。前者快但超限,后者有功率余量却多了等待。

所以“wave越小越好”同样不成立。真正要问的是:放行多少请求、相隔多久,能让服务持续进行又不堆出过高峰值?

为什么从“按SM批次”改成“按字节桶”

各SM持有的权重数量不同。一次放行同样数量的SM,不代表放行同样多的数据。代码进一步对每条加载指令LD覆盖的64-byte内存行计数,累计到一个字节桶预算后换下一个时间事件。

其中编号63的任务组充当软件计时与放行组,使用等待指令WAIT和向量指令VEC发出这些时间事件,其他WG等相应事件再继续装载;它没有新增硬件调度器。WG63的第二层数据延后到第一层计算期间装入,使用前补齐依赖。这里的第二层数据在第一层计算时还不会被使用,因而有机会延后装入;但必须在第二层真正使用前完成等待。这样把“何时搬”也放入软件排程。

先后试了SM wave、桶大小和时间间隔。桶有16,384/28,672/32,768 B等候选。但比较间隔的效果时必须固定桶和程序阶段,否则会混入其他改动。

同一代码系列里,间隔缩小到哪一步

下面四项均来自“已优化偏置和激活等收尾操作 + 延后编号63任务组装载”的同系列,桶为28,672 B:

事件间隔参数 D1周期 峰值功率 从这组可得的判断
104 48,265 18.919680 W 仍有功率余量。
102 48,103 19.197199 W 略快,峰值上升。
100 47,904 19.724952 W 继续略快,仍合格。
98 47,635 19.866022 W 四个已测点中最快。

最终选98;再对D1做直接K/V写回,降到47,049周期,功率保持19.866 W。日志中还出现别的间隔,但所属代码版本或其他设置不同,不能连接成同一条单变量曲线,也不能据此声称98是整个连续区间最优。

字节桶/间隔只是发射安排,不能直接视为真实持续带宽。请求可能排队、被其他活动延迟,最终仍以官方模拟的周期和窗口功率判断。

证据:分桶与事件生成代码、fast104/102/100/98及directkv98记录。

9. 最后117个周期:最高峰的位置会改变

从这里开始读:本节研究最后的功率验收。W1是前馈网络的第一次矩阵变换,GELU是随后逐元素执行的激活函数;Q/K/V是注意力需要的查询、键、值。P1处理整段输入,D1逐步生成8个新位置;两份程序共用硬件,都要满足1000周期窗口平均功率不超过20瓦。P1已经足够快,agent此时需要找出具体在哪一段稍作等待,才能用很小的速度代价换取合格。

为什么这时需要看功率时间线

本轮已有让P1的两段独立输入错开推进的更激进候选:326,828周期,却达到21.709 W。更快还不够。D1的改进让两题周期乘积已有五万分余量,因此P1可以花一点周期,把最热窗口压进预算。

只看“峰值20.10 W”不知道该改哪里。radical_profile.py按模拟事件的动态能量与持续时间重建功率序列,计算每个1000周期窗口,找到最大者,再列出与该窗口重叠的指令;代码核对重建峰值与官方结果一致。这把一个全局数字变成可检查的具体时间和操作。

第一次定位后改W1;改完要重新定位

候选状态 最热1000周期窗口 窗口覆盖的指令 峰值
网格、移除SH后的版本 241,058–242,058 94条向量计算指令VEC、64条存储指令ST 20.099857 W
改为每块完成偏置、激活等收尾操作后立即写回 16,432–17,432 23条向量计算指令VEC、64条存储指令ST 20.051679 W

第一处结合指令与地址对应 W1 的GELU结果写回。当时说明明确把注意力转向“等整批激活完成后写回”与“逐块写回”的对照。

改完后,最高峰移到了前面的QKV写回。此时继续只修改W1可能没有效果,因为决定资格的是新的最高窗口。于是继续尝试QKV写回间隔、写回相位等控制。

表里的VEC/ST条数是窗口覆盖计数,不能当作各类操作的功率占比。定位依赖事件时间、操作数地址和代码阶段的对应,不能仅凭“ST多”认定所有功率都来自ST。

为什么只多117周期就够

P1写回安排 P1周期 峰值功率 资格
逐块完成收尾就写回,尚未加QKV间隔 337,359 20.051679 W 超限。
增加QKV写回间隔16 337,476 19.971397 W 进入预算。

只多117周期,约0.035%,就跨过20 W。等待集中在已经定位的写回附近,其对全程序的代价很小。期间也试了48/128/256等间隔,以及集体写回相位;它们是保留下来的其他候选,并非16有理论最优证明。

最终配D1的47,049周期、共同面积22.494565 mm²,使用随机输入种子7的完整评分为 50,416.649483。P1功率余量约0.029 W,D1约0.134 W;这是该教学模型中的合格点。

证据:W1峰值窗口原报告、峰值移位后的原报告、分析程序、最终grade摘录。

10. 怎样把这个过程变成人类下次能用的方法

从这里开始读:本节把前面的实验转成可复用的判断方式。即使没读其他小节,也只需记住:agent可以改变数据如何分块、存放和调度;每次改动都要经过数值、耗时和功率检查。下面区分“记录中实际做过的事”与“我们据此提出的工作建议”。

如果只记“用RF网格、用分片、做融合”,下次遇到不同工作负载,还是不知道先做哪一个。更可执行的是保留什么观察触发什么试验,以及怎样判断该换方向。

看到的现象 接着问什么 能检验它的下一步
数据跨步反复使用 全驻留需要多少活跃空间? 先像8-SM例子那样扣临时区、历史,再做真实放置。
一个阶段只有少数SM忙 任务能沿哪个数学维度拆? 查可合并的部分结果;测片数,同时计算归约代价。
计算单元空闲、RF忙 同一输入块被谁反复读取? 沿生产消费关系列复用,再测布局、网格或融合。
改了某段,峰值却没动 干预是否碰到真正最高窗口? 重新定位窗口并查后续搬运,保留不改善的对照。
代理更优、完整程序却慢 代理漏了启动、通信、依赖中的哪项? 补代表对照;若变量无法表达所需结构,就改模板。
加速后刚好超功率 哪些活动集中到同一窗口? 只在相关装载/写回试节奏,重新检查全局最高峰。

给下一次实验写一张短卡,可以具体到这个程度:

观察: QKV广播间隔从256改1024,P1多5,268周期,峰值仍20.1301398 W。
怀疑: 当前最高峰可能在没有被这次干预改变的后续K/V导出。
试验: 固定硬件和D1,把K/V从RF直接写最终地址,同步改消费者;先查数值,再测周期和功率。
支持它的结果: 峰值显著降低,并进入20 W;若仍不动,就继续查新窗口,而不能宣布问题已解决。
实际结果: 442,153周期、18.398 W;随后两题配对的完整评分为42,737.81。

搜索也可以用同一张卡约束:每个变量必须对应一个怀疑的机制,每个固定项要注明当前没有覆盖,每个简化预测模型中的“最优”都要带范围。反复返回这张卡,能避免把大量枚举误当作有效探索。

关于“我的先验为何只到一万多分”

现有记录不足以判断“注入先验”本身导致分低。两轮起点、可修改的生成器、时间和覆盖区域都不同;本轮也继承了前期RF驻留等成果。可观察到的是,Astra多次因新证据扩大可改的对象:从面板归属到融合任务,从总流量到具体发射节奏,从一个功率峰到下一个峰。

因而可以迁移的一条做法是:把先验写成带适用范围、允许被对照推翻的假设。 例如“更多WG能填等待”后面必须同时保留32WG/4行分片变慢的反例;“K分片无收益”也只能限定在当时模板,后来的RF网格组合需要重测。

证据范围和阅读入口

从这里开始读:本节说明本复盘可以支持多强的结论。历史过程来自代码、报告和agent当时发给用户的进度说明;没有完整原生对话,因此无法还原所有试验及未记录的判断。

最终两题在随机输入种子7下完成整套评分并合格;更换到种子13后,两题的数值正确性检查也均通过,最大绝对误差约2.998×10⁻⁶ / 9.537×10⁻⁷。本复盘核对了保存报告与配置、程序hash,没有重新运行长时搜索和评分。

导入的157条记录包括61双题、33个D1、63个局部核,保留各自追加顺序。三个完成整套评分的检查点为30,217.71、42,737.81、50,416.65;其他记录会注明估计、局部核、超限或失败。失败消息为空时,不补写原因。

没有完整全因素消融,不能把总提分精确拆成每个技巧的独立贡献;也没有覆盖全部软硬件空间或证明全局最优。本文的“为什么”有当时明确说明,也有根据代码补的机制解释,已在相关处区分。

继续读另一条过程:方案三如何检验、回退与更新 → · 保留的最初详细版本