在 Hyak 上构建可复现的稀疏矩阵基准
SparseBench++ 一开始是一个正确性优先的稀疏矩阵基准测试框架,而不是一个急着声称新 SpMV kernel 比成熟库更快的项目。第一个有用目标更窄,也更实际:把一个 C++ CSR SpMV 实现,从仓库内的小型测试矩阵推进到华盛顿大学研究计算集群 Hyak 上的真实 SuiteSparse 输入,同时不丢失到底运行了什么的证据链。
这个定位很重要,因为性能数字很容易被讲过头。如果数据路径不清楚,批处理作业悄悄用了 fallback 矩阵,或者结果目录无法追溯到某个 commit,那么看起来很快的 benchmark 也没有什么价值。现在这个项目已经有了一条可追踪路径:从 parser 测试,到 Slurm 作业,到 CSV 输出,到分析摘要,再到报告图表。
从小型测试矩阵到真实矩阵
最早的测试数据是 data/tiny/ 下刻意做得很小的 Matrix Market 文件。它们让 parser 行为容易验证,也让本地 CTest 保持便宜。这个选择后来很有用:等 Slurm 流程跑通之后,SuiteSparse 下载器暴露了真正的 parser 边界。第一批小型 SuiteSparse 矩阵并不全是 coordinate real general。
这推动 parser 从最初的窄格式扩展到当前 v0.1.1 覆盖范围:
coordinate real generalcoordinate integer generalcoordinate pattern generalcoordinate real symmetric
不支持的 Matrix Market 变体仍然会失败,而不是被静默误读。这不如“什么都支持”听起来漂亮,但对 benchmark 框架来说是正确默认值。错误的输入处理会污染后续每一个计时数字,而这种失败应该尽早、明确地暴露出来。
Slurm 是 gate,不只是 launcher
Hyak 脚本逐渐变成了 gate,而不只是 launcher。真正的 benchmark 作业会验证 manifest,拒绝 diag5.mtx fallback 输入,在计算节点上构建,运行 CTest,然后才输出 CSV。
中等规模 scaling 运行使用的 manifest 是:
/gscratch/scrubbed/junyej/sparsebench/data/medium_matrices.txt
它包含六个 SuiteSparse 矩阵:cant、consph、cop20k_A、mac_econ_fwd500、mc2depi 和 pdb1HYS。同一个 manifest 现在同时作为 96-core SparseBench scaling run 和 32-core Eigen comparison 的受控输入。
96-core SparseBench scaling
Job 34825519 在 cpu-g2-mem2x 上运行 SparseBench CSR SpMV 路径,分配了 96 个 CPU,线程数为 1,2,4,8,16,32,64,96。它完成时 CTest 为 3/3,stderr 为空,并产生了 48 个 CSV 文件。
这个结果有价值,但它不是一个线性 scaling 的故事。最佳观测 speedup 范围是 1.693x 到 2.123x,而且每个矩阵都在 96 线程之前达到峰值。efficiency 图从另一个角度说明了同一件事:这个 CSR SpMV 路径主要受内存流量和稀疏模式影响,而不是受浮点吞吐限制。
这个阶段最重要的结果不是“速度故事”本身,而是 benchmark 路径在机械流程上已经成立。同一套 build、test、manifest 和 CSV pipeline 现在可以承载后续实验,而不需要读者相信某个手工整理的表格。
加入一个真实 baseline
在 SparseBench-only scaling 运行之后,下一个有用问题并不是 SparseBench 单独看起来是否“快”。更有意义的问题是:在同一套 manifest discipline 下,当前实现和一个成熟 sparse backend 在同一批输入上相比如何。
Job 34852262 在 cpu-g2 上加入了 Eigen baseline。它使用 SPARSEBENCH_USE_EIGEN=ON 构建,加载 cesg/eigen/3.3.9,在同六个矩阵上运行两个 backend,并针对线程数 1,2,4,8,16,32 产生了 72 个成对 CSV 文件。
在这次运行中,Eigen 赢下了全部 36/36 个矩阵/线程组合的 median-time 对比。这是一个有用的工程信号,不是失败。它说明当前 SparseBench 路径已经足够稳定,可以进行诚实对比,也给出了具体的优化目标,而不是停留在“应该还能更快”的感觉上。
Eigen 运行被明确标记为 32-core cpu-g2 comparison。它不是待完成的 192-core cpu-g2-mem2x probe 的证据,它的绝对时间也不应该和单独的 mem2x scaling job 混在一起解释。
仍然 pending 的内容
192-core probe 是 job 34851174。它仍然因为 QOSGrpCpuLimit 处于 pending 状态,没有 allocation,也没有产生结果 CSV。在它完成并通过同样检查之前,不应该把它纳入 benchmark claim。这些检查包括:Slurm COMPLETED 0:0、干净的 stderr、CTest,以及预期的矩阵/线程覆盖。
下一步
最直接的下一步是保存证据:34852262 Eigen evidence 位于 /gscratch/scrubbed,这是会被清理的 scratch 空间。它应该在存储被清理前被打包或镜像。
之后路径很清楚:
- 持续跟踪 192-core probe,并且只在它干净完成后报告。
- 在 Eigen 路径稳定后,加入更多外部 baseline。
- 继续使用当前 report pipeline 生成未来图表,而不是手动复制 raw data。
- 等 SpMV 报告流程变得稳定且可重复之后,再推进 CG 和 Lanczos。
这次工作的主要经验是:项目还很小,Eigen 在当前 measured comparisons 里更快,但证据链已经足够扎实,可以继续在其上构建。这正是这个阶段最需要拿到的结果。