架构设计壁垒(上):数据流架构与计算单元设计
大家好,我是你们的老朋友。今天咱们聊聊芯片架构里最核心、也最“烧钱”的部分——数据流架构和计算单元设计。
说实话,我入行那会儿,大家还在争论“通用计算”和“专用计算”谁更牛。现在呢?AI芯片已经用脚投票了。你想想看,一个Transformer模型动辄几百亿参数,传统CPU那套“取指-译码-执行”的玩法,根本跑不动。所以,今天的内容,说白了就是回答一个问题:AI芯片凭什么比CPU快那么多?
一、传统冯·诺依曼瓶颈:到底卡在哪?
先聊个基础问题。冯·诺依曼架构,就是咱们电脑、手机里CPU用的那套。它有个经典问题——存储墙。
什么意思呢?CPU算得飞快,但内存读写慢。CPU大部分时间在等数据。我打个比方:你是个顶级大厨(计算单元),但配菜员(内存)半天才递一个菜过来。你大部分时间在干等,真正炒菜的时间很少。
在AI场景下,这个问题被放大了。模型参数动不动几十GB,权重矩阵反复搬运。我见过一个项目,芯片算力标称100TOPS,实际跑起来连20TOPS都不到。为什么?数据搬运把时间全吃掉了。
核心矛盾:计算单元利用率低,不是因为算力不够,而是数据喂不饱。
还有个问题——功耗墙。数据从DRAM搬到SRAM,再从SRAM搬到寄存器,每搬一次,功耗就涨一截。我记得有个数据:一次DRAM访问的能耗,相当于做几十次乘法。你想想看,这得多浪费?
二、数据驱动架构:换个思路
传统CPU是“指令驱动”——指令告诉它怎么取数据、怎么算。AI芯片换了个玩法:数据驱动。
说白了,就是数据流到哪,计算就跟到哪。不需要复杂的指令调度,数据一来,计算单元自动开工。这就像流水线——零件到了工位,工人直接干活,不用等班长喊口令。
我参与过一个项目,早期用CPU做推理,延迟高得离谱。后来换了数据流架构,延迟直接降了一个数量级。为什么?因为去掉了指令取指、译码的开销,也去掉了分支预测失败的惩罚。
我的经验:数据流架构特别适合“计算模式固定”的场景,比如矩阵乘法、卷积。但如果算法经常变,数据流架构的灵活性就不如CPU了。所以现在很多AI芯片是“混合架构”——数据流做核心计算,CPU做控制。
三、计算单元设计:三种主流方案
聊完数据怎么流,咱们看看计算单元本身。目前主流的有三种:SIMT、Systolic Array、近存计算。我一个个说。
1. SIMT(单指令多线程)
这是GPU的看家本领。一条指令,控制多个线程同时执行。比如你要做1000个加法,SIMT可以一次发一条指令,让1000个线程同时算。
但这里有个坑——线程发散。如果线程里有个if-else分支,一部分线程走A路,一部分走B路,那SIMT的效率就暴跌。我踩过这个坑:一个模型里有个条件判断,导致GPU利用率从80%掉到30%。后来改了算法,把条件判断去掉,性能才回来。
// SIMT 伪代码示例
// 假设有 32 个线程同时执行
__global__ void vec_add(float* a, float* b, float* c, int n) {
int idx = threadIdx.x + blockIdx.x * blockDim.x;
if (idx < n) {
c[idx] = a[idx] + b[idx]; // 所有线程执行同一指令
}
// 如果这里加个 if(idx % 2 == 0) 就会导致线程发散
}
避坑指南:我曾经在优化一个推荐模型时,发现GPU利用率上不去。查了半天,发现是Embedding层里有个动态形状的查表操作,导致线程发散。后来改成固定形状,利用率直接翻倍。所以,用SIMT时,尽量避免线程内的条件分支。
2. Systolic Array(脉动阵列)
这是Google TPU的杀手锏。说白了,就是一堆计算单元排成阵列,数据像心跳一样在阵列里“脉动”传递。每个单元只做一件事:乘加运算。
为什么它快?因为数据复用率高。比如做矩阵乘法,传统做法是反复从内存读数据。Systolic Array呢?数据从左边流进来,从上边流进来,在阵列里“边走边算”,算完结果从右边流出去。数据只读一次,但被用了很多次。
我记得Google第一代TPU,用256x256的Systolic Array,算力做到92TOPS。当时业界都震惊了。后来我研究了一下,发现它的核心优势就是数据本地化——数据尽量在阵列内部流动,不出去。
// Systolic Array 计算矩阵乘法的简化逻辑
// 假设 4x4 的阵列
for (int k = 0; k < K; k++) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
// 每个PE(处理单元)做一次乘加
C[i][j] += A[i][k] * B[k][j];
}
}
}
// 实际硬件中,A和B的数据是“脉动”输入的
关键点:Systolic Array的瓶颈在于“边界带宽”。如果阵列太大,边界上的数据喂不进去,内部单元就会闲置。所以阵列大小要跟芯片的访存带宽匹配。我见过一些设计,阵列做得特别大,但带宽跟不上,利用率不到50%。
3. 近存计算
这个思路更激进——把计算单元放到内存旁边,甚至放到内存里面。数据不用搬远,直接在“家门口”算完。
我接触过一个近存计算的项目,用的是HBM(高带宽内存)加逻辑芯片。计算单元直接堆在HBM的硅中介层上。数据从HBM到计算单元,延迟只有传统方案的十分之一。功耗也降了很多。
但近存计算有个问题——散热。计算单元和内存堆在一起,发热量很大。我记得有个原型芯片,跑起来温度直接飙到90度。后来加了液冷才压住。
| 方案 | 优势 | 劣势 | 典型代表 |
|---|---|---|---|
| SIMT | 灵活性高,适合多样化计算 | 线程发散时效率低 | NVIDIA GPU |
| Systolic Array | 数据复用率高,计算密度大 | 边界带宽受限,灵活性差 | Google TPU |
| 近存计算 | 访存延迟低,功耗低 | 散热难,工艺复杂 | 三星 HBM-PIM |
四、我的个人体会
做了这么多年芯片,我最大的感受是:没有完美的架构,只有合适的场景。
SIMT适合灵活多变的场景,比如训练。Systolic Array适合计算密集的场景,比如推理。近存计算适合访存密集的场景,比如推荐系统。
我建议大家在选型时,先搞清楚你的 workload 是什么。是计算密集?还是访存密集?还是两者都有?然后根据这个去选架构。千万别盲目追新——我见过有人非要用Systolic Array做稀疏计算,结果利用率不到10%,还不如用GPU。
一个小技巧:如果你不确定选哪种架构,可以先用Roofline模型分析一下。它能告诉你,你的瓶颈是计算还是访存。然后对症下药。
好了,今天的内容就到这里。数据流架构和计算单元设计,是AI芯片最核心的壁垒。下一章咱们聊聊存储层次和互联架构,那也是个大坑。
公众号:蓝海资料掘金营,微信deep3321