Linux PM_QoS介绍

一、 PM_QoS引入的背景

QoS(Quality Of Service,服务质量),大多数时候都是网络领域的名词,指网络能够利用各种基础技术,为指定的网络通信提供更好的服务,解决延迟、网络阻塞等问题的技术。它属于一种安全机制,用于保证整体的质量。广义地讲,它可以简化为对一个服务的满意程度。在Linux的电源管理领域,不管是suspend、Runtime PM还是idle等等,它的一个主要功能就是省功耗,在没必要的时候器件该休眠的休眠,该下电的下电,clk该关的关,但是有一点,需要省到什么程度呢,不可能一味地偏向功耗,比如在usb传输的时候把dma给限制了,导致传输速率下降,这些是不希望看到的,如果把Linux PM当做一种服务,那么他对其他模块的影响就类比为服务的质量,要满足其他指标不受到影响的情况下最大化的省电,这才是最终目标。那么这里PM QoS的作用就是定义一套框架,以满足系统(如设备驱动等)对QoS的期望为终极目标,通俗的讲:根据实际场景,这些期望可以描述为:xxx不大于某个值等等。

二、PM QoS的概述和框架

上面大致介绍了下PM QoS的一个概念,那么问题来了,目前有哪些质量指标呢,对这些指标是如何去满足的呢。

  • 问题一:PM QoS有哪些指标

A:针对这个指标PM QoS有一个专门的名词:constraint(约束),其实也比较好理解,可以看做其他模块对PM的诉求和限制,目前PM QoS针对这些指标分为两类:一类是系统级的,包括:cpu&dma latency、network latency、network throughput和memory bandwidth,定义在kernel/power/qos.c中(在最新的kernel-5.4版本中,这一类constraint从4个缩减到只有cpu&dma latency这一个,同时增加了一类cpufreq的constraint,具体链接见文末),本文是以kernel-4.19为例展开介绍;另外一类是device层级的,针对各个device在具体场合的latency(主要是从低功耗状态resume的latency和active 状态的latency),定义在drivers/base/power/qos.c。

  • 问题二:这些指标该如何去满足呢

A:这里就要涉及到后面提到的PM QoS框架,简单来说就是三方协作,

  • 需求方:如进程、drivers等,它们根据自身的特性提出一系列需求(如cpu&dma latency等),

  • 框架层:PM QoS framework对这些需求进行汇总,根据实际情况,计算出来极值(比如cpu&dma的latency不能小于xx等),

  • 执行方:执行方需要确保自身的行为可以满足这些需求,这里的执行方很容易想到都是电源管理相关的,比如cpuidle,需要确保cpuidle等级满足cpu&dma latency的最低要求等等,可以参考下第三章的实例。

 

1. 整体框架

根据上面提到的PM QoS指标的类别,kernel提供了两个不同的QoS framework:一个是系统级的(称作PM QoS classes framework),一个是device级的(称作per-device PM QoS framework),两者的作用的场合不同,但是有着共同的实现流程:向一系列的需求方提供需求的add/update /remove等接口,将需求进行分类计算极值;然后向执行方提供这些需求的查询接口等,两种实现方式类似,本篇仅介绍其中的PM QoS classes framework,另外系统级的Qos framework通过misc设备,向用户空间提供了一套接口,以方便用户空间对PM QoS的需求,具体在:

/dev/cpu_dma_latency

/dev/network_latency

/dev/network_throughput

/dev/memory_bandwidth

整体的框架如下:

2. 主体数据结构

上面提到三方协作,这里重点介绍其中PM QoS framework的部分。

PM QoS framework主要工作是汇总需求方诉求,将这些需求分类汇总计算出极值,汇总的时候就自然涉及到为各需求方封装add/update/remove等接口,在介绍这些关键接口之前先说下PM QoS framework涉及到的一些主要数据结构:

1) struct pm_qos_request,pm qos request句柄,用于request的add/update/remove等操作

这个结构体主要看下后面三个变量:

node,这里面是用的struct plist_node类型来定义的,这里比较巧妙,plist_node类型除了双向链表的通用功能外还定义了一个prio变量,这个变量刚好可以保存request的value值,而plist_node链表在添加一个新的node的时候是会按照prio的数值按照进行升序排序,即prio最小的优先级越高在链表越靠前位置,这样在取指标的极小或者极大值的时候就更便捷了。

pm_qos_class,就是上面这些枚举的值,定义了系统级的一些PM QoS指标。

delay work,用于实现pm_qos_update_request_timeout接口。

2) struct pm_qos_constraints,pm qos约束,用于抽象某一个特定的PM QoS class。

list,所有该class的需求都会挂在这个链表。

target_value、default_value,分别是该指标的目标值(满足所有需求的value,可以是极大值或者极小值等,某一个指标关注的是极大值还是极小值在初始化的时候已经确定),默认值(该指标的默认值,通常是0,表示没有限制)。

type,主要是表示这几个指标极值的类型,极大/极小/求和,比如cpu_dma_latency的极值就是取极小值,这部分在各个contraints初始化的时候已经确定好。

notifiers,用于constraint value改变时通知其它driver。

3) struct pm_qos_object,在给每个class定义pm_qos_constraints结构体的同时也为每个class定义了miscdev变量,用于给用户空间提供接口。

3. 主体API:

主要的数据结构介绍完了,下面介绍下PM QoS framework用到的几个主要函数接口,像上面提到的一样,这些接口主要实现各类PM QoS需求的汇总和计算极值的工作:add/update/remove等,并且提供接口给到用户空间process,用于用户空间的QoS需求,另外还提供了一些notifier API,用于跟踪指定的PM QoS的变化。

主要API:

  • void pm_qos_add_request(struct pm_qos_request *req,int pm_qos_class, s32 value)

  • void pm_qos_update_request(struct pm_qos_request *req,s32 new_value)

  • void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value, unsigned long timeout_us)//在update的基础上多出来一个定时器,用于特定需求的延迟更新

  • void pm_qos_remove_request(struct pm_qos_request *req)

1) pm_qos_add_request,该接口用于向PM QoS framework添加一个QoS请求,主要是根据指定的pm_qos_class,向pm_qos_class链表中插入一个新的pm_qos_request节点,并且更新target value。

pm_qos_add_request

将里面pm_qos_update_target函数单独拿出来如下:

2) pm_qos_update_request/pm_qos_update_request_timeout,如果应用场景变化需要满足不同的要求(比如串口波特率变大,相应的响应延迟需要变小),则需要调用该接口来更新相应的qos请求。函数体的主要部分pm_qos_update_target和Add相似,这里就不再介绍。

3) pm_qos_remove_request,如果对该class没有需求,则可以调用该接口将请求移除。

4) 借助misc设备向用户空间提供的接口(open/read/write等),调用的接口和上面提到的add/remove等类似,这里就不再赘述。

5) pm_qos_add_notifier/ pm_qos_remove_notifier,有部分实体(如cpuidle,比较关注cpu_dma_latency的指标)会比较关注某一个pm qos class的target value的变化,kernel提供了这样一个notifier的机制,该实体可以通过pm_qos_add_notifier接口添加一个notifier,这样当value变化时,framework便会通过notifier的回调函数,通知该实体。

三、PM_QoS的用法

上面两个章节主要介绍了PM QoS的一些背景、框架和实现原理,那么在实际工作中该怎么使用呢,下面以一个实例来介绍下。

pm qos framework对外的主要接口有

  • pm_qos_add_request/pm_qos_update_request/pm_qos_remove_request----kernel drivers等

  • pm_qos_add_notifier/ pm_qos_remove_notifier/pm_qos_request----PM service等

  • /dev/cpu_dma_latency等----user space

以pm qos class其中一个指标CPU_DMA_LATENCY为例(路径:drivers/media/platform/via-camera.c)

在启动camera的时候,这里请求了一个cpu_dma_latency的指标,为50us,即camera driver申请的cpu_dma允许的延迟时间不能超过50us,对于cpuidle idle来说,一般有C1~C3几个等级,在C3等级的退出延迟时间是57us(不同平台会有差别),那么这里camera driver需求的50us容忍延迟就可以让cpuidle退到C2 idle等级(即前面章节提到的执行方需要确保自身的行为满足这些pm qos的需求),就不会导致上面说的DMA transfer gets corrupted的问题了。

参考文献:

1、http://www.wowotech.net/tag/pm_qos

2、kernel-5.4源码:

https://android.googlesource.com/kernel/common/+/refs/heads/android11-5.4

3、kernel-4.19源码:

https://android.googlesource.com/kernel/common/+/refs/heads/android-4.19-stable

长按关注

内核工匠微信

Linux 内核黑科技 | 技术文章 | 精选教程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OPPO内核工匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值