ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Score-P与Scalasca实战:HPC并行程序性能分析工具的源码编译与部署指南

Score-P与Scalasca实战:HPC并行程序性能分析工具的源码编译与部署指南 前阵子帮组里一位做流体仿真的同事搭性能分析环境他那边攒了几个跑得很慢的 MPI 作业程序本身没有报错但就是能用一半核不干活的那种“匀速慢”。我想着用 Score-P 和 Scalasca 这套组合给他做一次插桩和同步错误检查结果装工具这一步就花掉了大半个下午——不是下载慢而是版本匹配、依赖顺序、编译器 wrapper 这些细节环环相扣稍不注意 configure 就给你撂挑子。这篇不是官方文档的搬运是我实际装完一遍踩完坑之后的完整记录。里面会讲到为什么我不建议直接apt install、Score-P 和 Scalasca 的分工、OTF2 和 Cube 到底该怎么就位、源码编译时 configure 参数逐条怎么选最后还会给出一个跑通的 MPI 示例和一份排错清单。适合需要在学校集群、公司服务器或自己工作站上从零部署这套工具的 HPC 使用者、平台管理员以及刚接触并行性能分析的同学参考。1. 装这两个工具前先搞清楚它们的分工和配套组件1.1 Score-P 与 Scalasca 各自负责什么很多人第一次听到 Score-P 和 Scalasca 会以为它们是同一个软件的两种安装方式其实它们的分工非常清晰Score-P 负责“采集”Scalasca 负责“分析和报告”。Score-P 是一套插桩基础设施。它通过包裹编译器scorep gcc、scorep mpicc的方式在编译阶段自动往你的程序里插入性能采集代码然后在程序运行时把函数调用、MPI 通信、OpenMP 并行区域、硬件计数器等信息写进 trace 文件。你可以简单把它理解成“给程序装了个行车记录仪”跑一遍行为全部录下来。Scalasca 则是在 Score-P 产出的 trace 基础上做自动分析。它最出名的是同步错误检测比如 MPI 死锁、集合操作不匹配以及给出 2D/3D 的并行行为热点报告。它能告诉你某个通信到底慢在哪里、是不是某几个进程在等其他人。所以实际工作流是scorep编译插桩mpirun跑出 tracescalasca -analyze自动分析 trace最后用 Cube 可视化报告。这也解释了为什么安装时必须先有 Score-P再装 Scalasca顺序反了 configure 会直接报找不到前者。1.2 三大配套组件OTF2、Cube 与 MPI 环境除了两个主角这套生态里还有三个绕不开的配套组件OTF2Open Trace Format 2trace 文件的底层格式库。Score-P 和 Scalasca 都通过它读写 trace它是两者之间的公共数据方言。版本不匹配时Score-P 生成的 trace 可能根本没法被 Scalasca 读出。Cube报告查看器和指标库。Scalasca 的分析结果会转成 Cube 格式你可以用 GUI 看进程×函数的二维热力图也可以在命令行里只输出文本摘要。MPI 环境OpenMPI、MPICH 或 Intel MPI 都行。工具在 configure 阶段会执行小测试程序来探测 MPI所以环境变量PATH里必须能直接找到mpicc/mpirun否则后面会死在这一步。我在实际安装中发现很多人卡在“装好了 Score-P 却跑不了 Scalasca”几乎都是因为它们拿到的 OTF2 或 Cube 版本不一致。这里我建议的经验是把 OTF2、Cube、Score-P、Scalasca 四个项目当作一个大版本族来管理尽量使用各自接近的 release 版本或者干脆用下文会提到的 Spack/EasyBuild 一次性固定版本。1.3 为什么我一律建议源码编译而不是包管理器Ubuntu/Debian 的软件源里其实有scorep包但版本更新很慢而且多数发行版仓库里根本没有 Scalasca。即使通过apt install scorep装成功你大概率会遇到两个尴尬一是版本太老和当前编译器的 ABI 对不上二是 apt 会把依赖装进系统目录等你后面想换版本或者装到用户目录时清理起来特别麻烦。另外HPC 场景有个特殊性——trace 文件格式是带版本约定的。你用手头旧版工具采集的 trace很可能打不开新版 Scalasca 生成的报告。源码编译虽然多花几分钟但能让你明确知道装的是哪个版本、依赖在哪后续排错成本反而最低。如果你所在集群已经有 EasyBuild 或 Spack 这类环境管理工具直接用它们安装 Score-P 和 Scalasca 是最省心的。下面我默认的场景是你只有一台服务器、一个普通用户账号需要从源码自己装这也是最通用的情况。2. 环境准备先花十分钟把编译器与依赖项对齐2.1 编译器与 MPI 的版本确认开工前先在终端里确认这几个信息能省掉后面一多半的麻烦gcc --version gfortran --version mpirun --version which mpicc我这次所用的环境是 GCC 11.4 OpenMPI 4.1 的组合。这里有个容易被忽略的点Score-P 的 configure 会调用mpicc去编译测试程序而mpicc又是基于 GCC 的所以如果你的 GCC 版本和 MPI 是不同时间装的最好先跑一个简单的 MPI Hello World 确认基础编译链没问题再进行下一步。如果你用的是 Intel oneAPI 工具链也没问题只需要确保mpiicc/mpirun在路径里并且 configure 时指定到对应的 MPI 家族即可后面第 3 节会详细说。Fortran 编译器不是严格必需但如果你要分析 Fortran 的 MPI 程序没有gfortran会导致 configure 阶段跳过 Fortran 支持插桩时才发现没法用所以我建议提前装好。2.2 依赖库清单哪些必须、哪些可选下表是我整理的高频依赖项按“必须”和“可选”分开依赖项必选/可选作用备注libzzlib1g-dev必须压缩 trace 数据几乎所有发行版默认都有OTF2必须trace 格式库建议手动编译路径后面让给 configureCube 库Scalasca 必须报告读写与视图GUI 可以不装但库必须有PAPI可选硬件计数器Cache miss 等没有也能装但指标少一截libunwind可选采样模式调用栈展开建议装性能分析很有用Qt5可选Cube GUI 显示只在你想看图形报告时才需要其中最容易忽略的是zlib。如果 configure 报“cannot find zlib.h”不要怀疑别的先apt install zlib1g-dev或yum install zlib-devel把它装上再重新 configure。2.3 决定安装前缀用户目录安装还是系统安装这个决定影响后面所有路径我建议非必要不要装进/usr/local。原因是这类工具升级频率不低而且不同项目可能需要不同版本共存。装进你的$HOME/tools下管理、卸载、切换版本都只需改环境变量。我推荐的目录结构是$HOME/tools/ ├── otf2 ├── cube ├── scorep └── scalasca每个组件一个前缀目录互不污染。用--prefix$HOME/tools/otf2这种方式指定。这样即使其中一个需要重装其他三个不会受影响。3. 构建 Score-Pconfigure 参数逐条说明3.1 获取源码与解压Score-P 的源码包在官网下载页可以拿到我写这篇时主线版本是 8.x。下载后解压cd $HOME/src wget https://www.score-p.org/release/scorep-8.0.tar.gz tar xf scorep-8.0.tar.gz cd scorep-8.0如果你的服务器无法访问外网可以在有网机器上下好之后传上去不需要额外依赖。注意源码目录不要放在 NFS 上编译构建否则大量小文件的 IO 会让你怀疑人生建议先在本地磁盘解压构建。3.2 configure 到底该怎么写这是我整个安装过程中最关键的一步。我的建议是不要直接./configure --prefix...就完事而是要显式告诉它 OTF2、Cube、MPI 的位置。下面是我实测可用的配置./configure \ --prefix$HOME/tools/scorep \ --with-otf2$HOME/tools/otf2 \ --with-cube$HOME/tools/cube \ --with-mpiopenmpi \ --with-papi/usr/local \ --with-libunwind/usr \ --enable-shared逐条解释一下--with-otf2显式指定 OTF2 安装前缀。如果不指定Score-P 有时会尝试在内部下载并构建 OTF2但那样到了 Scalasca 阶段你还得再装一份容易造成路径混乱。--with-cube和上面同理指定 Cube 库位置。Cube 可以先装库也可以连 GUI 一起装关键是这里要让 configure 找到它的头文件和库文件。--with-mpiopenmpi告诉 configure 它面对的是 OpenMPI。如果用了 MPICH 就写--with-mpimpichIntel MPI 则常见用--with-mpiimpiv2。不指定的情况下 configure 会尝试自动探测绝大多数失败都发生在这个“自动探测”上所以建议总是手动指定。--with-papi指定 PAPI 安装前缀。如果你的机器没装 PAPI直接去掉这一行工具也能正常编译只是后续看不到硬件计数器相关指标。--enable-shared生成动态库避免后续运行时反复调整 LD_LIBRARY_PATH 的麻烦。如果你是在集群登录节点上远程编译而没有图形界面Cube GUI 没必要现在就配齐。可以先让 Cube 库就位GUI 后面需要再补。3.3 编译安装与快速自检configure 跑完后在config.log里确认没有 fatal error然后make -j$(nproc) make install这里的一个提示make -j的并行数量取决于机器核数但 Score-P 编译过程对内存比较敏感如果你用的是登录节点且机器内存不大保守一点用make -j4即可避免 OOM 导致出现莫名其妙的编译失败。装完后先不要急着往下走做一次自检export PATH$HOME/tools/scorep/bin:$PATH scorep --version如果能看到版本号输出说明基础安装成功。接着可以再跑一条scorep info这个命令会列出 Score-P 构建时支持的功能比如 MPI、OpenMP、PAPI 等。我建议在这里停留半分钟确认里面确实有MPI字样否则后面插桩 MPI 程序时会发现工具根本不认你的并行代码。4. 接着装 ScalascaOTF2、Cube、Score-P 三者的版本铁三角4.1 为什么 OTF2 和 Cube 要先就位安装 Scalasca 之前我强烈建议先确认 OTF2 和 Cube 都已经独立装好。原因在于Scalasca 的 configure 同时需要找到 OTF2用于读写 trace和 Cube用于生成报告如果你想让 Scalasca 与刚才装的 Score-P 配合使用它还需要知道 Score-P 的安装位置。听起来像是废话但实际中很多人因为“先装了 Score-P 再装 Scalasca”结果在 configure 阶段反复报“otf2 not found”一查才发现自己没有预先编译 OTF2而是让 Score-P 内部自动构建了一份藏在它的 build 目录里。这种情况下哪怕 Scalasca 装上了运行时找库也会莫名其妙。所以我的建议一直是把 OTF2 和 Cube 当作独立软件先装好给出明确 prefix然后 Score-P 和 Scalasca 都指向同一份。这样才能保证它们三个“说同一种语言”。OTF2 和 Cube 的编译通常没什么坑标准三步wget otf2-source-url tar xf otf2-*.tar.gz cd otf2-* ./configure --prefix$HOME/tools/otf2 make -j8 make installCube 我会先只编译库而不编译 GUI这样能省去 Qt 依赖./configure --prefix$HOME/tools/cube --without-qt make -j8 make install其实--without-qt这个选项非常有用。HPC 集群上绝大多数是没有图形界面的Cube GUI 装了也只能偶尔加个ssh -X来看但它带来的 Qt 依赖却可能在编译期给你制造麻烦。先只装库将来想看图形报告再单独编译带 GUI 的版本不影响已经生成的 trace 文件。4.2 Scalasca 的 configure 与 make 流程拿到 Scalasca 源码后我的典型配置是./configure \ --prefix$HOME/tools/scalasca \ --with-scorep$HOME/tools/scorep \ --with-otf2$HOME/tools/otf2 \ --with-cube$HOME/tools/cube这里有几个细节值得注意--with-scorep是可选的但建议写上。因为 Scalasca 需要调用scorep进行交叉插桩如果找不到它可能退化成只做纯在线分析功能会少一大截。如果 configure 报“Cube library not found”先确认是不是之前的 Cube 只装了 GUI 没装库或者--without-qt后有没有执行make install。make -j$(nproc)后务必看一眼make install的输出有没有 error。Scalasca 偶尔会因为 Cube 版本过新或过老在链接报告组件时报错这种错误往往不影响主程序安装但会让你后面分析时摸不着头脑。装完后同样验证export PATH$HOME/tools/scalasca/bin:$PATH scalasca --version如果输出正常就说明核心组件都已经就位。4.3 版本匹配参考表“版本不匹配”是我在所有安装问题中见到最多的一类因为它不会在安装时报错而是等到分析 trace 时才炸开。我根据自己和同行踩坑的经验整理了一个大致的版本对应关系仅供快速参考工具族版本Score-PScalascaOTF2Cube较新主线8.x2.6.x2.3.x4.8.x较老主线7.x2.5.x2.2.x4.6.x严格来说每个项目的 release notes 里会写明兼容关系所以最稳妥的做法是下载源码时同时打开四个项目各自的 release notes确保它们的主线版本处于同一时期。不要混搭“Score-P 8 Scalasca 2.4”这种组合容易踩到隐性的 ABI 断裂。如果你嫌逐个项目检查麻烦Spack 路线就更有优势了它会把版本矩阵帮你管好。5. 跑通一个 MPI 示例来验证整套工具链5.1 bashrc 环境变量建议在集群上我不太建议把路径直接写进.bashrc里让每个用户都生效——除非你是管理员。更灵活的做法是为这个工具集单独准备一个环境脚本比如$HOME/tools/env.shexport PATH$HOME/tools/otf2/bin:$HOME/tools/cube/bin:$HOME/tools/scorep/bin:$HOME/tools/scalasca/bin:$PATH export LD_LIBRARY_PATH$HOME/tools/otf2/lib:$HOME/tools/cube/lib:$HOME/tools/scorep/lib:$HOME/tools/scalasca/lib:$LD_LIBRARY_PATH这样的好处是需要用时source ~/tools/env.sh不需要时就不加载避免和其他软件的环境变量打架。我在帮同事配置时就发现他先前自己往.bashrc里加了好几条不存在的LD_LIBRARY_PATH结果很多程序启动变慢、偶发找不到库都是这类“全局污染”引起的。5.2 用 scorep 包装编译器完成插桩我们写一个简单的 MPI 程序来验证整个链路。文件叫mpi_ping.c内容大致是进程两两通信一个消息统计耗时。#include mpi.h #include stdio.h int main(int argc, char **argv) { int rank, size; int msg 42; double start, end; MPI_Init(argc, argv); MPI_Comm_rank(MPI_COMM_WORLD, rank); MPI_Comm_size(MPI_COMM_WORLD, size); start MPI_Wtime(); MPI_Barrier(MPI_COMM_WORLD); if (rank 0) { MPI_Send(msg, 1, MPI_INT, 1, 0, MPI_COMM_WORLD); MPI_Recv(msg, 1, MPI_INT, size-1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if (rank 1) { MPI_Recv(msg, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } MPI_Barrier(MPI_COMM_WORLD); end MPI_Wtime(); if (rank 0) { printf(barrier ring time %f s\n, end - start); } MPI_Finalize(); return 0; }用 Score-P 编译插桩只需要把普通的编译命令换成source ~/tools/env.sh scorep mpicc -o mpi_ping_inst mpi_ping.c这一步不需要额外写-I、-L因为scorepwrapper 会自动把 OTF2、Cube 等头文件和库路径加进去。如果这里报找不到mpicc说明前面 MPI 环境没配对如果报一堆链接错误大概率是 Score-P 与 MPI 的匹配出了问题回到第 3 节重新核对--with-mpi参数。5.3 scalasca 分析流程与结果文件解读插桩后的程序直接用mpirun跑mpirun -n 4 ./mpi_ping_inst运行完后当前目录下会多出一个类似scorep_mpi_ping_inst_*的目录里面就是 trace 文件。确认有了 trace 后用 Scalasca 做自动分析scalasca -analyze mpiexec -n 4 ./mpi_ping_inst注意这里换成了scalasca -analyze它内部会自动跑一遍程序并分析同步行为所以不需要手动指定 trace 目录。分析结束后会生成一个scalasca_*报告目录里面包含 Cube 格式的时间和通信摘要。想看文本结果直接敲scalasca -examine scalasca_*这条命令会逐条列出程序中的同步错误和性能热点如果代码里有死锁这里通常会出现 timeout 提示。想可视化就在有图形环境的机器上用 Cube 打开cube scalasca_*/scorep_*/traces.cubex正常打开的界面里左侧是函数列表中间是进程/线程分布右侧是指标。能同时看到每条 MPI 调用花了多少时间、哪个函数在哪个进程上最慢。我自己的经验是第一次看到跑成功的 ScalaSca 报告目录时事就成了。后续再做实际项目基本就是从“验证链路”过渡到“定位问题”了。6. 安装过程中最常出现的坑与排错清单6.1 找不到 OTF2/Cube 库这类问题通常表现为 configure 时的OTF2 not found或运行时libotf2.so: cannot open shared object file。前者多半是路径没对回到--with-otf2参数检查$HOME/tools/otf2/lib是否存在后者则说明安装成功但运行时找不到库需要在LD_LIBRARY_PATH里把它加上。这里有个技巧configure 成功后把当时的config.log里和otf2、cube相关的搜索路径记下来。后面排错时对照看能快速确认到底是头文件缺了还是库文件没找到。别问我怎么知道的我第一次排这种错就把大量时间花在了瞎改环境变量上。6.2 MPI 识别失败configure 报错说找不到 MPI或者干脆卡在checking for mpi_init...很久。这通常不是因为 MPI 没装而是因为你没有指定--with-mpiopenmpi/mpich/impiv2configure 的自动探测在你的环境里失效了。解决办法很简单export PATH/path/to/openmpi/bin:$PATH export LD_LIBRARY_PATH/path/to/openmpi/lib:$LD_LIBRARY_PATH ./configure --with-mpiopenmpi ...另一个我见过的坑是机器上同时装了多个 MPI 实现configure 探测到的mpicc和实际使用的mpirun来自不同套件。这种情况建议在 configure 之前先用which mpicc mpirun确认它们属于同一个安装前缀。6.3 报告内存不足与乱码分析大型作业时Scalasca 会默认给 trace 设置一个总内存预算默认值往往不够大。如果你在分析时看到报错或 trace 信息被截断可以在运行前设置export SCOREP_TOTAL_MEMORY2G这个变量控制 Score-P 运行时用于缓冲 trace 的内存上限预算太小会丢弃数据或报告失败。官方默认应该在 128MB 左右对小的测试程序够用但在真实CFD、分子动力学这类高通信频次的应用里一定要调大。另外如果你的程序用了大量小消息通信生成的 trace 文件可能非常大几十 GB 不夸张所以要留意磁盘空间最好在 scratch 目录下跑分析而不是丢在/home里。6.4 没有 root 权限时怎么办Spack 与 EasyBuild 路线如果你的集群里已经装了 Spack那么安装要轻松得多spack install scorep scalascaSpack 会自动处理 OTF2、Cube、MPI 依赖和版本匹配并且支持在一个环境里锁定版本。EasyBuild 也类似用eb ScoreP-...和eb Scalasca-...就能装。对平台管理员来说我其实是推荐用这类工具统一管理的毕竟源码编译的灵活性是有代价的——版本组合一多就容易上头。但如果你是单机用户没有 root、也不想引入 Spack 一大套体系那手动源码编译完全够用我在文中给的这套就是我实际长期使用的方式。6.5 卸载与升级的建议最后说一个容易忽略的点。当你需要升级 Score-P 或 Scalasca 时不要只是在旧版本目录上重新make install。我建议先单独下载新版本、编译到另一个前缀目录比如$HOME/tools/scorep-8.1然后切换环境变量指过去。这样做的好处是如果新版本出问题你可以立刻切回旧版旧 trace 也能用旧版工具重新打开免得升级后出现读不了旧 trace 的尴尬。我在实际使用中发现只要把 OTF2、Cube、Score-P、Scalasca 这个“铁三角”的版本固定好后续基本能稳定用很久。真正容易出问题的反而是隔了几个月后升级了其中一个。所以我现在都会习惯性地记录一份“当时安装环境和版本号”的备忘放在工具目录旁边方便自己和同事日后排查。
返回列表