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。

發佈了35 篇原創文章 · 獲贊 46 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章