Linux性能诊断从lmbench开始:编译、使用与结果解读完整指南

发布时间:2026/10/6 16:48:38
Linux性能诊断从lmbench开始:编译、使用与结果解读完整指南 简介lmbench-3.0是一款轻量级开源基准测试工具聚焦内存带宽与内存延时两大核心指标面向系统管理员、驱动开发者及硬件评估人员用于多平台性能对比、系统瓶颈定位与配置调优。压缩包共225个文件以C源码、man手册页、表格定义为主另有配置脚本、文档及基准测试工具整体仅508KB结构清晰、易于部署。已有3660人学习下载覆盖Linux、FreeBSD等Unix-like系统适用于从入门评估到深入调优的不同阶段。资源内置完整源码、构建配置及多种内存测试模式涵盖内存拷贝、填充、随机访问等常见模型可量化内存吞吐量与响应延迟同时支持多线程并行评估允许调整数据块大小与迭代次数帮助读者深入理解缓存层次、内存控制器行为并为算法选型、内核参数调优及硬件验证提供实测依据也可生成直观的对比结果用于团队决策。1. 为什么一个 20 年前的工具仍是衡量系统延迟与带宽的起点业务系统变慢时大多数人第一反应是看 CPU、内存、磁盘占用率但很多性能问题的根子不在资源占用而在底层基本操作的延迟和带宽发生了变化。举个例子有一次遇到数据库连接数上不去、每条查询都慢 10 毫秒的情况表面看负载很低最后发现系统调用和上下文切换的开销比正常基线高了一倍。这种问题靠监控面板很难定位靠业务日志又太粗糙。lmbench-3.0 就是用来量化这类底层操作的微基准测试套件它把系统调用延迟、进程创建开销、上下文切换时间、内存复制带宽、文件读写带宽这些“零件”逐一拆出来测输出可以直接对比的数值。对要做系统调优、换硬件选型、验证内核参数改动的人来说它是最好的起点。这套工具的设计思路很朴素每个测试程序只干一件小事。比如lat_syscall只测一次系统调用从进入到返回花多少纳秒bw_mem只测内存复制能跑到多少 MB/s。因为任务单一结果很难被业务逻辑干扰所以能当“尺子”用。更关键的是它足够老也足够稳Linux 发行版换了一轮又一轮它的测试模型照样有效。接下来这篇文章会从编译开始讲到怎么跑通首轮测试、怎么读懂输出里的延迟和带宽数据、会遇到哪些坑以及怎么把结果整理成能用的报告。2. 编译 lmbench-3.0 并跑通首轮测试configure、make 与最小运行集2.1 configure 前的三件事编译器、内核头文件、以及磁盘空间拿到 lmbench-3.0 源码后别急着 configure先确认三件事能省掉后面一大半报错。第一编译器。最常见的是 gcc版本别太老也别太新gcc 8 到 gcc 13 之间基本都能顺利编译。太老的版本可能不支持源码里用到的某些内建函数太新的版本有时会因为默认开了-fcf-protection之类选项导致链接报错。我一般先执行gcc --version确认再which make确认 make 存在。第二内核头文件。lmbench 里部分测试会引用系统调用相关的内核头文件比如asm/unistd.h和linux/version.h。如果头文件缺失编译时会直接报找不到某个头文件而不是报函数未定义。Debian/Ubuntu 系需要确认build-essential和linux-libc-dev已安装CentOS/RHEL 系则需要确认kernel-devel和glibc-devel。这一步可以用一行命令检查# 验证 gcc 和 make 可用 gcc --version make --version # 检查内核头文件是否存在以常见路径为例 ls /usr/include/linux/version.h || echo 内核头文件缺失这段命令里前半段只是确认工具链后半段用文件是否存在来判断内核头文件。如果输出“内核头文件缺失”先装对应开发包否则后面 configure 的探测编译很可能在中途失败。这里花五分钟比编译到一半翻车再回头省钱得多。第三磁盘空间。lmbench-3.0 完整编译产物体积不大几百 MB 足够但 configure 脚本会往/tmp写临时文件和尝试编译小片段/tmp空间太紧会导致探测误判。检查一下df -h /tmp如果只剩几十 MB先把/tmp清理一下或者把TMPDIR指到一个余量充足的地方再跑 configure。2.2 一次可行的编译命令序列与常见报错确认完这三件事编译流程本身并不复杂。下载源码 tarball 后解压进入顶层目录依次执行# 解压源码包按实际文件名调整 tar -xzf lmbench-3.0.tar.gz cd lmbench-3.0 # 赋予脚本执行权限避免个别文件没有可执行位 chmod x configure config/scripts/* scripts/* # 执行配置探测自动识别操作系统和编译器 ./configureconfigure的作用是探测当前系统类型把检测到的 OS、编译器、CPU 型号、cache 大小等信息写进结果文件并生成各子目录的 Makefile。正常情况下终端会列出一长串 CPU 信息包括型号、主频、cache 大小最后提示配置完成。看到这些信息就说明探测成功了。接下来进入源码目录编译cd src # 编译全部测试程序 makemake会生成bw_mem、lat_mem、lat_ctx、lat_syscall等几十个测试二进制。如果只想快速确认编译没问题也可以先跑make看到全部目标文件生成即可不需要等完整测试流程。这里有一个常见坑如果你直接用 root 执行 make部分老版本源码在链接阶段可能因为/usr/local/lib权限或链接路径问题报错。遇到这类情况第一反应不要改源码先确认系统里 32 位库是否齐全。lmbench 个别老代码在 64 位系统上编译时会出现隐式声明冲突标准做法是加CFLAGS-O2 -fcommon再试这是编译老代码最常见的救法之一。# 遇到旧代码重复定义问题时显式指定 -fcommon 重新编译 make clean make CFLAGS-O2 -fcommon-fcommon是让编译器采用旧的“公共块”合并规则新 gcc 默认改成-fno-common后一些老代码里多个文件各自定义的全局变量会发生冲突。这个选项就是专门给这类历史项目准备的后悔药。2.3 用最小的运行集确认机器能正常出数完整一套make results会把所有测试跑一遍耗时取决于机器性能慢的要一两个小时第一次跑先别急着全量执行。我一般先手动运行四个核心程序确认工具链能出数再决定要不要跑全套。cd src # 测内存读延迟64MB 内存块、以 64 字节步长遍历 ./lat_mem -P 1 -W 1 -N 8 64m 64 # 测内存复制带宽64MB 内存块、读操作 ./bw_mem -P 1 -W 1 -N 8 64m rd # 测一次系统调用延迟 ./lat_syscall -P 1 -W 1 -N 8 null # 测 4 个进程间的上下文切换开销 ./lat_ctx -P 1 -W 1 -N 8 2 4这四个程序分别对应延迟、带宽、系统调用、进程调度四类最常用的基础指标。参数里的-P 1表示单进程执行排除多进程争抢 CPU 的干扰-W 1表示预热 1 轮让 cache 状态稳定再计入成绩-N 8表示重复 8 次取综合结果。lat_mem的64m是内存块大小64是每次访问的步长步长越小越能测出 cache line 内连续访问的延迟步长越大越能压到内存控制器。跑完后终端会直接打印结果。lat_mem输出的是 nanosecond 级别的延迟bw_mem输出的是 MB/s 级别的带宽。只要能看到具体数字并且数值在合理范围内比如内存延迟通常在几十纳秒量级就说明工具链没问题可以跑完整套件的make results了。常见的典型结果区间可以参考下表。测试程序典型输出量级说明lat_mem几个 ns 到几十 ns取决于 cache 层级L1 命中比 L3 命中低得多bw_mem数千到上万 MB/s取决于内存通道数和 DDR 代数lat_syscall几十 ns 到几百 ns不同系统调用开销差异明显lat_ctx几微秒到几十微秒与进程数和 cache 命中率强相关注意这些只是量级参考不同架构差异很大关键是要“看着像话”。如果 lat_mem 打出几千纳秒bw_mem 打出几十 MB/s那多半是配置或参数有问题别拿这种数据写报告。3. 读懂 lmbench 输出从 bw 与 lat 两个维度看系统边界3.1 bw_mem 和 lat_mem 的分工为什么它们能测出内存层次lmbench 把测试分成两个维度bw 开头的是带宽测试测的是单位时间内能搬运多少数据lat 开头的是延迟测试测的是完成一次操作要等多久。这两个维度看着相关实际经常互相矛盾。比如内存带宽很高但随机访问延迟可能很差CPU 主频很高但一次系统调用要经过很长的内核路径延迟照样降不下来。bw_mem的做法是申请一块指定大小的内存然后反复执行读、写或者读写混合操作。它有两个核心参数内存块大小和操作模式。内存块从 1MB 到 64MB 甚至 256MB 变化时能直观看到 cache 容量边界数据放得进 L2 cache带宽就高放不进去带宽立刻掉下来。操作模式rd是纯读wr是纯写cp是复制不同模式能分别暴露读路径和写路径的瓶颈。lat_mem则完全不同它测的是随机访问延迟。程序会准备一块内存然后按给定步长在内存块里跳着读。步长为 64 字节时基本等价于逐条 cache line 访问数字反映的是内存延迟步长为 4KB 甚至 1MB 时每次访问都要跨页甚至跨 TLB 条目反映的是 TLB 和大页的影响。这个测试跑出来的曲线能直接画出整个内存层次——L1、L2、L3、DRAM 每一级的容量边界和访问延迟比看lscpu上的 cache 数字直观得多。3.2 关键参数对齐从 -P 到 WARMUP 与 REPEAT跑 lmbench 最忌讳的是不动脑子直接跑默认参数。同一个lat_mem 64m 64在不同机器上结果差一倍都可能原因往往出在参数不一致或者系统状态不一致。要拿结果做对比必须先把这几组参数固化下来。-P决定并行进程数。测单核能力必须用-P 1否则内核会调度到不同核心cache 亲和性被破坏。但有些场景你确实想知道多核并行的总带宽比如压测内存控制器极限这时候-P设为 CPU 物理核数反而更真实。我个人的经验是报告里给两套数据单核一套全核一套分别标注。只给单核数据容易让看重吞吐的读者觉得不落地只给全核数据又掩盖了单核效率下降的问题。-W是预热次数-N是重复次数。warmup 的作用是把 TLB、cache、分支预测器“加热”到稳定状态。老版本 lmbench 默认值偏低内存类测试最好设-W 1因为第一轮结果通常偏高或偏低不稳定。重复次数-N设为 5 到 8 轮太少结果受噪声影响大太多浪费时间。这里有个血泪经验不要只取平均值要同时记录每轮原始值。某个数据点如果和其他轮次差 20% 以上那一般是瞬时干扰比如后台 cron 启动直接剔掉。平均值会被那一轮拉偏但中位数几乎不受影响。所以完整做法是跑 8 轮记录 8 个值汇报时用中位数。3.3 结果文件的后处理把 summary 变成可对比的清单跑完make results后lmbench 会在results/目录下生成一堆文本文件。文件名通常包含机器名和日期比如test.results或者是按测试项分开的输出。直接用文本编辑器看也能读懂但几十个文件翻起来效率太低。我一般会写一个小命令把需要的关键行提取出来拼成一个总表# 提取四类核心测试结果到单个文本文件 cd results # 匹配带宽、延迟、系统调用、上下文切换关键行 grep -E bw_mem|lat_mem|lat_syscall|lat_ctx *.results all_key_metrics.txt # 按测试名排序方便横向对比 sort all_key_metrics.txt | uniq all_key_metrics_sorted.txtgrep是把所有结果文件里带bw_mem或lat_mem的行抽出来这些行本身已经带有测试参数比如bw_mem 64m rd和对应的 MB/s 数值。排序后同一个测试项会排在一起机器间对比时就很容易看出哪一项变差了。如果结果文件命名不统一也可以换用cat * all_results.txt先合并再 grep效果一样。这一步能把原始输出的“黑匣子”感去掉后面往报告里贴数据也能直接用这份整理过的清单。这里有个容易忽略的点make results跑出来的结果可能直接被写进results/summary.out之类的汇总文件但汇总文件里的内容不一定包含所有参数细节。所以我自己干活时基本不看 summary只看按测试项拆分的原始行。摘要方便但不完整原始文件才是不说谎的。4. lmbench 三层常见故障排查编译失败、超时误报与数据抖动4.1 configure 提示“未知操作系统”导致探测中断现象执行./configure后终端输出类似Unrecognized OS或cannot determine OS type然后直接退出。原因lmbench-3.0 的探测脚本维护年份较早对新版本内核和发行版的名字识别不全。比如新版内核把utsname里的系统版本号格式改了脚本里做字符串匹配时对不上。解决不要尝试去改探测脚本的模糊匹配逻辑那是无底洞。更快的做法是手动指定系统类型参数。可以先执行./configure --help看支持的参数通常涉及--os或--target-os。如果还是不行就临时修改探测脚本里返回系统名的那几行把当前发行版名称映射成它认识的老名字比如把新版系统的标识改写成某个它已支持的系统名。这个改动只影响编译时的系统标识不影响测试程序行为。注意修改脚本前先备份。探测脚本里通常有一段缓存机制改完不生效时多半是缓存了旧值删掉缓存文件再重跑。4.2 编译时死报undefined reference或缺少头文件现象make执行到一半编译器报undefined reference to xxx或者直接fatal error: 某个头文件 not found。原因这一类绝大多数不是 lmbench 源码的问题而是系统开发环境和源码期望的环境不匹配。undefined reference多出现在链接阶段通常是缺少某个库的符号常见于 64 位系统缺 32 位兼容库或者某项内核接口改名。头文件缺失则是内核头文件没装全。解决先看报错的是哪一行如果是某个内核数据结构的头文件确认linux-libc-dev或kernel-devel装好。如果是链接阶段报符号缺失优先尝试make clean make CFLAGS-O2 -fcommon这能解决一大半老代码在 gcc 10 之后的问题。如果还不行把报错行里的函数名在源码里搜一下看看是哪个测试程序引用的直接在对应源码文件头部注释掉相关检测逻辑或者补一个条件编译。这种改法不优雅但微基准测试工具本来就是拿来跑的不是拿来当艺术品维护的。4.3 跑make results时长时间停滞疑似卡死现象屏幕上停在某个测试项比如lat_mem 256m 4等了好几分钟都没有新输出。原因不是卡死是某些组合确实非常慢。lat_mem的 size 越大、stride 越小访问次数越多。lat_mem 256m 4相当于以 4 字节步长在 256MB 内存里跳着访问随便一算就是上亿次访存再叠加重复轮次耗时极长。解决先并行开一个终端执行top -H -p 测试进程pid观察 CPU 占用。如果 CPU 占用接近 100%说明还在正常工作耐心等。如果 CPU 占用为 0说明进程被阻塞了再用cat /proc/pid/stack或strace -p pid看它卡在哪一步。为了节省时间我一般会把这类高开销组合从测试集里拿掉只保留像lat_mem 64m 64这种能反映内存延迟曲线又不会跑到地老天荒的配置。4.4 带宽结果比理论内存带宽还高先别急着高兴现象bw_mem 64m rd跑出来的带宽超过硬件理论内存带宽一大截甚至接近 CPU 的 cache 带宽。原因很可能是被测内存块还没超过最后一级 cache 的容量数据全在 cache 里打转。比如测试块设成 8MB而机器 L3 有 32MB那么它测的是 L3 带宽不是内存带宽。另一种可能是-P设了多进程并行多个核同时跑带宽叠加后当然高。解决把测试块尺寸加大到明显超过 L3 容量比如总内存的 1/4 或至少 256MB再重跑。同时用-P 1锁定单进程排除并行带宽叠加。要确认 L3 容量可以用lscpu看到。最稳的验证方式是跑两组不同尺寸比如 64MB 和 256MB如果两组带宽接近说明数据确实落到了内存如果 64MB 明显高说明刚才测到的是 cache重新选尺寸。4.5 重复运行同一测试数值抖动超过 5%现象连续跑三次lat_syscall null三次结果分别是 120ns、180ns、140ns波动幅度很大。原因后台进程抢占、CPU 频率调度、numa 内存分配位置不一致都可能造成抖动。特别是开启了动态调频的笔记本或服务器CPU 频率随时在变延迟类微基准对频率极其敏感频率高时结果好频率低时结果差。解决先锁定 CPU 核心运行用taskset -c 2 ./lat_syscall -P 1 -W 1 -N 8 null把测试进程钉在一个核上。然后检查 CPU 调频模式临时把scaling_governor设成performance# 查询当前调频策略 cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor # 临时切到性能模式重启失效 echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor这是把电源管理策略临时切到“性能优先”防止频率波动影响结果。如果想要的是真实业务场景下的数据切不切取决于你有没有故意模拟省电模式。但做回归对比时必须保持两次测试的频率策略一致否则数值差异根本说不清是系统改动引起的还是调频引起的。做完这两步再重跑如果抖动还超过 5%就加一轮测试次数取中位数并把原始轮次全部打出来人工排除异常点。5. 把 lmbench 用起来与同门工具对比与回归测量方法5.1 用 lmbench-3.0 的结果与同类微基准工具交叉验证lmbench-3.0 的数值能不能信最好的验证方式是拿另一套独立工具在同一台机器上测同一个指标看量级是否一致。比如测内存带宽可以用dd配合/usr/bin/time -v估算一个粗略值或者用系统自带的perf stat里的内存访问事件辅助验证。这类交叉验证不用做到数值完全相等只要同一量级就说明 lmbench 的结果没有系统偏差。如果双方差出十倍多半是你的测试参数设错了而不是工具打架。交叉验证还有一个作用在审查报告时别人翻到数据后会问“你凭什么说这个数字是对的”。你可以答同样的操作我用笨办法重测过误差在合理范围内。这比甩一个工具名有说服力得多。我自己做内核参数回归时会先记录 lmbench 基线再记录 perf stat 的上下文切换事件计数两项数据同时变化才敢写进结论。5.2 通过二进制交换和参数扫描做回归测试回归测试的核心是固定变量。固定编译器版本、固定编译选项、固定 CPU 掩码、固定内存分配策略、固定内核版本然后只改变一个目标变量比如内核参数、驱动版本或者 CPU 调频策略。lmbench 的版本也要固定我一般锁在 lmbench-3.0 上不要拿它和不同版本的输出直接比因为不同版本之间的默认参数和统计口径有差异混着用容易得出假结论。参数扫描的常见组合是内存块尺寸从小扫到大。比如bw_mem把尺寸从 1m、2m、4m、8m、16m、32m、64m、128m 逐步加大每个尺寸单独记带宽。这样能直接看出 cache 层级拐点在哪里。lat_mem则固定尺寸、扫描步长比如固定 64m步长从 64 到 128、256、512、1024、4096观察延迟增长曲线。这两条曲线合起来就是一套机器内存子系统的完整画像改 BIOS 内存配置、改内核transparent_hugepage、换 CPU 后重新扫一遍一眼就能看出哪里变了。5.3 一套可复用的快速回归脚本手工一条条敲命令会疯掉我习惯把常用测试写成一个带循环的脚本跑完自动汇总成 CSV。下面是一个精简版本覆盖内存延迟、内存带宽、系统调用、上下文切换四个核心项每项跑三轮取中位数。#!/bin/bash # lmbench 快速回归脚本固定 CPU 核心三轮取中位数 # 用法./quick_regression.sh result.csv PREFIXtaskset -c 2 ./ OUT_FILE/tmp/lmbench_regression_$(date %Y%m%d_%H%M).csv echo test,round,value $OUT_FILE # 函数跑三项延迟测试并记录结果 run_lat_tests() { for round in 1 2 3; do # 内存延迟 64MB 块、64 字节步长 val$($PREFIX lat_mem -P 1 -W 1 -N 5 64m 64 | tail -1 | awk {print $2}) echo lat_mem_64m_64,$round,$val $OUT_FILE # 空转系统调用延迟 val$($PREFIX lat_syscall -P 1 -W 1 -N 5 null | tail -1 | awk {print $2}) echo lat_syscall_null,$round,$val $OUT_FILE # 两个进程的上下文切换延迟 val$($PREFIX lat_ctx -P 1 -W 1 -N 5 2 2 | tail -1 | awk {print $2}) echo lat_ctx_2proc,$round,$val $OUT_FILE done } # 函数跑内存带宽测试并记录结果 run_bw_test() { for round in 1 2 3; do val$($PREFIX bw_mem -P 1 -W 1 -N 5 64m rd | tail -1 | awk {print $2}) echo bw_mem_64m_rd,$round,$val $OUT_FILE done } run_lat_tests run_bw_test echo 结果已写入 $OUT_FILE脚本里taskset -c 2固定到 2 号核心防止调度器把进程切到别的核导致 cache 和 TLB 状态变化。每个测试跑三轮awk {print $2}是提取 lmbench 输出行中的数值列。跑完后用排序取中位数cd /tmp sort -t, -k1,1 -k2,2n lmbench_regression_*.csv | awk -F, { arr[$1] $3; cnt[$1]; if ($3 min[$1] || min[$1] 0) min[$1] $3; if ($3 max[$1]) max[$1] $3; } END { for (k in arr) { printf %s,median%.2f,min%s,max%s\n, k, arr[k]/cnt[k], min[k], max[k]; } } | sort这个统计片段的作用是按测试项名分组计算均值、最小值和最大值。实际看结果时我优先看最大值和最小值差距差距大于 10% 就该查后台进程或者考虑调频干扰而不是直接信平均值。整个脚本跑完一分钟左右足够日常快速验证内核参数改动的效果不需要每次开全套make results。6. 把结果变成报告一个顺手的数据汇总技巧写报告最烦的是把十几个测试项、三四台机器的结果排成一张干净表格。手工复制粘贴容易抄错我习惯直接在命令行把多个结果文件合并成一张 CSV丢进 Excel 再格式化。做法是按测试项聚合每个测试项一行列分别是机器名、原始值、单位。下面这段脚本可以一次处理results目录下的多份结果文件cd results for f in *.results; do machine$(basename $f .results) grep -E ^(lat_mem|bw_mem|lat_syscall|lat_ctx) $f | \ awk -v m$machine {print m,$1_$2_$3,$NF} done all_combined.csv head -20 all_combined.csv这里的逻辑是文件名的前缀当作机器名行首的测试名和参数拼成新列行尾的数值作为结果。合并后可以按机器名排序同一测试项在相邻行出现上下对比非常直观。比如你拿新机器和旧机器对比先把两台机器的结果合并到同一张表每一项谁快谁慢一排序就清楚了。这份 CSV 再配上测试时间和内核版本两列就是一个可以反复回查的性能基线库。最后说一个我自己的习惯每次跑回归测试前先把numactl --hardware的输出存一份确认内存插槽和 CPU 的亲和关系没有变化。曾经有一次对比同一台机器改内核参数前后的结果怎么测都差 8%后来发现有人动过 BIOS 设置内存通道从双通道变成了单通道。这类问题 lmbench 本身测不出来但它能让你看到数据变了逼你去查环境差异这就是微基准工具最大的价值所在。工具可以老测量环境不能乱。希望这篇笔记能帮你把 lmbench-3.0 真正用起来拿到一组能说服自己、也能说服别人的可信数据。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询