4. 基准测试工具链与环境搭建
性能基准测试的可信度,首先取决于工具链是否选对、环境是否可控。同一段代码在不同编译器、不同驱动、不同频率策略下可能相差数倍,若工具链与环境没有固定,测出的数字就无法横向比较,更无法用于优化决策。本节围绕四类主流框架——Google Benchmark、CUDA Samples、rocBLAS、STREAM——说明各自定位与最小可运行示例,并给出 CPU/GPU 异构环境的可重复性配置要点。
四类框架的定位与分工
Google Benchmark 是 C++ 微基准框架,擅长对单个函数或小段代码做纳秒级计时,自动处理预热、迭代次数自适应、统计方差,并支持参数化扫描与 JSON 输出,适合 CPU 侧算法与内核的细粒度对比。CUDA Samples 是 NVIDIA 官方示例集合,其中 bandwidthTest、deviceQuery、matrixMul 等既是教学样例也是快速体检工具,适合验证 GPU 是否可用、显存带宽与计算能力是否达到预期。rocBLAS 是 AMD ROCm 平台的 BLAS 实现,自带 benchmark 客户端,可对 SGEMM、DGEMM 等做规模扫描,用于评估 GPU 浮点吞吐。STREAM 则是内存带宽基准的经典实现,通过 Copy、Scale、Add、Triad 四个内核测量可持续访存带宽,是判断“是否受内存带宽限制”的第一道标尺。
Google Benchmark:CPU 微基准的最小闭环
以测量一个向量点积为例,先写基准函数,再用 BENCHMARK 注册并指定迭代范围。框架会自动决定运行次数,使单次测量时长落在合理区间,并输出中位数与标准差。
#include <benchmark/benchmark.h>
#include <vector>
static void BM_DotProduct(benchmark::State& state) {
std::vector<float> a(state.range(0), 1.0f), b(state.range(0), 2.0f);
for (auto _ : state) {
float sum = 0.0f;
for (size_t i = 0; i < a.size(); ++i) sum += a[i] * b[i];
benchmark::DoNotOptimize(sum);
}
state.SetBytesProcessed(state.iterations() * state.range(0) * sizeof(float) * 2);
}
BENCHMARK(BM_DotProduct)->RangeMultiplier(4)->Range(1<<10, 1<<24);
BENCHMARK_MAIN();
编译时使用 -O2 -DNDEBUG 并链接 benchmark 库,运行后得到每个规模下的耗时与 GB/s。关键判断:当规模增大而 GB/s 趋于平台,说明已进入内存带宽受限区;若 GB/s 随规模持续上升,则仍受循环开销或缓存未命中影响。示例中 DoNotOptimize 防止编译器把求和优化掉,这是微基准最常见的陷阱。
CUDA Samples 与 rocBLAS:GPU 侧体检与算力扫描
GPU 环境先做体检:运行 deviceQuery 确认设备可见、计算能力与显存容量符合预期;再运行 bandwidthTest 得到主机到设备、设备到主机的实测带宽,与理论值(如 HBM 带宽)对比,若实测不足理论值的六成,应排查 PCIe 代际、驱动或 ECC 配置。算力侧可用 matrixMul 或 rocBLAS 客户端做规模扫描:
# rocBLAS 自带客户端示例(AMD ROCm)
./rocblas-bench -f gemm -r f32_r --m 4096 --n 4096 --k 4096 \
--alpha 1 --beta 0 --transA N --transB N --iters 100
输出中的 GFLOPS 应与设备峰值浮点吞吐对照。示例假设某卡 FP32 峰值为 20 TFLOPS,若 4096³ 规模实测约 14 TFLOPS,则达到峰值七成,属正常范围;若仅 3 TFLOPS,需检查是否误用 FP64 路径、是否受显存容量限制导致分块过小。规模扫描的意义在于找到“算力饱和点”,小于该规模的矩阵乘法更多反映启动开销而非硬件能力。
STREAM:先判断是否受带宽限制
STREAM 的 Triad 内核 a[i]=b[i]+scalar*c[i] 最接近真实科学计算访存模式。编译时需根据 CPU 支持选择向量化选项,并把数组大小设为远大于末级缓存(例如每数组 512 MB),线程数设为物理核数并绑核。运行后取多次结果中稳定值,与内存理论带宽比较:若 Triad 带宽接近理论值七成以上,说明访存效率良好;若明显偏低,应检查 NUMA 跨节点访问、内存通道是否插满、是否被其他进程抢占。
可重复性配置清单
把上述工具串成可复现流程,需要固定以下变量并随结果一同归档:编译器版本与优化选项、CUDA/ROCm 与驱动版本、CPU 绑核与频率策略(如 cpupower frequency-set -g performance)、GPU 时钟锁定与功耗上限、运行次数与统计口径(取中位数还是最小值)、以及基线版本号。建议每次测试至少运行 5 次,剔除首次冷启动,报告均值与波动率;波动率超过 5% 时先排查环境抖动,再解读性能差异。只有工具、环境、口径三者同时固定,基准数据才具备跨版本、跨平台比较的资格。