Linux电源管理实例分析

描述

  实例分析

  最近博主遇到 i2c 传输慢和中断触发慢的问题,一般这种【慢】的情况大都和【性能与功耗冲突】相关,研究了 Qos 系统,打了笔 patch 解决了。

  中断触发慢:注册的下降沿中断,从下降沿打到芯片中,到跑到中断处理函数,快则 270us,慢则 2.7ms。由于所做功能对中断处理时间有要求,因此要解决中断处理慢的问题。

  抓 trace 分析

  使用上次博主发的脚本,可以抓到 ftrace,这个脚本中博主使能了 sched_switch、sched_wakeup、irq、irq_handler_entry、irq_handler_exit、cpu_idle、pm_qos_update_request 等 event。这些 event 可以记录下 CPU 调度和中断处理情况。

  从抓到的 trace 分析,中断处理慢并不是由于 CPU loading 重导致的处理不及时,而是中断来的时候,CPU0 处于 idle 状态,而 kernel-5.10 以后除了特定的 feature,所有的中断都默认发到 CPU0,这样即便设置了中断可以唤醒系统,把 CPU0 从 idle 转为 active 也要 1ms。

  问题确定后,就是如何处理的问题了。找了低功耗的同事,确认 CPU 在没事情做的时候就是会进入 idle,即便在游戏场景,也不会禁止 CPU 进入 idle。

  研究了一下 Linux 电源管理子系统,发现 Qos 有接口可以使用:在某一段时间内拉 Qos,可以让 CPU 在这段时间不进入 idle,使用完毕再去掉 Qos,让 CPU 可以进入 idle,这样满足了性能需求,带来的功耗也不是特别高。

  PM QoS classes framework 位于 kernel/power/qos.c 中,负责系统级别的 PM QoS 管理。per-device PM QoS framework 位于 drivers/base/power/qos.c 中,负责 per-device 的 PM QoS 管理。Common header 位于 include/linux/pm_qos.h 中,负责通用数据结构的抽象、函数声明等工作。

  在 kernel/power/qos.c 中,有 cpu_latency_qos_update_request 接口可以使用,通过该接口将 Qos 拉到 150,使用完毕再将 Qos 拉到 -1(关闭)。

  使用方法:

  1、文件开头注册自己的结构体:struct pm_qos_request my_qos_request;

  2、自己驱动的 probe 函数加上:cpu_latency_qos_add_request(my_qos_request, PM_QOS_DEFAULT_VALUE);

  3、在做事情前加上:cpu_latency_qos_update_request(my_qos_request, 150);

  4、在做事情后加上:cpu_latency_qos_update_request(my_qos_request, PM_QOS_DEFAULT_VALUE);PM_QOS_DEFAULT_VALUE 其实就是 -1

  这样在自己做事情期间,CPU 就不会进入 idle,自己模块的性能就会好很多。如果还要更好,可以在此期间调节 CPU 频率,但调频带来的功耗很高,需要自己评估。

  该 patch 解决的问题:

  1、中断处理慢,可以在第一次中断打进来后,拉 Qos,这样自己后面的几次中断处理一定会快,使用完毕后,去掉 Qos。

  2、i2c 传输慢,其中一种情况是 i2c 传输完毕返回时,CPU0 进入 idle,导致 i2c 中断打不进来,这种情况,我们在调用 i2c_transfer 前后加上 cpu_latency_qos_update_request 的接口,就可以解决该问题。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分