suspend-then-hibernateは、ラップトップPCでLinuxを使う際に役立つ便利な機能です。
この機能は、まずサスペンド(Suspend)モードに入り、その後さらに長い時間が経過するとハイバネート(Hibernate)モードに移行するというものです。
一方で、この機能の設定や動作はわかりにくいため戸惑うことがあります。この記事ではsystemdにおけるsuspend-then-hibernateの正しい設定方法とその動作原理について詳しく解説します。
要約
suspend-then-hibernateは、パラメータを設定せずに使うと可能な限り長い時間サスペンド状態を維持し、その後ハイバネートに移行します。休止状態に移行するときにはあまり電池が残っていません。
この動作を変更したい場合は、/etc/systemd/sleep.conf.d/*.confのHibernateDelaySec=パラメータを使用して、サスペンド状態からハイバネート状態に移行するまでの時間を明示的に設定する必要があります。
同じ設定ファイルのSuspendEstimateSec=パラメータは、システムがサスペンド状態に入る前の時間を決めるアルゴリズムを助けるためのものであり、ハイバネートへの移行時間には直接影響しません。また、このパラメータは通常は設定する必要がありません。
わかりにくいsuspend-then-hibernateの動作
suspend-then-hibernateは、直感的には非常に理解しやすい動作です。
「最初にサスペンドして、時間が経過したら休止する」
しかしながら、これを実際に設定しようとするとパラメータの設定に戸惑ってしまいます。理由は、動作が不明確だからです。例えば[電源管理/サスペンドとハイバーネートArchWi…
suspend-then-hibernateは、ラップトップPCでLinuxを使う際に役立つ便利な機能です。
この機能は、まずサスペンド(Suspend)モードに入り、その後さらに長い時間が経過するとハイバネート(Hibernate)モードに移行するというものです。
一方で、この機能の設定や動作はわかりにくいため戸惑うことがあります。この記事ではsystemdにおけるsuspend-then-hibernateの正しい設定方法とその動作原理について詳しく解説します。
要約
suspend-then-hibernateは、パラメータを設定せずに使うと可能な限り長い時間サスペンド状態を維持し、その後ハイバネートに移行します。休止状態に移行するときにはあまり電池が残っていません。
この動作を変更したい場合は、/etc/systemd/sleep.conf.d/*.confのHibernateDelaySec=パラメータを使用して、サスペンド状態からハイバネート状態に移行するまでの時間を明示的に設定する必要があります。
同じ設定ファイルのSuspendEstimateSec=パラメータは、システムがサスペンド状態に入る前の時間を決めるアルゴリズムを助けるためのものであり、ハイバネートへの移行時間には直接影響しません。また、このパラメータは通常は設定する必要がありません。
わかりにくいsuspend-then-hibernateの動作
suspend-then-hibernateは、直感的には非常に理解しやすい動作です。
「最初にサスペンドして、時間が経過したら休止する」
しかしながら、これを実際に設定しようとするとパラメータの設定に戸惑ってしまいます。理由は、動作が不明確だからです。例えば電源管理/サスペンドとハイバーネートArchWikiには、次のように書いてあります。
systemctl suspend-then-hibernate は、最初は可能な限り長くシステムを RAM にサスペンドし、RTC アラームで復帰し、そしてハイバネートします。RTC アラームは systemd-sleep.conf(5) 内の HibernateDelaySec で設定します。デフォルトの値は、システムのバッテリーレベルが 5% に下がるまでの推定された時間に設定されます。システムにバッテリーが存在しない場合は、デフォルトで2時間に設定されます。推定時間は、systemd-sleep.conf(5) 内の SuspendEstimationSec によって指定された時間後のバッテリーレベルの変化から計算されます。SuspendEstimationSec の時間後、システムは短い間サスペンドから復帰し、計測を行います (システムが手動でサスペンドから復帰された場合も、計測が行われます)。
「なるほどわからん」という気分はこういう時のためのものか、と感心するほかありません。失礼ながら最初は訳が悪いのかと思ったのですが、英語版も同じくらいわかりにくいです。
結局、systemd-sleep.conf - man(5)(258.2-2)を読んで、どうして上の説明が理解しにくいのかが理解できました。おおもとのこの説明がわかりにくいから、下流が混乱するのです。suspend-then-hibernateに関する記述を全文引用します。
A low power state where the system is initially suspended (the state is stored in RAM). When the battery level is too low (less than 5%) or a certain timespan has passed, whichever happens first, the system is automatically woken up and then hibernated. This establishes a balance between speed and safety.
If the system has no battery, it would be hibernated after HibernateDelaySec= has passed. If not set, then defaults to "2h".
If the system has battery and HibernateDelaySec= is not set, low-battery alarms (ACPI _BTP) are tried first for detecting battery percentage and wake up the system for hibernation. If not available, or HibernateDelaySec= is set, the system would regularly wake up to check the time and detect the battery percentage/discharging rate. The rate is used to schedule the next detection. If that is also not available, SuspendEstimationSec= is used as last resort.
最初の2段落は問題なく理解できます。問題は3段落目です。ここで述べられていることを整理すると、以下のようになります。
- システムにバッテリーがあり、
HibernateDelaySec=が設定されていない場合、ACPIの低バッテリーアラーム(_BTP)が最初に試され、これが利用可能であればシステムはハイバネートのために起動される。 - ACPIの低バッテリーアラームが利用できない場合、または
HibernateDelaySec=が設定されている場合、システムは定期的に起動して時間をチェックし、バッテリーの残量と放電率を検出する。この放電率は次の検出のスケジュールに使用される。 - これも利用できない場合、
SuspendEstimationSec=が最後の手段として使用される。
一つ一つの文章に分割してもまだわかりません。この段落は内部動作を説明することでsleep.confのパラメータの意味を説明しようとしているのですが、舌足らずなので読む方が混乱してしまうのです。
コードを読み解く
結局、Copilotに助けを借りてコードを読んで理解しました。ソースコードはsrc/sleep/sleep.c at main - systemd/systemd - GitHubです。
大まかにその動作を解説します。
まず、電池を持たないシステムの場合です。これは簡単で、一定時間経過後に休止に移行します。ここで一定時間とは、HibernateDelaySec=が設定されていればその時間であり、設定されていなければ2時間です。
電池を持つシステムの場合は、HibernateDelaySec=が設定されているかどうかで動作が分かれます。
-
HibernateDelaySec=が設定されている場合は、その時間が経過したら休止に移行します。休止に移る前は、バッテリー残量監視のために定期的に起床します。バッテリー残量が5%未満であれば、HibernateDelaySec=に達する前に休止に移行します。 -
HibernateDelaySec=が設定されていない場合は、さらにACPIの低バッテリー(BTP)アラームが利用可能かどうかで分かれます。 -
利用可能な場合は、低バッテリーアラームが発生したときに休止に移行します。
-
利用できない場合は、システムは定期的にサスペンドから起床してバッテリーの残量と放電率をチェックし、これに基づいて次のチェックのタイミングを決定後にサスペンドします。このチェックができない場合に限り、
SuspendEstimationSec=が使用されます。
HibernateDelaySec=が設定されていない場合は、ACPIの低バッテリーアラームの有無にかかわらずシステムは可能な限り長い時間サスペンド状態を維持し、その後休止に移行します。したがって、この場合は休止に移行する時点で電池がほとんど残っていないことになります。
HibernateDelaySec=とSuspendEstimateSec=が同時に設定されている場合はどうなるでしょうか。
HibernateDelaySec=がSuspendEstimateSec=よりも大きい場合には、システムはSuspendEstimateSec=で指定した時間周期でサスペンドから起床し、バッテリーの状態をチェックします。バッテリーの残量が5%未満であれば休止に移行します。それ以外は次の起床をスケジュールしてサスペンドします。この動作はHibernateDelaySec=に達するまで続き、その後休止に移行します。HibernateDelaySec=がSuspendEstimateSec=よりも小さい場合には、システムはHibernateDelaySec=に達した時点で休止に移行します。SuspendEstimateSec=は無視されます。
SuspendEstimateSec=は捨て置いてもよい
さて、suspend-then-hibernateの動作を理解した上でSuspendEstimateSec=を設定する意味はあるか考えてみましょう。
このパラメータは、システムがサスペンド状態に入る前の時間を決めるアルゴリズムを助けるためのものであり、休止への移行時間には直接影響しません。無指定時のデフォルト値は3600秒(1時間)で、これは通常は適切な値です。
非常に特殊な、というか病的な状況においてはこのパラメータへの設定が役立つのかもしれませんが、それがどういう状況であるかは思いつきませんでした。
結局、SuspendEstimateSec=は捨て置いても構わないということです。
まとめ
以上の理解に基づいて、suspend-then-hibernateの設定をまとめます。
まず、快適性を重視する場合は、何も設定せずにおきます。この場合、システムは可能な限り長い時間サスペンド状態を維持しするため、ラップトップPCの蓋を開けるとすぐに利用可能になります。休止状態は電池切れによりサスペンドがデータ喪失を起こさないためのセーフティーネットとして機能します。ただし、このままPCを長期間放置すると、過放電でバッテリーの寿命が縮む可能性があります。毎日充電する人はこの方法でよいでしょう。
たまにしか充電しない人は、/etc/systemd/sleep.conf.d/*.confのHibernateDelaySec=を適切な時間に設定します。例えば900秒(15分)に設定すると、システムは15分間サスペンド状態を維持した後に休止に移行します。この方法は休止の前にサスペンド期間を設けることにより、快適性を向上させていると考えられます。
いずれの場合もSuspendEstimateSec=は設定しなくても結構です。
以上、suspend-then-hibernateの正しい設定方法とその動作原理について解説しました。自分のライフスタイルに合わせて快適性重視か、電池寿命重視を選ぶことができます。