1. CPU Idle有什么用?
答案就是“省電”,當(dāng)多核CPU沒有任務(wù)執(zhí)行的時候,這時候需要將除主Core之外的其他Core進行低功耗處理,這件事就是CPU Idle機制做的。
idle狀態(tài): 在Linux kernel中,當(dāng)cpu中沒有任務(wù)在執(zhí)行,也沒有任何中斷、異常信號過來的時候,我們稱為處于idle狀態(tài),針對這種狀態(tài)Linux設(shè)計了一套cpuidle framework框架,專門用于cpuidle的管理。
Linux系統(tǒng)初始化時會為每個cpu創(chuàng)建一個idle線程,當(dāng)沒有其他進程需要運行的時候,便運行idle線程。
對于不同的功耗及恢復(fù)時間的要求,可以根據(jù)芯片硬件支持的情況定義多種idle狀態(tài),這些狀態(tài)按功耗從低到高(對應(yīng)著恢復(fù)時間從少到多)排列,利用linux提供的cpuidle框架,用戶選用不同的idle策略。這么做的目的就是盡可能在不影響性能的前提下,減少功耗。
在ARM64架構(gòu)中,至少會提供一個wfi的idle狀態(tài),有些芯片可能還會提供core下電的idle狀態(tài)。當(dāng)CPU idle時,根據(jù)預(yù)測的idle時間、功耗受益大小、恢復(fù)的時間長短,選用一個idle狀態(tài),比如進入wfi,關(guān)掉CPU的arch timer以便降低功耗,當(dāng)有中斷觸發(fā)時,CPU又會恢復(fù)回來。
2. CPU Idle整體框架
首先是CPUIdle子系統(tǒng)通過sysfs向userspace提供的節(jié)點:
一類是針對整個系統(tǒng)的/sys/devices/system/cpu/cpuidle,通過其中的current_driver、current_governor、available_governors等節(jié)點可以獲取或設(shè)置CPUIdle的驅(qū)動信息以及governor。
一類是針對每個CPU的/sys/devices/system/cpu/cpux/cpuidle,通過子節(jié)點暴露各個在線的CPU中每個不同Idle級別的name、desc、power、latency等信息。
什么時候進入idle?
關(guān)閉一些核可以節(jié)省功耗,但關(guān)閉之后對時延(性能)必會造成一定的影響,如果在關(guān)閉之后很短的時間內(nèi)就被喚醒,那么就會造成功耗/性能雙方都不討好,在進入退出idle的過程中也是會有功耗的損失的,如果在idle狀態(tài)下面節(jié)省的功耗還無法彌補進入退出該idle的功耗,那么反而會得不償失。
--解決方法就是:策略。是由cpuidle framework會根據(jù)不同的場景來進行仲裁選擇使用何種的idle狀態(tài)。
在kernel中cpuidle framework主體包含三個模塊,分別為cpuidle core、cpuidle governors和cpuidle drivers,
cpu idle core:負(fù)責(zé)整體框架,同時負(fù)責(zé)和sched模塊對接,當(dāng)調(diào)度器發(fā)現(xiàn)沒有任務(wù)在執(zhí)行時候,就切換到idle進程,通知到cpuidle framework的cpuidle core模塊要做接下來的idle操作。向cpuidle driver/governors模塊提供統(tǒng)一的driver和governors注冊和管理接口,向用戶空間程序提供governor選擇的接口。
cpuidle driver:負(fù)責(zé)具體idle機制的實現(xiàn)(不同等級下面idle的指標(biāo)也是在這個模塊進行填充),不同的平臺會有不同的drivers實現(xiàn)。
cpudile governors:在這個模塊進行cpuidle的選擇,選擇的算法主要是基于切換的功耗代價和系統(tǒng)的延遲容忍度,電源管理的目標(biāo)就是在保證延遲在系統(tǒng)可以接受的范圍內(nèi)盡可能的節(jié)省功耗。
3. Idle狀態(tài)判斷
在Linux系統(tǒng)啟動的時候,會在每個cpu上創(chuàng)建對應(yīng)的idle進程,start_kernel()函數(shù)初始化內(nèi)核需要的所有數(shù)據(jù)結(jié)構(gòu),并創(chuàng)建一個名為init的進程(pid=1),當(dāng)init進程創(chuàng)建完后,cpu的idle進程處于cpu_idle_loop()無限循環(huán)中,當(dāng)沒有其他進程處于TASK_RUNNING狀態(tài)時候,調(diào)度器才會執(zhí)行cpu idle線程,讓cpu進入idle模式.其函數(shù)調(diào)用關(guān)系簡要概括如下:
start_kernel –> rest_init –> cpu_startup_entry, 在cpu_startup_entry這個函數(shù)中,最終程序會進入無限循環(huán)do_idle loop中。
這里我們又進入看代碼環(huán)節(jié),可以參考公眾號之前的文章# Linux驅(qū)動-IMX6ULL開發(fā)板qemu環(huán)境搭建,我們修改好qemu啟動腳本加-s -S后,在VS中打斷點,進行代碼查看。
cpu_idle_loop()函數(shù)中會不斷的進行輪詢判斷
while (1) { ... if (cpu_is_offline(cpu)) { cpuhp_report_idle_dead(); arch_cpu_idle_dead(); } local_irq_disable(); arch_cpu_idle_enter(); ... }
3. cpuidle core
cpuidle core抽象出了三個數(shù)據(jù)結(jié)構(gòu):
cpuidle device:用于描述CPU核的cpuidle設(shè)備。
cpuidle driver:用于描述CPU核的cpuidle驅(qū)動。
cpuidle governor:主要根據(jù)cpuidle的device和driver狀態(tài)來選擇策略。
以cpuidle-pcsi.c為例,整個cpuidle注冊流程如下圖:
4. 注冊初始化
cpuidle初始化包括governor注冊、驅(qū)動注冊和設(shè)備注冊三部分
4.1 cpuidle governor注冊
cpuidle governor在cpuidle驅(qū)動和設(shè)備之前注冊,內(nèi)核使用一個鏈表維護系統(tǒng)中所有已注冊的governor。當(dāng)前新版內(nèi)核一共支持ladder、menu、teo和haltpoll四種governor,它們都通過調(diào)用cpuidle_register_governor函數(shù)將自身注冊到系統(tǒng)中。
Haltpoll governor:它是用于優(yōu)化虛擬機性能的一種cpuidle governor。其原理為當(dāng)vcpu進入idle時,通過guest端執(zhí)行poll操作,以避免使其陷入host中。它的優(yōu)點是減少了vm切換和通過ipi喚醒vcpu的成本,但它也造成在guest睡眠時,host無法復(fù)用該vcpu對應(yīng)的物理cpu,從而降低系統(tǒng)吞吐量的問題。
Ladder governor:該governor通過cpu前一次idle狀態(tài)的駐留時間是否超過該state延遲時間一個特定的值(promotion_time_ns),以及下一個state的延遲時間是否超過系統(tǒng)延遲容忍度,來確定是否需要提升idle state。由于該governor每次只能提升一個state,因此其state提升方式就像梯子一樣逐級往上,這也是它的名字由來。它往往用于periodic timer tick system。
Menu governor:直接選擇可能滿足需求的最深休眠態(tài),就好像你拿著菜單(menu)選菜一樣。如果深度的idle state更好,那么就會直接進入到深度的idle state。
Teo governor:采用的策略跟menu governor一樣,都是預(yù)測接下來會有多長時間能待在idle狀態(tài),然后據(jù)此選擇合適的idle mode。不過它跟menu governor考慮多方因素的策略是不同的。teo的理念是,多數(shù)系統(tǒng)上CPU喚醒最頻繁的喚醒源都是timer events,而不是設(shè)備中斷(device interrupts)。timer中斷的數(shù)量要比其他中斷高幾個數(shù)量級。所以只要依據(jù)timer event就可以做好預(yù)測工作了。
4.2 cpuidle driver注冊
cpuidle驅(qū)動注冊流程比較簡單,它主要包含以下三部分內(nèi)容
idle state相關(guān)參數(shù)設(shè)置、以及可能的broadcast timer
若設(shè)置了local-timer-stop屬性,則為每個cpu設(shè)置相應(yīng)的broadcast timer
若為該driver指定了governor,則切換current governor
cpuidle driver的主要工作是定義所支持的cpuidle state,以及state的enter接口,如下面所示,cpudile driver就要負(fù)責(zé)將平臺定義的idle-state信息填充到這個結(jié)構(gòu)體中
4.3 cpuidle device注冊
cpuidle設(shè)備注冊主要包括初始化一些參數(shù)值,將該設(shè)備添加到全局設(shè)備鏈表中,然后為其初始化sysfs屬性和使能該設(shè)備。
注冊之后,cpuidle設(shè)備、cpuidle驅(qū)動及governor之間建立起了連接,最終系統(tǒng)經(jīng)由cpuidle framework,通過接口來調(diào)用下層的接口,進而完成具體的硬件操作。
在現(xiàn)在的SMP系統(tǒng)中,每個cpu core都會有一個對應(yīng)的cpuidle device,內(nèi)核是通過使用struct cpuidle_device抽象cpuidle device,該結(jié)構(gòu)體主要成員含義如下:
lenabled:設(shè)備是否已經(jīng)使能 lcpu:該device對應(yīng)的cpu number llast_residency:該設(shè)備上一次停留在idle狀態(tài)的時間 lstates_usage:記錄了該設(shè)備的每個idle state的統(tǒng)計信息
5.cpuidle觸發(fā)流程
Idle task通過cpu_startup_entry為入口,調(diào)用到cpuidle_framework,流程如下圖:
cpu啟動完成時,會通過cpu_startup_entry函數(shù)將其自身切換到idle線程。除此之外,當(dāng)某個cpu上沒有可運行線程時,也會切換idle線程(上流程沒畫出,后面梳理進程調(diào)度的時候再細講)。切換idle線程后,最終都會執(zhí)行idle線程的主函數(shù)do_idle,并最終通過該函數(shù)將cpu設(shè)置為特定的idle state。
其中g(shù)overnor中的select、reflect函數(shù)是cpuidle的核心功能,決定了cpuidle狀態(tài)的選擇策略。
審核編輯:劉清
-
電源管理
+關(guān)注
關(guān)注
115文章
6183瀏覽量
144506 -
Linux系統(tǒng)
+關(guān)注
關(guān)注
4文章
593瀏覽量
27397 -
調(diào)度器
+關(guān)注
關(guān)注
0文章
98瀏覽量
5249
原文標(biāo)題:電源管理入門-9 CPU Idle
文章出處:【微信號:OS與AUTOSAR研究,微信公眾號:OS與AUTOSAR研究】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論