電源管理/掛起與休眠

出自 Arch Linux 中文维基

多種方法可用於掛起,特別是:

Suspend to idle(掛起到空閒狀態)
英特爾稱之為 S0ix,微軟稱之為現代待機(以前是「保持網絡連接的待機」),內核稱之為 S2Idle。設計用於替代 S3 睡眠狀態的支持系統,提供相同的節能,但大大減少了喚醒時間。
提示:雖然這種狀態會導致 WindowsmacOS 上的電池消耗問題,因為它們支持在這種狀態下喚醒設備進行網絡活動,但 Linux 軟件生態系統目前沒有使用這種特性,應該不會受到影響。
Suspend to RAM(掛起到內存,通稱掛起/睡眠)
ACPI 定義的 S3 睡眠狀態。通過將機器中大多數和 RAM 不相關的部件斷電來工作,RAM 是恢復機器狀態所必需的。由於可以節省大量電力,建議筆記本電腦在使用電池運行且蓋子關閉時(或用户在一段時間內處於非活動狀態)自動進入此模式。
Suspend to disk(掛起到硬盤,通稱休眠)
ACPI 定義的 S4 睡眠狀態。將機器狀態保存到交換空間並關閉機器。再次開機後,恢復狀態。直到開機前,機器都不會有任何待機功耗
Suspend to both(掛起到兩者)
掛起和休眠的混合,有時稱為混合掛起。將機器狀態保存到交換空間,但並不關閉電腦,而是調用默認的掛起機制,從而使未掉電的電腦能立刻恢復。如果電腦掉電(斷電且電池耗盡),系統也可以從硬盤的交換空間中恢復,儘管比從內存中恢復慢一些。

以上三者均由許多底層接口提供基礎功能,再由高級接口進行一定調整,以適配一些較為複雜的硬件與內核模塊(如顯卡喚醒後的重新初始化)

底層接口[編輯 | 編輯原始碼]

直接使用低級接口顯然會比任何高級接口都快很多,因為執行睡眠/休眠前後的鈎子(hooks)需要時間。然而,鈎子可以提供很多功能,如正確設置設備時鐘、恢復無線網絡狀態等。因此,雖然這些接口可以被直接使用,我們仍然建議用户使用高級接口進行睡眠/休眠。

內核休眠(軟件休眠,swsusp)[編輯 | 編輯原始碼]

最直接的方法是直接吿知內核中的軟件掛起代碼(swsusp)進入掛起狀態,具體的方法和狀態取決於硬件支持的程度。在現代內核中,向 /sys/power/state 寫入特定字符串是觸發此掛起的主要機制。

更多信息詳見內核文檔

用户空間軟件休眠(uswswsp)[編輯 | 編輯原始碼]

uswsusp(「Userspace Software Suspend」)是內核Suspend to RAM機制的封裝,該機制在掛起前和恢復後從用户空間執行一些有關圖形適配器的操作。

詳見 Uswsusp英語Uswsusp

高級接口[編輯 | 編輯原始碼]

這些軟件包的目標是提供二進制文件或腳本,使用户可以調它們來進行睡眠或休眠。在實際使用中,往往由其它軟件(如桌面環境/DE)將它們與電源按鈕、菜單點擊或筆記本電腦蓋事件聯繫起來。如果不想藉助其他軟件調用高級接口,又希望設備能在某些電源事件(如合上蓋子或電池耗盡)時自動睡眠/休眠,你也許需要看看Acpid

systemd[編輯 | 編輯原始碼]

systemd為睡眠、休眠和混合休眠提供原生支持。詳見電源管理#用 systemd 進行電源管理。systemd 是 Arch Linux 默認使用的接口。

關於配置睡眠或休眠鈎子,詳見電源管理#睡眠鈎子。又見 systemctl(1)systemd-sleep(8)systemd.special(7)

更改掛起方法[編輯 | 編輯原始碼]

在 S0ix 掛起不能提供與常規 S3 睡眠相同的節能的系統上,或者當節能優於快速的恢復時間時,可以更改默認掛起方法。

提示:S0ix 被認為可以提供與 S3 睡眠相同或更好的節能,請參閱以下英特爾博客文章 如何在 Linux 中實現 S0ix 狀態Linux S0ix 故障排除在 Linux 上高效空閒:一個案例研究,以檢查您是否可以使其按預期工作。

首先,檢查硬件是否公佈支持其他方法,如下面的示例所示:

$ cat /sys/power/mem_sleep
[s2idle] shallow deep

如果您的硬件沒有公佈 deep 睡眠狀態,請首先檢查 UEFI 是否公佈了它的某些設置,通常是在「電源(Power)」或「睡眠狀態(Sleep state)」或類似的用詞下,並使用名為 Windows 10, Windows and LinuxS3/Modern standby support 關於 S0ix 的選項,以及 Legacy, Linux, Linux S3S3 enabled 關於 S3 睡眠的選項。否則,您可以繼續使用 s2idle,考慮使用休眠或嘗試給 DSDT 表打補丁(或在線查找補丁版本)。

注意: 最後一個解決方案可能會給你留下問題,製造商已經停止修復 ACPI S3 狀態的錯誤(因為默認情況下,Windows 系統被鼓勵使用「現代待機」):如果它們主動地不公佈它,它可能會在某種程度上出問題。

通過在更改睡眠方法後測試幾個睡眠周期,測試硬件是否沒有 S3 睡眠問題:

# echo "deep" > /sys/power/mem_sleep

如果沒有發現任何問題,可以使用 mem_sleep_default=deep 內核參數使更改永久化。

在一些相反的情況下,有缺陷的固件公佈支持 deep 睡眠,但只支持 s2idle。在這種情況下,通過 sleep.conf.d(5) 中的 SuspendState 可以以另一種方法使用 s2idle

/etc/systemd/sleep.conf.d/freeze.conf
[Sleep]
SuspendState=freeze

休眠[編輯 | 編輯原始碼]

為了使用休眠,用户需要創建一個交換分區或文件。使用resume= 內核參數向內核傳遞swap信息,該參數應通過引導程序配置。您還需要#配置 initramfs。這將讓內核嘗試從早期用户空間中的指定swap分區/文件恢復。下面將詳細描述這三個步驟。

swap分區/文件的大小[編輯 | 編輯原始碼]

即使swap比內存小,成功休眠的可能性仍然很大。參見內核文檔中的「image_size」部分以獲取關於 image_size sysfs(5) pseudo-file 的更多信息。

您可以減小 /sys/power/image_size 的設定值以使休眠鏡像儘可能小(對於小交換分區),或者增大它以加快休眠過程(也許)。對於 RAM 很大的系統,較小的值可能會顯著提高系統從休眠中恢復的速度。這是一個臨時文件,參閱Systemd#臨時文件以固定你的修改。

/etc/tmpfiles.d/hibernation_image_size.conf
	
#    Path                   Mode UID  GID  Age Argument
	
w    /sys/power/image_size  -    -    -    -   0
	

休眠鏡像不能跨多個交換分區和/或交換文件。它必須完全適配一個交換分區或一個交換文件[1]

配置 initramfs[編輯 | 編輯原始碼]

  • 當使用帶有 base 鈎子的 initramfs 時(這是默認值),/etc/mkinitcpio.conf 中需要 resume 鈎子。無論是通過卷標還是通過 UUID,交換分區都是通過 udev 設備節點來引用的,因此 resume 鈎子必須在 udev 鈎子之後。這是一個使用默認鈎子配置的示例:
HOOKS=(base udev autodetect keyboard modconf block filesystems resume fsck)
編輯後記得重新生成 initramfs
注意: 如果使用 LVM 分區,需要將 resume 放在 lvm2 後面
  • 當使用帶有 systemd 鈎子的 initramfs 時,已經提供了恢復機制,不需要額外添加鈎子。

必需的內核參數[編輯 | 編輯原始碼]

想要休眠,必須傳遞內核參數 resume=swap_device。(以 persistent block device naming 方法中的任何一個替換掉swap_device )如:

  • resume=UUID=4209c845-f495-4c43-8a03-5363dd433153
  • resume="PARTLABEL=swap分區卷標"
  • resume=/dev/archVolumeGroup/archLogicalVolume——如果swap在LVM邏輯卷上(UUID 和 標籤應該同樣可以工作)

內核參數只有在重新啟動後才會生效。要想不重啟而立即休眠,請從lsblk獲取卷的主要和次要設備號,並 echo major:minor/sys/power/resume。如果使用交換文件,則還應將 resume offset 添加到/sys/power/resume_offset[2]

例如,如果交換設備是8:3

# echo 8:3 > /sys/power/resume

或者在休眠到交換文件時,如果交換文件位於卷8:2上並且offset為38912

# echo 8:2 > /sys/power/resume
# echo 38912 > /sys/power/resume_offset

休眠到交換文件[編輯 | 編輯原始碼]

使用交換文件需要設置 resume=UUID=swap_device_uuid,另外還需要設置resume_offset=swap_file_offset內核參數。見內核文檔

swap_device 是交換文件所在的卷,其格式與root parameter相同。swap_file_offset的值可以通過運行filefrag -v swap_file來獲得,輸出為表格形式,所需的值位於physical_offset列的第一行。例如:

# filefrag -v /swapfile
Filesystem type is: ef53
File size of /swapfile is 4294967296 (1048576 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..       0:      38912..     38912:      1:            
   1:        1..   22527:      38913..     61439:  22527:             unwritten
   2:    22528..   53247:     899072..    929791:  30720:      61440: unwritten
...

在本例中,swap_file_offset 的值是38912(第一行physical_offset下面,兩個英文句點..前面的數字)。

提示:
  • 以下命令的結果可用於獲取swap_device_uuidfindmnt -no UUID -T /swapfile
  • 以下命令的結果可用於獲取swap_file_offsetfilefrag -v /swapfile | awk '$1=="0:" {print substr($4, 1, length($4)-2)}'
  • swap_file_offset 的值也可以通過運行 swap-offset swap_file 來獲得。工具集 Uswsusp英語Uswsusp 中提供了 swap-offset 二進制文件。如果使用此方法,則必須在 /etc/suspend.conf 通過鍵 resume deviceresume offset。在這種情況下,不需要重新啟動。
注意:
  • 對於堆疊塊設備,如加密容器(LUKS)、RAID或LVM,resume參數必須指向包含交換文件的文件系統的未鎖定/映射設備。
  • 如果交換文件在/home/中,則systemd-logind將無法確定其大小,因此將阻止休眠,並顯示以下消息:Failed to hibernate system via logind: Not enough swap space for hibernation。解決辦法見systemd issue 15354
提示:如果你只想休眠而不擴展RAM,則可能需要減少交換文件的交換值

休眠到 Btrfs 上的交換文件中[編輯 | 編輯原始碼]

本文或本章節可能需要合併到#Hibernation into swap file

附註: Now the instruction is simple enough to be merged with the previous section.(在 Talk:電源管理/掛起與休眠 中討論)

不要嘗試使用 filefrag 工具,在 Btrfs 上,從 filefrag 獲得的 physical_offset 不是實際 offset。因為 btrfs 有一個虛擬磁盤地址空間以支持多個設備。[3]

btrfs-progs 6.1,提供了一個命令來檢查用於休眠的交換文件及其偏移值。參見 btrfs-inspect-internal(8)

# btrfs inspect-internal map-swapfile -r path/to/swapfile
198122980

休眠到精簡配置的LVM卷中[編輯 | 編輯原始碼]

在精簡配置的LVM卷中休眠是可能的,但必須確保該卷已完全分配。否則系統將無法從中恢復,參見 FS#50703

可以通過簡單地用零填充來完全分配LVM卷。例如:

# dd if=/dev/zero of=/dev/vg0/swap bs=1M status=progress

想確認卷是否已完全被分配,使用:

# lvs
 LV                   VG  Attr       LSize   Pool Origin    Data%  Meta%  Move Log Cpy%Sync Convert
 swap                 vg0 Vwi-aot--- 10.00g  pool           100

完全分配的卷將顯示為具有100%的Data%

警吿: 不要在用於休眠的精簡配置的swap分區上使用TRIM,即:不要在/etc/fstab使用discard,也不要在swapon時加入-d--discard參數。否則已被使用的空間會被重新去分配

需要添加resume=/dev/sdxY (sdxY 是swap分區的名字) ,讓系統在啟動時讀取swap分區中的內容。

英特爾快速啟動技術(Intel Rapid Start Technology,IRST)[編輯 | 編輯原始碼]

英特爾快速啟動技術是一種休眠的固件解決方案,允許在預定義的時間間隔或電池狀態後從休眠。這應該比常規休眠更快更可靠,因為它是由固件而不是在作業系統級別完成的。通常,它必須在固件中啟用,固件還支持設置暫停/電池事件觸發休眠後的持續時間,然而,儘管固件中支持 IRST,但某些設備僅允許通過英特爾的 Windows 驅動程序進行配置。在這種情況下,下面描述的 intel-rst 內核模塊應該能夠在 Linux 下配置事件。

啟用英特爾快速啟動技術(IRST)後,從深度睡眠中恢復需要「比從 S3 恢復長几秒,但比從休眠中恢復快得多」。

許多基於英特爾的系統都支持 IRST 固件,但需要在 SSD(而不是 HDD)上使用特殊分區。Windows 的 OEM 部署可能已經有一個預先存在的 IRST 分區,可以在 Arch Linux 安裝過程中保留(而不是擦除和重新分區整個 SSD)。它應該顯示為與系統 RAM 大小相等的未格式化分區。

警吿: 英特爾快速啟動分區未加密;「如果您使用基於軟件的磁盤加密,英特爾建議禁用英特爾快速啟動技術」。[4]

但是,如果您打算擦除並重新分區整個驅動器(或者已經這樣做了),那麼如果您也計劃使用該技術,則必須重新創建IRST分區。這可以通過創建一個與系統 RAM 大小相等的空分區,並將其分區類型設置為 GUID D3BFE2DE-3DAF-11DF-BA40-E3A556D89593(對於 GPT 分區)或 ID 0x84(對於 MBR 分區)來實現。您可能還需要在系統的固件設置中啟用對IRST的支持。

提示:可以在系統的固件設置中調整 IRST 啟動前(掛起後)的持續時間。

IRST 休眠過程的持續時間(即將RAM的全部內容複製到特殊分區)取決於系統的 RAM 大小和 SSD 速度,因此可能需要20–60秒。一些系統可以用 LED 指示燈指示過程的完成,例如停止閃爍。

在 Linux 中啟用 IRST 休眠事件需要配置 CONFIG_INTEL_RST=y,如果要從模塊載入,則需要加載 intel-rst 模塊。一旦通過 modprobe intel_rst 加載,它應該創建了 wakeup_events 和 wakeup_time 文件,例如/sys/bus/acpi/drivers/intel_rapid_start/*/wakeup_events,這些文件可用於進一步配置。該模塊有簡單的文檔,請參見源文件 drivers/platform/x86/intel/rst.c 了解更多詳情。

另請參閱英特爾快速啟動技術的一般問答用户手冊

故障排除[編輯 | 編輯原始碼]

ACPI_OS_NAME[編輯 | 編輯原始碼]

你也許需要調整你的 DSDT table 來讓它工作。 參閱 DSDT 詞條。

睡眠/休眠無法進行,或無法穩定進行[編輯 | 編輯原始碼]

有相當多的錯誤報吿指出,他們的屏幕在給出可讀的錯誤信息前就關閉了,有時屏幕關閉了,卻再也無法喚醒。這些故障在筆記本電腦和台式機上都曾發生。(這不是個官方解決方案),但切換到舊的內核,尤其是LTS內核,或許可以修復這個問題。

使用硬件看門狗(默認是禁用的,詳閱systemd-system.conf(5) § OPTIONS中的RuntimeWatchdogSec=條目。存在bug的硬件看門狗可能會在系統成功創建休眠鏡像前就重置電腦狀態。

有時屏幕會因為 initramfs 中進行的設備初始化過程而變黑。移除 Mkinitcpio#模塊(MODULES)裡你可能設置了的任何模塊,尤其是KMS顯卡驅動 KMS_早啟動並重新構建initramfs,也許能解決這個問題。喚醒前初始化這樣的設備可能會帶來一些衝突,這些衝突將阻止系統從休眠中喚醒。但這一般不會影響系統從睡眠(掛起)中喚醒。可參考一篇博文: best practices to debug suspend issues

將舊的 radeon 驅動換成新的 AMDGPU 驅動也許能讓休眠與喚醒過程更加成功。

對於英特爾核芯顯卡,啟用 early KMS 也許能解決休眠黑屏的問題。詳見 KMS_早啟動

在升級到內核版本 4.15.3 後,喚醒系統時可能會黑屏,只在黑屏上留下一個靜止不動的鼠標指針。將模塊 nvidiafb 加入黑名單可能會有幫助。[5]

使用 Intel CPU 並且為觸摸板加載 intel_lpss_pci 模塊的筆記本電腦,可能會在喚醒時發生內核崩潰(Caps Lock燈閃爍)。[6]這個模塊需要以這樣的方式加入 initramfs 裡:

/etc/mkinitcpio.conf
MODULES=(... intel_lpss_pci ...)

然後重新生成initramfs

網絡喚醒(WoL, Wake-on-LAN)[編輯 | 編輯原始碼]

如果網絡喚醒被啟用,網卡可能會消耗電力,即使電腦處於休眠狀態。

掛起後被立即喚醒[編輯 | 編輯原始碼]

參見電源管理/喚醒觸發器#掛起後被立即喚醒

如果您在 AMD CPU 上使用 Linux 內核6.1及更高版本,這也可能是由內核中s3相關的控制策略問題引起的。臨時解決方案是關閉相關 i2c 設備的喚醒。要找到它可以通過

$ ls /sys/bus/i2c/devices/*/power/wakeup

設備名稱的格式應為 i2c-ELAN0679:00i2c-MSFT0001:00。然後,測試以下命令是否可以進入掛起:

# echo disabled > /sys/bus/i2c/devices/device_name/power/wakeup
# systemctl suspend

如果它有效,您可以通過添加 udev 規則來持久化此配置:

/etc/udev/rules.d/99-avoid-i2c-wakeup.rules
KERNEL=="device_name", SUBSYSTEM=="i2c", ATTR{power/wakeup}="disabled"

系統在休眠後沒有斷電[編輯 | 編輯原始碼]

當你把你的系統休眠,系統應該(在保存狀態後)斷電。有時你會看見電源 LED 仍然亮着。如果存在這樣的情況,在 sleep.conf.d(5) 裡把 HibernateMode 設置為 shutdown 也許有用:

/etc/systemd/sleep.conf.d/hibernatemode.conf
[Sleep]
HibernateMode=shutdown

在進行了上述設置後,如果其它一切正常,當調用 systemctl hibernate 時,電腦就會正常地休眠後斷電了。

休眠後啟動時未找到作業系統(或啟動錯誤的作業系統)[編輯 | 編輯原始碼]

當引導磁盤是外部磁盤時,可能會發生這種情況,這似乎是由 BIOS/固件限制引起的。BIOS/固件嘗試從內部磁盤啟動,而休眠是從外部(或其他)磁盤上的作業系統完成的。

類似於#系統在休眠後沒有斷電,設置 HibernateMode=shutdown以永久解決問題。如果您已經將自己鎖定在外,您可以嘗試重新啟動系統4次(每次等待錯誤出現),這在某些BIOS上強制執行正常的引導過程。