Linux 上的電源管理
前言
這篇文章主要是偏向我對於網路上關於 Linux 電源管理的內容的整理,以及我自己在筆電上實作的結果,如果想要更加了解可以查看文章中的參考資料。
我的筆電型號是 Swift SFX14-41G, CPU 為 5800U,因此在底下的實作中有針對只能在 AMD 與 Ryzen 上進行的電源管理設定。
CPU
如果不算 GPU 的話,一個系統中 CPU 大概率是最耗電的部分,因此大部分的電源管理都是針對 CPU 來進行,像是限制運行頻率之類的, CPU 如果可以省電,那麼將可以給電池續航帶來顯著的提升。
CPU 的省電主要是靠調節 CPU 運行的頻率,而 Linux 中調整 CPU 頻率依靠 CPUFreq 子系統, CPUFreq 定義了Scaling governors
和Scaling drivers
兩個選項,可以透過改變這兩個選項來改變 CPU 的調度,更詳細的內容,可以查看 Archwiki[1]裡的介紹。
Scaling governors
和Scaling drivers
的功能如下
- Scaling governors: 調度策略,決定 CPU 頻率要跑哪個頻率,並傳遞給 Scaling drivers 執行,大部分的 driver 都定義了四種調度器,每種 driver 提供的調度策略雖然名稱相同,但調度並不完全一樣,大部分情況下 ondemand 或 schedutil 可以滿足多數需求
- performance: 始終維持 CPU 最大頻率
- powersave: 始終維持 CPU 最小頻率
- ondemand: 在負載時使用高頻率,閒置時逐漸降低到最低
- schedutil: 根據 CPU 使用率調整頻率,且調速快
- Scaling drivers: 調度驅動,直接與 CPU 交互,將 governors 決定的頻率傳到 CPU,調整 CPU 的頻率
Scaling drivers
因為我使用 AMD 的 CPU,這部份就只會提 AMD CPU 可使用的調度器,完整列表可參考 Archwiki[1]
在 AMD 平台上可以使用的 driver 有3種,acpi_cpufreq
、amd_pstate
和amd_pstate_epp
,其中amd_pstate
又有三種模式,分別為passive
、guided
和active
,設定為active
模式時使用的 driver 為amd_pstate_epp
,可以在 kernel command line parameters 中設定選擇哪一種 driver 的哪種模式[2]
amd_pstate=disable
使用的 driver 為acpi_cpufreq
,此 driver 為核心中 CPUFreq 負責,使用 ACPI 提供的 CPU 能效等級來調度,好處是基本所有的 CPU 都可使用此 driver,但是調度較粗糙,無法達到精細的調度來省電amd_pstate=active
使用的 driver 為amd_pstate_epp
,在此模式下由 CPPC(Collaborative Power and Performance Control) 決定運行頻率,只提供 performance 與 powersave 兩種 governor, driver 將 governor 與 EPP(energy performance preference) 的值提供給 CPPC 來決定頻率,由於需要 CPU 內有 CPPC,因此只有 zen2 後支援此 driver;這個 driver 除了可以調整 governor,還可以額外設定 EPP,可以理解成在 governor 的電源指示上做微調,有4種 EPP,性能和耗電從高到低分別是 performance、balance_performance、balance_power、power,這個部分就按需選擇即可amd_pstate=guided
使用的 driver 為amd_pstate
的guided
模式,此模式同樣使用 CPPC,但是可以在 OS 內設定最高及最低性能, CPPC 會在範圍之間自動決定運行頻率,同樣的,因為對 CPPC 有需求,只有 zen2 後可以使用此 driveramd_pstate=passive
使用的 driver 為amd_pstate
的passive
模式,此模式下由 driver 來決定運行頻率,類似acpi_cpufreq
,但可能會好一點
目前大部分的核心編譯設定CONFIG_X86_AMD_PSTATE_DEFAULT_MODE=3
,即核心在沒有設定時預設使用amd_pstate_epp
,可以在/proc/config.gz
裡的 Config 中找到目前運行核心的編譯設定。
核心編譯設定的定義可以在 kernel 的源始碼中找到,在 drivers/cpufreq/Kconfig.x86 中config X86_AMD_PSTATE_DEFAULT_MODE
底下有定義設定數值對應預設使用的 driver
- 1 -> Disabled
- 2 -> Passive
- 3 -> Active (EPP)
- 4 -> Guided
至於這幾種 driver 要選擇哪一種的問題,我參考了 phoronix 的測試[3],amd-pstate-epp
的表現很好,在 CPU 閒置時他可以達到接近acpi_freq
在powersave
governors 的耗電量,但是在有需求時它可以自動 boost 到較高的頻率,而不是像其他 driver 的powersave
governor,只會保持在最低頻率,幾乎不可使用。我個人的體驗覺得amd-pstate-epp
的表現不錯,相比於passive
或guided
在續航上有較好的表現。
Setting
可以透過操作/sys
底下的檔案來改變 kernel 設定的 driver 與 governor
driver
1 |
|
<driver>的值可以為 active/guided/passive/disable
governor
1 |
|
<governor>的值可以是/sys/devices/system/cpu/cpu*/cpufreq/scaling_available_governors
中提供的選項
EPP
1 |
|
<EPP>的值可以是/sys/devices/system/cpu/cpu*/cpufreq/energy_performance_preference
中提供的選項
frequencies
1 |
|
boost
設定是否開啟 turbo boost
1 |
|
工具
前面章節介紹了調整 CPU 省電的方法,但是如果每次拔下插頭都要做一堆設定總是不方便的,雖然可以自己寫一個腳本被 udev rules 觸發或是寫一個 daemon 監控 acpi 電源事件,不過目前 linux 上已經有很多成熟的電源管理專案了,沒有必要重複造輪子。
目前 Linux 常見的電源管理方案有以下幾種
- tlp: 大部分人的推薦,省電設定包含了 CPU、無線、USB、GPU 等等,幾乎所有設備的省電設定都可設置,而且可以使用 tlpui 來用 GUI 進行設定,可以設定一套接 AC 時的設定和使用電池時的設定,可以在離電後自動切換,也可手動切換模式,堪稱電源管理工具的瑞士刀,只是需要良好的設定。
- power-profiles-daemon: 一個較新的電源管理工具,只針對 CPU 做幾項設定,可使用 tlp 重現相同的功能[4] (後文會說明), ppd 會內置3種配置 power、balanced、performance,優點是不需配置,就可以達成不差的效果,雖然只針對 CPU 做省電設定(前文有提到大部分耗電是 CPU 造成的),而且對桌面環境有很好的支持, KDE Plasma 和 Gnome 都可以直接在 Taskbar 上進行三種配置的切換。
- tuned: 和 tlp 相似,有豐富的省電選項可以設置,這款工具由 RetHat 負責維護,因此 RH 系的 Linux 大部分都是使用這個, Fedora 在41後預設安裝 tuned 而不是 ppd[5];使用人數較 tlp 少,但最近 tuned 推出了 tuned-ppd 這個提供 ppd 的兼容層,可以達成和 ppd 一樣對桌面環境很好的支持,同時又有和 tlp 一樣豐富的功能,也許我之後會嘗試這個工具。
- auto-cpufreq: 也是近幾年討論比較多的工具,它一樣只針對 CPU 做設定,調整 CPU 的頻率,根據它的文檔,這個工具可以根據工作負載自動決定 CPU 的頻率來達到省電的功能,我個人是覺得 CPU 內的 CPPC 單元應該可以有更好的效果啦,畢竟判斷工作負載同樣需要算力,有興趣可以自己測試看看。
- thermald: 這個工具和省電其實沒有很大的關係,它主要關注發熱,可以設定達到溫度自動降頻,好處是和前面幾個工具都不衝突,前面幾個工具一般都是建議只裝其中一個,畢竟每個工具都是用同樣的操作方式進行省電設定,如果幾個都在跑大概率會衝突。
- powertop: 這個工具其實也和省電沒有什麼關係,主要是它可以查看目前系統 CPU 的耗電量、idle、C 狀態之類的,不過他也有提供
--auto-tune
選項,不過這個選項的省電設定會很激進,可能會影響系統的使用,我一般只有在需要極致省電的時候才會在開啟了 tlp 下再執行sudo powertop --auto-tune
在 tlp、ppd、tuned 和 auto-cpufreq 這4個工具中,我曾經使用過 tlp 和 ppd,目前是又從 ppd 換回 tlp 了,大概可以多提升幾十分鐘的續航,畢竟多了一些外圍設備的省電;我個人建議筆電一定要進行省電設定,如果不想查文檔,可以直接裝 ppd 即可,如果不做電源管理,可能 windows 下能用6小時, Linux 下只剩2~3小時,哪怕只有 ppd,也可以把續航拉回正常的水平
Tuned-ppd vs tlp - Fedora Discussion
Confused about power saving: TLP vs tuned vs powertop, etc : r/Fedora
TLP or Power-Profiles for Battery Life - General system / Newbie - EndeavourOS
[TRACKING] PPD v TLP for AMD Ryzen 7040 - Framework Laptop 13 / Linux - Framework Community
tlp vs. power-profiles-daemon : r/Fedora
這些討論都只是參考,如果想要達成最好的省電,還是要在自己的電腦上做測試,我是懶得做精細的測試了,就 tlp 用著就很好
TLP
這段主要會講我對 tlp 在使用電池下的設定,我設定在連接 AC 下是什麼省電都關閉,抱持最大性能的運行
在使用電池時我設定 tlp 的 CPU 設定與 ppd 的 power 模式下相同,並做了一些修改, ppd 的三種模式的設定相當於 tlp 中的PLATFORM_PROFILE_ON_AC/BAT
、CPU_ENERGY_PERF_POLICY_ON_AC/BAT
和CPU_BOOST_ON_AC/BAT
[4]
ppd 的 performance 設定等於
1 |
|
balanced
1 |
|
power
1 |
|
我個人在使用電池下,有關處理器的設定為
1 |
|
可以視自己的機器不同來做調整, tlpui 裡都有對每個選項做相關設定
CPU 以外的部分我基本沒有更改什麼設定,如果有發現像是 USB 斷線或是網路/音訊設備閒置後斷線,可以把那部份的省電關掉即可
other Tools
- cpupower: 前面就有用到的工具,可以設定 CPU 使用的 governors、運行的頻率,也可以查看目前 CPU 調度相關的資訊,
cpupower frequency-info
- turbostat: 用來查看 CPU 每顆核心 boost 的狀態,也會顯示 C 狀態的比例,一般不太會需要這個工具
- lm_sensors: 統整電腦內各種感測器的狀態,可以獲得各種零部件的溫度或是風扇轉速
Ryzen only Tools
- ryzenadj: 可以理解為等同 Intel XTU 的工具,如果 BIOS 有開放設置,可以在 OS 內設定 CPU 的功耗、溫度牆或是超頻,只是我電腦 BIOS 沒有開放這些選項,所以我無法使用
- zenpower3/zenpower: 提供 zenpower 的 dkms 模組,可以更精確的獲得 CPU 內感測器的數值,如電壓、電流等
- zenmonitor3/zenmonitor: 將 zenpower 的資訊列表呈現在 GUI 上的工具
- amdctl: 纇似 ryzenadj,同樣無法使用
- zenstate: 調電壓曲線的工具,好像也可以超頻,同樣無法使用
- ryzen-ppd: 一個用來幫助 ryzen 省電的工具,但我跑不動,看起來也沒什麼人用
- ryzen_smu: 一個 CPU 內 SMU(System Management Unit)驅動的核心模組
不過 AMD 沒有公布 SMU 可以使用的指令,目前只有 Matisse 和 Vermeer 的指令有被試出來,在 ryzen_smu 的 github[6]上有給出,其他處理器系列能使用的指令只有 Test 和 GetSMUVersion 這兩個,我個人測試5800U 也只有這兩個指令會有反應
1 |
|
參考
- CPU frequency scaling - ArchWiki ↩
- amd-pstate CPU Performance Scaling Driver — The Linux Kernel documentation ↩
- Ryzen Mobile Power/Performance With Linux 6.3’s New AMD P-State EPP Driver - Phoronix ↩
- power-profiles-daemon — TLP 1.7.0 documentation ↩
- Changes/TunedAsTheDefaultPowerProfileManagementDaemon - Fedora Project Wiki ↩
- ryzen_smu/docs/rsmu_commands.md at master · leogx9r/ryzen_smu ↩