User: gem5 garnet 的演进,原理,实验的详细教程
Kimi: # gem5 Garnet 片上网络(NoC)详细教程
一、演进历史
1.1 Garnet 的起源与发展
| 版本 | 年份 | 核心特性 |
|---|---|---|
| Garnet (原始版) | 2009 | 5级流水线虚拟通道路由器,由 Niket Agarwal 和 Tushar Krishna 开发 |
| Garnet2.0 | 2016 | 1级流水线,更高可配置性,支持异构 SoC 建模 |
| Garnet3.0 / HeteroGarnet | 2020+ | 支持非对称拓扑、更丰富的路由算法、功耗统计 |
Garnet 是 gem5 Ruby 内存系统内部的周期精确 片上网络(NoC)模型。与 Simple Network 相比,Garnet 能精确建模竞争、路由器资源利用率和功耗统计 。
二、核心原理
2.1 系统架构与组件
Garnet 网络由以下核心组件构成 :
┌─────────────────────────────────────────────────────────┐
│ GarnetNetwork │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ NI │◄──►│ Router │◄──►│ Link │ │
│ │(Network │ │ (5-stage│ │(Network/ │ │
│ │Interface)│ │ pipeline│ │ Credit) │ │
│ └────┬────┘ └─────────┘ └─────────┘ │
│ │ │
│ Cache/Directory Controller │
└─────────────────────────────────────────────────────────┘
关键组件说明:
| 组件 | 功能 | 对应文件 |
|---|---|---|
GarnetNetwork |
顶层对象,实例化所有 NI、路由器和链路 | GarnetNetwork.py / .cc |
NetworkInterface |
连接一致性控制器与路由器,将消息拆分为 flits | NetworkInterface.cc |
Router |
5级流水线虚拟通道路由器,管理仲裁和流控 | Router.cc |
NetworkLink |
传输 flits(数据链路),支持跨时钟域 | NetworkLink.cc |
CreditLink |
传输 VC/缓冲区 credits(流控链路) | CreditLink.cc |
2.2 路由器微架构(5级流水线)
Garnet 路由器采用经典的 5级流水线虚拟通道路由器 :
┌────────────────────────────────────────────────────────────┐
│ BW │ RC │ VA │ SA │ ST │ LT │
│ 写缓冲│路由计算│VC分配│开关分配│开关遍历│链路遍历 │
└────────────────────────────────────────────────────────────┘
各阶段详细说明:
| 阶段 | 全称 | 功能 |
|---|---|---|
| BW | Buffer Write | 输入 flit 被写入对应虚拟通道的缓冲区 |
| RC | Route Compute | 根据路由表计算输出端口(由 RoutingUnit 完成) |
| VA | VC Allocation | 为 HEAD/HEAD_TAIL flit 分配下游 VC |
| SA | Switch Allocation | 输入 VC 竞争交叉开关(先输入仲裁,后输出仲裁) |
| ST | Switch Traversal | 获胜 flit 通过交叉开关 |
| LT | Link Traversal | flit 通过链路到达下一跳路由器 |
默认配置下,BW、RC、VA、SA、ST 均在1个周期内完成,LT 在下一个周期完成。 多周期路由器可通过 router_latency 参数配置 。
2.3 流控机制:虚拟通道(Virtual Channel)
Garnet 采用 Virtual Channel Flow Control :
- 每个虚拟网络(Vnet)包含多个虚拟通道(VC)
- 控制包:默认 1-flit,缓冲区深度 1
- 数据包:默认 5-flit,缓冲区深度 4
- 通过 Credit-based 流控传递缓冲区状态信息
关键参数(在 GarnetNetwork.py 中定义):
python
class GarnetNetwork(RubyNetwork):
ni_flit_size = Param.UInt32(16, "network interface flit size in bytes")
vcs_per_vnet = Param.UInt32(4, "virtual channels per virtual network")
buffers_per_data_vc = Param.UInt32(4, "buffers per data virtual channel")
buffers_per_ctrl_vc = Param.UInt32(1, "buffers per ctrl virtual channel")
routing_algorithm = Param.Int(0, "0: Weight-based Table, 1: XY, 2: Custom")
2.4 拓扑结构
Garnet 利用 Ruby 内存系统的拓扑基础设施,支持任意异构拓扑 。
内置拓扑类型:
| 拓扑 | 描述 | 命令行调用 |
|---|---|---|
Crossbar |
所有控制器通过简单开关连接到中央交叉开关 | --topology=Crossbar |
CrossbarGarnet |
每个控制器通过 Garnet 路由器连接 | --topology=CrossbarGarnet |
Pt2Pt |
每对控制器之间直接链路 | --topology=Pt2Pt |
Mesh_XY |
2D Mesh,XY 路由(先X后Y) | --topology=Mesh_XY --mesh-rows=N |
Mesh_westfirst |
2D Mesh,West-first 路由 | --topology=Mesh_westfirst |
MeshDirCorners_XY |
2D Mesh,目录放在四角 | --topology=MeshDirCorners_XY |
拓扑文件位置 :src/mem/ruby/network/topologies/
2.5 路由算法
Garnet 支持三种路由模式 :
-
基于权重的表路由(默认) :
--routing-algorithm=0- 自动填充最短路径路由表
- 多路径时选择权重最小的链路
-
XY 路由 :
--routing-algorithm=1- 2D Mesh 中先沿 X 方向,再沿 Y 方向
- 实现于
RoutingUnit.cc::outportComputeXY()
-
自定义路由 :
--routing-algorithm=2- 通过
src_outport和dst_inport命名链路方向 - 实现
outportComputeCustom()函数
- 通过
三、实验指南
3.1 环境编译
方式 A:Standalone 模式(纯网络模拟,无 CPU)
Standalone 模式用于研究 NoC 本身,不涉及缓存一致性协议 :
bash
# 1. 配置编译选项
scons defconfig build/NULL build_opts/NULL
scons setconfig build/NULL RUBY_PROTOCOL_GARNET_STANDALONE=y
# 2. 编译
scons build/NULL/gem5.debug -j$(nproc)
# 或使用旧版命令
scons build/Garnet_standalone/gem5.debug PROTOCOL=Garnet_standalone -j$(nproc)
方式 B:集成模式(带 Ruby 一致性协议)
bash
# 例如使用 MESI Two Level 协议
scons build/X86/gem5.opt PROTOCOL=MESI_Two_Level -j$(nproc)
3.2 运行 Synthetic Traffic 实验
Standalone 模式使用合成流量生成器测试网络性能 :
bash
./build/NULL/gem5.debug configs/example/garnet_synth_traffic.py \
--num-cpus=64 \
--num-dirs=64 \
--network=garnet \
--topology=Mesh_XY \
--mesh-rows=8 \
--sim-cycles=100000000 \
--synthetic=uniform_random \
--inj-vnet=2 \
--injectionrate=0.15 \
--router-latency=1 \
--link-latency=1 \
--vcs-per-vnet=4 \
--routing-algorithm=1 \
--sys-clock=1GHz \
--ruby-clock=1GHz \
--link-width-bits=128
合成流量模式(--synthetic):
| 模式 | 描述 |
|---|---|
uniform_random |
每个节点随机选择目标节点 |
transpose |
节点 (i,j) 发送到 (j,i) |
bit_complement |
按位取反确定目标 |
shuffle |
循环移位 |
neighbor |
发送到相邻节点 |
tornado |
发送到 (i+N/2)%N |
3.3 集成 Ruby 协议的完整系统模拟
bash
./build/X86/gem5.opt configs/example/ruby_random_test.py \
--num-cpus=16 \
--num-dirs=16 \
--network=garnet2.0 \
--topology=Mesh_XY \
--mesh-rows=4 \
--vcs-per-vnet=4 \
--router-latency=2 \
--link-latency=1
3.4 关键参数配置表
| 参数 | 说明 | 默认值 |
|---|---|---|
--num-cpus |
源节点(注入节点)数量 | - |
--num-dirs |
目的节点(弹出节点)数量 | - |
--network |
网络模型:simple 或 garnet2.0 |
simple |
--topology |
拓扑结构 | Crossbar |
--mesh-rows |
Mesh 行数(仅 Mesh 拓扑) | 0 |
--router-latency |
路由器流水线级数(≥1) | 1 |
--link-latency |
链路延迟(周期) | 1 |
--vcs-per-vnet |
每个虚拟网络的 VC 数 | 4 |
--link-width-bits |
链路位宽 | 128 |
--routing-algorithm |
0=表路由, 1=XY, 2=自定义 | 0 |
--garnet-deadlock-threshold |
死锁检测阈值(周期) | 50000 |
3.5 结果分析
模拟结束后,在 m5out/ 目录查看 stats.txt,关键指标:
bash
# 网络级统计
grep "packets_injected" m5out/stats.txt
grep "packets_received" m5out/stats.txt
grep "average_packet_latency" m5out/stats.txt
grep "average_packet_queueing_latency" m5out/stats.txt
grep "average_packet_network_latency" m5out/stats.txt
# 路由器级统计(每个路由器)
grep "router.*flits_in" m5out/stats.txt
grep "router.*flits_out" m5out/stats.txt
核心性能指标:
| 指标 | 含义 | 理想值 |
|---|---|---|
average_packet_latency |
平均包延迟(周期) | 越低越好 |
packets_injected |
总注入包数 | 反映负载 |
packets_received |
总接收包数 | 应与注入匹配 |
average_hops |
平均跳数 | 与拓扑相关 |
max_packet_latency |
最大包延迟 | 检测热点/死锁 |
3.6 批量实验脚本示例
以下脚本用于扫描不同注入率下的网络饱和度 :
bash
#!/bin/bash
# run_sweep.sh - 注入率扫描实验
TRAFFICS=("uniform_random" "transpose" "bit_complement")
INJ_RATES=(0.01 0.05 0.10 0.15 0.20 0.25 0.30)
TOPOLOGY="Mesh_XY"
ROWS=8
CPUS=64
DIRS=64
for traffic in "${TRAFFICS[@]}"; do
for inj in "${INJ_RATES[@]}"; do
outdir="results/${traffic}_${inj}"
mkdir -p $outdir
./build/NULL/gem5.debug -re $outdir \
configs/example/garnet_synth_traffic.py \
--num-cpus=$CPUS \
--num-dirs=$DIRS \
--network=garnet \
--topology=$TOPOLOGY \
--mesh-rows=$ROWS \
--sim-cycles=1000000 \
--synthetic=$traffic \
--injectionrate=$inj \
--vcs-per-vnet=4 \
--routing-algorithm=1 \
--link-width-bits=128
# 提取关键结果
latency=$(grep "average_packet_latency" $outdir/stats.txt | awk '{print $2}')
echo "$traffic,$inj,$latency" >> sweep_results.csv
done
done
四、进阶主题
4.1 自定义拓扑
在 src/mem/ruby/network/topologies/ 下创建新的拓扑文件,继承 Topology 类,定义 init() 方法连接 routers、NI 和 links。
4.2 自定义路由
修改 src/mem/ruby/network/garnet/RoutingUnit.cc:
cpp
// 在 outportComputeCustom() 中实现自定义逻辑
int outportComputeCustom(RouteInfo route, int inport, PortDirection direction) {
// 例如:基于下游 VC 空闲状态的自适应路由
int outport = -1;
// ... 自定义算法 ...
return outport;
}
然后使用 --routing-algorithm=2 调用。
4.3 功耗建模
Garnet 可生成路由器功耗统计,需配合 Orion 或 DSENT 等功耗模型库。通过 --enable-power 相关参数启用。
五、常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 早期拥塞(Early Congestion) | VC 数不足、缓冲区太小 | 增加 --vcs-per-vnet 或 buffers_per_data_vc |
| 死锁(Deadlock) | 路由算法无死锁自由保证 | 使用 XY 路由或增加 VC |
| 饱和吞吐量低于理论值 | 链路宽度、路由器延迟配置 | 检查 --link-width-bits 和 --router-latency |
| 编译错误 | 协议选择错误 | 确认 RUBY_PROTOCOL_GARNET_STANDALONE=y |
参考资源
- Georgia Tech Garnet 页面:http://synergy.ece.gatech.edu/garnet
- gem5 官方文档:https://www.gem5.org/documentation/general_docs/ruby/garnet-2/
- Garnet2.0 教程幻灯片(ARM Research Summit 2017):详细讲解微架构和配置
- GitHub NoC Tutorial:https://github.com/xinchen13/gem5-noc 提供中文实践指南