4.1 基准测试套件
核心内容:
- ✅ Rodinia基准测试
- 专注于GPU计算的基准测试套件
- 包含多种并行算法
- ✅ Parboil基准测试
- 专注于GPGPU优化的基准测试
- 包含实际应用案例
- ✅ CUDA SDK示例
- NVIDIA官方示例程序
- 覆盖各种CUDA特性
- ✅ 自定义测试程序
- 根据研究需求编写
- 针对特定架构特性
Rodinia基准测试:
# 获取Rodinia
git clone https://github.com/gunrock/rodinia.git
cd rodinia
# 编译CUDA版本
cd cuda/backprop
make
# 在Gem5中运行
./build/GPU/gem5.opt configs/example/gpu_ruby.py \
--cmd=./backprop \
--options="10000 100"
常用Rodinia程序:
表格
| 程序 | 描述 | 复杂度 |
|---|---|---|
| backprop | 神经网络反向传播 | 简单 |
| bfs | 广度优先搜索 | 中等 |
| cfd | 计算流体力学 | 复杂 |
| heartwall | 医学图像处理 | 复杂 |
| hotspot | 热点分析 | 中等 |
| lavaMD | 分子动力学 | 复杂 |
| nw | Needleman-Wunsch序列比对 | 中等 |
| particlefilter | 粒子滤波 | 中等 |
Parboil基准测试:
# 获取Parboil
git clone https://github.com/parboil/parboil.git
cd parboil
# 编译和运行
cd benchmarks/stencil
make CUDA
./stencil_default_cuda
实践建议:
- ✅ 从简单的程序开始(backprop, hotspot)
- ✅ 逐步尝试复杂程序(cfd, heartwall)
- ✅ 记录每个程序的性能数据
- ✅ 分析性能瓶颈
4.2 性能分析
核心内容:
- ✅ stats.txt解析
- 理解统计指标含义
- 提取关键性能数据
- ✅ gpu_stats.txt分析
- GPU特定统计信息
- SM利用率分析
- ✅ 性能瓶颈识别
- 内存带宽瓶颈
- 计算资源瓶颈
- 同步开销分析
- ✅ 多维度性能对比
- 不同配置对比
- 不同程序对比
- 不同架构对比
关键性能指标:
# stats.txt中的重要指标
cpu.ipc # 指令每周期
cpu.numCycles # 总周期数
cpu.numInsts # 总指令数
system.l1dcache.overall_miss_rate::total # L1D缓存失效率
system.l2cache.overall_miss_rate::total # L2缓存失效率
system.mem_ctrls.avg_mem_lat # 平均内存延迟
gpu.sm_occupancy # SM占用率(GPU)
gpu.kernel_time # 内核执行时间
gpu.memory_bandwidth # 内存带宽
Python分析脚本:
#!/usr/bin/env python3
# stats_analyzer.py
import re
import pandas as pd
import matplotlib.pyplot as plt
class StatsAnalyzer:
def __init__(self, stats_file):
self.stats_file = stats_file
self.data = {}
def parse_stats(self):
"""解析stats.txt文件"""
with open(self.stats_file, 'r') as f:
for line in f:
# 匹配统计行:metric value # comment
match = re.match(r'(\S+)\s+([\d\.e\+\-]+)\s+#\s+(.+)', line)
if match:
metric = match.group(1)
value = float(match.group(2))
comment = match.group(3)
self.data[metric] = {'value': value, 'comment': comment}
def get_metric(self, metric_name):
"""获取特定指标"""
if metric_name in self.data:
return self.data[metric_name]['value']
return None
def print_summary(self):
"""打印关键指标摘要"""
print("=" * 60)
print("Gem5 Simulation Performance Summary")
print("=" * 60)
metrics = {
'cpu.ipc': 'IPC',
'system.cpu.numCycles': 'Total Cycles',
'system.cpu.numInsts': 'Total Instructions',
'system.l1dcache.overall_miss_rate::total': 'L1D Miss Rate',
'system.l2cache.overall_miss_rate::total': 'L2 Miss Rate',
}
for metric, desc in metrics.items():
value = self.get_metric(metric)
if value is not None:
print(f"{desc:30s}: {value:.4f}")
print("=" * 60)
def plot_metrics(self, metrics_list, title="Performance Metrics"):
"""绘制指标图表"""
values = [self.get_metric(m) for m in metrics_list]
names = [m.split('.')[-1] for m in metrics_list]
plt.figure(figsize=(10, 6))
plt.bar(names, values)
plt.title(title)
plt.ylabel('Value')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('performance_metrics.png')
print("Chart saved as performance_metrics.png")
# 使用示例
if __name__ == "__main__":
analyzer = StatsAnalyzer('m5out/stats.txt')
analyzer.parse_stats()
analyzer.print_summary()
# 绘制缓存失效率
cache_metrics = [
'system.l1dcache.overall_miss_rate::total',
'system.l1icache.overall_miss_rate::total',
'system.l2cache.overall_miss_rate::total'
]
analyzer.plot_metrics(cache_metrics, "Cache Miss Rates")
GPU性能分析:
# gpu_stats_analyzer.py
class GPUStatsAnalyzer:
def __init__(self, gpu_stats_file):
self.gpu_stats_file = gpu_stats_file
self.gpu_data = {}
def parse_gpu_stats(self):
"""解析gpu_stats.txt"""
with open(self.gpu_stats_file, 'r') as f:
for line in f:
parts = line.strip().split()
if len(parts) >= 2:
metric = parts[0]
try:
value = float(parts[1])
self.gpu_data[metric] = value
except ValueError:
pass
def analyze_sm_utilization(self):
"""分析SM利用率"""
total_cycles = self.gpu_data.get('gpu_total_cycles', 0)
active_cycles = self.gpu_data.get('gpu_active_cycles', 0)
if total_cycles > 0:
utilization = (active_cycles / total_cycles) * 100
print(f"GPU SM Utilization: {utilization:.2f}%")
# 分析warp状态
warp_metrics = {
'active_warps': 'Active Warps',
'stalled_warps': 'Stalled Warps',
'eligible_warps': 'Eligible Warps'
}
print("\nWarp Distribution:")
for metric, desc in warp_metrics.items():
value = self.gpu_data.get(metric, 0)
print(f" {desc:20s}: {value}")
性能瓶颈识别方法:
- 高缓存失效率 → 内存子系统瓶颈
- 解决方案:增加缓存大小,优化缓存策略
- 低IPC → CPU计算瓶颈
- 解决方案:优化算法,减少分支预测失败
- 高内存延迟 → 内存带宽瓶颈
- 解决方案:优化内存访问模式,使用预取
- 低SM利用率 → GPU计算瓶颈
- 解决方案:增加并行度,优化warp调度
4.3 修改与实验
实践项目:
项目1:修改GPU SM数量
# 修改GPU配置
system.gpu.num_SM = 8 # 默认可能是4或16
system.gpu.warp_size = 32 # 可以尝试16或64
项目2:调整缓存大小
# 修改缓存配置
class L1Cache(Cache):
size = '64kB' # 尝试32kB, 128kB
assoc = 8 # 尝试4, 16
tag_latency = 1
data_latency = 1
class L2Cache(Cache):
size = '256kB' # 尝试512kB, 1MB
assoc = 16
tag_latency = 10
data_latency = 10
项目3:更改一致性协议
# 在配置脚本中
system.ruby.protocol = "VI_hammer" # 或 "MOESI_hammer"
项目4:对比不同配置性能
# 创建实验脚本
#!/bin/bash
# run_experiments.sh
configs=("config_sm4.py" "config_sm8.py" "config_sm16.py")
programs=("backprop" "hotspot" "nw")
for config in "${configs[@]}"; do
for prog in "${programs[@]}"; do
echo "Running $prog with $config"
./build/GPU/gem5.opt $config --cmd=$prog > results/${config}_${prog}.log
done
done
项目5:自定义实验设计
# parameter_sweep.py
import subprocess
import json
# 参数扫描实验
sm_counts = [4, 8, 16, 32]
cache_sizes = ['64kB', '128kB', '256kB']
results = {}
for sm_count in sm_counts:
for cache_size in cache_sizes:
config_file = f"config_sm{sm_count}_cache{cache_size}.py"
# 生成配置文件(略)
# 运行模拟
cmd = f"./build/GPU/gem5.opt {config_file} --cmd=backprop"
result = subprocess.run(cmd, shell=True, capture_output=True)
# 解析结果
# (略)
results[f"SM{sm_count}_Cache{cache_size}"] = performance_data
# 保存结果
with open('experiment_results.json', 'w') as f:
json.dump(results, f, indent=2)
实验记录模板
# 实验记录:GPU SM数量对性能的影响
## 实验目的
研究不同SM数量对GPU程序性能的影响
## 实验配置
- CPU: TimingSimpleCPU x 1
- GPU SM: 4, 8, 16, 32
- L1 Cache: 64kB
- L2 Cache: 256kB
- Memory: 4GB DDR4
## 测试程序
- backprop (Rodinia)
- hotspot (Rodinia)
- nw (Rodinia)
## 结果数据
| SM数量 | backprop (cycles) | hotspot (cycles) | nw (cycles) |
|--------|-------------------|------------------|-------------|
| 4 | 1,234,567 | 2,345,678 | 3,456,789 |
| 8 | 856,432 | 1,567,890 | 2,345,678 |
| 16 | 623,456 | 1,123,456 | 1,678,901 |
| 32 | 589,123 | 987,654 | 1,456,789 |
## 分析结论
1. 增加SM数量显著提升性能
2. 性能提升呈现边际递减效应
3. 对于计算密集型程序(nw),SM数量影响更大