1. 项目概述:为什么需要HPL与HPCG?
如果你在折腾高性能计算(HPC),或者刚拿到一台新服务器想摸摸它的“底”,那你大概率听说过这两个名字:HPL和HPCG。它们就像是给超级计算机做体检的“血压计”和“心电图”,一个测峰值性能,一个测实际应用潜力。HPL,全称High-Performance Linpack,是衡量系统理论浮点计算能力的黄金标准,TOP500榜单就靠它排名。而HPCG,全称High-Performance Conjugate Gradient,则更贴近真实科学计算应用中的稀疏矩阵求解性能,能反映出内存带宽、延迟对实际算力的影响。
光跑一个HPL,你看到的可能是一个漂亮的、理论上的“天花板”分数。但加上HPCG,你才能知道这台机器在应对更复杂、数据访问模式更不规则的现实问题时,到底能发挥出几成功力。对于系统管理员、HPC应用开发者,甚至是采购硬件的决策者,同时安装并测试这两者,是评估系统综合性能、发现潜在瓶颈(比如内存墙、通信效率)的必备操作。这不仅仅是跑个分那么简单,它关乎你后续所有计算任务的效率预估和资源调优。
2. 环境准备与依赖解析
在开始编译安装之前,一个干净、一致且依赖完备的基础环境是成功的一半。很多人卡在编译错误上,根源往往就是依赖没装全或者版本冲突。
2.1 系统环境与基础工具
首先,确保你在一个典型的Linux HPC环境上操作,比如CentOS/RHEL 7/8、Rocky Linux、Ubuntu 20.04/22.04 LTS等。你需要拥有sudo权限来安装系统级的开发包。
核心的基础工具链必须就位:
- 编译器:GCC(建议7.3以上)或Intel编译器套件(icc/icpc/ifort)。对于追求极致性能,尤其是Intel平台,后者通常是首选,但GCC更通用。本文将以GCC为例,兼顾通用性。
- MPI库:消息传递接口,用于多节点并行计算。主流选择有OpenMPI、MPICH和Intel MPI。OpenMPI因易用性和特性丰富更受欢迎。
- 数学库:这是性能的关键。BLAS(基础线性代数子程序)和LAPACK(线性代数包)的实现。强烈推荐使用高度优化的数学库,如OpenBLAS、Intel MKL或AMD的AOCL。自行编译的Netlib BLAS/LAPACK性能会差好几个数量级。
2.2 依赖包的安装
不同的Linux发行版,安装命令略有不同。以下分别给出基于YUM(RHEL/CentOS/Rocky)和APT(Ubuntu/Debian)的示例。
对于RHEL系系统:
sudo yum groupinstall -y "Development Tools" sudo yum install -y epel-release sudo yum install -y wget git make cmake gcc-c++ environment-modules sudo yum install -y openmpi-devel openblas-devel lapack-devel对于Ubuntu/Debian系系统:
sudo apt update sudo apt install -y build-essential wget git cmake sudo apt install -y libopenmpi-dev openmpi-bin libopenblas-dev liblapack-dev注意:
environment-modules或lmod包用于管理环境模块,在大型HPC集群中管理多版本软件非常方便。如果是单机测试,可以暂不安装,但了解它是有益的。
安装完成后,建议进行快速验证:
which mpicc # 应返回MPI C编译器的路径,如 /usr/bin/mpicc gcc --version # 查看GCC版本 mpirun --version # 查看OpenMPI版本2.3 数学库的选择与配置要点
这里重点讲一下数学库。OpenBLAS是一个优秀的开源选择,通过yum install openblas-devel或apt install libopenblas-dev安装后,其库文件通常位于/usr/lib64/libopenblas.so或/usr/lib/libopenblas.so。你可以使用find /usr -name \"libopenblas*.so*\"来定位。
如果你使用的是Intel处理器并安装了Intel oneAPI基础工具包,那么MKL是性能更优的选择。你需要source MKL的环境变量脚本,例如source /opt/intel/oneapi/setvars.sh。之后,MKL的链接选项通常更复杂,但可以通过mkl-link-line工具获取。
为了简化,我们后续示例将使用OpenBLAS,因为它配置简单且性能足够好。记住数学库的路径,在编译HPL和HPCG时会用到。
3. HPL的安装与配置实战
HPL的安装过程主要是下载、解压、根据你的系统架构和软件环境编写配置文件(Makefile),然后编译。
3.1 获取源码与解压
官方源码可以从Netlib获取,但为了方便,我们通常使用预打包的版本。
cd ~ wget http://www.netlib.org/benchmark/hpl/hpl-2.3.tar.gz tar -zxvf hpl-2.3.tar.gz cd hpl-2.33.2 详解Makefile的配置
HPL的编译精髓全在setup目录下的模板Makefile里。我们需要复制一个模板并修改它。
cp setup/Make.Linux_PII_CBLAS . mv Make.Linux_PII_CBLAS Make.myconfig现在,用文本编辑器(如vim或nano)打开Make.myconfig。你需要修改以下几个关键部分:
1. 指定架构和编译器:
ARCH = Linux_PII_CBLAS # 这部分通常不用大改,它主要是一个标识符。2. 设置顶层目录:
TOPdir = /home/your_username/hpl-2.3 # 确保这里是你解压HPL的绝对路径。3. 配置MPI库:
MPdir = /usr/lib64/openmpi # MPI库的安装路径。如果你的OpenMPI库路径不同,请修改。 # 可以使用 `find /usr -name \"mpi.h\"` 来定位include目录,其上级lib目录通常就是MPdir。 MPinc = -I$(MPdir)/include MPlib = $(MPdir)/lib/libmpi.so4. 配置数学库(最关键的一步):
LAdir = /usr/lib64 # OpenBLAS库的路径。如果库文件在/usr/lib,则改为 /usr/lib。 LAinc = # OpenBLAS通常不提供独立的头文件,其接口通过CBLAS标准,这里可以留空或指向/usr/include。 LAlib = -L$(LAdir) -lopenblas -lm # -lopenblas 链接OpenBLAS, -lm 链接数学库。5. 调整编译器与编译选项:
CC = mpicc CCFLAGS = $(HPL_DEFS) -O3 -march=native -fomit-frame-pointer -funroll-loops -Wall # -O3 激进优化,-march=native 针对当前CPU微架构优化,-funroll-loops 循环展开。 LINKER = mpicc LINKFLAGS = $(CCFLAGS)实操心得:
-march=native是一个双刃剑。它能为你的当前CPU生成最优代码,但编译出的二进制可能无法在其他不同型号的CPU上运行。如果你需要在异构集群上分发可执行文件,应将其替换为更通用的选项,如-msse4.2 -mavx2(根据你的集群所有节点共有的指令集来定)。
3.3 编译与验证
配置完成后,保存文件,开始编译:
make arch=myconfig # 注意,这里的‘arch=’参数对应你配置文件的‘Linux_PII_CBLAS’部分,但实际使用的是我们重命名的Make.myconfig。 # 更规范的做法是创建一个以‘Make.’开头的文件,如‘Make.Linux_MyPC’,然后执行 `make arch=Linux_MyPC`。如果一切顺利,你将在bin/myconfig/目录下找到编译好的可执行文件xhpl。你可以先在一个小规模配置下快速测试它是否能运行:
cd bin/myconfig/ mpirun -np 4 ./xhpl # 使用4个MPI进程运行,如果没有HPL.dat配置文件,它会报错并退出,这至少说明可执行文件是好的。4. HPCG的安装与配置实战
HPCG的安装流程与HPL类似,但它的配置更现代化,通常使用CMake。
4.1 获取源码
HPCG的源码托管在GitHub上。
cd ~ git clone https://github.com/hpcg-benchmark/hpcg.git cd hpcg4.2 使用CMake进行配置与编译
HPCG推荐使用CMake进行跨平台构建。创建一个构建目录并进入:
mkdir build && cd build接下来是关键的CMake配置命令。你需要指定MPI编译器、数学库和优化级别。
cmake .. \ -DCMAKE_C_COMPILER=mpicc \ -DCMAKE_CXX_COMPILER=mpicxx \ -DCMAKE_Fortran_COMPILER=mpif90 \ -DHPCG_ENABLE_MPI=ON \ -DHPCG_WITH_BLAS=ON \ -DBLAS_LIBRARIES=/usr/lib64/libopenblas.so \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_FLAGS=\"-O3 -march=native\" \ -DCMAKE_C_FLAGS=\"-O3 -march=native\"参数解析:
-DCMAKE_*_COMPILER:明确告诉CMake使用MPI包装器作为编译器。-DHPCG_ENABLE_MPI=ON:启用MPI并行。-DHPCG_WITH_BLAS=ON和-DBLAS_LIBRARIES:链接BLAS库。这里直接指定了OpenBLAS库的完整路径。-DCMAKE_BUILD_TYPE=Release:启用Release级别的优化。-DCMAKE_*_FLAGS:传递额外的优化编译选项。
执行CMake后,如果配置成功,会生成Makefile。然后进行编译:
make -j$(nproc) # 使用所有CPU核心并行编译,加快速度。编译完成后,在build/bin/目录下会生成hpcg可执行文件。
4.3 为HPCG生成问题规模配置文件
HPCG需要一个输入文件来定义问题规模、运行时间等参数。源码中提供了示例:
cd ~/hpcg cp setup/sample-hpcg.dat ./hpcg.dat你需要编辑这个hpcg.dat文件。关键参数有:
LocalDomainDimensions x y z: 每个MPI进程处理的局部三维网格大小。x*y*z决定了单进程内存消耗。例如104 104 104,总网格点约112万。Runtime: 期望的基准测试运行时间(秒)。HPCG会迭代运行直到达到这个时间。建议设置为60-300秒,太短可能热身不充分,太长则耗时。NumThreads: 如果编译时启用了OpenMP,这里可以设置线程数。我们目前未启用,设为1。
一个适用于单节点、内存适中的配置示例:
HPCG benchmark input file Sandia National Laboratories; University of Tennessee, Knoxville 104 104 104 605. 测试执行与结果分析
安装完成,真正的挑战在于如何设计测试,并正确解读结果。
5.1 HPL测试配置与运行
HPL的行为由HPL.dat文件控制。在bin/myconfig/目录下创建一个新的HPL.dat。你可以从源码的setup目录下复制一个例子来修改。
cd ~/hpl-2.3/bin/myconfig cp ../../setup/HPL.dat .编辑HPL.dat,以下是一个针对单节点(比如有16个物理核心)的简化配置示例:
HPLinpack benchmark input file Innovative Computing Laboratory, University of Tennessee HPL.out output file name (if any) 6 device out (6=stdout,7=stderr,file) 1 # of problems sizes (N) 20000 Ns 1 # of NBs 256 NBs 0 PMAP process mapping (0=Row-,1=Column-major) 1 # of process grids (P x Q) 2 Ps 8 Qs 16.0 threshold 1 # of panel fact 2 PFACTs (0=left, 1=Crout, 2=Right) 1 # of recursive stopping criterium 4 NBMINs (>= 1) 1 # of panels in recursion 2 NDIVs 1 # of recursive panel fact. 1 RFACTs (0=left, 1=Crout, 2=Right) 1 # of broadcast 1 BCASTs (0=1rg,1=1rM,2=2rg,3=2rM,4=Lng,5=LnM) 1 # of lookahead depth 1 DEPTHs (>=0) 2 SWAP (0=bin-exch,1=long,2=mix) 64 swapping threshold 0 L1 in (0=transposed,1=no-transposed) form 0 U in (0=transposed,1=no-transposed) form 1 Equilibration (0=no,1=yes) 8 memory alignment in double (> 0)关键参数解释:
Ns: 问题规模(矩阵大小N)。这是最重要的参数。N的大小决定了测试的强度和内存占用。一个经验法则是,总内存占用约为8 * N^2字节(双精度)。对于一台有64GB内存的服务器,可以尝试设置N使得8*N^2接近但不超过0.8倍总内存。例如,N=20000时,内存约8*20000^2 ≈ 3.2GB,这显然太小,无法压测出峰值。你需要不断增大N,直到运行时间合理(几分钟到一小时)且系统内存使用率较高。可以尝试N=50000, 80000等。NBs: 分块大小。通常设置为256或更大,是缓存友好的一个值。P x Q: 进程网格。P * Q应等于你使用的MPI进程总数。例如,你用16个进程,可以设置为2 8或4 4。不同的网格形状可能影响通信效率,可以稍作尝试。
运行测试(假设使用16个MPI进程):
mpirun -np 16 ./xhpl程序会输出详细的迭代过程,最终在末尾给出性能结果,核心是这一行:
WR11C2R4 20000 256 2 8 60.70 2.199e+02其中2.199e+02就是性能,单位是Gflops(每秒十亿次浮点运算)。将其乘以1000,就是Tflops。
5.2 HPCG测试运行
HPCG的运行相对简单,因为它会自动适应进程数。进入构建目录运行:
cd ~/hpcg/build/bin mpirun -np 16 ./hpcg程序会读取当前目录下的hpcg.dat配置文件,开始迭代计算。运行结束后,它会在标准输出和生成的HPCG-Result-*.txt文件中报告结果。关注的核心指标是HPCG Gflops。这个值会远低于HPL的峰值。一个健康的系统,HPCG性能通常能达到HPL峰值的1%到10%之间。比例越高,说明系统在应对不规则内存访问时效率越好。
5.3 结果解读与性能瓶颈初判
将两个测试结果放在一起看:
- HPL Tflops: 代表了你的系统在理想、规整、计算密集型任务下的理论峰值能力。它受CPU主频、核心数、AVX指令集利用率影响最大。
- HPCG Gflops: 代表了系统在更真实、数据访问密集型任务下的实际可持续性能。它极度依赖内存带宽和延迟。
对比分析:
- 如果HPCG/GFLOP与HPL/TFLOP的比值非常低(比如<0.5%),这可能是一个强烈的“内存墙”信号。意味着你的CPU计算单元经常在等待数据从内存中送来。可能的原因包括:内存频率低、通道数未满配(比如该用四通道只插了两条)、或者NUMA架构下进程绑核不佳导致跨NUMA节点访问内存。
- 如果HPL本身跑分就远低于预期(根据CPU型号的理论峰值估算),则可能问题出在:编译器优化选项不对、数学库未正确链接或版本不佳、进程绑核导致缓存失效、或者BIOS里能效模式未关闭(如关闭了Turbo Boost,或运行在低功耗模式)。
6. 常见问题排查与性能调优技巧
在实际操作中,你几乎一定会遇到各种问题。这里记录一些典型的坑和解决方法。
6.1 编译与链接错误
问题1:编译HPL时找不到cblas.h或blas.h。
原因与解决:这通常是因为
LAinc路径没设对,或者系统安装的OpenBLAS不提供独立的CBLAS头文件。OpenBLAS的符号通常直接包含在libopenblas.so里。可以尝试:
- 在
Make.myconfig中,将LAinc设为-I/usr/include/openblas(如果该目录存在)。- 更常见的方法是,安装
openblas-devel或libopenblas-dev包,它通常会提供头文件。然后使用find /usr -name \"cblas.h\"定位,并将路径填入LAinc。- 如果实在找不到,可以注释掉HPL源码中
include的cblas.h行(不推荐),或者从Netlib下载标准CBLAS头文件放到本地目录并包含。
问题2:运行xhpl或hpcg时提示libopenblas.so.0: cannot open shared object file。
原因与解决:动态链接库路径未找到。解决:
# 临时添加库路径到当前shell export LD_LIBRARY_PATH=/usr/lib64:$LD_LIBRARY_PATH # 或者永久添加,将上行写入 ~/.bashrc更根本的办法是检查
/etc/ld.so.conf.d/下的配置文件,确保包含OpenBLAS库的路径,然后运行sudo ldconfig更新缓存。
6.2 运行时错误与性能低下
问题3:MPI运行时错误,如ORTE was unable to reliably start one or more daemons。
原因与解决:常见于OpenMPI环境。可能的原因和尝试方案:
- SSH免密登录未配置:在多节点运行时,主节点必须能免密SSH到所有计算节点。单节点运行时也可能需要本地免密。
- 主机名解析问题:确保
/etc/hosts文件正确包含了本机的主机名和IP映射。- 使用
--allow-run-as-root:在docker容器或某些环境下,可能需要mpirun --allow-run-as-root -np ...。- 指定主机文件:单机测试可以显式指定:
mpirun --host localhost:16 -np 16 ./xhpl。
问题4:HPL运行速度慢得离谱,远低于预期。
排查思路:
- 检查
N的大小:N太小,问题规模完全在CPU缓存内,无法体现内存带宽,且启动开销占比高。逐步增加N,观察Gflops是否上升并趋于稳定。- 检查进程绑定:如果不做绑核,操作系统可能会在核心间迁移进程,破坏缓存局部性。使用
mpirun的绑定参数,例如对于OpenMPI:mpirun -np 16 --bind-to core --map-by core ./xhpl。- 检查CPU频率:运行
watch -n 1 \"cat /proc/cpuinfo | grep 'MHz'\",观察所有核心是否运行在标称的高频(Turbo Boost)下。如果在BIOS或OS中设置了节能模式,性能会大打折扣。在BIOS中关闭节能选项(如C-States, P-States),在Linux中使用performance调速器:sudo cpupower frequency-set -g performance。- 检查数学库:确认
xhpl链接的是高性能数学库。使用ldd xhpl | grep blas查看。如果链接的是libblas.so.3(Netlib的参考实现),性能会极差。
问题5:HPCG运行报错或结果异常。
排查思路:
- 内存不足:HPCG对内存需求较高。确保
LocalDomainDimensions三个数的乘积乘以8(双精度)再乘以进程数,不超过系统可用物理内存的80%。可以从小规模开始测试。- 运行时间太短:
Runtime设置太短(如10秒),程序可能刚热身就结束了,结果不稳定。建议至少60秒。- MPI进程数与网格大小不匹配:HPCG对进程数有要求,最好是2的幂次方,并且三维网格在每个维度上的划分要合理。如果进程数不能很好地被网格大小整除,可能会出错或性能极差。参考官方文档调整
LocalDomainDimensions。
6.3 进阶调优建议
当你完成了基本测试,想要挖掘最后10%的性能时,可以考虑:
NUMA控制:在多路CPU(多NUMA节点)的服务器上,默认的内存分配策略可能导致进程访问远程内存。使用
numactl进行绑核绑内存。例如,对于双路系统,可以尝试让一半进程绑定到第一个CPU和它的内存,另一半绑定到第二个。# 假设有2个NUMA节点,每个节点16核 mpirun -np 16 numactl --cpunodebind=0 --membind=0 ./xhpl : -np 16 numactl --cpunodebind=1 --membind=1 ./xhpl这需要根据你的具体硬件拓扑来设计。
尝试不同的数学库和编译器:用Intel MKL替换OpenBLAS,并用Intel编译器重新编译,在Intel CPU上通常能获得最佳性能。对于AMD CPU,则可以尝试AMD的AOCL库。
调整HPL的
NB、P、Q参数:进行一个参数扫描的小实验。固定N,尝试不同的NB(128, 192, 256, 384, 512)和不同的PxQ网格组合(保持P*Q=总进程数),记录性能,找到最优组合。这个过程可以写个简单的shell脚本自动化。
安装和测试HPL/HPCG的过程,本身就是对HPC系统软硬件栈的一次深度遍历。从编译器、MPI、数学库的配置,到操作系统内核参数、BIOS设置的了解,再到最后对性能数据的解读,每一步都藏着学问。我第一次跑通HPL看到那个Tflops数字时,感觉只是开始。后来对比了HPCG的结果,才真正意识到内存子系统对实际应用的影响有多大。调优的过程更像是在解一个多维度的方程,每一个参数都可能牵一发而动全身。我的建议是,做好实验记录,每次只改变一个变量,耐心地对比,你对你手中系统的理解会越来越透彻。