简介:面向国产处理器选型与性能评测需求的技术文档,聚焦基于 SPEC CPU2017 的 CPU 性能对比分析方法,适合芯片评测、服务器选型与系统软件优化方向的研究人员、开发者参考。内容以 ARM 架构的国产 Hi1616 和 X86 架构的 Intel E5-2650v4 为对象,分别比较不同线程数下的计算速度性能与不同任务拷贝数下的吞吐量性能,并分析 GCC 编译器版本对测试结果的影响;结论表明多任务高并发场景下 Hi1616 更具优势,单线程科学计算场景则由 Intel 平台较好满足。压缩包仅含 1 份 PDF,约 1.08MB,篇幅紧凑,涵盖测试方法、实验数据和国产 CPU 发展现状梳理,可作为性能基准测试入门、测试方案搭建及评测报告撰写的参考,兼具专业指导与文献查阅价值。已有 2891 人学习下载。
1. 跑分高 12% 的机器,业务上反而更慢
两台服务器摆在机房里做对比:一台 32 核高主频,一台 48 核低主频。拿 SPEC CPU2017 的 intrate base 跑下来,前者比后者低大约 12%,采购单差点按这个结论签。上线压测时反过来了,48 核那台在并发 200 的混合读写场景里 QPS 反而低一截,原因是副本铺得开但单线程路径被内存带宽拖住。
SPEC CPU2017 度量的是整机吞吐,不是你的业务时序。一份《基于 SPEC CPU2017 的 CPU 性能对比分析》如果只有总分,没有套件、口径、编译器版本和内存配置,结论基本不可复用。下面按选口径、搭环境、跑命令、读结果、固化配置这条线,把这套对比自己做一遍,适合做服务器选型、虚拟化密度规划和容量报告的人。
2. SPEC CPU2017 的套件构成与 base/peak 口径怎么选
SPEC CPU2017 的交付形态是源码包加编译运行脚本,在目标机上自己编译、自己跑,所以结果里天然带着编译器、数学库和内存子系统的指纹。做 CPU 性能对比分析,第一步不是敲命令,是先定套件和口径,因为这决定了后面所有参数的默认值。
2.1 intrate、intspeed、fprate、fpspeed 分别适合什么对比场景
整数与浮点两族各有一个 speed 套件和一个 rate 套件,合计四套。intspeed 和 intrate 由 10 个整数基准构成,fpspeed 和 fprate 由 13 个浮点基准构成,浮点套件里 Fortran 代码占比不低,对工具链版本更敏感。
| 套件 | 度量对象 | 并发方式 | 典型对比场景 |
|---|---|---|---|
| intspeed | 单任务整数性能 | 单实例串行 | 数据库单连接延迟、编译机 |
| intrate | 整机整数吞吐 | N 个副本并发 | Web 集群、容器密度评估 |
| fpspeed | 单任务浮点性能 | 单实例串行 | 单线程仿真、数值求解 |
| fprate | 整机浮点吞吐 | N 个副本并发 | 批量计算节点、预处理集群 |
选择规则不复杂:评估单机承载多少业务实例,看 rate;评估低延迟服务的响应能力,看 speed。两边都跑一遍的价值在于能解释「为什么单核强但吞吐弱」这类反直觉结果,只跑一半就没法归因。
2.2 base 与 peak 的差别不只是优化开关
base 要求同一套件内所有基准使用完全相同的编译与运行选项,peak 允许针对每个基准单独挑选项。报告规则上,提交 peak 分数必须同时提交对应的 base 分数,所以公开渠道上的对比通常以 base 打底。
跨机器对比时我一般只看 base。原因很直接:peak 分数里包含大量编译器调优工作,两个团队在不同时间调出来的 peak 没有可比性;base 把变量压缩到硬件和工具链版本上,剩下的差异才更可能来自 CPU 架构本身。如果一定要出 peak 数据,务必把编译器版本、优化 flag 清单一起写进对比表,否则数字没法复用。
2.3 可报告口径的硬性约束与参数对照
| runspec 参数 | 作用 | 报告要求 |
|---|---|---|
| --reportable | 启用可报告口径校验 | 必需 |
| --iterations 3 | 跑 3 次取中位数 | 必需 |
| --tune base | 使用 base 优化档 | 与提交口径一致 |
| --rate N | 指定副本数 | 需在配置中注明 |
| --output | 把运行日志落盘 | 保留原始记录 |
注意:可报告口径会检查各次运行的选项一致性。改一个 flag 只跑一次,结果只能算内部参考,不能进对外报告。
2.4 安装与自检的最小步骤
SPEC CPU2017 是商业授权套件,需要合法获取介质,安装包本身就是一个 install.sh。
# 安装到固定路径,路径统一便于跨机器对比和归档 sudo mkdir -p /opt/spec2017 cd /path/to/spec-cpu2017-media sudo ./install.sh # 交互式安装,按提示把安装目录填成 /opt/spec2017 cd /opt/spec2017 . ./shrc # 把 runspec 与工具链路径注入当前 shell runspec -V # 打印版本信息,确认环境变量已生效 # 用 test 规模做一次冒烟验证,几分钟出结果,只用于确认工具链完整 runspec --config=Example-gcc-linux-x86.cfg --tune=base \ --size=test --noreportable intspeed--size=test 用的是小数据集,对内存带宽几乎不敏感,绝不能拿它的结果写对比结论;--noreportable 关闭报告校验,速度快但不合规。这两条是最常见的误用,尤其是在赶报告的时候。冒烟通过后再切回 ref 规模做正式对比,中间的差异往往就是几倍量级。
3. 用 runspec 跑通一次可对比的基准测试
对比的两个前提是环境一致和参数可复现。环境不一致,再精确的脚本也救不回来;参数不写进配置文件,换个人重跑就是另一套数字。
3.1 从示例 cfg 派生自己的配置文件
# 先看套件自带哪些示例配置,挑最接近目标平台的一份作为起点 ls /opt/spec2017/config/ | head -20 cp /opt/spec2017/config/Example-gcc-linux-x86.cfg \ /opt/spec2017/config/my-compare.cfg不要直接改示例文件。派生一份自己的配置,命名里带上平台和日期,例如 my-compare-epyc-2024.cfg,两台机器共用同一份,配置内容才具备可比性。cfg 文件本身就是最好的实验记录,任何时候都能把当时的编译选项和运行环境还原出来。
3.2 runspec 最小可跑命令与参数拆解
cd /opt/spec2017 . ./shrc # 在 16 个物理核上跑 intrate base,3 次迭代,输出可报告结果 runspec --config=my-compare.cfg \ --tune=base \ --rate 16 \ --iterations 3 \ --reportable \ --output=/tmp/intrate-base-16.txt \ intrate参数说明:
- --config 指定配置文件,两台机器必须指向内容等价的文件。
- --tune=base 固定优化档,避免误用 peak 让结论失去可比性。
- --rate 16 开 16 个并发副本,一般取物理核数减 2,给系统和监控留余量,同时避开最后几个核被中断占用后反复抢占。
- --iterations 3 跑三次取中位数,可报告口径的硬性要求。
- --output 把 runspec 的完整日志落盘,事后复核参数全靠它。
- 末尾的 intrate 是套件名,换成 intspeed 就是单任务口径,其余参数含义相同,只是 rate 不再生效。
3.3 内存布局与 NUMA 绑定写进 cfg
# my-compare.cfg 节选:把副本绑定与内存布局固化,不依赖 shell 现场拼命令 int=default=default=default: CPUSET=0-15 ENV_MEM_LAYOUT=CHANNELS=8,CHANNEL_INTERLEAVE=0 ENV_OMP_NUM_THREADS=1 ENV_KMP_AFFINITY=granularity=fine,compact,1,0CPUSET 限制副本可用的 CPU 集合,防止调度器把两个副本塞进同一个物理核;ENV_MEM_LAYOUT 声明内存通道数以及是否交织,写错会让结果偏乐观或偏悲观,必须按机器真实通道数填;ENV_OMP_NUM_THREADS=1 保证每个副本单线程,否则 rate 的副本数含义就被改变了;ENV_KMP_AFFINITY 控制 OpenMP 线程贴核策略,浮点套件受影响尤其明显。
3.4 频率、超线程与温度状态怎么固定
# 固定 performance 调速器,防止跑分中途降频 sudo cpupower frequency-set -g performance # 关闭自动 NUMA 平衡,让副本分布可复现 echo 0 | sudo tee /proc/sys/kernel/numa_balancing # 记录拓扑与超线程状态,写进对比报告 lscpu | grep -E 'Socket|Core|Thread|NUMA|MHz'SPEC 的 rate 分数对频率非常敏感,调速器停留在 schedutil 或 powersave 时,分数可能低 5% 到 15%,而且每次都不一样。NUMA 自动平衡会在跑分中途迁移线程,导致三次迭代的离散度变大。超线程开不开没有统一答案,但两台机器必须一致,并且写在报告里。
提示:跑分机器上不要同时跑日志归档、监控采集这类常驻任务,它们抢的是同一批物理核和内存带宽。
3.5 怎么确认副本真的在满负荷跑
# 每秒采样一次整体状态,看 us+sy 是否稳定在高位、id 是否长期接近 0 vmstat 1 20 # 单独看每个副本进程落在哪个核上 ps -eo pid,psr,pcpu,comm --sort=-pcpu | head -20 # Linux 查看 CPU 温度,确认没有触发温度墙 watch -n 2 'sensors | grep -E "Package|Core"'如果 id 长期高于 10%,通常意味着副本没铺满或者有副本在等锁;如果多个副本的 psr 落在同一个核上,说明绑定没生效,回去检查 CPUSET。跑分周期动辄几十分钟,中途任何一次温度墙触发都会污染中位数,所以温度监控必须与跑分同时进行,而不是跑完再看。
4. SPEC CPU2017 结果解析与两台机器的对比分析
4.1 结果目录里哪几个数才是要对比的
| 位置 | 内容 | 用途 |
|---|---|---|
| result/CPU2017.*.txt | runspec 原始日志 | 留档、复核参数 |
| result/CINT2017.rate.csv | 各子项 ratio 汇总 | 做对比表 |
| 各基准的 log 目录 | 单基准耗时与编译命令 | 定位异常子项 |
分数只看汇总数字是不够的,逐子项的表才是归因的入口。
4.2 用 Python 把子项结果汇总成对比表
import csv, math def load_ratios(csv_path): """从 SPEC 输出的 CSV 中提取 {基准名: ratio}""" ratios = {} with open(csv_path, newline='', encoding='utf-8') as f: for row in csv.reader(f): # 有效数据行的首列是基准编号,形如 500、502 if len(row) < 3 or not row[0].strip().isdigit(): continue name = row[1].strip() try: ratios[name] = float(row[-1]) except ValueError: continue return ratios def geomean(xs): """SPEC 官方汇总方式:几何平均,不是算术平均""" return math.exp(sum(math.log(x) for x in xs) / len(xs)) a = load_ratios('/tmp/runA/CINT2017.rate.csv') b = load_ratios('/tmp/runB/CINT2017.rate.csv') print('A geomean:', round(geomean(a.values()), 2)) print('B geomean:', round(geomean(b.values()), 2)) for name in sorted(set(a) & set(b)): delta = (b[name] - a[name]) / a[name] * 100 print(f'{name:>16} A={a[name]:8.2f} B={b[name]:8.2f} delta={delta:6.2f}%')总分是各子项 ratio 的几何平均,用算术平均会让领先幅度被高估,这是手工汇总时最常犯的错误。逐子项打印 delta 的价值在于识别「总分接近但子项分化」的情况:一台在内存密集子项领先,另一台在分支密集子项领先,业务该怎么分配就有了依据。
4.3 rate 与 speed 的数字不能混着解读
rate 的分数本质是 N 个副本的总吞吐折算到单副本的比值,副本数翻倍分数大致翻倍,所以跨机器比 rate 必须写明副本数。speed 是单实例串行耗时,与副本数无关。把 A 机器的 rate 数字和 B 机器的 speed 数字放进同一张对比表比大小,是这类分析文档里最常见的错误,而且很难被读者发现。
4.4 用 perf 定位分数差异落在哪
# 挑出差异最大的子项单独跑,用 perf 统计关键事件 perf stat -e cycles,instructions,cache-misses,cache-references,\ LLC-load-misses,LLC-loads,branch-misses \ -p $(pgrep -f mcf_r | head -1) sleep 30instructions 与 cycles 一起看能算出 IPC;cache-misses 配合 LLC-load-misses 用来判断是否卡在最后一级缓存;branch-misses 高说明分支预测压力大。判断路径很清晰:IPC 接近而频率不同,差异来自频点;IPC 差而频率一致,差异来自微架构和内存子系统。这一步做完,对比报告里的结论就从「A 比 B 快 12%」变成「A 在缓存敏感子项上领先,B 在带宽敏感子项上落后」。
4.5 把跑分结论和真实业务负载对齐
CPU 使用率过高的危害在容量报告里常被写成一句「扩容即可」,而扩容决策依赖的正是这类性能对比数据。我一般会补一轮业务流量回放:观察 p99 延迟和 CPU 利用率曲线,把 intrate 的领先幅度与 QPS 的领先幅度并列写进同一张表。两者方向一致时可以下结论;SPEC 领先而业务持平甚至落后,就要回头查内存带宽、跨 NUMA 访问和超线程这几个变量。服务器 CPU 天梯图上的排名可以作为候选清单,但不能替代这套流程。
5. 让对比结论经得起复盘的固化技巧
5.1 用一份清单把 BIOS、cfg、内核参数一起锁定
# bench-lock.yaml:跑分前逐项核对,任何一项不同就不进入对比 platform: "2 socket x 16 core" bios: hyper_threading: on numa: enabled power_profile: performance kernel: numa_balancing: 0 governor: performance spec: config: my-compare.cfg tune: base rate: 16 iterations: 3这份清单的意义在于让半年后重跑的人知道当时环境长什么样。对比结论失效最常见的场景不是算错,而是第二次运行时 BIOS 被人改过、内核升级换了默认调速器。
5.2 交叉验证的三条落点
验证不能只靠 SPEC 一个来源。第一条落点是 perf:重复测出 IPC 和缓存命中率的稳定区间,确认差异不是噪声;第二条落点是业务压测:用同一份流量回放脚本打两台机器,对比 p99 与 CPU 利用率;第三条落点是重跑:隔一周用完全相同的配置再跑一次,中位数波动控制在 2% 以内,这组数据才有资格进采购文档。三条都过,结论才算立住。
5.3 三个最容易让结果作废的细节
- 用 test 规模的结果当正式数据,内存带宽和缓存容量的差异被完全掩盖。
- 副本数与物理核数不匹配,多开导致副本互相抢占,少开导致分数偏低,两种都会误导选型。
- 只跑一次直接报分,没有中位数,单次运行恰好遇到降频或后台任务就会把结论带偏。
跑分结束先别急着下机,把 result 目录连同 bench-lock.yaml 一起打包,路径里带上日期和硬件序列号,下一次对比直接按序列号翻历史数据,省掉重新对齐环境的整段时间。
本文还有配套的精品资源,点击获取