ThinkCentre M75q-1 のファン爆音問題 の履歴(No.2)

更新


公開メモ

ThinkCentre M75q-1 (Debian) のファン爆音問題を ryzenadj で解決する

Claude さんに作業内容を記事にしてもらいました。

問題の概要

Lenovo ThinkCentre M75q-1 に Debian をインストールして運用していたところ、 特に高負荷な処理をしていないにもかかわらずファンが突然フル回転し、 うるさい風切り音が続くという問題が発生した。

調査の結果、以下の構造的な問題が判明した:

  • CPU(AMD Ryzen 5 PRO 3400GE)はアイドル時でも 55〜65°C になりやすい設計特性を持つらしい
  • ThinkCentre M75q-1 の EC(組み込みコントローラ)のファン制御は ON/OFF の二値制御に近く、 約 62°C でフル回転、約 53.5°C で停止するという粗い動作をする
  • Windows 環境では Lenovo Vantage がバックグラウンドで TDP を適切に制御しているが、 Linux にはそのドライバが存在しない
  • Linux からは EC のファン制御曲線を変更する手段がない(WMI・thinkpad_acpi ともに使用不可)

結果として、少しの負荷でも 62°C を超えてファンがフル回転し、冷えたら止まる というサイクルを繰り返す状態になっていた。

  • 吸入口のフィルタに掃除機を当てたら気持ち改善したが、これから夏本番であることを考えるとつらい
  • それでも年々悪化している気がするのはサーマルグリスが劣化しているせいかもしれないため、 塗りなおすのを試すのもいいかも

以下はこんなサーバー機をだましだまし使うための設定。

解決策の方針

EC のファン制御は変更できないため、""CPU 自身に温度上限を設けてクロックを自律的に制御させる"" 方向で解決した。具体的には `ryzenadj` を使って CPU のサーマルスロットリング閾値(tctl-temp)を 62°C 未満に設定することで、ECがファンを回す前に CPU が自ら発熱を抑えるようにした。

環境

  • 機種: Lenovo ThinkCentre M75q-1
  • CPU: AMD Ryzen 5 PRO 3400GE(コードネーム: Picasso)
  • OS: Debian 12 (bookworm)
  • カーネル: 6.1.0-49-amd64

調査手順

センサーの確認

LANG: console
$ sudo apt install lm-sensors
$ sudo sensors-detect
$ sensors

ThinkCentre M75q-1 では `k10temp` のみが使用可能で、 ファンの PWM 制御端子(`fan*`, `pwm*`)は hwmon に存在しない。 EC がファンを完全に管理しており、Linux 側から制御できない。

LANG: console
$ # hwmon の内容を確認
$ for d in /sys/class/hwmon/hwmon*; do echo "==$d=="; ls $d; done

温度のリアルタイム監視

LANG: console
$ # 時刻付きで温度を継続表示(60秒間隔)
$ while true; do
    echo "$(date +%T) $(sensors | grep Tctl)"
    sleep 60
  done

CPU クロックと温度の同時確認

LANG: console
$ while true; do
    echo "$(date +%T) $(sensors | grep Tctl) $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq | awk '{printf "%d MHz", $1/1000}')"
    sleep 5
  done

ファンの ON/OFF 閾値の特定

上記の監視コマンドを使い、ファンが回り始める温度と止まる温度を記録した。 本環境では:

  • ON 閾値: 約 62°C
  • OFF 閾値: 約 53.5°C(ヒステリシス約 8.5°C)

負荷プロセスの調査

LANG: console
$ # プロセスごとの CPU 使用率合計
$ ps aux | awk 'NR>1 {sum += $3} END {print "Total CPU%:", sum}'

$ # pidstat で長期記録
$ sudo apt install sysstat
$ pidstat -u 60 | tee /tmp/pidstat_log.txt

$ # 記録後に集計
$ awk '
    /^[0-9]/ && $NF != "Command" {
       cpu[$NF] += $7
       count[$NF]++
   }
   END {
       for (p in cpu)
           printf "%.2f\t%d samples\t%s\n", cpu[p]/count[p], count[p], p
   }
 ' /tmp/pidstat_log.txt | sort -rn | head -20

本環境では特定の重いプロセスは見当たらず、複数の軽いプロセスが常時動いている状態だった。

## ryzenadj のインストールと設定

### 必要なパッケージのインストール

LANG: console
$ sudo apt install cmake libpci-dev build-essential dkms linux-headers-$(uname -r)

### ryzen_smu カーネルモジュールのビルドとインストール

`ryzenadj` は `ryzen_smu` カーネルモジュールと連携して動作する。 オリジナルの `leogx9r/ryzen_smu` は古くメンテされていないため、 アクティブにメンテされている `amkillam/ryzen_smu`(バージョン 0.1.7)を使用する。

LANG: console
$ git clone https://github.com/amkillam/ryzen_smu.git
$ cd ryzen_smu

$ # バージョン確認(0.1.7 であることを確認)
$ grep "^VERSION" Makefile

$ # DKMS でインストール(カーネル更新時に自動再ビルドされる)
$ sudo make dkms-install

$ # モジュールのロードと確認
$ sudo modprobe ryzen_smu
$ sudo dmesg | grep ryzen_smu | tail -5
$ sudo cat /sys/kernel/ryzen_smu_drv/drv_version

`/sys/kernel/ryzen_smu_drv/` 以下にファイルが展開されていれば正常。

ryzenadj のビルド

LANG: console
$ cd ~
$ git clone https://github.com/FlyGoat/RyzenAdj.git
$ cd RyzenAdj
$ mkdir build && cd build
$ cmake ..
$ make
$ sudo cp ryzenadj /usr/local/bin/

現在の設定確認

LANG: console
$ sudo ryzenadj --info

`THM LIMIT CORE`(tctl-temp)がデフォルト 95°C になっていることを確認できる。

tctl-temp の設定

ファン ON 閾値(62°C)より少し低い値に設定する。
本環境では 60°C に設定したところ、CPU が 58°C 台で安定しファンが回らなくなった。
スロットリングは閾値の手前から徐々に効き始めるため、設定温度より数度低い温度で安定する。

LANG: console
$ sudo ryzenadj --tctl-temp=60
$ # 確認
$ sudo ryzenadj --info 2>&1 | grep "THM LIMIT"

永続化(起動時の自動適用)

systemd サービスの作成

LANG: console
$ sudo nano /etc/systemd/system/ryzenadj.service
[Unit]
Description=RyzenAdj power settings
After=multi-user.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/ryzenadj --tctl-temp=60
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

`ryzenadj` は SMU に値を書き込んで即終了するコマンドであり、常駐しない。
`Type=oneshot` は「起動時に一度だけ実行して終了するサービス」を表す systemd の設定で、このような用途に適している。
`RemainAfterExit=yes` を指定することで、コマンド終了後もサービスが「active」状態として扱われ、`systemctl status` で確認しやすくなる。

LANG: console
$ sudo systemctl daemon-reload
$ sudo systemctl enable ryzenadj.service
$ sudo systemctl start ryzenadj.service
$ sudo systemctl status ryzenadj.service

再起動後の確認

LANG: console
$ sudo ryzenadj --info 2>&1 | grep "THM LIMIT"
$ # THM LIMIT CORE | 60.000 と表示されれば成功

結果

設定前後の比較:

設定前設定後
アイドル温度60〜62°C58°C 程度で安定
ファン挙動加熱→ 62°C でフル回転→
冷却→53.5°Cで停止→繰り返し
ほぼ停止
クロック最大 3400MHz1300〜1400MHz 付近で自律制御

注意事項

  • `tctl-temp` を低く設定するほど CPU クロックが抑制され処理性能が低下する。 用途に応じて値を調整すること。
  • この設定はサーマルスロットリングを意図的に早めるものであり、 CPU 保護の観点からは問題ないが、高負荷処理(動画エンコード等)では パフォーマンス低下が顕著になる場合がある。
  • `ryzen_smu` はカーネルの taint(汚染)フラグを立てる out-of-tree モジュールである。
  • DKMS によりカーネル更新時に自動再ビルドされるが、 大幅なカーネルバージョン変更時には動作確認を推奨する。

コメント





Counter: 69 (from 2010/06/03), today: 1, yesterday: 3