這個系列的文章,介紹了CPU 電源管理的一個重要分支CPUidle subsystem,所謂CPU idle,就是在CPU沒有事情做的時候,通過clock gating或power gating的方式降低或是關閉CPU internal某些單元的clock或power的方式,降低CPU的功耗并改善發熱問題。
文章是在參考了多位大神文章的基礎上,結合自己對Linux kernel cpuidle 相關code以及ACPI spec的了解形成的,記錄在這裡,并不斷地疊代修正,實作螺旋形上升成長。
cpuidle 相關的文章分5大部分,旨在解決以下幾個問題:
1)why to idle?
2)what’s idle state?
3)when to idle?
4)which idle state to enter?
5)how to enter/exit idle state?
該系列文章包括:
概述,即本文,介紹一些背景知識和 cpuidle framework in Linux;
【what‘s idle states,】從ACPI spec定義和Linux kernel實作兩個方面介紹各種idle state;
【cpuidle driver】解決how to enter idle state的問題。
【cpuidle device】利用linux裝置模型的概念,虛拟出來一個cpuidle device,用來管理CPU idle相關的操作,并提供一些sysfs interface供userspace來控制;
【cpuidle governor】解決which idle state to enter的問題。
Why to Idle?
計算機系統中,CPU的功能是執行程式,就是取指、譯碼、執行。那麼問題來了,如果沒有程式要執行,CPU該怎麼辦呢?為了省電,需要停掉CPU,但什麼時候停、怎麼停呢?這就需要我們仔細斟酌了,因為實際的軟硬體環境是非常複雜的。
在Linux系統中,CPU被兩類程式占用:一類是程序(或線程),也稱為程序上下文;另一類是中斷、異常的處理程式,也稱中斷上下文。程序的存在是用來處理事務的,比如讀取使用者的輸入,并顯示在螢幕上。但是事務總有處理完的時候,如果使用者不再輸入,也沒有新的内容需要顯示在螢幕上。此時,該程序就可以讓出CPU,但是要随時準備回來(使用者可能突然有按鍵動作)。同理,如果系統沒有中斷、異常事件,CPU就不會花時間在中斷上下文。
在Linux kernel中,把這種CPU無所事事的狀态,稱作idle state,并引入了idle framework來管理這種狀态。
CPUidle Framework in Linux
Linux kernel中,cpuidle framework相關的代碼在drivers/cpuidle目錄下,主要有cpuidle core、cpuidle driver和cpuidle governor三部分構成,再結合kernel sched 中的cpuidle,共同完成cpuidle管理。
kernel sched
主要負責實作idle線程,代碼位于kernel/sched/idle.c中。
CPUidle core 子產品
Cpuidle core負責實作CPUidle framework的整體架構,主要實作以下功能:
1) 抽象出cpuidle device、cpuidle driver和cpuidle governor;
2) 向cpuidle driver子產品,提供統一的driver注冊和管理接口;
3) 向cpuidle governor子產品,提供統一的governor注冊和管理接口;
4) 向上層sched提供接口,比如cpuidle_enter、cpuidle_select等;
5) 以sysfs的形式,向userspace提供接口;
CPUidle governor子產品
Cpuidle governor根據目前CPU load,确定進入哪個idle state。
Linux kernel中提供了menu和ladder兩種governor,根據具體的場景選擇進入哪個idle state,相應的代碼在drivers/cpuidle/governors目錄下。
CPUidle driver 子產品
負責實作CPU idle,即解決如何進入idle state的問題。
不同的arch、CPU core,會有不同的cpuidle driver。你可以在cpuidle core提供的架構下,開發自己的cpuidle driver,我這裡分析使用的是acpi cpuidle driver,對應的代碼主要在drivers/acpi/processor_idle.c中。
了解了CPUidle framework之後,我們來看如何利用這個framework來實作CPU在normal execution state和low power state之間的轉換。
CPU idle流程
進入idle state
CPU從C0切換到low power state時,需要解決以下三個問題:when to idle state?which idle state to enter?how to enter idle state?
-
when to idle state?
sched中的idle線程被排程時,表示目前沒有其他任務在執行,CPU可以進入到idle state以省電。
-
which idle state to enter?
這就需要cpuidle governor來根據目前的CPU load,預計會idle的時間以及系統支援的idle state狀态來選擇一個合适的idle state了,在滿足系統響應responsibility的前提下,盡可能省電。
-
how to enter idle state?
這個由cpuidle driver來負責,不同的CPU arch在進入idle state時會有不同的方式,不同的idle state也會有不同的進入方式,這個我們會在cpuidle driver中詳細說明。
退出idle state
CPU退出low-power state時,需要解決以下兩個問題:什麼條件下退出?退回到哪個power state?退回之後需要哪些額外處理?
-
什麼條件下退出?
每個low power state,都會定義一些waking event用來讓CPU退出目前的power state;
-
退回到哪個power state?
一般是會退回到C0 state;
-
退回到C0後,CPU如何操作?
在進入idle state之前,會調用local_irq_disable關閉local irq。
是以,退出idle state時,會先退回到idle thread,調用local_irq_enable之後,重新開機local irq,才能去執行相應的IRQ handler。在IRQ handler裡面可能會喚醒其他等待的線程,CPU去執行其他線程;如果沒有排程其他線程,則繼續執行idle線程。
參考檔案
ACPI spec6.0
窩窩科技-cpuidle