关闭

Linux PM QoS framework

513人阅读 评论(0) 收藏 举报
分类:


 转自:蜗窝科技www.wowotech.net

Linux PM QoS framework(1)_概述和软件架构

1. 前言

QOS为Quality Of Service(服务质量)的简称,对PM QoS而言,表示Linux kernel电源管理相关的服务质量。那到底什么是服务质量呢?

我们知道,Linux PM的主要功能,是节省功耗,但同时,会付出一定的性能代价,例如延迟(latency)增加、吞吐量(throughput)下降。可以把PM当作一种服务,把它对性能的影响,类比为服务的质量(QoS)。对性能的影响越大,QoS越低,反之越高。

不过,PM QoS framework的存在,并不是为了定义并测量系统的服务质量(Linux系统对实际的qos没有任何兴趣),而是为了定义一套框架,以满足系统各个实体(如进程、设备驱动等等)对QoS的期望为终极目标。根据实际的场景,这些期望可描述为:xxx不大于某个值;xxx不小于某个值;等等。

这个终极目标,是基于这样的事实:机器是极端的实用主义者。最理想的状况,是刚刚满足系统各个实体对QoS的期望,因而可以在满足需求的同时,最大化的省电。粗俗一点,就是“我能考60分,为什么要多花一点力气去考61分?”。这样的思路,值得我们深思。

本文将基于PM QoS framework整体的软件架构,介绍它的功能、应用场景、使用方式等。

2. 工作原理

kernel将“系统各个实体对QoS的期望”抽象为一个一个的constraint(可以理解为约束),围绕这些constraint,可以将系统的实体分为三类:requestor、pm qos framework和requestee。示意图如下:

pm qos

requestors提出对QoS的constraint。常见的requestor包括应用进程、GPU device、net device、flash device等等,它们基于自身的实际特性,需要系统的QoS满足一定的条件,才能正常工作。

pm qos core负责汇整、整理这些constraint,并根据实际情况,计算出它们的极值(最大或者最小)。

requestee在需要的时候,从pm qos core处获取constraint的极值,并确保自身的行为,可以满足这些constraints。一般情况下,requestee都是电源管理有关的service,包括cpuidleruntime pmpm domain等等。

注:requestor和requestee这两个词汇,是蜗蜗自己造出来的,只是为了理解方便。实际上,Linux kernel使用“QoS dependencies”的概念,分别用“Dependents on a QoS value”和“Watchers of QoS value”表述这两个实体,具体可参考kernel/power/qos.c和drivers/base/power/qos.c的文件header。

介绍完requestor和requestee之后,还要再回答一个问题:系统中到底有哪些constraint?这决定了request的对象。截至到目前,PM QoS framework将constraint分为2类,每一类包括若干个constraint,具体如下。

1)系统级的constraint,包括cpu&dma latency、network latency、network throughput和memory bandwidth 4个constraint。

2)设备级别的constraint,包括从低功耗状态resume的latency、active状态的latency和一些QoS flag(如是否允许power off)。

蜗蜗会在后续的文章中详细描述这些constraints的意义,这里先有个大概的认识即可。

3. 软件架构

根据上面2类constraint,Linux kernel提供了2个不同的QoS framework:

一个是系统级别的,用于cpu&dma latency、network latency、network throughput、memory bandwidth等场合,称作PM QoS classes framework。

另一个是device级别的,用于per-device场合,称作per-device PM QoS framework。

这2个framework有着共同的目标,即:向requestors提供request的add、modify、remove等接口,用于管理QoS requests;将QoS requests分门别类,计算出极值(简称value);向requestee提供request value的查询接口。其软件架构(非常简单)如下:

pm qos framework

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中,负责通用数据结构的抽象、函数声明等工作。

需要说明的是,PM QoS classes framework会通过misc设备,向用户空间程序提供PM QoS的request、modify、remove功能,以便照顾到它们对PM QoS的需求。

********************************************************************************************************************************************************************************

Linux PM QoS framework(2)_PM QoS class

1. 前言

回顾上一篇文章(Linux PM QoS framework(1)_概述和软件架构),PM QoS framework抽象出4个系统级别的QoS constraint(统称为PM QoS class),分别是cpu&dma latency、network latency、network throughput和memory bandwidth。并提供一系列的接口,动态的搜集、整理系统对这些constraint的需求情况。

2. API汇整

PM QoS class framework提供的API有2类:一类是以函数调用的形式,为kernel space的driver、service等提供的;另一类是以misc设备的形式,为用户空间进程提供的。

2.1 向kernel其它driver提供的,用于提出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); 
void pm_qos_remove_request(struct pm_qos_request *req);

int pm_qos_request_active(struct pm_qos_request *req);

1)pm_qos_add_request

该接口用于向PM QoS framework添加一个QoS请求,pm_qos_class为QoS请求的类型(kernel称作pm qos class),value为期望的QoS值,不同的class有不同的含义。pm qos class的定义如下:

   1: /* include/linux/pm_qos.h */
   2: enum {
   3:         PM_QOS_RESERVED = 0,
   4:         PM_QOS_CPU_DMA_LATENCY,
   5:         PM_QOS_NETWORK_LATENCY,
   6:         PM_QOS_NETWORK_THROUGHPUT,
   7:         PM_QOS_MEMORY_BANDWIDTH,
   8:  
   9:         /* insert new class ID */
  10:         PM_QOS_NUM_CLASSES,
  11: };

PM_QOS_CPU_DMA_LATENCY,CPU和DMA的延迟(单位为us),它的实际意义是,当产生一个事件之后(如一个中断),CPU或DMA的响应延迟。例如有些CPU的串口控制器,只有几个byte的FIFO,当接收数据时,CPU或DMA必须在FIFO填满前,将数据读走,否则就可能丢失数据或者降低数据的传输速率。

后面几个class,不再详细说明。

以PM_QOS_CPU_DMA_LATENCY为例,pm_qos_add_request的逻辑可以总结为:我要求CPU&DMA的latency不大于‘value’个us

另外,为了便于对已添加请求的维护(修改、移除等),framework会将该请求保存在一个句柄中,就是第一个参数--struct pm_qos_request指针。调用者不需要知道该结构的具体内容,只要定义一个变量,并把指针传给pm_qos_add_request接口,以后使用该指针进行修改、移除等操作。

2)pm_qos_update_request/pm_qos_update_request_timeout

如果应用场景改变(如串口波特率变大,相应的响应延迟就要变小),可以通过该接口更新QoS请求。req为句柄指针,new_value为新的value。

pm_qos_update_request_timeout多了一个timeout参数,用于需要在一段时间(timeout时间)内修改QoS value的场景。framework会在timeout后,自动将QoS value修改为一个默认值(一般为无效值,代表不再对该QoS有要求)。

3)pm_qos_remove_request

如果对该pm qos class不再有要求,则可以调用该接口将请求移除。

4)pm_qos_request_active

该接口可以获取某一个QoS请求的active状态。

2.2 向kernel PM有关的service提供的,用于获取、跟踪指定PM QoS需求的API

int pm_qos_request(int pm_qos_class); 
int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier); 
int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier); 

每当有新的QoS请求时。framework都会根据该QoS class的含义,计算出满足所有请求的一个极值(如最大值、最小值等等)。该值可以通过pm_qos_request接口获得。例如cpuidle framework在选择C state时,会通过该接口获得系统对CPU&DMA latency的需求,并保证从C state返回时的延迟小于该value。

另外,如果某个实体在意某一个class的QoS value变化,可以通过pm_qos_add_notifier接口添加一个notifier,这样当value变化时,framework便会通过notifier的回调函数,通知该实体。

同理,pm_qos_remove_notifier用于删除notifier。

2.3 向per-device PM QoS framework提供,low level的PM QoS操作API

int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, 
                         enum pm_qos_req_action action, int value); 
bool pm_qos_update_flags(struct pm_qos_flags *pqf, 
                         struct pm_qos_flags_request *req, 
                         enum pm_qos_req_action action, s32 val);

s32 pm_qos_read_value(struct pm_qos_constraints *c);

QoS class和per-device PM QoS都是基于底层的pm qos constraint封装而来的。对QoS class的使用者而言,可以不用关心这些底层细节。对per-device PM QoS framework而言,则需要利用它们实现自身的功能。

这些接口就是提供给per-device PM QoS framework的low level接口,后面再详细介绍。

2.4 向用户空间process提供的,用于提出QoS需求的API

根据不同的PM QoS class,包括(cpu&dma latency、network latency等等):

/dev/cpu_dma_latency 
/dev/network_latency 
/dev/network_throughput 
/dev/memory_bandwidth 

打开文件,将会使用默认值向PM QoS framework添加一个QoS请求;关闭文件,会移除相应的请求;写入value,更改请求的值;读取文件,将会获取QoS的极值。

具体和2.1中的各个接口类似,不再详细说明了。

3. 实现思路和内部逻辑

3.1 主要数据结构

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

   1: struct pm_qos_request {
   2:         struct plist_node node;
   3:         int pm_qos_class;
   4:         struct delayed_work work; /* for pm_qos_update_request_timeout */
   5: };

node,一个struct plist_node类型的节点,在保存request的value值(node.prio)的同时,可以将request按照一定的顺序,保存在一个全局的链表中;

pm_qos_class,该request对应的qos class,可以为PM_QOS_CPU_DMA_LATENCY、PM_QOS_NETWORK_LATENCY、PM_QOS_NETWORK_THROUGHPUT、PM_QOS_MEMORY_BANDWIDTH中的一种;

一个delay work,用于实现pm_qos_update_request_timeout接口。

struct plist_node是一个按照优先级(prio)降序排列的双向链表(Descending-priority-sorted double-linked),除了常规链表所具备的head和tail之外,有一个prio字段,刚好可以应用在PM QoS class的场景中。

2)struct pm_qos_constraints,pm qos的内部抽象,用于抽象某一特定的PM QoS class

   1: struct pm_qos_constraints {
   2:         struct plist_head list;
   3:         s32 target_value;       /* Do not change to 64 bit */
   4:         s32 default_value;
   5:         s32 no_constraint_value;
   6:         enum pm_qos_type type;
   7:         struct blocking_notifier_head *notifiers;
   8: };

list,链表头,所有该class的request,都会挂到该list上;

target_value,该constraint的目标值,即可以满足所有该class的request那个value。通常情况下,根据request的类型(enum pm_qos_type),可以是所有request中的最大值,所有request中的最小值,或者所有request的和;

default_value,该constraint的默认值,通常为0,表示没有限制(或没有要求);

no_constraint_value,当该class的qos不存在请求时,pm_qos_get_value返回的值,通常为默认值,表示没有限制(或没有要求);

type,该constraint的类型,具体请参考下面的描述;

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

enum pm_qos_type包括PM_QOS_MAX、PM_QOS_MIN和PM_QOS_SUM。PM_QOS_MAX表示在所有的request中取最大值,即可满足所有的request,如network_throughput;PM_QOS_MIN表示在所有的request中取最小值,即可满足所有的request,如cpu_dma_latency;PM_QOS_SUM表示在所有的request中取和,才能满足所有的request,如memory_bandwidth。

当调用pm_qos_get_value接口时,framework会更具qos type,从list head中,取最小值、最大值或者所有值的和。

3.2 实现逻辑

QoS class framework为每个class定义了一个全局的struct pm_qos_constraints变量,用于保存所有该class的request。同时为每个class定义一个misc device变量,用于向用户空间提供接口。最终,将这些信息组织在一个内部的数据结构中(struct pm_qos_object),如下(具体内容可参考kernel/power/qos.c,这里不再详细介绍):

   1: struct pm_qos_object {
   2:         struct pm_qos_constraints *constraints;
   3:         struct miscdevice pm_qos_power_miscdev;
   4:         char *name;
   5: };
   6:  
   7: ...
   8:  
   9: static struct pm_qos_object *pm_qos_array[] = {
  10:         &null_pm_qos,
  11:         &cpu_dma_pm_qos,
  12:         &network_lat_pm_qos,
  13:         &network_throughput_pm_qos,
  14:         &memory_bandwidth_pm_qos,
  15: };

 

1)pm_qos_add_request

request add接口会以qos class为index,从qos array中取出constraint指针(pm_qos_array[pm_qos_class]->constraints),并指针和request的value为参数,调用pm_qos_update_target接口。

pm_qos_update_target会将该request添加到constraint的list中,并根据qos type,计算处该class qos的target value。

pm_qos_update_request/pm_qos_update_request_timeout的逻辑类似,不再详细描述。

2)pm_qos_request

直接从该class对应的constraint变量中,获取target value(已经在新的request被add之后更新)。

3)misc设备注册

当kernel会在QoS class framework的初始化接口(pm_qos_power_init)中,调用misc_register,将各个class的miscdevice变量,注册到kernel中。misc设备提供了open、release、read、write等接口(pm_qos_power_fops,具体可参考源文件),用于qos的request、update和remove。


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:4403次
    • 积分:75
    • 等级:
    • 排名:千里之外
    • 原创:3篇
    • 转载:1篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档