GPU 用成千上万个简单核心换吞吐,FPGA 走的是另一条路:用可重构的逻辑资源「现场烧出」一个专用电路。没有指令取指、没有缓存层级、没有调度开销,数据流过精心排布的运算单元,延迟以纳秒计且完全确定。这让 FPGA 在低延迟、高能效、非标准数据宽度的场景里独占鳌头——高频交易、基因组比对、网络包处理、实时信号处理。但代价是开发周期长、编程抽象低、峰值算力不及 GPU。本文讲清 FPGA 的硬件结构、两条开发路径与选型权衡。与 GPU 的通用优化方法可对照 GPU 内核性能优化 阅读。
为什么选择 FPGA
FPGA 的竞争力来自三个「反 GPU」的特性:
| 维度 | GPU | FPGA |
|---|---|---|
| 延迟 | 微秒级(内核启动+访存) | 纳秒~微秒级,确定 |
| 能效 | 高(但含调度/访存开销) | 极高(无冗余电路) |
| 数据宽度 | 固定(32/64 位) | 任意定制(如 3 位、12 位) |
| 峰值算力 | 极高(TFLOPS 级) | 中等 |
| 开发周期 | 天~周 | 周~月 |
| 重配置 | 不可 | 现场重配置 |
位宽定制是 FPGA 最被低估的优势。机器学习推理里的量化模型可能只需要 4 位整数运算,GPU 仍要按 8/16 位打包,FPGA 可以造出恰好 4 位的乘法器,把资源利用率翻倍。确定性延迟则是金融与工业控制的生命线——GPU 内核启动的微秒级抖动在高频交易里足以致命。
FPGA 的硬件结构
FPGA 由可编程逻辑块阵列与可编程互连构成,核心资源:
| 资源 | 全称 | 用途 |
|---|---|---|
| LUT | Look-Up Table | 实现任意组合逻辑函数 |
| FF | Flip-Flop | 存储状态,构成寄存器/流水线 |
| DSP | DSP Slice | 硬核乘加单元,做算术 |
| BRAM | Block RAM | 片上块存储(几十 KB/块) |
| URAM | Ultra RAM | 更大的片上存储(Xilinx UltraScale+) |
| I/O | I/O Block | 高速收发器、PCIe、HBM 接口 |
一个 6 输入 LUT 可以实现任意 6 输入 1 输出的逻辑函数。成千上万个 LUT + FF + DSP + BRAM 通过可编程互连连接,就构成一个可定制的数据通路。
典型现代 FPGA(如 Xilinx Alveo U250):
~170 万 LUT / ~340 万 FF
~12,000 DSP Slice
~2,700 块 BRAM(合计约 50 MB)
多路 HBM2 / DDR4 接口 + PCIe Gen4
设计者在综合(synthesis)阶段把 HDL/HLS 代码映射到这些资源,布局布线(place & route)决定它们在芯片上的物理位置。时序收敛(timing closure)是核心挑战:设计必须满足目标时钟频率,否则综合器报时序违例。
两条开发路径
HDL:Verilog/VHDL
传统路径用硬件描述语言直接描述电路。控制精确、时序可预测,但开发慢、易出错。
// 一个 8 点滑动平均的流水线实现
module moving_avg (
input wire clk,
input wire rst,
input wire [15:0] din,
input wire valid_in,
output wire [15:0] dout,
output wire valid_out
);
reg [15:0] shift0, shift1, shift2, shift3;
reg [17:0] sum;
reg v0, v1, v2;
always @(posedge clk) begin
if (rst) begin
{shift0, shift1, shift2, shift3} <= 0;
v0 <= 0; v1 <= 0; v2 <= 0;
end else begin
shift0 <= din;
shift1 <= shift0;
shift2 <= shift1;
shift3 <= shift2;
v0 <= valid_in; v1 <= v0; v2 <= v1;
end
end
assign sum = shift0 + shift1 + shift2 + shift3;
assign dout = sum[17:2]; /* 除以 4,右移 2 位 */
assign valid_out = v2;
endmodule
注意:没有循环、没有指令,每个时钟周期数据前进一级寄存器——这是流水线(pipelining) 的硬件表达,也是 FPGA 吞吐的来源。
HLS:高层次综合
HLS(High-Level Synthesis)把 C/C++/OpenCL 综合成硬件,开发效率高得多,代价是对硬件资源的控制不如 HDL 精细。
// Vitis HLS:向量加法的流水线实现
#include "hls_stream.h"
void vecadd(hls::stream<float> &a, hls::stream<float> &b,
hls::stream<float> &c, int n) {
#pragma HLS INTERFACE axis port=a
#pragma HLS INTERFACE axis port=b
#pragma HLS INTERFACE axis port=c
for (int i = 0; i < n; i++) {
#pragma HLS PIPELINE II=1 // 每周期接受一个新输入
c.write(a.read() + b.read());
}
}
关键 pragma:
| Pragma | 作用 |
|---|---|
PIPELINE II=1 | 流水化循环,每周期启动一次迭代 |
UNROLL | 展开循环,并行多份运算单元 |
ARRAY_PARTITION | 拆分数组,增加访存端口 |
DATAFLOW | 函数级流水,任务并行 |
II=1(Initiation Interval,启动间隔)表示流水线每周期吞一个元素,是吞吐的关键指标。若数据依赖或资源冲突导致 II>1,吞吐直接打折。
OpenCL / oneAPI
更上层的抽象用 OpenCL 或 SYCL/oneAPI 写内核,由工具链综合到 FPGA:
// SYCL 内核(oneAPI for FPGA)
queue.submit([&](handler &h) {
h.parallel_for(range<1>(n), [=](id<1> i) {
out[i] = in1[i] * in2[i] + bias[i];
});
});
抽象越高,可移植性越好但性能调优空间越小。oneAPI 的跨架构愿景(CPU/GPU/FPGA 同一份 SYCL 代码)与 Kokkos 与 oneAPI 可移植编程 的讨论一脉相承。
数据搬运与内存
FPGA 加速的最大瓶颈往往不是计算,而是数据进出。板卡通过 PCIe 与主机通信,带宽有限(PCIe Gen4 x16 约 32 GB/s),而片上计算可能远超此速度。
内存层级
主机 DRAM ──PCIe──> 板卡 DDR/HBM ──> 片上 BRAM/URAM ──> 运算单元
慢 中 快
优化的核心是让数据尽可能靠近运算单元、只搬一次。策略:
- HBM 优先:带 HBM 的加速卡(如 Alveo U280)提供 TB/s 级板载带宽,避免 PCIe 瓶颈。
- 片上缓存:把频繁访问的数据(如卷积核权重)放进 BRAM,复用时不重复访存。
- DMA 流水:用 DMA 引擎在计算的同时预取下一批数据,重叠搬运与计算。
// 用流水线重叠 DMA 与计算(伪代码)
for (int tile = 0; tile < ntiles; tile++) {
#pragma HLS DATAFLOW
dma_read(tile, buf_in); // 预取 tile+1 的数据
compute(buf_in, buf_out); // 计算当前 tile
dma_write(tile, buf_out); // 写回上一 tile 结果
}
流水线与并行度
FPGA 的吞吐 = 并行度 × 时钟频率。提升并行度的手段是循环展开与数据流:
串行循环: 每次迭代 1 个运算,吞吐 = 1/周期
UNROLL=4: 4 个运算单元并行,吞吐 = 4/周期(资源 ×4)
DATAFLOW: 多个阶段流水,各阶段同时工作
资源是硬约束:展开越多,消耗的 DSP/LUT 越多,可能超出芯片容量或导致时序不收敛。调优是在「并行度」与「资源/频率」之间找平衡点。
设计方法论:从算法到电路
把算法搬上 FPGA,需要一次「软件思维到硬件思维」的转换。
识别可流水化的数据流
软件里的循环在硬件里对应流水线。设计的第一步是找出数据依赖链:哪些计算可以重叠,哪些必须等待。
软件循环:
for i: y[i] = a[i]*b[i] + c[i]
(每次迭代独立 → 可完全流水化,II=1)
依赖循环:
for i: y[i] = y[i-1] + a[i]
(存在跨迭代依赖 → 需重构为前缀和或放宽 II)
跨迭代依赖是流水线的天敌,它迫使 II>1,吞吐成倍下降。破解办法是循环变换(如把前缀和改成对数步的并行前缀)。
定点化
FPGA 的 DSP 擅长定点运算,浮点需消耗大量资源。把算法从浮点改到定点,往往能换来数倍资源节省:
分析数据动态范围 → 选定位宽与小数点位置 → 验证精度损失
例如:0~1 的概率值用 Q0.16(16 位小数)表示
定点化的风险是溢出与精度累积,需用软件模型先仿真验证,与 浮点精度 的误差分析方法相通。
空间架构
GPU 是「时间架构」(同一硬件分时执行多线程),FPGA 是「空间架构」(不同硬件单元同时执行)。设计时要把算法的并行性映射到物理空间:
时间架构(GPU):1000 个线程轮流用 128 个核心
空间架构(FPGA):为每个并行分支实例化一份独立电路
这意味着 FPGA 的性能优化是「复制硬件」,受限于芯片资源——并行度不是无限的,要在资源与吞吐间权衡。
典型加速场景
| 领域 | 加速点 | 优势来源 |
|---|---|---|
| 基因组比对 | Smith-Waterman、BLAST 过滤 | 位宽定制、流水线、低延迟 |
| 高频交易 | 行情解析、风控计算 | 纳秒级确定性延迟 |
| 网络处理 | 包分类、正则匹配 | 线速处理、无中断 |
| 信号处理 | FFT、波束成形 | 定点定制、实时流 |
| 机器学习推理 | 量化推理、稀疏 | 任意位宽、低延迟 |
| 密码学 | 哈希、加解密 | 位运算密集、流水线 |
基因组比对的经典案例:Smith-Waterman 动态规划在 CPU 上受限于内存带宽与串行依赖,FPGA 用流水线把 DP 矩阵沿对角线并行计算,配合位宽定制(得分用 8~16 位),能效比可达 CPU 的数十倍。这类「规则、流式、位宽可裁剪」的负载正是 FPGA 的主场。
部分重配置
「可重构」不只是上电时烧一次。动态部分重配置(Dynamic Partial Reconfiguration, DPR) 允许在运行时把芯片的一部分逻辑替换成新功能,其余部分继续运行:
静态区:PCIe 接口、DMA 引擎、内存控制器(始终存在)
动态区:加速内核(可运行时切换,如先跑 FFT 再换 AES)
应用场景:同一块 FPGA 按作业阶段切换加速器——训练阶段用矩阵内核,推理阶段换成量化内核,无需重启。这带来「时分复用」的硬件利用率,但也引入重配置延迟(毫秒级)与设计复杂度(需划分静态/动态区、管理部分比特流)。
部分重配置对多租户云 FPGA 尤其有价值:不同租户的加速器可分时占用同一块芯片,提高利用率。
工具链与生态
| 厂商 | 器件 | 工具链 | 高层抽象 |
|---|---|---|---|
| AMD/Xilinx | Alveo、Versal | Vivado、Vitis | HLS、SYCL |
| Intel/Altera | Stratix、Agilex | Quartus | oneAPI、OpenCL |
| Microchip | PolarFire | Libero | HLS |
| Lattice | 中小规模 | Diamond | - |
主流工作流(以 AMD Vitis 为例):
# 1. HLS 综合内核
v++ -c -t hw --platform xilinx_u250_gen3x16 --kernel vecadd vecadd.cpp -o vecadd.xo
# 2. 链接成比特流
v++ -l -t hw --platform xilinx_u250_gen3x16 vecadd.xo -o vecadd.xclbin
# 3. 主机程序加载并运行
./host vecadd.xclbin
生态的另一面是库与 IP 复用:厂商提供 FFT、矩阵运算、编解码等现成 IP,应用开发者可直接调用,避免从零造轮子。Vitis Libraries 与 oneAPI 的 oneMKL 都在推动这种复用,降低 FPGA 的入门门槛。
与 CPU/GPU 协同
FPGA 很少单独使用,而是作为异构系统的一环:
CPU:控制流、调度、I/O、复杂分支
GPU:大规模规则并行(矩阵乘、深度学习训练)
FPGA:低延迟、流式、定制位宽、确定性任务
例如网络包处理流水线:CPU 管理连接状态,FPGA 做线速过滤与转发,GPU 做深度包检测。三者通过 PCIe/NVLink/网络互联,各司其职。这种异构分工与 SIMD 向量化 在 CPU 上的思路一致——都是「把负载放到最适合的硬件单元上」。
性能与能效评估
评估 FPGA 不能只看峰值算力,而要看端到端指标:
| 指标 | 说明 |
|---|---|
| 吞吐(ops/s) | 流水线深度 × 并行度 × 频率 |
| 延迟(μs/ns) | 数据从进入到离开的时间,含抖动 |
| 能效(ops/W) | FPGA 的杀手锏,常达 GPU 的数倍 |
| 资源利用率 | LUT/DSP/BRAM 占用百分比 |
| 端到端加速比 | 含数据搬运的实测值 |
端到端加速比才是最终裁判。一个计算内核在 FPGA 上比 GPU 快 5 倍,但若数据搬运耗时占 80%,端到端可能反而更慢。因此评估必须包含完整的数据路径,而非孤立的内核。
| 场景 | 推荐硬件 |
|---|---|
| 大规模训练、高吞吐计算 | GPU |
| 低延迟、确定性、流式 | FPGA |
| 通用计算、复杂控制 | CPU |
| 极低位宽推理、能效优先 | FPGA / ASIC |
局限与选型
FPGA 并非万能:
- 开发成本高:HDL/HLS 开发周期以周计,团队门槛高。
- 峰值算力有限:不适合大规模稠密矩阵运算(GPU 的主场)。
- 频率低:通常 200~500 MHz,靠并行度而非频率取胜。
- 编译慢:布局布线可能耗时数小时,迭代成本高。
- 可移植性差:代码与具体芯片绑定,换芯片需重新综合。
选型决策树:
需要低延迟/确定性? ── 是 ──> FPGA
│ 否
需要极高能效且位宽可裁剪? ── 是 ──> FPGA(或 ASIC,量大时)
│ 否
是大规模规则并行? ── 是 ──> GPU
│ 否
──> CPU(多核 + SIMD)
只有当延迟、能效或位宽定制成为决定性因素时,FPGA 的开发成本才划算。把它当作异构工具箱里的一件专用武器,而非通用替代品。
小结
FPGA 用可重构逻辑换取 GPU 无法提供的确定性延迟与极致能效。理解 LUT/DSP/BRAM 的资源模型、HDL 与 HLS 两条开发路径、流水线与数据搬运的优化重心,以及「位宽定制」这一独特优势,你就能判断一个负载是否适合 FPGA。它的短板是开发成本与峰值算力,长处是低延迟、高能效与任意数据宽度。在现代异构系统里,CPU 管控制、GPU 管吞吐、FPGA 管延迟与能效,三者协同而非互替,才是性能与成本的最优解。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。