本章深入探讨近存储计算(Processing-in-Memory, PIM)和近数据处理(Processing-near-Data, PND)架构,这是解决”内存墙”问题的革命性方案。我们将分析如何通过将计算单元集成到内存系统中,大幅减少数据移动开销,提升系统能效比。重点介绍Samsung HBM-PIM、SK Hynix AiM等工业界先进实现,以及在AI推理、图计算等应用中的实践。
学习目标:
过去几十年,处理器性能以每年约60%的速度增长,而DRAM访问延迟仅以每年7%的速度改善。这种差距导致了严重的”内存墙”问题:
性能差距 = (1.6)^n / (1.07)^n ≈ (1.5)^n
其中n为年数
数据移动能耗已成为系统功耗的主要来源:
1. 真PIM(True PIM) 将逻辑单元直接集成在存储阵列内部:
┌──────────────────────────┐
│ Memory Array │
│ ┌────┬────┬────┬────┐ │
│ │Cell│Cell│Cell│Cell│ │
│ ├────┼────┼────┼────┤ │
│ │ ALU│ ALU│ ALU│ ALU│ │ ← 计算单元
│ ├────┼────┼────┼────┤ │
│ │Cell│Cell│Cell│Cell│ │
│ └────┴────┴────┴────┘ │
│ Sense Amplifiers │
└──────────────────────────┘
2. 近数据处理(PND) 在内存控制器或基础逻辑层集成计算单元:
┌──────────────────────────┐
│ DRAM Die Stack │
├──────────────────────────┤
│ Through Silicon Vias │
├──────────────────────────┤
│ Logic Base Die │ ← 计算层
│ ┌─────────────────────┐ │
│ │ Processing Units │ │
│ │ Cache & Controllers │ │
│ └─────────────────────┘ │
└──────────────────────────┘
第一代(1990s):
第二代(2000s):
第三代(2010s-至今):
Samsung HBM-PIM在HBM2 Aquabolt基础上,在每个伪通道(Pseudo Channel)集成了一个SIMD处理单元:
┌─────────────────────────────────────┐
│ Host Processor │
├─────────────────────────────────────┤
│ Memory Controller │
└────────┬───────────────────┬────────┘
│ 1024-bit Bus │
┌────────▼───────────────────▼────────┐
│ HBM-PIM Stack │
│ ┌──────────────────────────────┐ │
│ │ DRAM Die 7 (4GB) │ │
│ ├──────────────────────────────┤ │
│ │ DRAM Die 6 (4GB) │ │
│ ├──────────────────────────────┤ │
│ │ ... │ │
│ ├──────────────────────────────┤ │
│ │ DRAM Die 0 (4GB) │ │
│ ├──────────────────────────────┤ │
│ │ Buffer/Logic Die │ │
│ │ ┌────────────────────────┐ │ │
│ │ │ 16 × PIM Units │ │ │
│ │ │ (2 per PC) │ │ │
│ │ └────────────────────────┘ │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────┘
每个PIM单元包含:
PIM Unit微架构:
┌─────────────────────────────────┐
│ To Memory Banks │
└────────────┬────────────────────┘
│ 256-bit
┌────────────▼────────────────────┐
│ Data Buffer (2KB) │
├─────────────────────────────────┤
│ ┌─────────┐ ┌─────────┐ │
│ │ FP16 │ │ INT8 │ │
│ │ MAC │ │ ALU │ │
│ └────┬────┘ └────┬────┘ │
│ │ │ │
│ ┌────▼────────────▼────┐ │
│ │ Register File (8×) │ │
│ └───────────────────────┘ │
├─────────────────────────────────┤
│ Instruction Buffer │
└─────────────────────────────────┘
计算能力:
带宽利用:
内部带宽 = 16 channels × 128-bit × 2 (DDR) × 1.2GHz
= 16 × 128 × 2 × 1.2 × 10^9 / 8
= 614.4 GB/s (per stack)
HBM-PIM的逻辑层必须在有限的面积和功耗预算内实现高效计算:
面积约束:
功耗预算:
总功耗预算 = 15W (典型HBM功耗)
PIM计算功耗 = 5W
内存访问功耗 = 8W
IO功耗 = 2W
1. SIMD宽度选择
宽度选择影响性能和面积:
性能 ∝ SIMD_width × 频率
面积 ∝ SIMD_width × log(SIMD_width) // 考虑互联复杂度
Samsung选择16-wide SIMD的原因:
2. 数据精度支持
支持多种精度的权衡:
面积开销比例:
FP16 MAC: 1.0×
INT8 MAC: 0.3×
BF16 MAC: 0.8×
混合精度: 1.5× (支持全部)
PIM架构支持三种访问模式:
1. 批处理模式(Batch Mode)
for batch in batches:
load_weights_to_pim() // 一次加载
for data in batch:
compute_in_pim(data) // 多次复用
store_results()
2. 流式处理模式(Streaming Mode)
while (data_available):
fetch_next_block() // 流水线取数
process_in_pim() // 并行计算
write_back_results() // 异步写回
3. 分块计算模式(Tiled Mode)
将大矩阵分块以适应PIM容量:
Matrix_size = M × N
Tile_size = m × n (受限于local buffer)
Tiles = ⌈M/m⌉ × ⌈N/n⌉
1. 指令集架构(ISA)
PIM-ISA包含以下指令类型:
// 数据移动指令
PIM_LOAD reg, mem_addr // 从DRAM加载到寄存器
PIM_STORE mem_addr, reg // 从寄存器存储到DRAM
// 计算指令
PIM_MAC dst, src1, src2 // 乘累加操作
PIM_ADD dst, src1, src2 // 向量加法
PIM_MUL dst, src1, src2 // 向量乘法
// 控制指令
PIM_SYNC // 同步屏障
PIM_FENCE // 内存屏障
2. 编程接口
高级API示例:
// C++ API示例
class PIMTensor {
public:
void gemm(const PIMTensor& A, const PIMTensor& B) {
// 自动分块和调度到PIM单元
auto tiles = partition(A, B);
for (auto& tile : tiles) {
schedule_to_pim(tile);
}
synchronize();
}
};
PIM编译器需要解决的关键问题:
1. 计算映射
原始代码:
for i in range(M):
for j in range(N):
for k in range(K):
C[i][j] += A[i][k] * B[k][j]
PIM优化后:
parallel_for pim_unit in [0..15]:
local_M = M / 16
for i in range(local_M):
pim_mac(C[pim_unit][i], A[i], B)
2. 数据布局优化
优化内存布局以最大化PIM并行性:
传统行主序:A[i][j] → memory[i*N + j]
PIM优化布局:A[i][j] → memory[channel][bank][row][col]
其中channel映射到PIM单元
1. 任务调度器
class PIMScheduler {
queue<PIMTask> ready_queue;
array<PIMUnit, 16> pim_units;
void schedule() {
while (!ready_queue.empty()) {
auto task = ready_queue.front();
auto unit = find_idle_unit();
if (unit != nullptr) {
dispatch(task, unit);
ready_queue.pop();
}
}
}
};
2. 内存管理
class PIMMemoryManager {
// 维护PIM可访问内存池
unordered_map<void*, PIMMemoryRegion> pim_regions;
void* allocate_pim_memory(size_t size) {
// 分配在PIM可访问的地址范围
auto region = find_free_region(size);
mark_as_pim_accessible(region);
return region.base_addr;
}
};
1. BERT推理优化
BERT-Base模型参数:
PIM加速关键操作:
// Attention计算
Q = Input × W_q // 适合PIM
K = Input × W_k // 适合PIM
V = Input × W_v // 适合PIM
Attention = softmax(Q × K^T) × V
性能提升:
- 矩阵乘法:2.7×
- 整体推理:1.8×
- 能效比:2.2×
2. CNN推理优化
ResNet-50在ImageNet上的推理:
卷积层计算密度:
FLOPS/Byte = (K × K × C_in) / (K × K × C_in × 4 + C_out × 4)
≈ 0.25 (低算术强度,适合PIM)
PIM优化策略:
- 权重驻留在PIM本地
- 输入特征图流式处理
- 部分和在PIM内累加
1. PageRank算法
传统实现伪代码:
for iteration in range(max_iter):
for v in vertices:
rank[v] = 0.15 + 0.85 * sum(rank[u]/out_degree[u]
for u in predecessors[v])
PIM优化:
- 邻接表存储在PIM本地
- 并行更新多个顶点
- 减少随机访问开销
性能提升:3.2× (对于大规模稀疏图)
2. 图神经网络(GNN)
GCN前向传播:
H^(l+1) = σ(D^(-1/2) × A × D^(-1/2) × H^(l) × W^(l))
PIM优化点:
- 稀疏矩阵乘法
- 特征聚合操作
- 邻居采样
加速比:2.5-4.0× (取决于图稀疏度)
稀疏矩阵求解器
SpMV操作(y = A × x):
传统实现内存访问模式:
- 不规则访问x向量
- 顺序访问A的非零元素
PIM优化:
- x向量分布存储
- 本地计算部分结果
- 减少全局归约
性能提升矩阵:
矩阵类型 加速比
带状矩阵 1.5×
随机稀疏 2.8×
幂律分布 3.5×
PIM系统需要解决的一致性问题:
1. PIM与主处理器的一致性
场景:CPU和PIM同时访问相同数据
解决方案:
- 弱一致性模型 + 显式同步
- 基于区域的一致性协议
- 版本化内存管理
2. 多PIM单元间的一致性
CPU
│
├──────┬──────┬──────┐
│ │ │ │
PIM0 PIM1 PIM2 PIM3
│ │ │ │
└──────┴──────┴──────┘
Coherence Bus
协议选择:
- 基于目录的协议(开销大)
- 基于令牌的协议(延迟高)
- 软件管理一致性(灵活性高)
1. 内存围栏(Memory Fence)
// PIM操作前后的围栏
void pim_compute_safe(void* data, size_t size) {
memory_fence(); // 确保之前的写入完成
pim_execute(data, size); // PIM计算
memory_fence(); // 确保PIM结果可见
}
2. 原子操作支持
PIM原子操作实现:
- Compare-and-Swap (CAS)
- Fetch-and-Add
- 原子归约操作
硬件支持:
- 锁定内存行
- 事务内存扩展
- 版本缓冲区
地址转换挑战:
传统TLB无法支持PIM访问模式
解决方案:
1. PIM-TLB设计
- 更大的页面(2MB/1GB)
- 预取机制
- 共享TLB结构
2. 段式内存管理
- 连续物理内存分配
- 减少转换开销
SK Hynix的AiM(Accelerator in Memory)采用了不同于Samsung的设计理念:
AiM-HBM架构:
┌────────────────────────────────┐
│ GDDR6 Interface │
├────────────────────────────────┤
│ AI Processing Unit (APU) │
│ ┌───────────────────────────┐ │
│ │ 512 RISC-V Cores │ │
│ │ @ 1.25 GHz │ │
│ └───────────────────────────┘ │
├────────────────────────────────┤
│ 16GB HBM3 Stack │
└────────────────────────────────┘
关键特性:
- 512个RISC-V核心
- 1.25 GHz运行频率
- 16 TFLOPS (FP16)
- 1.2 TB/s内部带宽
AiM编程特点:
// 基于数据流的编程模型
class AiMKernel {
void execute() {
// 自动数据分区
auto partitions = data_flow_partition(input);
// 并行执行在512个核心上
parallel_for(auto& p : partitions) {
local_compute(p);
}
// 硬件加速的归约
hardware_reduce(partitions);
}
};
基准测试结果对比:
| 工作负载 | Samsung HBM-PIM | SK Hynix AiM | 传统GPU+HBM |
|---|---|---|---|
| GEMM | 1.0× | 1.8× | 0.5× |
| SpMV | 2.3× | 2.1× | 1.0× |
| BERT | 1.8× | 2.2× | 1.0× |
| GCN | 2.5× | 3.1× | 1.0× |
| 功耗 | 35W | 40W | 150W |
SK Hynix AiM的软件栈:
应用层: TensorFlow | PyTorch | ONNX
─────────────────────────────
框架层: AiM Runtime API
─────────────────────────────
编译器: MLIR-based Compiler
─────────────────────────────
驱动层: AiM Device Driver
─────────────────────────────
硬件层: AiM-HBM Hardware
第四代PIM预期特性:
性能目标(2025-2027):
计算密度:100 TFLOPS/stack
能效比:10 TFLOPS/W
内存容量:64GB/stack
带宽:2 TB/s
JEDEC PIM标准化:
近存储计算架构通过将计算能力集成到内存系统中,从根本上改变了传统的冯·诺依曼架构限制。关键要点:
关键公式总结:
1. PIM架构分类 描述真PIM和近数据处理(PND)的区别,并给出各自的优缺点。
2. 性能计算 假设一个矩阵乘法C = A × B,其中A、B、C都是1024×1024的FP16矩阵。计算: a) 传统架构的数据移动量 b) PIM架构的数据移动量(假设权重驻留) c) 能耗节省比例(假设数据移动功耗是计算的20倍)
3. SIMD宽度选择 解释为什么Samsung HBM-PIM选择16-wide SIMD而不是32-wide或8-wide。
4. 一致性协议设计 设计一个简化的PIM系统一致性协议,支持CPU和多个PIM单元同时访问共享数据。要求:
5. 编译器优化 给定以下代码,展示如何将其优化以在PIM上高效执行:
# 稀疏矩阵向量乘法
for i in range(n):
for j in row_ptr[i]:row_ptr[i+1]:
y[i] += val[j] * x[col_idx[j]]
6. 应用场景分析 分析以下哪些应用最适合PIM加速,并说明原因: a) 密集矩阵LU分解 b) 图的广度优先搜索 c) 快速傅里叶变换 d) K-means聚类
7. 性能建模 建立一个PIM系统的性能模型,考虑:
8. 未来架构设想 设计一个理想的下一代PIM架构,包括: