ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

第19章 高通平台UFS调优实战:UFS Gear与速率调优、Queue Depth与IO调度调优、UFS功耗与性能平衡

第19章 高通平台UFS调优实战:UFS Gear与速率调优、Queue Depth与IO调度调优、UFS功耗与性能平衡 UFS调优这件事说实话是我在项目中踩坑最多的地方之一。很多工程师觉得UFS就是配几个寄存器的事跑不起来就降速功耗高了就限流。但实际做下来你会发现UFS的调优是个系统工程牵一发而动全身。这一章我就把我在高通平台上做UFS调优的经验拆开来讲。咱们从三个维度入手Gear与速率、Queue Depth与IO调度、功耗与性能的平衡。每个点我都会结合实战案例告诉你哪些坑我替你们踩过了。19.1 UFS Gear与速率调优不是越快越好UFS的速率由Gear决定。Gear越高单lane的速率越快。比如UFS 3.0支持Gear 411.6Gbps per laneUFS 4.0支持Gear 523.2Gbps per lane。但问题来了——你配了Gear 5系统就一定能跑满吗我在一个旗舰机项目上就遇到过。芯片支持UFS 4.0我们直接配了Gear 5结果跑稳定性测试时频繁丢数据。查了半天发现是PCB走线的信号完整性没跟上。说白了高速信号对layout的要求极高不是芯片支持就万事大吉。核心原则Gear的选择要基于链路训练结果而不是直接写死最高档。高通平台的做法是先做链路训练让UFS设备和控制器协商出一个双方都能稳定工作的Gear。你可以在dts或驱动里设置一个初始Gear但最终跑哪个Gear要看训练结果。举个例子在QTI平台上你可以通过以下方式控制Gear/* 在UFS驱动初始化阶段 */ static int ufs_qcom_set_gear(struct ufs_hba *hba, u32 gear) { /* 设置目标Gear */ hba-dev_info.gear gear; /* 发起链路训练 */ ufshcd_link_startup(hba); /* 检查训练后的实际Gear */ if (hba-dev_info.gear ! gear) { pr_warn(Gear fallback: requested %d, got %d\n, gear, hba-dev_info.gear); return -EAGAIN; } return 0; }我个人习惯的做法是先尝试最高Gear如果训练失败或链路不稳定就逐级降档。降档不是失败是为了稳定。你想想看跑Gear 4但稳定比跑Gear 5但时不时卡死要强得多。实战技巧在量产阶段建议把链路训练结果打印出来。如果发现某批次的UFS芯片普遍降档就要排查PCB或物料问题了。我曾经靠这个数据帮硬件团队定位了一版PCB的阻抗偏差。19.2 Queue Depth与IO调度调优别让UFS闲着UFS的Queue Depth队列深度决定了它能同时处理多少个IO请求。UFS 3.0支持最多32个队列每个队列深度32。但实际使用中不是深度越大越好。为什么因为IO调度器会决定请求怎么分发。如果队列深度太大调度器又不够智能就会出现请求堆积反而增加延迟。我在一个项目上做过对比测试队列深度顺序读MB/s随机读IOPS延迟us8180045000120162100520009532220048000130看到了吗深度从16增加到32顺序读只涨了不到5%随机读反而下降了延迟也上去了。这就是过犹不及。在高通平台上你可以通过sysfs调整队列深度# 查看当前队列深度 cat /sys/block/sda/device/queue_depth # 设置队列深度为16 echo 16 /sys/block/sda/device/queue_depthIO调度器方面我推荐用mq-deadline或none。UFS本身有内部的命令队列管理上层调度器太复杂反而会干扰。我习惯的做法是顺序读写多的场景如视频录制用none调度器减少调度开销随机读写多的场景如应用启动用mq-deadline保证延迟可控注意不要在生产环境用cfq或bfq。这些调度器是为机械硬盘设计的在UFS上只会增加不必要的CPU开销。我曾经接手过一个项目IO性能差查了一圈发现调度器配成了cfq。改回none后随机读IOPS直接翻倍。19.3 UFS功耗与性能平衡鱼和熊掌怎么兼得UFS的功耗问题在手机这种电池供电的设备上尤其敏感。UFS有几种功耗状态Active、Idle、Sleep、Deep Sleep。状态切换的延迟和功耗成反比。举个例子从Deep Sleep唤醒到Active需要几十微秒。如果频繁唤醒功耗是省了但性能就崩了。反过来一直保持Active性能好但电池扛不住。高通平台提供了UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS这样的quirk来控制状态切换行为。但更实用的方法是调整idle_timeout参数/* 在UFS驱动中调整idle超时 */ static int ufs_qcom_set_idle_timeout(struct ufs_hba *hba, u32 timeout_ms) { /* 设置空闲超时单位毫秒 */ hba-idle_timeout_ms timeout_ms; /* 更新电源管理策略 */ ufshcd_update_pm_policy(hba); return 0; }我个人建议的调优策略是前台场景如游戏、视频设置较长的idle_timeout比如100ms减少状态切换保证性能后台场景如待机、音乐播放设置较短的idle_timeout比如10ms尽快进入低功耗状态高通平台支持通过devfreq框架动态调整UFS频率和电压。你可以这样配置/* devfreq配置示例 */ static struct devfreq_simple_ondemand_data ufs_ondemand_data { .upthreshold 80, /* 负载超过80%升频 */ .downdifferential 20, /* 负载低于60%降频 */ }; /* 注册devfreq */ devfreq_add_device(dev, ufs_devfreq_profile, simple_ondemand, ufs_ondemand_data);这里有个坑升频阈值和降频阈值不要设得太接近。否则UFS会在高频和低频之间来回跳功耗反而更高。我一般留20%以上的回差。平衡之道功耗和性能的平衡不是找一个固定的中间值而是根据场景动态调整。前台要性能后台要省电。高通平台的PM QoS机制就是干这个的——让各个模块根据自己的需求投票UFS根据投票结果决定跑在什么状态。19.4 实战案例一次完整的UFS调优过程最后我分享一个实际项目的调优过程。这个项目是某款旗舰手机UFS 4.0跑Android。初期测试发现两个问题应用安装速度慢只有竞品的70%待机功耗偏高UFS贡献了约15%的功耗我的调优步骤第一步检查Gear通过链路训练日志发现实际跑在Gear 4但芯片和UFS都支持Gear 5。排查后发现是PCB走线过长导致信号衰减。和硬件团队沟通后调整了走线长度重新打样后Gear 5稳定运行。应用安装速度提升到竞品的95%。第二步调整Queue Depth默认队列深度是32。我做了多组测试发现深度16时随机读写性能最好。改完后应用安装速度又提升了5%达到竞品的100%。第三步优化功耗策略待机场景下UFS频繁进入Deep Sleep又唤醒。我调整了idle_timeout从50ms改为20ms同时将后台IO请求合并处理。待机功耗降低了8%UFS贡献的功耗从15%降到7%。最终这个项目的UFS性能达标功耗也控制在合理范围。调优不是一蹴而就的需要反复测试、验证。嗯这就是实战。总结一下UFS调优的三个核心——Gear要稳队列要准功耗要动态。别追求单一指标的最优系统级的平衡才是王道。下次遇到UFS性能问题先别急着改代码把链路训练日志和IO调度情况摸清楚再说。
返回列表