(Linux) Intel GPU でフリーズが起こる

Intel GPU におけるフリーズ
Intel GPU で 3D ゲームなどをしていると、頻繁にフリーズすることがあります。
(Skylake で確認)

その場合、システムログ (# dmesg または $ journalctl) 上において、フリーズが発生した時間に、以下のようなエラーが記録されています。

i915 0000:00:02.0: [drm] Resetting rcs0 for preemption time out
i915 0000:00:02.0: [drm] <appname> context reset due to GPU hang
i915 0000:00:02.0: [drm] GPU HANG: ecode 9:1:84df7efc, in <appname>

また、Wine + DXVK の場合、アプリを実行している端末に、以下のようなエラーが出る場合があります。

DxvkSubmissionQueue: Command submission failed: VK_ERROR_DEVICE_LOST
DxvkDevice: waitForIdle: Operation failed
症状
  • 負荷の高い 3D ゲームをプレイしていると、数十分〜1・2時間程度の頻度で発生する。
    「Wine + DXVK」「Wine + Gallium Nine」ほか、3D をプレイする通常の Linux アプリでも起きる。
  • 頻度はそれほど多くないが、ブラウザで YouTube 動画を見ている時もたまに起こる。
  • デスクトップが完全にフリーズし、操作できない状態になる。
  • Alt+Ctrl+F* で仮想端末を切り替えた後、kill コマンドでアプリを強制終了すると、復帰出来る場合もある。
  • Alt+Ctrl+F* で切り替えることに成功したり、kill コマンドで強制終了させても、数秒後に全く何も受け付けない状態になる場合がある。
    そうなると、PC 本体のリセットボタンを長押しして、強制再起動するしかない。
  • 普通にデスクトップを操作している時は、全く起こらない。

エラーメッセージで検索してみると、他にも似たような報告があるので、個別のアプリの問題ではなく、Mesa ドライバなど、根本的なところに問題がありそうです。
解決方法
ネット上で紹介されている対策方法(環境変数の設定、i915 モジュールの設定、タイムアウト時間を増やすなど)を色々と試してみましたが、ほとんど効果はありませんでした。

しかし、最終的に以下の方法を使うと、フリーズは起こらなくなりました。

・Intel GPU のツール intel_gpu_frequency を使って、GPU の周波数を最大に固定する。
intel_gpu_frequency
intel_gpu_frequency コマンドは、GPU の周波数を調整するツールです。

intel-gpu-tools パッケージに含まれているので、こちらをインストールする必要があります。

※このコマンドは、常に root 権限で実行する必要があります。--help オプションですら、一般権限では動作しません。

周波数の確認
-g, --get オプションで、現在の GPU の周波数を確認できます。

# intel_gpu_frequency --get

cur: 350 MHz
min: 350 MHz
RP1: 350 MHz
max: 950 MHz

普段は min〜max までの間で変動するようになっています。

周波数を最大で固定する
-m, --max オプションで、GPU の周波数を最大に固定できます。

# intel_gpu_frequency --max

//確認
# intel_gpu_frequency --get

cur: 883 MHz
min: 950 MHz
RP1: 350 MHz
max: 950 MHz

min が最大値と同じになっています。
cur は現在の周波数です。最大値にはなっていませんが、350 → 883 に変化しています。

デフォルトに戻す
システムのデフォルトに戻したい場合は、-d, --defaults オプションを使います。
使い方
フリーズしそうなアプリを実行する前に、-m, --max で最大に固定します。
アプリが終わって通常の動作に戻したい時は、-d, --defaults でデフォルトに戻します。
(PC を再起動すると、デフォルトに戻ります)

Intel GPU は、システムの要求に基づいて、周波数を自動的に調整し、必要な場合は周波数を上げ、必要のない場合は周波数を下げます。
普段使いで省電力にしたい場合は、デフォルトのままにしておくと良いでしょう。