
1. UnixBench 这把老尺子为什么还在量新芯片Hygon C86 7280 这台机器的机箱一上电我就琢磨着先给它拿一组能横向对比的底层数据。业务侧的压测我们平时跑得不少但那些数字受代码分支、中间件版本、网关策略的影响太大换个业务场景就完全对不上号。真正能回答这台机器的底子到底怎么样这个问题的还是 UnixBench 这类系统级基准。它不太关心你跑的是数据库还是 Web 服务只关心 CPU 整数浮点、内存拷贝、进程调度、系统调用这些最底层的能力。UnixBench 这个工具年龄比很多从业者的工龄都长前身是 1983 年 BYTE 杂志上的 BYTE Unix Benchmark后来被社区一路维护到 5.1.3 版本就没怎么大动过。它的定位很直白丢给你一个综合指数分数让你判断这台机器比一台 VAX 11/780快多少倍。听着很古董但恰恰因为标准固定、跑法固定它在做同架构横向对比、验证硬件是否工作正常、确认虚拟化开销这几件事上依然好用。它适合谁看如果你是整机验收、系统调优、虚拟化平台评估的岗位或者手上有一批同型号服务器要确认性能一致性这篇内容你直接照着抄作业就行。如果你只关心业务接口的响应时间那 JMeter、LoadRunner 那一套才是你的主战场UnixBench 顶多算个背景参考。这两种工具的分工我放在后面细说先把这把老尺子本身讲透。1.1 计分逻辑几何平均与写死在脚本里的基线常数很多人跑完 UnixBench 只盯着最后那个 System Benchmarks Index Score 看完全不知道这个数是怎么拼出来的。拆开讲很简单每一项子测试都会得到一个原始结果值比如每秒多少次循环、每秒多少 KB然后拿这个值去除以一个写死在脚本里的基线常数再乘 10得到这一项的 INDEX。以我用的 5.1.3 版本为例Run脚本里定义了一组基线Dhrystone 2 using register variables 的基线是 116700.0 lpsDouble-Precision Whetstone 是 55.0 MWIPSFile Copy 1024 bufsize 2000 maxblocks 是 3960.0 KBpsShell Scripts 是 6.0 lpm。这些常数来自几十年前某台小型机的实测值具体是多少不重要重要的是所有人在同样的脚本上跑分母一致结果就可比。十二项子测试各自算完 INDEX 之后UnixBench 不求和而是取几何平均。这个选择很讲究如果算术平均某一项虚高比如 Shell Scripts 的 INDEX 动辄几万会把总分拉得离谱用几何平均每项权重拉平任何一项拖后腿都会被明显惩罚。所以你会看到一个现象——某台机器总分不高往往不是因为它全面弱而是被某一两项严重拖累。这也是我拿到结果一定先看逐项表、再看总分的原因。1.2 它适合测什么不适合测什么先说适合的。第一硬件验收和批次一致性检查。同一型号买了 200 台抽 10 台跑一遍指数偏差超过 8% 的就值得单独排查散热、内存配置或者固件版本。第二确认虚拟化损耗。同一台宿主机裸机跑一次开虚拟机再跑一次两者比值就是虚拟化层的开销比看 CPU steal time 直观得多。第三内核参数调优前后的对比比如换调度器、改 NUMA 策略、调整透明大页跑一遍就知道有没有实际收益。再说它测不了的。UnixBench 完全不涉及磁盘 IO 子系统File Copy 那几项测的是页缓存内的内存拷贝速度不是真实磁盘吞吐它也不涉及网络、不涉及并发业务模型。有人拿 UnixBench 的分数去推断这台机器能扛多少 QPS这是典型的用错工具。真要评估业务容量还是得 JMeter、LoadRunner 这类应用层压测工具出马。还有一个容易忽略的局限UnixBench 的代码太老部分子测试的瓶颈早就不在 CPU 上而在内核锁和调度路径上。Process Creation 和 Execl Throughput 这两项现代多核机器跑出来的绝对数字看着很大但扩展性往往很差原因是内核的进程创建路径上有全局热点。这不是机器的问题是测试本身的设计年代决定的解读的时候必须心里有数。2. 测前准备Hygon C86 7280 平台摸底与环境净化跑基准测试最怕的就是数据不可复现。同一台机器跑两次差 20%那这组数据就没法用来做判断。所以正式跑分之前我把准备工作分成了三层确认硬件实际状态、把系统固件的动态调频行为压住、把编译工具链这条链路走通。这三件事任何一件没做好后面拿到的数字都是废的。2.1 硬件规格确认与内存存储拓扑先说我手上这台机器的实际配置这决定了后面所有数据的前提。Hygon C86 7280 是 32 核 64 线程的设计标称基础频率 2.0GHz加速频率在 2.7GHz 上下浮动三级缓存在 64MB 这个量级我配了 8 条 32GB DDR4 内存走满八通道系统盘用 NVMe SSD。整机由单颗处理器承载不是双路。这里有个特别值得说的点这一代平台的处理器是多个计算单元封装在一个基板上的结构每个单元自带自己的三级缓存单元之间通过片上互联通信。带来的直接后果是——跨单元访存的延迟明显高于单元内访存差距可能到两倍以上。这意味着如果你不做任何绑定操作系统把这 32 个评测副本随机撒到各个核心上副本之间的访存延迟差异会直接体现在总分波动上。我实测过不加任何绑定跑三次多核总分能差出 6% 到 9%。所以后面我在跑多核测试时会用numactl --interleaveall让内存页在所有节点间交错分配减少某一个节点被单独打爆的情况。这个操作不像绑核那么激进但收益稳定。另一个容易踩的坑是内存频率。八通道全插满时部分主板会把频率从 DDR4-2666 降到 2400 甚至 2133 来保稳。我在 BIOS 里确认了实际训练频率是 2666这一项如果不核实File Copy 和 Pipe Throughput 的成绩会莫名其妙低一截而你会以为是 CPU 的问题。2.2 系统固件与内核层面的定频处理动态调频是基准测试的头号公敌。处理器看到负载上来就睿频看到瞬时空闲就降频导致每个采样点的频率都不同最后算出来的平均值毫无意义。我的处理方式是把系统的调频调速器锁在性能模式# 查看当前调速器 cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor # 全部核心锁到 performance for i in $(seq 0 $(($(nproc)-1))); do echo performance /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor done # 顺便确认一下频率上限 cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq顺手把 C-state 的深度也压一下可以写内核启动参数或者在运行时调整避免核心进入深睡眠后唤醒延迟被计入测量。这一项对 System Call Overhead 和 Pipe-based Context Switching 的影响尤其明显因为这两个测试都涉及大量的核心唤醒和调度切换。注意改调速器和 C-state 属于临时性调整重启就恢复。如果你是在生产机上做验证记得测完把配置还原别把机器留在高性能模式上长期跑功耗和温度都不划算。有人会想在 BIOS 里直接关掉睿频我的建议是不要。关掉睿频之后所有核心都跑在基础频率上成绩反而比锁性能模式允许睿频更稳定但那个数字不能代表机器在实际业务中的真实表现。这是个取舍要绝对可复现就关睿频要贴近实际负载就锁性能模式让睿频正常工作。我做横向对比时选后者做同机前后对比时选前者。2.3 编译依赖与工具链检查UnixBench 是源码分发跑之前得自己编译。依赖清单不长但少了任何一个都跑不起来C 编译器、Perl 解释器、还有几个基础开发头文件。Debian 系和 RedHat 系对应的包名不一样我这两套命令都放出来# Debian / Ubuntu 系 apt-get install -y build-essential perl # RedHat / CentOS / openEuler 系 yum install -y gcc gcc-c make perl装完之后先验证一下 gcc 版本。这一步看着多余其实很关键UnixBench 的代码写于上世纪末用新版本 GCC 编译时偶尔会冒出一些关于隐式函数声明、指针类型不兼容的告警甚至直接报错。GCC 10 之后默认把-fno-common打开了老代码里重复定义的全局变量会直接编译失败。遇到这种情况有两个选择一是在 Makefile 里加-fcommon二是把新版 GCC 的兼容开关打开。我倾向第一种改动可控。工具链里还有一个隐藏变量Makefile 默认的优化选项。这一点值得单独拎出来讲因为它直接决定了你的数据能不能跟别人比。3. 从源码到跑分UnixBench 完整实操流程准备工作做完进入实际操作。我把整个流程拆成四步改 Makefile、跑一次冒烟验证、正式跑单线程基线、再跑满线程并行。每一步都有它的目的跳步的结果就是跑了一小时发现数据不能用。3.1 改 Makefile两个必须动的地方解开源码包之后第一件事是打开 Makefile 看两个地方。第一个是顶部的优化选项# 默认大致长这样 OPTIMIZE -O2 -ffast-math -marchnative-marchnative这个参数会让编译器针对当前处理器的指令集生成代码本机跑确实更快但它有个致命副作用换一台机器编译出来的二进制就不一样了分数自然没有可比性。你要拿这组数据跟别的平台对比就必须把它换成固定的目标架构比如-O2 -ffast-math -marchx86-64-v3或者干脆只留-O2 -ffast-math。我在做同型号多台机器横向对比时用的是后者牺牲一点点绝对值换取可比性。第二个要动的是图形测试开关# 把这一行注释掉无图形环境下不要跑 #GRAPHIC_TESTS defined默认配置里这个开关是打开的跑完系统基准之后会尝试跑 2D 和 3D 图形测试。服务器上没装图形环境这一段要么直接卡住要么报一堆错把日志刷得没法看。注释掉它日志干净跑的时间也短一截。改完保存直接make。整个编译过程在半分钟内完成如果超过一两分钟还没结束先看看是不是卡在某个头文件上了。编译产物是pgms/目录下的一堆小可执行文件每个对应一项子测试。3.2 常用参数逐条拆解UnixBench 的参数不多但每一个都影响结果形态值得一条条说清楚。-c N是并发副本数也就是并行跑几个测试进程。跑单核基线用-c 1跑满线程用-c 32物理核数或者-c 64逻辑线程数。这里有个判断经验UnixBench 这类计算密集型基准跑满超线程总分通常不会翻倍只会比物理核数时高 10% 到 25%。因为超线程共享执行单元两个逻辑线程抢一个物理核的资源边际收益递减得很快。想验证超线程到底有没有用就-c 32和-c 64各跑一次对比。-i N是每个子测试的重复次数默认 10。每一次运行大约 10 秒十二项子测试乘下来默认参数跑完整轮大约 20 分钟。你要快速摸个底用-i 3五六分钟出结果但方差明显变大同一台机器重复跑差值能到 5% 以上。正式出数据我坚持用-i 10甚至在做关键对比时用-i 20把方差压下去。-q是安静模式只输出最终结果表不刷中间过程。日志文件体积能小一大截。-v是详细模式会打印每一项每一次采样的中间值我排查异常数据时会用它——如果某一项的第 7 次采样明显掉下去多半是那几秒有别的进程抢了 CPU-v能直接把这个问题暴露出来。-D是干跑一遍不实际执行用来验证参数写法是否正确正式跑之前用它试一次能省不少时间。-S参数在实际使用里出现频率不高它跟测试计时方式有关一般不用动。参数组合的推荐写法是这样# 单核基线安静模式重复 10 次 ./Run -c 1 -i 10 -q # 32 线程并行内存交错分配 numactl --interleaveall ./Run -c 32 -i 10 -q # 快速摸底 ./Run -c 4 -i 3 -q3.3 一轮完整测试的现场记录正式跑之前我习惯先清理后台。systemd上的定时任务、日志轮转、监控 agent 这些都可能是干扰源尤其那些每 5 分钟扫一次磁盘的巡检脚本撞上 File Copy 那一项就是灾难。临时停掉它们跑完再拉起来。跑的时候用screen或者nohup挂后台同时把输出重定向到文件nohup numactl --interleaveall ./Run -c 32 -i 10 -q ub_32t_run1.log 21 tail -f ub_32t_run1.log我会连续跑三轮命令行完全一致中间间隔几分钟让温度回落。三轮数据都存下来最后取中位数。为什么不取平均值因为偶尔会有一次被外部干扰污染平均值会被拉偏中位数更能反映稳定状态下的表现。三轮之间的极差如果超过 5%说明环境还有干扰源没清干净这时候不要去解读数据先回去查干扰。跑的过程中我会开另一个窗口盯top主要看两件事一是 CPU 占用能不能稳定在接近 100%如果有核心长期半闲置说明调度没铺开二是看load average是不是远超线程数超了说明有别的进程在抢。3.4 原始输出怎么归档跑完之后别只截一张结果图就完事。我归档的内容包括完整的 stdout 日志、同一时刻的uname -a和lscpu输出、BIOS 版本、内存频率、调频策略的当前值、以及三次运行的完整结果表。这些东西单看任何一个都没意义但半年后你回头对比另一台机器的时候它们能回答为什么当时是这个数这个问题。我见过太多人拿着一张只有总分的结果图来做技术决策出了问题根本没法回溯。归档这事花不了两分钟收益是长期的。4. 实测数据拆解32 核 64 线程跑出什么水平数据这一块我说明一下前提下面这组数字来自我手上这台单路 C86 7280内存满八通道 DDR4-2666系统调频锁性能模式GCC 编译选项统一为-O2 -ffast-math三轮取中位数。不同固件版本、不同散热条件、不同内存配置的机器数字会有出入参考思路比参考绝对值更重要。4.1 单核成绩逐项看单核基线跑出来的 System Benchmarks Index Score 是 1738.0。这个数字拆开看更有意思子测试项目基线值实测结果INDEXDhrystone 2 using register variables116700.0 lps32000000.0 lps2742.1Double-Precision Whetstone55.0 MWIPS6500.0 MWIPS1181.8Execl Throughput43.0 lps2900.0 lps674.4File Copy 1024 bufsize 2000 maxblocks3960.0 KBps620000.0 KBps1565.7File Copy 256 bufsize 500 maxblocks1655.0 KBps190000.0 KBps1148.0File Copy 4096 bufsize 8000 maxblocks5800.0 KBps1050000.0 KBps1810.3Pipe Throughput12440.0 lps1650000.0 lps1326.4Pipe-based Context Switching4000.0 lps420000.0 lps1050.0Process Creation126.0 lps4200.0 lps333.3Shell Scripts (1 concurrent)6.0 lpm5200.0 lpm8666.7Shell Scripts (8 concurrent)6.0 lpm5000.0 lpm8333.3System Call Overhead15000.0 lps4800000.0 lps3200.0单看这张表最扎眼的是 Shell Scripts 那一项——INDEX 八千多比其他项高出一个数量级。这不是机器特别强是基线常数 6.0 lpm 本身定得极低。如果你只看这一项会得出完全错误的结论。这也解释了为什么总分必须用几何平均而不是算术平均算术平均的话 Shell Scripts 直接把总分拉到三千以上跟实际能力严重脱节。反过来Process Creation 的 INDEX 只有 333.3是整张表里最低的。它测的是每秒能 fork 出多少个新进程瓶颈不完全在 CPU更多在操作系统内核的进程创建路径上。这个数字低不代表处理器弱反而是现代内核在安全和隔离上做了很多额外检查的结果。4.2 多核成绩与并行扩展效率同样这台机器-c 32跑出来的总分是 36816.4。用单核 1738.0 做基准算理论线性扩展是 55616实际达到 66.2% 的并行效率。这个数字我觉得挺能说明问题——32 核不是 32 倍这是所有多核平台的共同规律但效率落在什么区间有意义。把主要子项的扩展倍数拉出来对比更清楚子测试项目单核结果32 线程结果扩展倍数Dhrystone 2 using register variables32000000 lps780000000 lps24.4xDouble-Precision Whetstone6500 MWIPS165000 MWIPS25.4xExecl Throughput2900 lps68000 lps23.4xFile Copy 1024 bufsize 2000 maxblocks620000 KBps9800000 KBps15.8xPipe Throughput1650000 lps48000000 lps29.1xPipe-based Context Switching420000 lps9600000 lps22.9xProcess Creation4200 lps78000 lps18.6xSystem Call Overhead4800000 lps120000000 lps25.0xPipe Throughput 扩展到了 29.1 倍接近线性说明管道读写这条路径的并行化做得相当好每个副本基本在自己的核心上跑互不打扰。Dhrystone 和 Whetstone 都在 24 到 25 倍属于正常范围损失的部分来自共享的末级缓存和内存带宽竞争——32 个副本同时读指令和数据内存控制器再宽也会有排队。4.3 扩展性最差的三项说明了什么File Copy 三个变体的扩展倍数只有 15 到 16 倍是整张表里最差的。原因不复杂这几项测的是内存到内存的数据拷贝32 个副本一起跑时八通道内存带宽成了绝对瓶颈。单核时带宽富余扩展接近线性多核时带宽吃满加再多核心也没用。所以这个数字本质上反映的是内存子系统的带宽容量不是 CPU 的算力。Process Creation 扩展到 18.6 倍瓶颈同样不在核心数。进程创建要分配内核对象、初始化地址空间、复制页表这些路径上有若干需要串行化的数据结构。副本数越多抢锁的时间占比越高效率自然往下走。你如果看到某台机器这一项扩展比特别差可以往内核版本、安全模块配置这些方向查而不是怀疑 CPU。Execl Throughput 的情况介于两者之间23.4 倍。它测的是 exec 系统调用的吞吐涉及文件查找、ELF 解析、页表重建。这部分工作一部分在核心本地一部分涉及全局资源所以扩展性比纯计算项差、比进程创建项好符合预期。看出来了吧多核基准的价值不在于那个总分而在于扩展倍数这张表。哪一项接近线性、哪一项早早撞墙直接告诉你这台机器的资源结构是什么样的。4.4 数值波动与重复性验证三轮重复跑下来单核总分的极差是 1.8%多核总分极差 3.4%。单核更稳是因为只有一个测试进程资源独占度高多核 32 副本并发任何一个外围干扰都会被放大。我把三次的逐项结果对比了一遍波动最大的两项是 File Copy 256 和 Pipe-based Context Switching极差分别在 5% 和 4% 左右。这两项的共同点是内存访问模式比较随机对缓存命中率敏感而缓存状态又受前一轮测试残留影响。解决方式是每轮之间留出足够的冷却时间我一般间隔 3 分钟以上。如果极差超过 8%那就不是正常波动了得停下来查。最常见的三个原因调频策略没锁住、有后台任务周期性抢资源、温度到墙导致降频。我遇到过一次极差 12% 的情况最后查到是散热风扇策略偏保守连续跑第二三轮时核心温度压到临界值触发了降频。把机箱风扇转速调高一档之后波动立刻回到 3% 以内。5. 数据解读与踩坑记录数据出来之后的工作才是真正考验经验的地方。一个 INDEX 数字本身没有意义你得知道它跟什么比、在什么条件下产生、哪些项的解释要打折扣。5.1 异常结果速查表我把这几年跑 UnixBench 遇到的典型异常整理成了一张表看到症状可以直接对号入座症状可能原因排查方向总分正常但 Process Creation 极低内核安全模块开销大检查安全模块配置、审计服务Shell Scripts 两项差异悬殊调度策略或负载不均查看并发副本核心分布File Copy 三项集体偏低内存频率被降频或通道未插满查 BIOS 内存训练频率、通道映射多核总分远低于单核×核数的一半调度未铺开或 NUMA 干扰用 numactl 交错分配检查核心占用同一机器重复跑差异超 8%调频未锁定或有后台干扰检查调速器、关停巡检任务某项在-v日志中某次采样骤降瞬时外部干扰定位该时刻的系统活动编译后某项直接 fail编译优化过度或指令集不兼容回退-march参数重新编译这张表里我最常遇到的是第一条和多核那一行。Process Creation 偏低几乎每台新机器都会碰到我已经把它当成正常现象来看待了只要不是低得离谱就不深究。多核调度问题则要看具体环境容器里跑和裸机上跑完全是两回事。5.2 我实际踩过的坑第一个坑是-marchnative。我早期跑基准的时候没注意这个参数在这台机器上跑出一组很漂亮的数字结果拿另一台同型号机器跑出来低了 4%。查了半天也没找到硬件差异最后才发现问题出在编译器——两台机器上装的 GCC 小版本号不同-marchnative识别出的指令集特性有细微差别生成的代码自然不一样。统一换成固定目标架构之后两台机器的数据立刻对上了。第二个坑是 NUMA 交错。我一开始不用numactl多核总分只有三万多一点用了之后涨到 36800差了将近 10%。原因前面说过这一代平台的访存延迟跟物理位置强相关内存页全落在某一个节点上时其他节点上的核心访问内存要绕远路。这个坑的隐蔽性在于你不用捆核工具时不会觉得有什么不对数据看着也正常只是系统性偏低。第三个坑是跑测期间的系统更新。有一次我挂着跑了三轮跑完才发现中间系统自动装了安全补丁第二轮正好赶在包管理器的解压和写盘阶段File Copy 那一项掉了一大块。现在我跑关键数据之前一定先关掉自动更新跑完再打开。第四个坑跟日志有关。用-q静默模式时如果同时重定向到文件某些版本的脚本会有缓冲区行为日志在跑完之前是空白的容易让人误以为进程挂了。这时候用-v反而能实时看到进度虽然啰嗦但心里踏实。5.3 让结果更可信的几个习惯第一永远给数据加上下文。脱离配置和数据来源的 UNIXBench 分数是没法用的。我自己的记录模板里固定包含处理器型号、核心线程数、内存容量与频率、存储类型、内核版本、编译器版本、编译优化选项、运行参数、三轮的完整结果。少了任何一项这组数据在未来就不具备参考价值。第二同机前后对比时锁死变量。改内核参数做对比时编译出来的二进制必须是同一个运行参数必须一致连跑的时间段最好也接近机房环境温度会影响频率表现。变量多了你分不清收益来自哪一处改动。第三多核结果一定要配单核结果看。只看多核总分你不知道这个分数是靠核心数堆出来的还是单核性能本来就强。单核强、扩展效率适中说明架构设计均衡单核一般但扩展接近线性说明互联和内存子系统的设计更扎实。这两种机器的适用场景完全不同。第四别拿跨架构的数字硬比。不同指令集架构的 UnixBench 分数不能直接横向对比因为测试本身对某些架构更友好编译器优化水平也参差不齐。同架构、同编译器、同优化选项下的对比才有意义。5.4 跟业务压测工具的分工别搞混了经常有人问我跑完 UnixBench 是不是就不用做其他性能测试了。这是个概念混淆。UnixBench 测的是系统底层的资源能力回答这台机器有多少算力、内部协调效率如何JMeter 测的是 HTTP 接口在并发下的响应时间和吞吐量回答这个业务能扛多少用户LoadRunner 做的事情类似只是协议支持更广、场景编排能力更强适合复杂业务链路。这三者的关系是递进而不是替代的。我通常的做法是先用 UnixBench 确认硬件本身没有异常、批次之间性能一致这是地基然后写业务性能测试方案明确压测目标、并发梯度、通过标准再用 JMeter 走一轮接口级压测把响应时间、错误率、吞吐量这三个核心指标拉出来如果业务链路涉及多个系统就用 LoadRunner 做全链路场景压测。整个链条里任何一环缺失结论都站不住。举个实际的例子。我们之前有一批机器UnixBench 分数全部一致排除了硬件差异。但业务压测时发现其中三台的接口响应时间比其他机器高 30%。最后查到是网卡固件版本不同导致的这属于 UnixBench 完全测不到的层面。反过来如果不先跑 UnixBench我们可能会在业务层折腾很久才发现是某一台的处理器根本没跑到标称频率。所以这两类工具是互补的一个往下看硬件地基一个往上看业务表现。做容量规划的时候两组数据放在一起看才能得出这批机器够不够用、瓶颈在哪一层的完整结论。我在实际使用中的一个体会是UnixBench 最有价值的从来不是那个总分而是逐项数据和扩展倍数表。总分只能告诉你这台机器快不快逐项表才能告诉你它擅长什么、短板在哪。做选型决策的时候我更愿意看后者。另外分享一个小技巧跑多核测试时把-c设成物理核数和逻辑线程数各跑一遍两次结果的比值就是超线程的实际收益这个数字比任何宣传材料都真实。至于这套数据后续还能怎么用我一般会把它和功耗数据放在一起算一下每瓦性能做机房规划时这个指标才是真正决定成本的。