ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RK3568 OpenBMC性能优化实战:CPU占用从12%降至3%

RK3568 OpenBMC性能优化实战:CPU占用从12%降至3% 1. 从一次真实的移植卡顿说起去年秋天我接手了一个基于瑞芯微RK3568的工控网关项目需求很明确把OpenBMC跑起来通过以太网和串口对外提供带外管理能力。第一版移植花了大概两周系统能启动、能进Web界面、能读到传感器数据看起来一切正常。但真正压测的时候问题全暴露了——风扇控制响应延迟超过800毫秒IPMI命令在并发场景下丢包率接近15%系统空闲时CPU占用率居然还有12%左右。这个表现放在实验室里勉强能看放到产线环境里就是不可接受的。于是有了这个系列的第二篇。第一篇讲的是怎么把OpenBMC在RK3568上跑起来属于“从无到有”的阶段这一篇要解决的是“从能用到好用”的问题核心就两件事性能优化和替代方案探索。前者是把现有方案榨干后者是给自己留后路——万一某条路走不通不至于整个项目卡死。这篇文章适合两类人看一类是正在做RK3568OpenBMC移植的嵌入式工程师另一类是对BMC性能调优感兴趣、想了解ARM平台带外管理实现细节的开发者。我会把踩过的坑、试过的参数、量化的对比数据都摊开讲尽量让每个结论都有实测支撑而不是“我觉得这样会快一点”。2. 性能瓶颈到底出在哪一次系统性的拆解2.1 先搞清楚“慢”的定义是什么优化最怕的就是凭感觉。你说系统慢慢在哪里是启动慢、响应慢、还是吞吐量低这三个问题的优化方向完全不同。我一开始也犯了这个毛病看到CPU占用高就想着降频、关服务结果折腾一圈发现真正卡的是I2C总线上的传感器轮询。所以第一步是建立可量化的性能基线。我用的方法很简单在系统稳定运行后用一组固定脚本采集以下指标连续跑30分钟取平均值和P95值。指标类别具体指标采集工具目标值CPU空闲占用率、中断分布top、mpstat空闲5%内存常驻内存、页缓存命中率free、vmstat常驻180MBI2C单次读取耗时、总线占用率i2c-tools 时间戳单次5ms网络IPMI响应延迟、吞吐量ipmitool 抓包P9550ms存储读写IOPS、挂载耗时iostat、systemd-analyze启动25s这张表是我后来整理出来的实际刚开始做的时候只测了CPU和内存走了不少弯路。建议你在动手优化之前先把这张表里的指标至少采集一轮否则你根本不知道优化有没有效果。2.2 RK3568这颗芯片的脾气RK3568是四核Cortex-A55主频最高2.0GHz带独立的NPU和VPU。但OpenBMC场景下NPU和VPU基本用不上真正吃资源的是CPU和I2C/SPI这些低速外设总线。这里有个很多人忽略的点A55的能效比虽然好但单核性能并不强如果你的BMC服务里有大量单线程阻塞操作很容易把某一个核跑满而其他三个核在围观。我实测过一个典型场景phosphor-hwmon在轮询I2C传感器时如果配置的采样间隔太短比如100ms单个核的占用率会直接飙到30%以上。后来把间隔调到500ms占用率降到8%左右而实际业务根本不需要那么高的采样频率。这就是典型的“参数没调对硬件背黑锅”。2.3 OpenBMC的架构特点与性能敏感点OpenBMC本质上是一堆D-Bus服务的大集合phosphor-*系列守护进程通过D-Bus互相通信。这个架构的好处是模块化、易扩展坏处是D-Bus本身有开销。每一次属性读取、每一次方法调用都要经过D-Bus daemon转发在ARM平台上这个开销比x86明显得多。我抓过D-Bus的流量一个简单的传感器读取请求从客户端发出到收到响应中间经过的D-Bus消息有6到8条。如果并发量上来D-Bus daemon本身就会成为瓶颈。所以性能优化的一条主线就是减少不必要的D-Bus通信合并请求降低频率。另一个敏感点是systemd的启动依赖。OpenBMC用了大量的systemd服务单元如果依赖关系没理顺启动时会串行等待白白浪费时间。我用systemd-analyze critical-chain看过默认配置下启动关键路径上有好几个可以并行化的服务被串行执行了。3. 性能优化实战从12%到3%的CPU占用3.1 传感器轮询策略的调整前面提到phosphor-hwmon的采样间隔这是最直接有效的优化点。默认配置在/etc/default/phosphor-hwmon或者对应的systemd unit里不同版本的OpenBMC路径可能不一样你可以用systemctl cat phosphor-hwmon.service确认。我的做法是分传感器类型设置不同间隔温度传感器1000ms温度变化本来就慢没必要高频采样电压/电流传感器500ms工控场景对电源异常需要较快响应风扇转速2000ms风扇惯性大采样太快没意义具体修改方式是在对应的.conf文件里加INTERVAL参数或者在hwmon的sysfs路径下调整。改完之后用i2cget配合time命令验证单次读取耗时确保没有因为间隔变化引入其他问题。注意采样间隔不是越大越好。如果你的系统有告警联动逻辑间隔太大会导致告警延迟。建议先确认业务对告警延迟的容忍度再反推最大允许间隔。3.2 D-Bus通信的合并与异步化OpenBMC里很多服务是同步调用D-Bus的一个请求没返回就阻塞在那里。我改了两个地方第一把phosphor-hwmon的属性更新改成批量提交。默认是每个传感器单独发一次D-Bus信号改成攒够一批或者每隔固定时间统一发一次。这个改动需要动源码但效果很明显——D-Bus消息数量下降了约60%。第二把IPMI的某些查询改成异步。ipmid在处理ipmitool sensor list这类命令时如果逐个同步读取传感器耗时会线性增长。改成异步并发读取后20个传感器的列表查询从原来的1.2秒降到了300毫秒左右。这里有个坑异步化之后要注意D-Bus的连接数限制。默认的session bus连接数在ARM平台上可能不够用需要调整/etc/dbus-1/session.conf里的max_connections参数。我一开始没改压测到50并发的时候开始报“Connection refused”排查了半天才发现是连接数满了。3.3 systemd服务的裁剪与并行化RK3568的OpenBMC镜像里默认带了不少用不上的服务比如某些调试工具、不需要的协议栈。我的原则是能关就关能延迟启动就延迟启动。具体操作分三步用systemctl list-unit-files --stateenabled列出所有开机自启的服务逐个确认是否当前项目必需非必需的用systemctl disable关掉对必需但启动慢的服务检查依赖关系看能不能改成After而不是Requires我关掉的服务包括phosphor-debug-collector调试用产线不需要、obmc-console串口控制台我们用独立串口、还有几个xyz.openbmc_project.*的示例服务。关完之后启动时间从32秒降到了24秒。并行化方面把phosphor-hwmon和phosphor-fan-control的启动顺序从串行改成并行因为它们之间没有强依赖。改完之后启动关键路径缩短了约3秒。3.4 内核层面的微调内核配置里也有几个对性能有影响的选项CONFIG_HZ默认可能是100或者250对于需要快速响应的BMC场景建议设成250。设成1000会增加调度开销反而不好。CONFIG_PREEMPT如果对实时性有要求可以开CONFIG_PREEMPT_VOLUNTARY但完全抢占式内核在ARM上可能引入额外开销需要实测权衡。CPU调频策略默认可能是ondemandBMC场景下负载比较稳定改成schedutil或者直接performance模式响应更一致。但要注意功耗和发热工控环境如果散热不好performance模式可能导致降频。我最后用的是schedutil配合把最小频率锁在800MHz既保证了响应速度又不会一直跑在最高频。3.5 优化效果汇总把上面这些改动都做完之后重新跑了一遍基线测试指标优化前优化后变化空闲CPU占用12%3.2%-73%常驻内存210MB165MB-21%IPMI P95延迟180ms42ms-77%启动时间32s22s-31%风扇控制响应800ms150ms-81%这个结果基本达到了项目要求。但我知道这套方案有个隐患改动越多维护成本越高。尤其是动了源码的部分每次OpenBMC版本升级都要重新打patch。这就引出了下一部分的思考——有没有更省心的替代方案4. 替代方案探索不把鸡蛋放在一个篮子里4.1 为什么需要考虑替代方案做嵌入式项目最怕的就是“一条路走到黑”。OpenBMC虽然功能强大但它的代码量、依赖复杂度、升级维护成本都不低。对于RK3568这种资源有限的平台有时候一个更轻量的方案反而更合适。我评估替代方案的标准有三条功能覆盖度能不能满足项目80%以上的核心需求资源占用在RK3568上跑起来吃多少CPU和内存维护成本后续升级、打patch、排查问题的难度基于这三条我试了三个方向轻量级IPMI实现、自定义管理服务、以及混合方案。4.2 方案一轻量级IPMI守护进程OpenBMC的ipmid功能很全但代码量也大。我试过用ipmitool配合一个自己写的简单守护进程只实现项目需要的几个IPMI命令读传感器、控制风扇、查电源状态。具体做法是用C写一个基于libipmi的轻量服务监听UDP 623端口收到请求后直接读sysfs或者I2C不经过D-Bus。这样省掉了D-Bus的开销响应延迟可以做到10ms以内。但这个方案的问题也很明显没有标准接口扩展性差。如果后面要加新功能基本等于从头写。而且IPMI协议本身有不少细节自己实现容易踩坑。我试了一周左右最后放弃了因为发现维护成本比优化OpenBMC还高。4.3 方案二基于Redfish的轻量管理服务Redfish是更现代的带外管理协议基于HTTP/JSON比IPMI友好得多。我在RK3568上试了用bmcweb的简化版只保留Redfish接口砍掉WebUI和IPMI。这个方案的好处是协议现代、调试方便用curl就能测。资源占用也比完整OpenBMC低常驻内存大概120MB左右。但问题是很多工控客户还是习惯用IPMI纯Redfish方案在兼容性上会有阻力。我最后的做法是混合方案保留OpenBMC的Redfish和IPMI接口但把WebUI换成更轻量的实现同时把不常用的服务全部裁掉。这样既保证了兼容性又控制了资源占用。4.4 方案三完全自研的极简BMC这是最激进的方向不用OpenBMC完全自己写一个极简的BMC服务。核心功能就三个传感器采集、风扇控制、远程开关机。用C或者Rust写直接操作sysfs和I2C不引入D-Bus和systemd的复杂性。我花了两周做了个原型跑起来确实轻——常驻内存不到30MBCPU占用接近0。但问题在于功能太单薄没有日志管理、没有固件更新、没有用户认证这些都要自己补。而且一旦客户提出新需求响应速度远不如基于OpenBMC改。所以这个方案我只推荐给需求非常明确、且长期不会变化的场景。对于大多数项目OpenBMC的生态价值还是值得的。4.5 替代方案对比与选型建议方案功能覆盖资源占用维护成本适用场景优化后的OpenBMC95%中中大多数工控/服务器场景轻量IPMI守护40%低高功能极简的定制设备Redfish轻量版70%中低中接受Redfish的现代数据中心完全自研30%极低极高需求固定、批量极大的产品我的建议是先用优化后的OpenBMC把项目跑起来同时把替代方案作为技术储备。如果后面遇到OpenBMC解决不了的问题或者维护成本超出预期再考虑切换。不要一上来就追求“完美方案”嵌入式项目里“能稳定跑”比“架构优雅”重要得多。5. 实操过程中的坑与排查技巧5.1 I2C总线锁死问题这是我在优化过程中遇到的最棘手的问题。现象是系统跑一段时间后I2C总线突然无响应所有传感器读数变成0或者报错。重启i2c服务能恢复但过一会儿又出现。排查过程先用i2cdetect确认设备还在然后用i2cget手动读发现返回Remote I/O error。查内核日志看到i2c-rk3x驱动报了timeout。最后定位到是多个进程同时访问同一条I2C总线导致的竞争。OpenBMC里phosphor-hwmon和phosphor-fan-control可能同时读同一个I2C设备如果没有互斥机制就会冲突。解决办法是在设备树里给I2C控制器加上i2c-bus-lock属性或者在用户态用文件锁保护。提示RK3568有多个I2C控制器尽量把不同功能的设备分到不同总线上减少竞争。比如传感器走i2c1风扇走i2c3。5.2 内存泄漏的定位方法优化后期发现系统跑24小时后内存会涨50MB左右虽然不多但长期运行有风险。用valgrind在ARM上跑太慢我改用heaptrack交叉编译版本配合LD_PRELOAD注入到phosphor-hwmon里。定位到是D-Bus信号订阅没有正确释放每次传感器更新都会创建一个新的match rule但旧的没有移除。改法是在服务退出时显式调用sd_bus_match_free或者用sd_bus_slot管理生命周期。这个问题的教训是OpenBMC的D-Bus封装虽然方便但资源管理要自己上心。尤其是长时间运行的服务任何小的泄漏都会累积。5.3 启动失败的快速排查流程优化过程中改了不少systemd配置偶尔会导致启动失败。我总结了一个快速排查流程systemctl --failed看哪些服务挂了journalctl -u 服务名 -b看具体报错如果是依赖问题systemd-analyze verify unit文件检查语法如果是权限问题检查User和Group配置如果是D-Bus问题busctl list看服务有没有注册成功这个流程帮我省了不少时间尤其是systemd-analyze verify能在重启之前就发现配置错误。5.4 常见问题速查表现象可能原因排查命令解决方法传感器读数全0I2C总线锁死dmesg | grep i2c加总线锁或分总线IPMI超时D-Bus连接数满busctl status调大max_connections启动卡住服务依赖循环systemd-analyze critical-chain改After/Requires内存持续增长D-Bus资源泄漏heaptrack显式释放match rule风扇控制延迟大采样间隔太长time i2cget调整INTERVAL参数6. 一些个人体会这个项目做完之后我最大的感受是嵌入式性能优化没有银弹都是一个个小改动累积起来的。12%到3%的CPU占用不是靠某一个神奇参数而是传感器间隔、D-Bus合并、服务裁剪、内核调频这些改动叠加的结果。每个改动单独看可能只贡献1%到2%但加起来就很可观。另一个体会是替代方案的价值不在于马上用而在于让你心里有底。知道最坏情况下可以退到哪个方案做决策的时候就不会慌。我最后没有用自研方案但那个原型的代码一直留在仓库里后来有个新项目需求更简单直接拿过来改改就用了省了不少时间。最后分享一个小技巧优化之前先做基线优化之后再做对比中间每改一个参数就测一次。不要一次性改一堆然后看总效果那样出了问题根本不知道是哪个改动导致的。我吃过这个亏改完发现系统起不来了回滚了三次才定位到是一个systemd依赖写错了。慢就是快在性能优化这件事上尤其如此。
返回列表