
1. 从一颗芯片的诞生说起为什么现在造AI芯片是件“想清楚再动手”的事这两年跟同行聊天话题绕来绕去总会落到同一个点上AI芯片到底还能不能造怎么造才不至于流片回来就变成一块昂贵的镇纸。我自己前前后后参与过几轮不同规模的芯片定义和软件栈搭建踩过的坑比想象中多。这个项目标题叫“新造一个AI芯片的思考”它不是一份流片报告也不是某个具体产品的宣传而是一次把“从需求到架构到软件栈到算子落地”整条链路重新捋一遍的复盘。核心关键词绕不开几个AI芯片、agent native、存算融合、软件栈、算子。如果你正在做芯片定义、系统架构、编译器或者算子开发这篇东西应该能帮你少走一些弯路如果你只是好奇一颗AI芯片是怎么被“想”出来的也能看个明白。先说清楚它解决什么问题。过去造芯片很多时候是硬件团队先把架构定死软件团队后知后觉地补驱动、补算子库最后发现某个高频算子性能拉胯回头改硬件已经来不及。这个项目的核心思路是反过来先想清楚这颗芯片要服务什么样的agent native负载再倒推存算融合的架构边界最后用软件栈和算子把硬件能力榨干。它适合谁看适合那些不满足于“堆MAC阵列”的架构师适合被算子性能折磨过的编译器工程师也适合想理解AI芯片全貌的产品和技术管理者。我特别想强调一点现在谈AI芯片如果还停留在“算力多少TOPS、功耗多少瓦”这种参数层面基本就输在起跑线了。真正决定一颗芯片能不能用的是它在真实负载下的有效算力而这个有效算力一大半由软件栈和算子质量决定。这也是为什么我把“算子”这个词放在这么重的位置——它既是硬件能力的出口也是软件栈的试金石。2. 整体设计与思路拆解agent native和存算融合到底改变了什么2.1 为什么“agent native”不是个营销词而是架构约束先解释一下agent native。传统AI负载大多是一次推理输入一张图或者一段文本前向算完就结束负载形态相对规整。但agent类负载不一样它是有状态的、多轮的、带工具调用的。一个agent在完成任务时可能先做一次规划推理然后调用检索再根据结果决定下一步中间还夹杂着记忆读写。这意味着芯片面对的不再是单一的大矩阵乘而是大量小规模、不规则、频繁切换的算子序列。这个变化对架构的冲击是根本性的。我举个具体例子传统推理芯片可以把batch做得很大靠吞吐摊薄开销但agent负载里很多算子的输入可能只有几十个tokenbatch小得可怜这时候如果还按大batch的思路设计硬件利用率会低到让人心疼。所以在这个项目里我们很早就把“小batch、低延迟、高频算子切换”作为第一约束而不是事后优化。提示如果你正在定义一颗面向agent的芯片先别急着画MAC阵列拿几个真实的agent trace跑一遍统计一下算子调用频率和平均规模你会发现很多想当然的假设都不成立。2.2 存算融合不是把计算塞进存储就完事存算融合这个词被说烂了但真正落地时大家走的路子差别很大。有的方案是在SRAM里做近存计算有的干脆用模拟电路做存内计算。这个项目里我们选择的是数字域的近存计算加分层存储原因很实际模拟存内计算精度和可编程性都还撑不起通用agent负载而纯数字近存计算虽然能效提升没那么夸张但胜在可控、可调试、可编程。具体来说我们把最频繁访问的权重和激活放在离计算单元最近的SRAM块里让一部分element-wise和归约操作直接在存储侧完成减少数据在总线上来回搬运。这里的关键不是“融合”本身而是融合的粒度。粒度太粗灵活性差粒度太细控制开销吃掉收益。我们最后选定的粒度是“算子级融合”也就是说一个算子如果能在存储侧完成就绝不搬到主计算阵列去。2.3 软件栈和算子的关系谁先谁后很多团队的做法是硬件先定软件栈后补。这个项目里我们尝试了一种更激进的方式软件栈和算子库的接口定义和硬件架构定义同步进行。听起来很理想做起来很痛苦因为两边经常互相推翻。但好处是等到硬件定型时算子库已经能跑通大部分关键路径不会出现“硬件很强但没算子可用”的尴尬。这里有个经验算子不是越多越好而是越“可组合”越好。我们早期列了一个几百个算子的清单后来发现真正高频的也就几十个剩下的都可以由这些基础算子组合出来。所以软件栈的设计重点放在了算子的融合、调度和内存复用上而不是盲目扩充算子数量。3. 核心细节解析与实操要点算子、软件栈和存算融合的硬骨头3.1 算子开发从“能跑”到“跑满”的距离算子开发这件事外行看是写几个循环内行看是跟硬件微架构搏斗。我拿一个最常见的例子来说拉普拉斯算子。在图像处理里它用来做边缘检测在AI负载里它可能出现在某些视觉agent的预处理阶段。这个算子本身计算量不大但访存模式很讲究。如果按朴素实现每个输出点都要读周围一圈输入访存次数是计算次数的好几倍硬件再强也白搭。我们的做法是分块加寄存器复用把输入切成适合片上缓存的小块块内数据加载一次多次复用。听起来简单但块大小怎么选直接决定性能。块太小复用率低块太大缓存放不下反而增加换入换出。我们最后是通过实测加建模找到一个和SRAM容量、总线位宽匹配的块尺寸。这个过程没有捷径就是测、调、再测。注意算子优化里最容易被忽视的是边界处理。很多性能问题不是出在主体循环而是出在边界分支上。如果你的算子有大量if-else处理边界考虑用padding或者分治把边界单独处理。3.2 软件栈调度器才是隐藏的性能杀手软件栈里最不起眼但最影响性能的是调度器。agent负载的算子序列是动态的调度器要在运行时决定哪个算子先跑、在哪个计算单元跑、数据放哪里。我们早期用了一个很朴素的贪心调度结果发现算子之间的依赖没处理好大量时间花在等待上。后来我们引入了基于依赖图的动态调度把算子之间的数据依赖显式建模调度时优先执行关键路径上的算子。这个改动带来的性能提升比单纯优化某个算子大得多。这里的关键是调度器要能感知硬件的存算融合能力如果一个算子可以在存储侧完成调度器就应该优先把它安排在存储侧避免数据搬运。3.3 存算融合的实操边界哪些算子适合哪些不适合存算融合不是万能的。我们总结了一个简单的判断标准访存密集、计算简单、数据局部性好的算子适合放到存储侧计算密集、需要大量跨数据交换的算子还是放在主计算阵列更合适。比如element-wise的加乘、简单的归约、部分激活函数都很适合近存计算而卷积、矩阵乘这种需要大量数据重排的放在主阵列更高效。这个边界不是拍脑袋定的是我们把常用算子一个个跑在两种模式下对比出来的。表格里是我们实测的一部分结果供参考算子类型近存计算收益主阵列收益建议放置element-wise加乘高中存储侧简单归约高中存储侧激活函数中高中存储侧小规模矩阵乘中高主阵列卷积低高主阵列数据重排低中主阵列这张表不是绝对的因为具体收益还跟数据布局、算子融合情况有关。但它能帮你快速判断一个算子该往哪放少走很多弯路。4. 实操过程与核心环节实现从算子清单到软件栈跑通4.1 第一步用真实负载提取算子清单我们做的第一件事不是画架构图而是收集负载。找了几个有代表性的agent任务把它们的执行trace完整记录下来然后统计算子调用频率、平均输入规模、数据依赖关系。这一步的产出是一张算子热度表。热度表里排前二十的算子基本决定了硬件和软件栈的设计重点。这里有个坑不要用合成负载。合成负载的算子分布和真实负载差别很大按合成负载设计的芯片跑真实任务时经常出现“设计时重点优化的算子根本用不上真正高频的算子没优化”的情况。我们早期就吃过这个亏后来全部换成真实trace才纠正过来。4.2 第二步定义算子接口和融合规则算子清单确定后下一步是定义算子接口。接口设计要考虑到融合也就是说两个算子如果能合并成一个接口上要支持。比如常见的“矩阵乘激活”如果接口设计得好可以在一次数据加载里完成省掉中间结果的写回和读取。我们定义的接口里每个算子都要声明自己的输入输出内存布局、是否支持原地计算、是否可融合。这些声明看起来繁琐但到了调度阶段调度器就是靠这些信息做决策的。接口定义得好后面软件栈的复杂度会低很多。4.3 第三步软件栈分层实现软件栈我们分了四层驱动层、运行时层、图编译层、算子库层。驱动层管硬件寄存器运行时层管内存分配和任务下发图编译层负责算子融合和调度算子库层就是具体算子的实现。这里重点说图编译层。它要做的事情包括把上层框架的图转成内部表示、做算子融合、做内存规划、生成调度序列。我们在这个层里实现了一个基于代价模型的融合决策对每一对相邻算子估算融合后的收益和代价收益大于代价就融合。代价模型里考虑了数据搬运量、计算量、并行度等因素。4.4 第四步算子实现与调优算子实现我们用了两种方式一种是手写高性能kernel针对最热的那几十个算子另一种是基于模板的自动生成覆盖长尾算子。手写kernel性能好但开发慢自动生成覆盖广但性能一般。两者结合既保证关键路径性能又保证算子覆盖率。调优阶段我们主要看两个指标硬件利用率和端到端延迟。硬件利用率高但端到端延迟没降说明瓶颈在调度或数据搬运上端到端延迟降了但利用率没升说明优化方向可能不对。这两个指标要一起看不能只看一个。5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 算子性能不达预期先查什么遇到算子性能差我的排查顺序是先看访存再看并行度最后看指令效率。大部分性能问题出在访存上比如数据布局不匹配导致缓存命中率低或者跨bank访问冲突。这些问题用性能计数器一看就知道。并行度问题通常是任务划分不合理导致部分计算单元空闲。指令效率问题最少见但一旦出现往往需要改微架构。5.2 软件栈和硬件对不齐怎么办这是最常见也最头疼的问题。硬件团队说软件没用好软件团队说硬件接口不合理。我们的解决办法是建立联合调试机制硬件提供性能计数器和trace接口软件把每个算子的执行时间、访存量、计算量都打点上报。两边对着同一份数据看争论就少了很多。5.3 存算融合带来的调试复杂度存算融合让数据流变得不直观调试难度上升。我们的应对是在仿真环境里保留完整的数据流trace每个数据块从哪来到哪去都能追。虽然仿真慢但定位问题时非常有用。另外我们给每个融合算子都保留了“非融合”的参考实现方便对比结果是否正确。5.4 常见问题速查表问题现象可能原因排查方向算子延迟高访存瓶颈查缓存命中率、bank冲突硬件利用率低任务划分不合理查并行度、负载均衡结果不正确融合逻辑错误对比非融合参考实现端到端延迟波动大调度不稳定查调度器决策日志功耗超预期数据搬运过多查总线活动、存算融合比例这张表是我们团队内部总结的实际排查时按这个顺序走大部分问题都能定位到。6. 一些个人体会和后续可以继续挖的方向做这颗芯片的过程中我最大的体会是AI芯片的竞争力越来越不在硬件本身而在硬件和软件栈、算子库的协同设计上。一颗参数漂亮的芯片如果软件栈跟不上实际表现可能还不如一颗参数普通但软硬协同好的芯片。agent native和存算融合这两个方向本质上都是在逼着我们把“协同”做得更深。另外算子这件事值得长期投入。算子不只是实现它还是硬件能力的抽象出口。一个好的算子库应该能让上层框架不用关心底层硬件细节同时又能把硬件能力发挥到极致。这个平衡很难找但找到了就是护城河。后续如果继续往下挖我觉得有两个方向值得关注一是算子的自动发现和自动优化让编译器能根据负载自动生成高效算子减少手写工作量二是存算融合的编程模型现在写融合算子还是太依赖专家经验如果能有一套更抽象的编程接口让普通开发者也能用好存算融合那价值就大了。这两个方向我自己也在摸索有进展再跟大家分享。