QoS(Quality Of Service,服務質量),一般在網絡報文中,某個報文的優先級比較高則優先傳輸,例如我們覺得微信聊天比看網頁更重要,我們就可以提高微信報文的等級即服務質量QoS,來提供好的網絡服務解決延遲、網絡阻塞等問題。
在電源管理里面的策略就各種governor,例如什么時候進入cpuidle、什么時候DevFreq等,這些策略是很單一的,算法也都是很單調的,未考慮到消費者的實際需求,那怎么樣把用戶的需求也在電源管理里面生效呢?
答案就是在governor中引入QoS,在governor中會去查QoS的策略,綜合起來進行決策。
1. 系統框架介紹
1.1 功耗控制可能影響用戶體驗的一些痛點
而且功耗管理會引入對性能的缺點,主要兩方面:
延時(latency)增加:時間的開銷,尤其是在恢復的過程中需要時間。比如,系統喚醒需要經過各驅動的恢復,power domain的上電過程也有時間開銷。
吞吐量(Throughput)減少:低功耗也會帶來算力的影響,會降低算力及網路的吞吐量。比如,cpu dvfs、cpu hotplug、cpu idle等會影響到cpu算力。
比如在usb傳輸的時候把dma給限制了,導致傳輸速率下降,這些是用戶不希望看到的。
又比如延時和性能開銷,影響到用戶的體驗,比如界面操作不流暢、卡頓,響應時間過長。
這就像蘋果手機很流暢,優先響應用戶的需求,安卓可能更高效但是有點卡,用戶就覺得屏幕劃不動了。但是很明顯蘋果手機更有市場,用戶體驗才是王道!
在面對用戶場景的情況下,我們需要在策略中考慮到用戶使用感受。在用戶眼里更多的看中應用服務,而且不是一味的強調功耗低,為了核心業務和用戶體驗是可以適當的犧牲功耗的,產品做出來最終還是要用戶用的,技術再好,功耗再低,不滿足用戶習慣就是0.
如果把Linux PM當做一種服務,那么他對其他模塊的影響就類比為服務的質量,要滿足其他指標不受到影響的情況下最大化的省電,這才是最終目標。那么這里PM QoS的作用就是定義一套框架,以滿足系統(如設備驅動等)對QoS的期望為終極目標,通俗的講:根據實際場景,這些期望可以描述為:xxx不大于某個值等等。
1.2 QoS框架
PM QOS使用constraint(約束)作為指標,用于各模塊對PM的訴求及限制。當前系統的指標主要有兩類,分別對應兩個PM QOS framework。
系統級constraint:包括cpu&dma latency(5.4內核),它的實際意義是,當產生一個事件之后(如一個中斷),CPU或DMA的響應延遲。例如有些CPU的串口控制器,只有幾個byte的FIFO,當接收數據時,CPU或DMA必須在FIFO填滿前,將數據讀走,否則就可能丟失數據或者降低數據的傳輸速率。由PM QoS classes framework管理,定義在kernel/power/qos.c中。
設備級constraint:包括從低功耗狀態resume的latency、active狀態的latency和一些QoS flag(如是否允許power off)。由per-device PM QoS framework管理,定義在drivers/base/power/qos.c。
整個PM QOS框架分為三部分:
需求方:各service、各driver。他們根據自己的功能需求,提出系統或某些功能的QOS約束,比如cpu&dma latency。
框架層:PM QOS framework,包含PM QOS classes、per device PM QOS。向需求方提供request的add、modify、remove等接口,用于管理QoS requests。對需求方的約束進行分類,計算出極值,比如cpu&dma latency不小于某個值。向執行方提供request value的查詢接口。PM QoS classes framework位于kernel/power/qos.c中,負責系統級別的PM QoS管理,通過misc設備(/dev/cpu_dma_latency),向用戶空間程序提供PM QoS的request、modify、remove功能,以便滿足各service對PM QoS的需求。per-device PM QoS framework位于drivers/base/power/qos.c中,負責per-device的PM QoS管理。
執行方:power management的機制,比如cpuidle、cpu dvfs等。需要滿足由框架層根據需求方提供的約束計算的極值,才能執行相應的低功耗機制。
2. 用戶空間操作流程
2.2 用戶空間數據結構和API
struct pm_qos_object { struct pm_qos_constraints *constraints; struct miscdevice pm_qos_power_miscdev; char *name; };
struct pm_qos_object,在給每個class定義pm_qos_constraints結構體的同時也為每個class定義了miscdev變量,用于給用戶空間提供接口。
這些接口主要實現各類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)
1)用于向PM QoS framework添加一個QoS請求,主要是根據指定的pm_qos_class,向pm_qos_class鏈表中插入一個新的pm_qos_request節點,并且更新target 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的基礎上多出來一個定時器,用于特定需求的延遲更新
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的回調函數,通知該實體。
需求方:
執行方:
2.1 struct pm_qos_constraints
struct pm_qos_constraints { struct plist_head list; s32 target_value;/* Do not change to 64 bit */ s32 default_value; s32 no_constraint_value; enum pm_qos_type type; struct blocking_notifier_head *notifiers; }; struct pm_qos_request { struct plist_node node; int pm_qos_class; struct delayed_work work; /* for pm_qos_update_request_timeout */ };
struct pm_qos_request用于request的add/update/remove等操作。
struct pm_qos_constraints,pm qos約束,用于抽象某一個特定的PM QoS class。
target_value、default_value,分別是該指標的目標值(滿足所有需求的value,可以是極大值或者極小值等,某一個指標關注的是極大值還是極小值在初始化的時候已經確定),默認值(該指標的默認值,通常是0,表示沒有限制)。
3. 初始化流程
static int __init pm_qos_power_init(void) { for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) { ret = register_pm_qos_misc(pm_qos_array[i], d); if (ret < 0) { printk(KERN_ERR "pm_qos_param: %s setup failed ", pm_qos_array[i]->name); return ret; } }
系統支持的QOS類型:
enum { PM_QOS_RESERVED = 0, PM_QOS_CPU_DMA_LATENCY, PM_QOS_NETWORK_LATENCY, PM_QOS_NETWORK_THROUGHPUT, PM_QOS_MEMORY_BANDWIDTH, /* insert new class ID */ PM_QOS_NUM_CLASSES, };
debugfs_create_file()會創建sysfs供用戶空間調用。
4. DMA舉例
例如啟動攝像頭的時候,我們系統即便在省電的情況下,也需要cpu_dma允許的延遲時間不能超過50us,否則影響畫面質量。
drivers/media/platform/via-camera.c中
pm_qos_add_request:在啟動camera的時候,這里請求了一個cpu_dma_latency的指標,為50us,即camera driver申請的cpu_dma允許的延遲時間不能超過50us
cpuidle初始化的時候會調用:
static inline void latency_notifier_init(struct notifier_block *n) { pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n); }
PM_QOS_CPU_DMA_LATENCY變化的時候會通知cpuidle
在進行cpuidle決策的時候,例如ladder governor中,
static int ladder_select_state(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct ladder_device *ldev = this_cpu_ptr(&ladder_devices); struct ladder_device_state *last_state; int last_residency, last_idx = ldev->last_state_idx; int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY);
pm_qos_request()函數會獲取target_value,根據這個值來決定進行什么級別的idle。
對于cpuidle idle來說,一般有C1~C3幾個等級,在C3等級的退出延遲時間是57us(不同平臺會有差別),那么這里camera driver需求的50us容忍延遲就可以讓cpuidle退到C2 idle等級(即前面章節提到的執行方需要確保自身的行為滿足這些pm qos的需求),就不會導致上面說的DMA transfer gets corrupted的問題了。
后記
內核版本有時候差異也挺大的,一個機制,特別是小眾的可能會有更新,我們在找資料的時候,就需要注意這點,找到合適的學習資料。不過主要的思想是不變的,變的就是結構體定義,api函數的調用流程等。
審核編輯:湯梓紅
-
電源管理
+關注
關注
115文章
6183瀏覽量
144506 -
內核
+關注
關注
3文章
1372瀏覽量
40290 -
網絡
+關注
關注
14文章
7565瀏覽量
88788
原文標題:電源管理入門-15 PM QoS
文章出處:【微信號:OS與AUTOSAR研究,微信公眾號:OS與AUTOSAR研究】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論