自宅の開発機(Ryzen 9 3900X、ASRock X570 Steel Legend、RTX 2060)がうるさかった。ヘッドレスで机の横に置いてあるので、ファンの音がそのまま作業の音になる。

調べ始めたら、騒音より先に別の問題が出てきた。CPUが92℃に達しても、ケースファンが1回転も速くならない。

Super I/O チップを読む

このマザーボードのファン制御チップは Nuvoton NCT6798D で、Linux の nct6775 ドライバで読める。初期構築時はロードされていなかったので、/etc/modules-load.d/ で自動ロードにした。ACPI のリソース競合は起きず、よく必要になる acpi_enforce_resources=lax は要らなかった。

ls /sys/class/hwmon/*/name | xargs -I{} sh -c 'echo "{}: $(cat {})"'   # nct6798 が出る

読んでみると、pwmN_enable は全ヘッダ 5 = SmartFan IV。つまり BIOS のファンカーブが効いていて、「常時フル回転」ではない。ただしアイドル時の下限が高いのが騒音の正体だった。

アイドル時
pwm の下限134/255(約53%)— ケースファン5基
fan6(チップセット)約3,300 rpm(pwm 165)。単体で一番うるさい
CPUTIN / Tctl45℃ / 68〜70℃

fan2 の回転数が 19,640 rpm のような明らかな異常値を返すことがある。タコメータの分周の誤りで、ヘッダに何も繋いでいないか3ピンの可能性が高い。fan2 の値は信用しないと決めた。

GPU(RTX 2060)のファンも、アイドル54℃で27〜29%回りっぱなしだった。こちらは VBIOS のカーブで、nvidia-settings は X サーバーを要求するのでヘッドレスでは変更できない。GPU ファンは制御不能として諦めた。

PWM の書き込みは効く

OS から回転数を制御できるか、実測した。pwmN_enable=1(手動)にして pwmN=90 を書く。

pwm 134 → 90
fan1850 → 612 rpm
fan31591 → 1032 rpm
fan4774 → 550 rpm
fan5834 → 576 rpm
fan63268 → 1936 rpm

全ヘッダが追従した。fancontrol(lm-sensors)で独自カーブを組めることは分かった。

ただ、制御方式には気をつけることが2つあった。

  • BIOS のカーブを直すほうが筋だが、この機体では BIOS を触ると TPM の PCR7 が変わって LUKS が解錠できなくなるリスクがある。 モニタと LUKS のパスフレーズを用意せずに触らない
  • OS 側で pwmN_enable=1(完全手動)にすると、デーモンが死んだ瞬間に回転数が固定される。 温度が上がっても誰も回さない。やるなら enable=2(Thermal Cruise。チップ内部で温度追従)にして目標温度だけ与えるか、unit の ExecStopPost で必ず enable=5 に戻す

どちらを選ぶかは、まず実負荷の温度分布を見てから決めることにした。ここで1分ごとの稼働ログ(温度・回転数・PWM・負荷)を溜め始めた。

6日分の温度分布

8/9〜8/14 の6日、6,783サンプル(1分刻み)を集計した。

Tctl(CPUダイ)CPUTIN(ソケット横)SYSTIN(ケース内)GPU
平均41.3℃34.5℃37.9℃52.7℃
中央37.8℃———
p9566.2℃———
最高96.1℃73.5℃54.0℃77.0℃

最高の96.1℃は、手動テストで pwm=90 に落としていた時間帯のものだ。ただ、テスト後の実負荷でも 8/10 に92.5℃、8/11 に86.2℃が出ている。中身は Playwright 53本 + node の build の並列。85℃超の時間は 8/10 が12分、8/11 が2分。

ケース内(SYSTIN)は40〜41℃止まりで、夏でも室温側は問題になっていない。

問題はここだ。Tctl が92℃に達しているとき、ケースファンの pwm は127/255のまま上がっていなかった。

原因: ケースファンは SYSTIN を見ていた

pwmN_temp_sel を読むと、各ヘッダがどの温度を参照しているかが分かる。

PWMヘッダtemp_sel参照している温度負荷時の挙動
pwm1/3/4/5/7ケースファン5基1SYSTIN(ケース内エアー)92℃でも 127固定・806rpm
pwm2CPU クーラー9SMBUSMASTER 0(= ダイ)158 → 255まで正常に上昇
pwm6チップセット7SMBUSMASTER 1(62℃で不動)155固定・3,100rpm

CPU クーラーは正常だった。死んでいたのはケースファン5基。

SYSTIN は、全コア負荷を90秒かけても 37.0℃から1目盛りも動かない。カーブの第1点(40℃)にすら到達しないので、構造上は永久に下限から動けなかった。CPU がどれだけ熱くなっても、ケースファンから見れば「ケース内は涼しい」ままだ。

最初は CPUTIN が原因だと思って記録したが、これは誤りで、実際は SYSTIN だった。CPUTIN よりさらにダイから遠い。

ダイの温度は、どれを参照できるか

チップは複数の温度を持っている。どれが本物のダイ温度か、負荷試験で確かめた。

TSI0_TEMP(temp13)は 50〜92℃の全域で Tctl と0.2℃以内で一致した。アイドル時のみ、Tctl のスパイクぶんだけ乖離する。SMBUSMASTER 0(temp9)も同じ値だった。どちらもチップが持っている本物のダイ温度だ。

ただし pwmN_temp_sel に TSI 系(13/14)は書けない。EINVAL で弾かれる。nct6775 ドライバは TSI 温度を別グループとして扱っていて、ファン制御の参照温度には指定できない。指定できるのは1〜12。よって 9(SMBUSMASTER 0)を使う。

対策: BIOS も手動モードも使わず、参照温度だけ変える

やったことは2つだけだ。

  1. ケースファン5基の temp_sel を 1(SYSTIN)→ 9(ダイ) に変える
  2. カーブを 40℃→100, 60→130, 75→190, 85→255 にする

pwmN_enable は5(SmartFan IV = チップ内部の自動制御)のまま、一切変更しない。 pwm を直接書く手動モードを使わないので、「デーモンが死んだ瞬間に回転数が固定される」事故は原理的に起きない。チップが自律制御を続ける。BIOS も触らないので、PCR7 と LUKS のリスクも無い。

再起動すると BIOS が既定値を書き直すので、systemd の unit で boot と resume の両方で再適用する。この機械は S3 サスペンド運用に入ることが決まっていたので、resume 側も最初から入れてある。実際、初めてのサスペンドからの復帰で、unit が自動で再適用されたのをログで確認した。

効果: 暴走が平衡に変わった

同一条件の全コア負荷で比較した。

修正前修正後
60秒時点90.2℃85.0℃
頭打ち78秒で92.2℃ → 中断(上昇継続中)87.7℃で平衡・120秒完走
負荷時 fan1 / fan3806 / 1,520 rpm(不動)1,309 / 2,818 rpm
アイドル pwm127100〜106
アイドル fan1 / fan3808 / 1,541 rpm648 / 1,182 rpm

修正前は Tjmax(95℃)に向かって上がり続けていて、78秒で中断した。修正後は88℃前後で平衡し、120秒完走した。

そしてアイドルはむしろ静かになった。カーブの第1点を127から100に下げたので、何もしていないときは以前より回らない。騒音から始まった調査なので、ここが本来の目的だった。

副次効果として、チップセットの温度も負荷中に63℃から61℃に下がった。ケースファンが実際に空気を動かすようになったので、ケース内の全部品が恩恵を受けている。

チップセットファンも半減させた

一番うるさかった fan6(pwm 160で3,200rpm回りっぱなし)も、同じ考え方で直した。

参照している SMBUSMASTER 1 は、ダイが56→75℃に上がる間も61〜62℃から動かない。独立した熱源、つまり X570 チップセットだ。BIOS 既定のカーブは第1点が50℃なので、62℃が常に第2点付近に当たり、構造上下がりようがなかった。

X570 チップセットは60〜70℃が正常域で、定格は100℃を超える。第1点を60℃にずらした。

BIOS 既定変更後
カーブ50→127, 60→153, 70→178, 75→204, 80→25560→100, 75→140, 85→190, 95→255
アイドル160 / 3,229 rpm80 / 約1,650 rpm
全コア負荷160 / 3,200 rpm107 / 約2,150 rpm

回転数はほぼ半減した。 参照温度は変えていない。85℃以上では BIOS 既定より強く回るカーブにしてあるので、異常時の余裕はむしろ増えている。

10分間の監視で61〜64℃。変更前のアイドル61〜62℃に対して実質+2℃で、64℃では pwm が107→110に自動追従していた。制御ループは設計どおり効いている。Prometheus に載せたので、以後の推移は Grafana で追える。

まとめ

  • 「ファンが回っている」と「CPU を冷やしている」は別のこと。 参照温度が違えば、CPU がどれだけ熱くてもファンは反応しない
  • pwmN_temp_sel を読めば、各ヘッダが何を見ているかが分かる。うちはケースファン5基が SYSTIN(ケース内エアー)を見ていて、全コア負荷90秒でも1目盛り動かなかった
  • ダイ温度は TSI0_TEMP が Tctl と0.2℃以内で一致するが、temp_sel には指定できない。SMBUSMASTER 0(9)を使う
  • enable=5 のまま参照温度とカーブだけ変える。 手動モード(enable=1)はデーモンが死ぬと回転数が固定される。BIOS を触ると PCR7 のリスクがある。どちらも避けられる
  • BIOS は再起動で既定値を書き直す。boot と resume の両方で再適用する
  • 結果: 78秒で92℃→中断 が、88℃で平衡・完走に。アイドルは静かになった
  • チップセットファンは参照温度が動かない熱源なので、カーブの第1点をその温度の上にずらす。回転数は半減
  • fan2 のような異常値を返すヘッダは、信用しないと決めておく

騒音を減らそうとして、冷えていないことが分かった。順番は逆でもよかったのだが、ログを溜めてから決めたおかげで、両方いっぺんに直せた。