第四代AMD EPYC 9554双路香港服务器,编译构建性能测试看哪些指标?
双路 EPYC 9554 配置 128GB DDR5 时,编译构建测试不应只记录一次 make 或 ninja 的完成时间。更有价值的结果需要同时覆盖单次构建延迟、并行吞吐、不同并发度下的扩展效率、CPU利用率、内存带宽与NUMA访问、存储等待,以及源码和依赖下载对香港机房网络的影响。
如果交付清单中的每颗 EPYC 9554 均为64核,那么整机通常对应128个物理核心、256个线程。但“核心多”不等于任意项目都能线性提速,128GB内存对双路高核心数平台也可能成为约束。测试的核心问题应当是:目标项目在什么并行度下达到稳定拐点,瓶颈位于CPU、内存、磁盘还是网络,以及这台服务器能够稳定承载多少个并行构建任务。
测试目标:先区分构建类型和使用场景
编译构建通常包含多个性质不同的负载。全量构建、增量构建、多个项目并发构建,以及依赖包下载,不能用同一组数据简单概括。
全量构建:观察峰值性能和资源上限
全量构建需要从干净的构建目录开始,覆盖尽可能多的源文件和链接任务,重点观察:
- 总完成时间,也就是端到端延迟;
- 编译阶段、链接阶段、代码生成阶段分别耗时多久;
- 并行度从低到高时的加速曲线;
- 峰值内存、磁盘读写、CPU频率和温度;
- 最后阶段是否因少量串行任务造成长尾。
全量构建更适合评估大型C/C++项目、编译器、操作系统内核、数据库或基础组件的首次构建能力。它对源码规模、编译器版本、链接器、编译参数和磁盘状态都比较敏感。
增量构建:观察日常开发延迟
增量构建只修改少量源文件,通常更接近日常开发和持续集成中的重复构建。测试时应固定修改范围,例如:
- 修改一个公共头文件,观察受影响目标数量;
- 修改一个普通源文件,观察局部重编译时间;
- 修改链接入口,观察重新链接耗时;
- 修改少量模块后执行完整增量构建。
增量构建不能与全量构建混为一谈。如果启用了 ccache、编译器模块缓存或构建系统缓存,重复构建时间可能明显缩短,但这并不等于服务器的原始编译能力提升。因此建议分别记录缓存关闭、缓存冷启动和缓存命中三种结果。
并发构建:观察吞吐和资源争用
持续集成环境往往不是一个项目独占服务器,而是同时处理多个分支、多个提交或多个组件。此时需要测试:
- 单个构建任务的完成时间;
- 两个、四个或更多构建任务并发时的完成时间;
- 单位时间完成的构建数量;
- 并发后每个任务的平均延迟和P95延迟;
- 内存、I/O队列和CPU频率是否出现明显波动。
单任务跑得快,不代表多任务吞吐一定高。双路平台在高并发时可能出现跨NUMA节点内存访问、存储队列堆积或内存不足,必须将“单任务性能”和“并行吞吐”分开验收。
A5数据的香港AMD服务器系列覆盖EPYC 9554等平台,并提供单路与双路方案,为大型项目全量编译、多分支持续集成和并发构建提供计算资源基础。香港产品还覆盖DDR5内存、NVMe存储,以及不同套餐的CN2与国际带宽选择,为源码存储、构建缓存、依赖拉取和制品传输提供相应资源,支持企业构建环境中计算、存储与网络环节的部署。
网络相关阶段:单独评估香港机房链路
香港服务器的地理位置主要影响源码仓库、依赖仓库、容器镜像仓库和制品存储的访问,不应直接归因于处理器性能。网络部分建议拆成三个阶段:
- 本地源码、本地依赖缓存,只测构建引擎;
- 源码和依赖需要从远端拉取,测下载与构建总耗时;
- 构建完成后向远端制品库上传,测发布阶段耗时。
这样才能判断“编译慢”还是“拉取依赖慢”。同一台服务器的CPU性能可能稳定,但不同时间段的跨境链路、远端仓库负载和丢包率会造成网络阶段较大波动。
指标含义:不要只看CPU利用率
端到端时间和阶段时间
构建总时间可拆分为:
总耗时 = 准备时间 + 源码及依赖获取时间 + 编译时间 + 链接时间 + 制品上传时间
其中,编译时间又可能包含预处理、编译、汇编和链接等不同阶段。建议构建系统输出详细日志,至少保留以下字段:
| 指标 | 含义 | 适用判断 |
|---|---|---|
| Wall time | 从构建开始到完成的真实经过时间 | 直接反映用户等待时间 |
| User CPU time | 用户态累计CPU时间 | 判断编译进程实际消耗的计算量 |
| System CPU time | 内核态累计CPU时间 | 判断I/O、进程调度和系统调用开销 |
| 阶段耗时 | 编译、链接、测试、打包分别用时 | 定位具体瓶颈 |
| 任务完成数 | 单位时间完成的目标或构建任务数量 | 适合持续集成吞吐分析 |
| P50/P95 | 中位数和高分位延迟 | 观察常态体验与长尾波动 |
并行构建时,所有子进程的CPU时间之和可能远大于Wall time,这是正常现象。Wall time适合回答“多久完成”,CPU time适合回答“实际用了多少计算资源”,两者不能相互替代。

CPU指标:核心数、频率、IPC和等待状态
建议同时采集以下CPU指标:
- 物理核心使用率;
- 逻辑线程使用率;
- 全核运行频率和频率波动;
cycles、instructions和IPC;- 上下文切换、进程迁移和软中断;
iowait、steal和CPU温度;- 是否发生功耗或温度降频。
IPC可以用“完成的指令数 ÷ 时钟周期数”理解。IPC较高而频率稳定,通常说明负载更偏计算;IPC较低并伴随较多缓存未命中,可能受到内存访问、分支预测或跨NUMA访问影响。但IPC没有脱离工作负载的统一合格线,不能只凭一个数值判断服务器性能。
在虚拟化环境中,steal尤其重要。如果构建期间CPU利用率看起来不高,但steal持续升高,说明虚拟机没有及时获得宿主机调度时间,这种结果不能直接当作EPYC处理器的实际编译能力。香港服务器是物理机、独立云主机还是共享宿主机,也应在测试报告中明确。
并行扩展:看加速比,不看单个并发参数
设并行度为 j,构建时间为 Tj,则:
- 加速比 =
T1 ÷ Tj - 任务并行效率 =
T1 ÷(j × Tj) - 顺序构建吞吐 =
3600 ÷ Tj,单位为每小时完成数
这里的 j 是构建任务数,不一定等于物理核心数。任务并行效率随着并行度增加而下降是常见现象,因为项目中存在串行阶段、文件依赖、链接任务和调度开销。
建议测试一组连续但有代表性的并行度,例如:
1、2、4、8、16、32、64、96、128、160、192、256
对于规模较小的项目,如果可并行任务数量不足,测试到128或256并不会产生有意义的结论。此时应记录“可用任务不足”,而不是把高并行度下的低CPU利用率归因于服务器性能不足。
内存和NUMA:128GB容量不是全部信息
双路EPYC平台通常包含两个NUMA节点,每个处理器拥有相对独立的内存控制器。编译进程访问本地内存和访问远端内存的延迟、带宽并不相同。
需要观察:
- 总内存和每个NUMA节点的内存容量;
- 每个节点实际插入的DIMM数量;
- 内存频率和通道是否对称;
- 构建进程峰值RSS;
MemAvailable最低值;- page fault数量;
- 本地内存访问和远端内存访问比例;
- swap是否发生;
- 内存带宽是否接近平台或配置上限。
128GB内存分配在双路系统中,如果两个CPU节点没有对称配置,可能导致一侧内存控制器负载更高。即使容量相同,DIMM插槽布局不均衡也会影响带宽。交付验收不能只查看操作系统显示的总内存,还应核对内存拓扑。

可以使用以下命令记录基础信息,命令适用于常见Linux环境:
lscpu
numactl --hardware
free -h
lsblk -o NAME,MODEL,SIZE,ROTA,PHY-SEC,LOG-SEC,MOUNTPOINT
sudo dmidecode -t memory
如果系统显示128GB而不是128GiB,不一定代表少内存。十进制GB与二进制GiB的换算不同,最终应以订单口径、固件信息和操作系统可用内存共同核对。
I/O指标:吞吐、延迟和队列要结合
编译负载并不总是持续顺序读写。大量小文件读取、目标文件写入、依赖扫描和链接阶段,会产生明显的随机I/O和元数据操作。
建议记录:
- 顺序读写吞吐;
- 随机读写IOPS;
- 平均响应时间和P95响应时间;
await;- 队列深度;
%util;iowait;- 构建期间读写量和临时文件数量;
- 源码所在文件系统和构建目录所在文件系统。
用以下命令观察构建窗口中的系统状态:
mpstat -P ALL 1
iostat -xz 1
pidstat -dur 1
如果需要进行独立存储基准测试,应使用专用测试目录,不要在生产源码目录或正在服务的磁盘上直接写入测试数据。例如:
fio --name=compile-readwrite --filename=/var/tmp/fio-compile.test --size=8G --rw=randrw --rwmixread=70 --bs=4k --iodepth=32 --numjobs=4 --direct=1 --runtime=60 --time_based --group_reporting
该命令会向指定文件写入测试数据,执行前应确认目录为专用测试文件系统、空间充足且不会覆盖业务文件。独立的 fio 数值不能替代真实编译结果,真实构建还会受到文件系统缓存、目录结构和元数据操作影响。
网络指标:将传输时间和构建时间拆开
网络测试至少应记录:
- DNS解析时间;
- TCP连接时间;
- TLS建立时间;
- 首字节等待时间;
- 下载和上传吞吐;
- RTT、丢包和重传;
- 依赖包命中本地缓存的比例;
- 远端仓库访问失败率。
传输速率计算时需要区分十进制GB和比特单位。例如,5GB文件在60秒内完成传输,按十进制GB计算:
5 × 8 × 1000 ÷ 60 = 666.7 Mbps
如果日志显示的是MiB、MB/s或Gbps,必须先统一单位再比较。网络阶段如果占总耗时一半以上,继续增加CPU并行度通常不会明显缩短整个流水线时间。
影响变量:同一颗CPU也可能跑出不同结果
硬件和固件状态
测试报告应记录以下平台条件:
- 两个CPU插槽是否均在线;
- 物理核心数和线程数;
- SMT是否开启;
- BIOS电源策略;
- Turbo或动态频率策略;
- CPU温度和是否降频;
- 内存DIMM布局和频率;
- 系统盘、源码盘和构建盘的型号;
- 是否使用RAID、加密层或网络文件系统;
- 物理机、虚拟机或容器环境。
对于双路高核心数服务器,BIOS的节能策略和性能策略可能影响全核频率。不能用一次短时间跑分推断长时间全量编译性能,必须至少安排一个持续数分钟的构建任务,观察频率和温度是否在中后段变化。
编译工具链和参数
以下项目应固定:
- GCC或Clang版本;
- binutils、链接器和构建工具版本;
-O2、-O3、LTO、PGO等编译参数;- Debug信息是否开启;
- 静态链接或动态链接方式;
- 源码提交号和依赖版本;
- 构建系统版本;
- 测试是否包含单元测试、打包和压缩。
LTO或大型链接任务可能使编译器整体表现从CPU密集型变成内存或I/O密集型。不同编译参数的结果不应放在一张表中直接排名。
缓存状态
缓存必须作为独立变量管理。建议至少分为:
| 测试状态 | 处理方式 | 主要用途 |
|---|---|---|
| 冷缓存全量构建 | 新建干净构建目录,缓存目录隔离 | 观察原始编译和存储压力 |
| 温缓存重复构建 | 保留文件系统缓存,但不使用编译缓存 | 观察热数据访问能力 |
| 编译缓存命中 | 使用独立的ccache目录并记录命中率 | 模拟重复提交和持续集成场景 |
| 增量构建 | 固定修改文件和依赖范围 | 观察开发者等待时间 |
在有其他业务运行的服务器上,不建议直接通过清空系统缓存制造“冷缓存”,因为这可能影响同机服务。更稳妥的做法是使用独立测试实例、快照或一次性构建目录,并在报告中写清楚缓存处理方式。
采样方法:固定环境,再固定重复次数
测试前记录基线
在正式测试前,先保存一份环境清单:
uname -a
cat /etc/os-release
lscpu
free -h
df -hT
再记录编译器和构建工具版本:
gcc --version
clang --version
ninja --version
cmake --version
如果实际项目使用Make、Bazel或其他工具,应记录对应版本,不要只记录操作系统版本。源码、依赖和编译参数也应写入测试清单,以便复测时恢复同一条件。
运行顺序和重复次数
一组可执行的采样方案如下:
- 预热运行1至2次,不纳入正式结果;
- 每个并行度至少执行5次,规模较大的项目建议执行7次;
- 交替运行不同并行度,避免高并行测试总是在最后、受到温度或宿主机负载影响;
- 每次运行记录Wall time、CPU time、峰值内存和I/O状态;
- 报告中同时给出中位数、最小值、最大值和标准差;
- 如果变异系数超过5%,先调查原因,不要简单删除“异常值”。
完整构建只有5次样本时,P95统计意义有限。若要报告可靠的P95延迟,最好累计20次以上完整任务,或者从构建系统的单个编译任务、依赖下载请求和制品上传请求中采集更多样本。
设计并行度矩阵
对于双路128物理核心、256线程的环境,可以按以下思路安排:
| 测试组 | 并行度范围 | 主要观察 |
|---|---|---|
| 低并行度 | 1、2、4、8、16 | 单任务延迟、串行开销 |
| 中并行度 | 32、64、96 | 物理核心扩展趋势 |
| 高并行度 | 128、160、192 | 两个NUMA节点和调度压力 |
| 线程超额 | 256及以上 | SMT收益、队列堆积和内存压力 |
| 多任务并发 | 2、4个构建任务 | 持续集成吞吐和资源争用 |
-j256不应被默认为最佳配置。对于受内存带宽、链接器或磁盘限制的项目,超过物理核心数后可能出现完成时间不再下降,甚至因为上下文切换和缓存争用而增加。
如果需要观察NUMA影响,可以对同一个构建任务分别测试默认调度、单节点绑定和跨节点交错分配:
numactl --cpunodebind=0 --membind=0 ninja -C /srv/build/project -j64
numactl --interleave=all ninja -C /srv/build/project -j128
单节点绑定结果只能代表单个NUMA节点的能力,不能与全机结果直接当作同一配置比较。它的价值在于识别远端内存访问是否造成明显损耗。
采集CPU和进程级数据
在构建命令外层加入时间和性能计数器:
/usr/bin/time -v ninja -C /srv/build/project -j128
如果系统允许使用perf,可以进一步采集指令、周期和调度数据:
perf stat -e task-clock,cycles,instructions,context-switches,cpu-migrations,page-faults ninja -C /srv/build/project -j128
构建任务通常会派生大量子进程,只观察父进程可能遗漏实际编译器进程。因此应结合系统级mpstat、iostat和pidstat,或者使用构建容器、cgroup或作业调度器统计整个任务组的资源消耗。
结果解释:从现象追到瓶颈
下面的示例数据仅用于说明分析方法,不代表该双路EPYC 9554香港服务器的实测结果。
| 并行度 | 完成时间 | 物理核心口径CPU利用率 | I/O等待 | 峰值RSS | 可能含义 |
|---|---|---|---|---|---|
| 16 | 920秒 | 55% | 1.2% | 38GB | 任务量有限或存在串行阶段 |
| 64 | 340秒 | 88% | 1.8% | 52GB | 并行度提升带来明显收益 |
| 128 | 238秒 | 96% | 2.5% | 66GB | 接近物理核心利用上限 |
| 256 | 247秒 | 92% | 8.0% | 70GB | SMT和队列压力抵消了部分收益 |
从这个示例不能得出“128线程一定最佳”的普遍结论。正确的解读是:该类负载在128附近已经接近收益拐点,继续增加任务数没有缩短完成时间,需要进一步检查编译器调度、内存带宽、链接阶段和磁盘队列。

CPU高利用率但时间仍长
如果CPU利用率高、频率稳定、iowait低,而且内存带宽没有达到瓶颈,说明任务确实在消耗计算资源。此时应关注:
- 编译参数是否启用了高成本优化;
- 是否存在少数无法并行的链接任务;
- 构建目标是否足够多;
- 单个源文件是否过大;
- 编译器版本和链接器是否适合该项目。
如果并行度从64增加到128后,CPU利用率已经接近满载但时间只缩短很少,通常是串行阶段或内存子系统限制,而不是核心数量不够。
CPU不高、I/O等待高
CPU利用率不高而iowait、await和磁盘队列明显升高,优先检查:
- 源码目录是否位于性能较弱的云盘或网络文件系统;
- 是否存在大量小文件扫描;
- 构建目录是否与系统日志、数据库等业务共享磁盘;
- 链接阶段是否产生大量临时文件;
- 文件系统缓存是否被其他任务挤出。
这类情况增加CPU核心通常收益有限。应先改善构建盘、文件系统、缓存和并发控制,再重新进行CPU并行度测试。
CPU和磁盘都不高,但内存指标异常
如果CPU利用率中等、磁盘等待较低,但远端内存访问比例、页面错误或内存带宽较高,应重点检查NUMA布局。典型表现包括:
- 绑定在单个NUMA节点时性能反而更稳定;
- 默认调度时运行时间波动明显;
- 128线程比64线程收益很低;
numastat显示远端访问较多;- 内存容量没有耗尽,但带宽已经成为限制。
这时不能简单把问题归咎于“128GB太少”。容量、通道数量、频率、页面分配策略和进程亲和性都可能影响结果。
增量构建很快,但全量构建很慢
这种结果通常说明缓存命中或受影响目标数量较少。应检查:
ccache命中率;- 预编译头是否生效;
- 文件系统缓存是否处于热状态;
- 实际重新编译的目标数量;
- 链接任务是否被跳过。
增量构建适合评价开发体验,但不能替代全量构建验收。发布镜像、工具链升级或缓存失效时,最终仍可能触发大规模冷构建。
网络阶段占比高
如果本地源码和依赖条件下的构建时间稳定,但远端依赖获取明显拉长总时长,说明主要问题位于网络或远端仓库。建议分别报告:
- 本地缓存命中时的纯构建时间;
- 远程拉取依赖耗时;
- 制品上传耗时;
- 失败重试次数;
- 不同时间段的P50和P95。
香港服务器适合服务不同地区的业务,但访问具体代码仓库和制品仓库时仍需以实际链路为准。不能只用机房所在地判断所有网络请求都会更快。
决策边界:什么结果才支持采购或扩容判断
判断是否适合大型单任务编译
可以把以下条件作为内部验收参考,而不是绝对行业标准:
- 全量构建在目标并行度下能够稳定完成;
- 连续运行时CPU频率没有明显降档;
- 构建期间不发生swap;
- 峰值内存与可用内存之间保留业务余量;
- 磁盘P95延迟没有随并行度快速恶化;
- 运行时间的变异系数保持在约3%至5%以内;
- 从64增加到128并行任务后仍有可解释的收益。
如果项目本身只能产生几十个并行任务,那么双路128物理核心的计算资源无法全部转化为构建速度。这并不意味着服务器配置错误,而是项目并行度不足,应将评价重点转向多项目并发吞吐。
判断128GB内存是否够用
不要用“每核心分配多少GB”直接判断编译容量,应以实测峰值和并发数计算。建议使用:
内存可承载并发数 = 向下取整(可用于构建的内存 ÷ 单个构建峰值内存)
其中,可用于构建的内存应扣除操作系统、监控、缓存和其他业务预留。假设系统实际可用内存为112GiB,预留20GiB,单个冷构建峰值为36GiB,则:
向下取整((112 - 20)÷ 36) = 2
这表示从内存容量角度看,两个任务较为稳妥,三个任务则可能触碰内存压力。实际决策还要同时检查CPU和I/O:
可承载并发数 = min(内存上限,CPU上限,I/O上限)
如果一个构建在稳定拐点使用56个物理核心,两个任务约需112个物理核心;如果两个任务的磁盘读写已经接近存储上限,那么最终并发数仍应按磁盘限制确定。
判断是否需要更大内存或更快存储
出现以下现象时,应优先考虑扩容内存、调整DIMM布局或升级存储,而不是继续提高-j:
- 峰值RSS长期超过可用内存的70%至80%;
- 高并行度下出现swap或大量page fault;
- CPU利用率下降,但内存带宽接近上限;
iowait和磁盘await随并行度同步上升;- 单任务尚可,多任务并发时长尾明显增加;
- 构建时间受远端内存访问影响大于受CPU频率影响。
双路高核心数配置配128GB内存可以用于一部分编译场景,但对于大型C++项目、LTO、多个并发流水线或容器化构建,内存容量和通道平衡需要单独验证。
验收时需要保留的记录
交付测试不宜只保留一个“完成用时”截图,至少应保存:
lscpu、numactl --hardware和内存拓扑信息;- CPU、内存、磁盘和网络型号;
- 操作系统、内核、编译器和构建工具版本;
- 源码提交号、依赖版本和编译参数;
- 每个并行度的运行时间和重复次数;
- 峰值RSS、CPU频率、
iowait、steal和磁盘队列; - 缓存命中率;
- 本地构建与远程依赖构建的拆分结果;
- 测试期间是否存在其他业务和宿主机争用。
复测与容量判断:让结果能够在交付后复现
复测时应保持CPU插槽、SMT、BIOS电源策略、内存插槽布局、存储挂载方式、编译器版本和源码提交号一致。只更换服务器而不固定这些条件,得到的差异无法归因于EPYC 9554或香港机房本身。
对于单任务场景,优先看全量构建中位数、链接阶段长尾和并行扩展曲线;对于持续集成场景,优先看每小时完成数、两个及以上任务并发时的P95延迟和内存余量;对于远程协作场景,则应把依赖拉取、制品上传和纯构建时间分开记录。
最终的容量判断可以采用三步法:
- 用
-j扫描找到单个项目的稳定拐点,而不是直接使用最大线程数; - 在该并行度下增加第二、第三个构建任务,观察内存、I/O和P95延迟;
- 以CPU、内存、存储和网络四项中最先达到稳定上限的资源,确定服务器的实际并发容量。
只有当不同并行度、不同缓存状态和不同并发数量下的结果都能解释,双路EPYC 9554加128GB DDR5香港服务器的编译价值才算被完整测量。



