12インチMacBookにLinuxをインストールして使っていたが、負荷が上がったときにMacBookがサスペンドする問題に困っていた。サスペンドが発生した時刻には、systemd-logindのログに
systemd-logind[299]: Suspend key pressed.
のようなイベントが記録されていた。このログは、LinuxカーネルでKEY_SLEEPと定義されたキーが押されたときにsystemd-logindのbutton_dispatch関数が記録しているものだった。button_dispatchの主な処理を引用する。
static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) { Button *b = userdata; struct input_event ev; ssize_t l; l = read(b->fd, &ev, sizeof ev); switch(ev.code){ case KEY_SLEEP: log_struct(LOG_INFO, "Suspend key pressed.", ...); manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true); break; case KEY_SUSPEND: log_struct(LOG_INFO, "Hibernate key pressed.", ...); ... } }
KEY_SLEEP定数はLinuxのヘッダファイルで定義されたもので、カーネルとsystemdではSuspendが意味するものが異なっているところは少し難しいが、とにかくスリープのようなキーが押されたことを意味する。
#define KEY_SLEEP 142 /* SC System Sleep */ #define KEY_SUSPEND 205
上のコードを読む限りでは、button_dispatchはキーイベントをread(2)しているだけなので、少なくともなんらかのハードウェアが原因だろうと思ったが、MacBookには電源ボタンはあるけれど押していないし、なんならリッドクローズドで使っている時は電源ボタンもないキーボードを使っているので、誤って物理キーを押したわけではない。
systemd-logindでサスペンドを無効化してみる
systemd-logindはサスペンドキーが押されたときの動作を/etc/systemd/logind.confで変更できる。例えば以下のようにignoreを設定するとキーイベントを無視できる。
-#HandleSuspendKey=suspend +HandleSuspendKey=ignore
これは実際に、systemd-logindのmanager_handle_actionで、HANDLE_IGNOREの場合はすぐに関数を抜けているところからもイベントを無視している様子が読み取れる。
/* If the key handling is turned off, don't do anything */ if (handle == HANDLE_IGNORE) { log_debug("Handling of %s (%s) is disabled, taking no action.", inhibit_key == 0 ? "idle timeout" : inhibit_what_to_string(inhibit_key), is_edge ? "edge" : "level"); return 0; }
しかし試したけれど残念ながら、状況は改善されなかった。負荷をかけるとすぐにサスペンドしてしまった。
デスクトップ環境でサスペンドを無効にする
GNOMEやKDEなどのデスクトップ環境は独自の電源管理を行っているので、これを無効化してみる。GNOMEの場合は、関連する設定は以下の通り。
$ gsettings get org.gnome.settings-daemon.plugins.power power-button-action 'suspend' $ gsettings get org.gnome.settings-daemon.plugins.power sleep-inactive-battery-type 'suspend' $ gsettings get org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type 'suspend' $ gsettings get org.gnome.settings-daemon.plugins.power sleep-inactive-battery-timeout 200 $ gsettings get org.gnome.settings-daemon.plugins.power sleep-inactive-ac-timeout 1200
これらの設定を無効にする。
$ gsettings set org.gnome.settings-daemon.plugins.power power-button-action nothing $ gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-battery-type nothing $ gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type nothing
これも、設定したあとで負荷をかけて様子をみたが、再発してしまったので関係がなかった。
CPU周波数を落とす
12インチMacBookはファンレスなので、熱の問題だろうと当たりをつけて対策する。このハードウェアのデフォルトはintel_pstateドライバのpowersaveガバナー(Governor)だった。
$ grep . /sys/devices/system/cpu/cpu?/cpufreq/scaling_driver /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver:intel_pstate /sys/devices/system/cpu/cpu1/cpufreq/scaling_driver:intel_pstate /sys/devices/system/cpu/cpu2/cpufreq/scaling_driver:intel_pstate /sys/devices/system/cpu/cpu3/cpufreq/scaling_driver:intel_pstate $ grep . /sys/devices/system/cpu/cpu?/cpufreq/scaling_governor /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor:powersave /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor:powersave /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor:powersave /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor:powersave
Intel Turbo Boostを無効にする
Turbo Boostは使っていないコアの電源を落とす替わりに、特定コアのクロックを上げる仕様らしい。
Turbo Boostはno_turboファイルに1を書き込むことで無効にできる。
$ echo 1 | sudo tee /sys/devices/system/cpu/intel_pstate/no_turbo
TurboBoostを無効にすると、突然サスペンドすることはなくなったが、クロックが最大1.4GHzまで落ちてしまうので普段使いするには少々厳しい性能になってしまった。
cpuの最大クロック数を制限する
cpupowerを使ってクロックを落とす方法。
$ sudo pacman -S cpupower $ sudo cpupower frequency-set -u '2.2GHz'
これで全てのコアが最大2.2GHzに制限される。ただしこの設定は再起動すると消えるので、永続化したい場合はsystemdで実行する。cpupowerをインストールしていれば、/etc/default/cpupowerに設定ファイルがあるので利用するといい。
-#max_freq="3GHz" +max_freq="2.2GHz"
その後、systemctlでサービスを有効にする。
$ systemctl enable cpupower.service
クロックを変更して実験した結果、2.2GHzまで落とさなければサスペンドが発生していた。実験したときは5月だけど、夏はもっと下げなければだめかもしれない。もっと下げると、TurboBoost無効時の1.4GHzとそれほど変らず、性能の劣化が気になる。
Thermaldで冷却する
一般的にはインストールして起動するだけで適切な動作をする。Ask Ubuntuの回答によると、このモードはZero Configuration Modeといって、DTS温度測定センサーやIntel P-stateを使って適切な調整をする。
coretempドライバのドキュメントは以下のURLにあった。
だけれども、MacBookの場合はZero Configuration Modeでは冷却されている様子がなかったので、/etc/thermald/thermal-conf.xmlで設定することにした。この方法は、上記Ask Ubuntuの回答によるとUser defined configuration modeにあたる。Thermaldに関係するマニュアルは以下の2つ。
thermal-conf.xml(5)には設定例もあるので、読めばだいたい雰囲気で分かるのだけど、難しかったところを少しまとめる。thermal-conf.xmlは大きく分けて3つの要素で構成される。
- ThermalSensor
- CoolingDevice
- TripPoint
ThermalSensor
センサーは温度を計測する場所のことで、たとえばCPUコアなどがそれに該当する。センサーを扱うためには/sys以下のファイルなどを<ThermalSensor>
要素で設定が必要になるが、/sys/class/thermal以下のデバイスはデフォルトで組み込まれているので、特に設定を追加せずとも利用できる。12インチMacBookの場合は以下の通り。
$ grep . /sys/class/thermal/thermal_zone*/type /sys/class/thermal/thermal_zone0/type:BAT0 /sys/class/thermal/thermal_zone1/type:x86_pkg_temp
BAT0はバッテリーで、x86_pkg_tempはCPUパッケージかな。/sys/class/thermal以下のファイル郡はACPI由来のもので、マニュアルではThermal sysfsと呼ばれている。/sys/class/thermalのカーネルドキュメントは以下のURLにある。
Thermal sysfs以外にも、MacBookには/sys/devices/platform/coretemp.0/subsystem/devices/applesmc.768などのセンサーがある。これらThermal sysfs以外のセンサーを参照して温度管理をする場合は、<ThermalSensor>
要素を使った設定が必要になる。sensorsコマンドを実行すると、他にどのようなセンサーがあるのか調べられる。
$ sensors BAT0-acpi-0 Adapter: ACPI interface in0: 8.58 V temp: +32.8°C curr1: 0.00 A (avg = +0.00 A) coretemp-isa-0000 Adapter: ISA adapter Package id 0: +44.0°C (high = +100.0°C, crit = +100.0°C) Core 0: +43.0°C (high = +100.0°C, crit = +100.0°C) Core 1: +43.0°C (high = +100.0°C, crit = +100.0°C) applesmc-isa-0300 Adapter: ISA adapter TA0V: +29.0°C TB0T: +32.5°C TB1T: +32.0°C TB2T: +32.5°C TBXT: +32.5°C TC0E: +43.8°C TC0F: +46.0°C TC0P: +39.5°C TC1C: +43.0°C TC2C: +43.0°C TCGC: +43.0°C TCHP: +37.0°C TCSA: +44.0°C TCXC: +43.5°C TH0A: +37.2°C TH0B: -127.0°C TH0C: -127.0°C TH0F: -47.8°C TH0R: -47.8°C TKBV: +36.8°C TM0P: +38.8°C TPCD: +39.0°C TPMV: +31.8°C TW0P: +37.2°C Th0N: +36.2°C Th0R: +31.8°C Ts0P: +32.2°C Ts0S: +36.0°C Ts1P: +30.5°C TsCH: +47.5°C TsFD: +60.0°C TsFS: +53.0°C TsHS: +2.0°C TsTH: +3.0°C TsTP: +50.0°C TsWS: +49.0°C BAT0-virtual-0 Adapter: Virtual device temp1: +32.8°C nvme-pci-0100 Adapter: PCI adapter Composite: +39.9°C
sensorsコマンドで出力された結果の意味は、以下の記事が参考になると思う。
CoolingDevice
冷却デバイスは温度を下げるための機構またはハードウェアのこと。空冷ファンは当然だけど、CPUのクロックを落とすしくみのような機構もCoolingDeviceに該当する。これもセンサーと同様に、/sys/class/thermal以下のデバイスは何も書かなくても利用できる。12インチMacBookの場合は以下の通り。
$ grep . /sys/class/thermal/cooling_device*/type /sys/class/thermal/cooling_device0/type:Processor /sys/class/thermal/cooling_device1/type:Processor /sys/class/thermal/cooling_device2/type:Processor /sys/class/thermal/cooling_device3/type:Processor /sys/class/thermal/cooling_device4/type:intel_powerclamp /sys/class/thermal/cooling_device5/type:LCD
また、マニュアルによると、以下のデバイスもCoolingDeviceとして使えるらしい。
それぞれがどんな動作をするのかは、ArchWikiのCPU 周波数スケーリングが詳しい。
TripPoint
この要素で、センサーと冷却デバイスをまとめて温度管理を行う。例えば以下のような設定になる。
<TripPoint> <SensorType>x86_pkg_temp</SensorType> <Temperature>75000</Temperature> <type>passive</type> <ControlType>PARALLEL</ControlType> <CoolingDevice> <index>1</index> <type>rapl_controller</type> <influence>50</influence> <SamplingPeriod>1</SamplingPeriod> </CoolingDevice> </TripPoint>
<Temperature>
は冷却を開始するセンサーの温度を設定する。75000の場合は75℃以上になったら開始する。<type>
は以下の3種類。
- active
- passive
- max
activeは、空冷ファンなどコストのかかる(追加の電源やノイズなどが発生する)を使う。passiveならパフォーマンスを落として温度を下げる。maxについてはよくわからない。
<SamplingPeriod>
を設定すると、前回の変化から設定した秒が経過するまでは温度の変化を検出しなくなる。未設定または0なら常に検出する。
設定例
現在設定している/etc/thermald/thermal-conf.xmlを貼っておく。だいたい期待どおりに動いているが、長時間の負荷を与えたときはまだ稀にサスペンドする場合があるので、もう少し調整は必要だと思う。
<?xml version="1.0"?> <ThermalConfiguration> <Platform> <Name>Macbook 2017</Name> <ProductName>*</ProductName> <Preference>QUIET</Preference> <!-- 空冷ファンなどactiveなデバイスを使わず冷却する --> <ThermalZones> <ThermalZone> <Type>x86_pkg_temp</Type> <TripPoints> <TripPoint> <SensorType>x86_pkg_temp</SensorType> <Temperature>75000</Temperature> <type>passive</type> <ControlType>PARALLEL</ControlType> <CoolingDevice> <index>1</index> <type>rapl_controller</type> <influence>50</influence> </CoolingDevice> <CoolingDevice> <index>2</index> <type>intel_pstate</type> <influence>40</influence> </CoolingDevice> <CoolingDevice> <index>3</index> <type>intel_powerclamp</type> <influence>30</influence> </CoolingDevice> <CoolingDevice> <index>4</index> <type>cpufreq</type> <influence>20</influence> </CoolingDevice> <CoolingDevice> <index>5</index> <type>Processor</type> <influence>10</influence> </CoolingDevice> </TripPoint> </TripPoints> </ThermalZone> </ThermalZones> </Platform> </ThermalConfiguration>
以下のURLにも設定例が書かれているので、参考になる。