自宅の開発機(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 / Tctl | 45℃ / 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 | |
|---|---|
| fan1 | 850 → 612 rpm |
| fan3 | 1591 → 1032 rpm |
| fan4 | 774 → 550 rpm |
| fan5 | 834 → 576 rpm |
| fan6 | 3268 → 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℃ | — | — | — |
| p95 | 66.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基 | 1 | SYSTIN(ケース内エアー) | 92℃でも 127固定・806rpm |
| pwm2 | CPU クーラー | 9 | SMBUSMASTER 0(= ダイ) | 158 → 255まで正常に上昇 |
| pwm6 | チップセット | 7 | SMBUSMASTER 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つだけだ。
- ケースファン5基の
temp_selを 1(SYSTIN)→ 9(ダイ) に変える - カーブを
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 / fan3 | 806 / 1,520 rpm(不動) | 1,309 / 2,818 rpm |
| アイドル pwm | 127 | 100〜106 |
| アイドル fan1 / fan3 | 808 / 1,541 rpm | 648 / 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→255 | 60→100, 75→140, 85→190, 95→255 |
| アイドル | 160 / 3,229 rpm | 80 / 約1,650 rpm |
| 全コア負荷 | 160 / 3,200 rpm | 107 / 約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のような異常値を返すヘッダは、信用しないと決めておく
騒音を減らそうとして、冷えていないことが分かった。順番は逆でもよかったのだが、ログを溜めてから決めたおかげで、両方いっぺんに直せた。