尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

lmbench微基准测试:从系统调用到内存延迟的底层性能剖析

lmbench微基准测试:从系统调用到内存延迟的底层性能剖析 简介lmbench-3.0是一套面向系统内存与整体性能评测的开源基准测试工具适合系统管理员、开发者和硬件工程师用于诊断内存带宽与延迟瓶颈、对比软硬件配置差异也可用于教学实验与二次开发。该资源共包含225个文件压缩包仅508KB以C语言源码、Makefile构建脚本和配置脚本为主同时附有tbl、1、3、8等格式的文档手册如定时、结果解析、基准程序说明以及pic/fig图表资源和结果汇总脚本结构清晰便于按需查阅。目前已有3649人学习下载。借助这套资料读者可以了解内存拷贝、填充、读/写/查找等带宽与延时测试的实现原理掌握在Linux及其他Unix-like系统上配置、编译和运行lmbench的方法并可参考其多线程并行评估、自定义数据块与迭代次数等参数调整思路结合结果统计和图形化脚本分析性能数据为系统优化、算法选型与基准对比提供依据。 上个月帮朋友看一台新到货的2U服务器硬件配置单很漂亮两颗最新一代CPU、八通道内存、企业级NVMe。可把业务压上去以后调用链路的P99延迟反而比旧机器还高。排查到最后一层问题出在一个很多人平时不会主动关注的细节——单次系统调用的固定开销和跨NUMA访问内存的延迟。想把这些底层开销“抠”出来看我第一个想到的不是跑分软件而是已经二十多岁的lmbench-3.0。lmbench是一套经典的Linux/Unix操作系统微基准测试工具集它专门测量系统调用、进程创建与切换、内存读写、文件系统操作、IPC通信等细粒度操作的延迟和带宽。别被它“上了年纪”的外表劝退至今很多内核补丁的提交说明、服务器选型评审、虚拟化性能对比里lmbench的数据仍然是重要参考。这篇文章我会把lmbench-3.0从编译、跑测、读表到踩坑的完整链路讲清楚适合性能工程师、SRE、内核开发者和做硬件选型的朋友直接参考。1. lmbench为什么“老”却不过时——这套基准测试集的特殊身价1.1 二十年历史的测量哲学把系统调用和进程开销“抠”出来lmbench的作者是Larry McVoy上世纪90年代他设计这套工具时目标就很明确主流benchmark都在比“大流量下的吞吐量”却没人认真回答“一次系统调用到底花多少钱”“fork一个进程要多久”“两个进程通过管道交换一个字节需要多少延迟”。这些细粒度操作恰恰是数据库、存储引擎、网关、消息队列等延迟敏感应用最在意的东西。lmbench的测量哲学可以浓缩为一句话不拿大流量吞吐量掩盖小操作的固定开销。就像高速公路总流量再大收费站的单辆车过站时间对物流公司同样关键——洪峰流量靠并行撑住但每一笔业务请求的时延往往被这些“收费站时间”牢牢卡住。这套工具跑完不过几分钟却能把内核的调度器、内存管理、文件系统、网络协议栈的“底牌”翻开给你看。1.2 它到底覆盖了操作系统哪些“细枝末节”lmbench-3.0的测试项分得很细先看一张分类表后面会逐个拆开讲分类典型测试项反映的问题带宽类bw_mem, bw_file_rd, bw_mmap_rd, bw_pipe, bw_tcp大块数据在内存、文件、管道、网络上的搬运能力延迟类lat_mem_rd, lat_rand, lat_ctx, lat_pipe, lat_proc单次读内存、切换进程、管道通信、创建进程的固定延迟文件系统lat_fs, lat_fop创建/删除/打开文件等元数据操作的代价进程/IPClat_sem, lat_sig, lat_unix, lat_select信号量、信号处理、Unix Socket、select的实际路径开销运算杂项lat_ops, tlb基本运算单元速度、TLB命中与缺失对随机访问的影响这套覆盖面意味着你不需要装一堆工具一个源码包就能完成一台机器的底层“体检”。而且lmbench对系统的影响很小跑完不会留下垃圾文件非常适合作为新环境上线前的基线测试。2. 一张结果表读懂一半lmbench核心测试项的分量与解读2.1 常见输出表格里那串数字代表什么第一次完整跑完lmbench很多人看到Results目录下的表格会发懵。拿经典的进程相关测试来说输出类似这样单位微秒HostnameOSMhznullnullopenslctsigsigforkexecshbox-aLinux36000.080.120.360.800.250.458.542.776.2这里“null”指无参数系统调用表中出现两次是因为测试了带参数和不带参数两种状态“open”是openclose一个简单文件的代价“slct”是select系统调用“sig”两次分别代表信号处理器的安装开销和一次信号触发开销。最后三项最有参考价值forkexit、forkexec、forksh。如果开启了SELinux、AppArmor这类安全模块或者容器里跑这些数字会明显膨胀有时能从8微秒涨到几百微秒。读这张表的核心心法不要背绝对值要记相对变化。同样一台机器加了一个审计模块、换了一个内核小版本、改了cgroup配置哪些列变了哪列没变变化幅度有多大这些信息比所谓“跑分高低”有用得多。2.2 带宽与延迟的经典组合内存、管道、文件系统内存测试里最常用的是lat_mem_rd和bw_mem。lat_mem_rd会按不同的数组大小和步长测读取延迟输出能看到非常漂亮的“台阶”L1缓存延迟大约1到2纳秒L2大约4到6纳秒L3大约12到20纳秒跨到主存后普遍在70到100纳秒区间。我习惯用-t 64M 128组合也就是最大数组64MB、步长128字节这样能完整覆盖L1/L2/L3/主存四个层级。bw_mem测的是内存拷贝/读写带宽常见操作有cpcopy、frd读、fwr写、fcp拷贝并填充。单线程下DDR4平台一般能跑到10到20GB/sDDR5和多通道平台更高。不看延迟只看带宽会严重误导——很多业务的瓶颈是每次访问几十纳秒的延迟而不是每秒能搬多少GB数据。管道测试bw_pipe和lat_pipe很有意思。bw_pipe是管道里持续灌大数据流测吞吐lat_pipe是两个进程间来回传一个字节测往返延迟。同一个IPC机制大数据流和小包延迟是两种完全不同的性格前者看内核缓冲区设计后者看调度和唤醒路径。文件系统测试lat_fs和lat_fop专门测创建/删除小文件的代价。这类元数据操作在日志型文件系统上开销特别明显一个小文件创建可能比大文件顺序写还慢。我通常在普通ext4和开启了某些日志选项的文件系统上各跑一遍对比一下就知道应用层的“大量临时文件操作慢”到底慢在哪里。2.3 上下文切换和进程创建调度器真实成本的探针lat_ctx是我最常跑的项目之一。它的核心参数是-s每个进程上下文大小和-P进程数。比如./bin/x86_64-linux-gnu/lat_ctx -s 0 -P 2 -N 50这里-s 0表示进程之间不共享额外内存数据纯测 scheduler 切换本身的成本-P 2表示两个进程互相接力-N 50是跑50次取结果。正常Linux系统上两个进程空切换大约在3到10微秒量级但如果CPU处于节能调频状态、或者系统里有大量软中断干扰数值会明显跳动。需要特别注意一个坑-s参数越大cache footprint越大切换时cache失效越严重延迟自然更高。很多人拿-s 1024的结果去和-s 0的结果对比得出“调度器变慢了”的错误结论。对比必须控制变量只改你想验证的那个维度。lat_proc测的是forkexit、forkexec、forksh三件套。这个测试直接反映进程创建的“固定成本”和“页表复制策略”的交互。现代内核大多用写时复制COW优化fork但如果父进程内存占用特别大fork的代价依然不低。跑这个项目时最好在干净环境里跑避免后台有大量进程频繁创建干扰结果。3. 从下载到出数一次干净、可信的lmbench-3.0实测3.1 源码获取与编译那些官方脚本没告诉你的细节lmbench-3.0的源码在代码托管平台很容易找到常见的版本目录是lmbench-3.0-a9。下载后进入目录cd lmbench-3.0-a9 make编译依赖gcc、make、perl绝大多数Linux发行版自带。如果机器上同时有多个gcc版本建议显式指定make CCgcc这里我想强调一个很多教程都不提的细节发行版默认的CFLAGS和lmbench源码里的默认编译选项可能不一致。比如某些操作系统为了安全默认加-fstack-protector这类选项会改变系统调用的栈布局导致延迟数据和非通用发行版上测出的结果没有可比性。最稳妥的办法是先直接make不要人为加优化参数保持lmbench官方默认编译方式。编译完成后可执行文件会放在bin/下对应的平台目录里例如bin/x86_64-linux-gnu/lmbench第一次跑全量测试前建议先跑make results脚本会以交互方式问你一些参数例如是否测试网络带宽、是否允许写临时文件等。如果不想处理交互选项直接回车接受默认值即可默认配置对绝大多数场景都适用。3.2 单测与全量测试两种跑法的选择全量测试用make results跑完用make see看结果汇总。全量覆盖所有测试项但耗时也长尤其bw_tcp这类网络测试和bw_mem这种大内存压力测试跑完全套少则十几分钟多则半小时。如果你只是快速验证一台机器我更推荐只跑核心单项。比如只测内存延迟./bin/x86_64-linux-gnu/lat_mem_rd -P 1 -t 64M 128只测两个进程的上下文切换./bin/x86_64-linux-gnu/lat_ctx -s 0 -P 2 -N 100只测pipe延迟./bin/x86_64-linux-gnu/lat_pipe单测的好处是快、干扰小、定位精准。我一般先跑几个关键单项建立初步印象再决定要不要全量扫描。全量结果存放在Results/hostname/目录下文件名对应测试项。make see会把它们汇总成表格但这些原生表格比较“原始”我建议把输出重定向到文件再用Python脚本或电子表格工具二次整理方便存档和对比历史数据。3.3 让数据稳定可信的三个前置操作跑微基准之前不先处理环境干扰数据就是“噪声”这一点比跑什么测试项都重要。第一绑定CPU核心。用taskset把测试进程绑到某个固定物理核上避免内核把它在两个核之间来回迁移taskset -c 0 ./bin/x86_64-linux-gnu/lat_mem_rd -P 1 -t 64M 128第二关闭CPU调频和节能强制跑在performance档位sudo cpupower frequency-set -g performance注意这会让CPU一直满频运行功耗变高测试完记得改回powersave或schedutil。在有业务负载的机器上不要这么干会短暂影响运行性能。第三多跑几次看数据是否稳定。微基准对运行环境极其敏感后台一个监控进程、一次定时任务都可能让数值跳变。我习惯每个测试项连跑三遍取中位数或最小值如果三次结果差异超过15%说明环境没洗干净先停下来排查干扰。4. 我用lmbench做的三次真实对比选型、虚拟化与内核参数4.1 新老服务器对比NUMA感知的差异肉眼可见回去看开头那台新服务器硬件明明更强但业务延迟更高。我用lat_mem_rd分别测旧机器和新机器发现新机器在默认配置下内存延迟反而高了大约30%而且波动剧烈。再用numactl --hardware一看新机器是双路NUMA架构默认内存分配策略下进程频繁跨Node访问远端内存。把测试绑到单Node上再测numactl --cpunodebind0 --membind0 ./bin/x86_64-linux-gnu/lat_mem_rd -P 1 -t 64M 128延迟立刻回落到正常水平。整个排查过程不到十分钟但如果没有lmbench这种微基准工具我可能还在业务层瞎猜。这件事之后我把lat_mem_rd写进了新服务器验收清单凡是多路服务器第一件事就是跑一遍绑核和不绑核的对比。4.2 裸机、容器与虚拟机微基准把虚拟化开销打在明处去年做容器化改造的前置评估领导问“容器对性能到底有没有损耗”我就在同一台物理机上分别测了裸机、Docker容器、KVM虚拟机三份lmbench数据。结果很典型容器的lat_mem_rd和lat_ctx和裸机几乎一致因为namespace和cgroup并不改变CPU调度和内存访问路径但KVM虚拟机的lat_syscall和lat_ctx有明显抬升虚拟中断和EPT缺页处理的额外开销全部暴露在数字里。这个对比说明一个道理性能问题不能靠“感觉”要靠可复现的基准数据支撑决策。容器和虚拟机虽然都能跑业务但底层开销模型完全不同具体到你的业务模型两种方案的延迟特征差异可能非常大。4.3 内核启动参数调优前后一次上下文延迟的修复记录另一台高负载机器上业务进程频繁出现调度延迟抖动。我在测试机上加了两组内核启动参数isolcpus把业务核从普通调度器中隔离出来nohz_full关闭隔离核上的周期性时钟中断。然后用lat_ctx反复测隔离核上两个进程的切换延迟加参数后中位数从8微秒左右降到了4微秒以下抖动也明显减小。这种验证不需要复杂的eBPF脚本、也不需要perf火焰图lmbench一个命令就能给出调度路径的延迟变化。当然这个测试只说明了“隔离有效果”是否值得为它牺牲普通核的动态负载均衡还需要结合业务实际判断但至少有了数据支撑不再靠玄学调优。5. 跑lmbench最容易踩的坑以及结果误读的几条经验5.1 五个高频坑第一编译参数被发行版“污染”。有些系统的编译器默认加堆栈保护、PIE之类的选项会让进程创建和系统调用路径的固定开销增加。建议不要自定义CFLAGS保持官方默认只在必要时用make CCgcc指定编译器。第二直接在cgroup或容器里跑全量测试。容器共享宿主内核部分测试项比如需要实时优先级或原始设备访问的可能没有权限或者数据被限额策略干扰。容器里跑单项做相对对比可以但不要当作物理机基线。第三忽略CPU调频影响。不开performancegovernor就跑延迟测试数字会忽高忽低尤其低负载场景CPU自动降频后延迟高得离谱却完全不代表真实上限。第四只看平均值不看分布。lmbench默认输出的是统计后的典型值但它对后台干扰依然敏感。我会把单测结果连续跑十次观察是否有极端值比单个中位数更有说服力。第五拿不同机器、不同内核版本、不同编译器的结果直接pk。lmbench是微基准对运行环境差异极其敏感跨环境对比时先把内核版本、编译器、内核配置、CPU governor统一再说。5.2 误读现场别拿一个数字给整台机器下结论有一次讨论某云主机性能对方贴出lat_mem_rd的主存延迟是90纳秒说“这云主机内存性能一般”。但同一份数据里L1/L2/L3的延迟和带宽都正常再一查宿主机可能是开启了内存加密或虚拟化嵌套页表导致部分访问路径变长。单看主存延迟就下结论反而掩盖了真正需要关注的上下文切换、磁盘元数据等其它问题。微基准的正确用法是“组合拳”用一组测试项互相印证结合业务特征找最相关的指标。数据库更关注内存延迟和文件系统元数据操作网关服务更关注进程创建、信号和socket延迟大数据任务更关注内存带宽和文件读带宽——先确定你的业务最痛哪一项再去看对应测试项。5.3 lmbench的替代与补充工具lmbench确实不完美它已经很多年没有大版本更新线程模型的测试偏少对NUMA的感知也没有刻意建模。实际工作中我还会配合perf bench sched pipe做调度延迟交叉验证用hackbench压调度器的多进程压力用cyclictest看实时性用iperf3看网络吞吐。需要全面基准报告时phoronix-test-suite可以方便地把多项测试汇总成可对比图表。但在所有工具里lmbench的独特价值依然是“快、轻、覆盖广”。它的核心可执行文件加起来不到几MB跑关键单项只要几分钟几乎不挑环境非常适合做新机器验收、内核参数回归、虚拟化方案对比这类高频粗粒度检查。说回开头那台新服务器。我用lmbench把问题定位到跨NUMA访问后在BIOS里调整了内存交织策略和启动参数再跑一遍lat_mem_rd和lat_syscall数据恢复正常业务P99也跟着回来了。后来我把lat_mem_rd -P 1 -t 64M 128、lat_ctx -s 0 -P 2 -N 100、lat_syscall这三条命令写进了新机器验收脚本凡是新到货的服务器第一件事就是跑一遍基线。根据这几年的实际经验如果你想快速判断一台机器有没有“暗病”lmbench是极少能让你在几分钟内看清系统底层真实状态的工具值得放进常备工具箱。本文还有配套的精品资源点击获取
返回列表