🦄

[CUDA]サスペンドできない場合の対処

2022/04/03に公開

これは何か

NVIDIAプロプライエタリドライバーとCUDAライブラリーをインストールした特定条件下において、サスペンドに失敗してしまいます。うちの環境ではばっちり再現性があり困っていました。
使用環境によりサスペンドは不要という場合がほとんどだと思いますが、私の環境では必須です。
調べていくと危険な沼[1]になっていることがわかりました。また.local/share/xorg/Xorg.0.logなどいろいろなものをじっくり読む資質が自分にはありません。
そこでここでは細部の正確性を無視して、回避策を提案します。

現象

  • 遭遇した現象
    • システムトレイからサスペンドを選択→サスペンドに失敗したあと勝手にログアウトする
    • sudo systemctl suspend→サスペンドに失敗したあと勝手にログアウトする
  • 他の事例では
    • 起動に失敗する
    • ログイン画面がループする

背景

NVIDIAによる説明(バージョン510)の適当な意訳

  • サスペンドの結果、ビデオメモリコンテンツが損失する可能性がある
  • これはレンダリングの破損やアプリケーションのクラッシュなどを引き起こす
  • だからデフォルト状態ではサスペンドさせないようにしている
    • NVIDIAとしてはsystemdとの統合を試みている
    • しかしながらまだ実験的
    • 意図的にシステムをいじって実験的機能を使うことができる[2]
    • 最終的にsudo systemctl suspendがうまく動けばラッキー
    • 結局組み合わせるシステム次第

補足

NVIDIAのドキュメントはドライバーのバージョンごとにこちらのページにまとめられています。
Index of /XFree86/Linux-x86_64
とはいえ、バージョンをまたいで同じ問題が同じ文章で載っていたりします。
多くが既知の問題として認識されていますが、NVIDIA単体ではどうにもできない苦慮がみてとれます。
私個人としてはシステムをいじくり回すよりも、簡単な回避策があるならそちらが良いです。

結論

  • nvidia-powerd.serviceがfailするのは意図的。

  • 解決する方法は、一応ある(意図する内容を理解しなおかつ実行しようとする人対象)

  • 私のような人は**pm-utilspm-suspendを使ったほうがお手軽**

    $ sudo apt install -y pm-utils
    $ sudo pm-suspend
    

現在の環境

ここからは考えたことや実行したことをダラダラと書いています。

  • Linux 5.13.0-39-generic #44~20.04.1-Ubuntu SMP Thu Mar 24 16:43:35 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
  • 08:00.0 VGA compatible controller: NVIDIA Corporation TU116 [GeForce GTX 1660 Ti] (rev a1)
  • AMD Ryzen 5 1400 Quad-Core Processor
  • nvidia-smi

前提

  • UEFIの設定に不正な値がないこと(重要)

  • ubuntu-drivers autoinstallを使用していること(重要。ディストリビューションが用意したパッケージを使うという意味です)

    wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin
    mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600
    apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/7fa2af80.pub
    add-apt-repository "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/ /"
    apt update && apt upgrade -y
    ubuntu-drivers devices
    ubuntu-drivers autoinstall
    apt install -y cuda
    

主なエラー

# 前半
kernel: nvidia-gpu 0000:08:00.3: i2c timeout error e0000000
kernel: ucsi_ccg 3-0008: i2c_transfer failed -110
kernel: ucsi_ccg 3-0008: ucsi_ccg_init failed - -110

# 後半
kernel: /usr/bin/nvidia-powerd[1228]: No matching GPU found
kernel: /usr/bin/nvidia-powerd[1228]: Failed to initialize RM Client
systemd[1]: Failed to start nvidia-powerd service.
systemd[1866]: Failed to start GNOME Power management handling.
systemd[1866]: Faikernel: [drm:nv_drm_master_set [nvidia_drm]] *ERROR* [nvidia-drm] [GPU ID 0x00000800] Failed to grab modeset ownership

State: degradedとなっていたりもします。

$ systemctl status
● user-comp
    State: degraded
     Jobs: 0 queued
   Failed: 1 units
    Since: Sat 2022-04-02 09:23:46 JST; 7h ago
   CGroup: /
           ├─368 bpfilter_umh
           ├─user.slice 
           │ ├─user-125.slice 
           │ │ ├─session-c2.scope 

これらのエラーは気にしなければ放っておいても大丈夫です。
復帰が異様に遅かったり黒い画面のままなら対策したほうがいいかも、くらいに捉えてください。

エラーを消したい場合

スパムログから解放されたい場合、モジュールをブラックリストに入れたりサービスユニットをdisableにしたりします。これによる副作用を考慮して行ってください。[3]

前半のエラー

kernel: nvidia-gpu 0000:08:00.3: i2c timeout error e0000000
kernel: ucsi_ccg 3-0008: i2c_transfer failed -110
kernel: ucsi_ccg 3-0008: ucsi_ccg_init failed - -110

「Type-CのUSB端子がないんだけれどどうなってるの?」という意味かと思いますがMSI GeForce GTX 1660 Ti AERO ITX 6G OCには元々USB端子がありません。その分お買い得。

補足

Kernel driver i2c-nvidia-gpuとは。

i2c-nvidia-gpuは、NVIDIA Turing以降のGPUに含まれるI2Cコントローラーのドライバーであり、GPU上のType-Cコントローラーとの通信に使用されます。

i2cカーネルモジュールの表示

$ modprobe -c | grep nvidia
blacklist nvidiafb
alias mbp_nvidia_bl apple_bl
alias pci:v000010DEd*sv*sd*bc03sc*i* nvidiafb
alias pci:v000010DEd*sv*sd*bc0Csc80i* i2c_nvidia_gpu  ←これ。
alias typec:id0955m* typec_nvidia

[4]そもそもこのblacklistをどうにかしないといけないのかもしれません

i2cの依存関係を表示

怖いので依存関係などを覗いています。

$ modprobe -D i2c_nvidia_gpu
insmod /lib/modules/5.13.0-37-generic/kernel/drivers/i2c/busses/i2c-nvidia-gpu.ko 

ucsi_ccgカーネルモジュールの表示

$ modprobe -c | grep ucsi
alias acpi*:PNP0CA0:* ucsi_acpi
alias i2c:ccgx_ucsi ucsi_ccg  ←これ。
alias symbol:ucsi_connector_change typec_ucsi
alias symbol:ucsi_create typec_ucsi
alias symbol:ucsi_destroy typec_ucsi
alias symbol:ucsi_get_drvdata typec_ucsi
alias symbol:ucsi_register typec_ucsi
alias symbol:ucsi_resume typec_ucsi
alias symbol:ucsi_send_command typec_ucsi
alias symbol:ucsi_set_drvdata typec_ucsi
alias symbol:ucsi_unregister typec_ucsi

ucsi_ccgの依存関係を表示

$ modprobe -D ucsi_ccg
insmod /lib/modules/5.13.0-37-generic/kernel/drivers/usb/typec/typec.ko 
insmod /lib/modules/5.13.0-37-generic/kernel/drivers/usb/typec/ucsi/typec_ucsi.ko 
insmod /lib/modules/5.13.0-37-generic/kernel/drivers/usb/typec/ucsi/ucsi_ccg.ko 

lspci -vのNvidiaの部分を抜粋

# VGAコントローラー
08:00.0 VGA compatible controller: NVIDIA Corporation TU116 [GeForce GTX 1660 Ti] (rev a1) (prog-if 00 [VGA controller])
	Subsystem: Micro-Star International Co., Ltd. [MSI] TU116 [GeForce GTX 1660 Ti]
	Flags: bus master, fast devsel, latency 0, IRQ 72
	Memory at f5000000 (32-bit, non-prefetchable) [size=16M]
	Memory at e0000000 (64-bit, prefetchable) [size=256M]
	Memory at f0000000 (64-bit, prefetchable) [size=32M]
	I/O ports at e000 [size=128]
	Expansion ROM at f6000000 [disabled] [size=512K]
	Capabilities: <access denied>
	Kernel driver in use: nouveau
	Kernel modules: nvidiafb, nouveau

# Audioコントローラー
08:00.1 Audio device: NVIDIA Corporation TU116 High Definition Audio Controller (rev a1)
	Subsystem: Micro-Star International Co., Ltd. [MSI] TU116 High Definition Audio Controller
	Flags: bus master, fast devsel, latency 0, IRQ 70
	Memory at f6080000 (32-bit, non-prefetchable) [size=16K]
	Capabilities: <access denied>
	Kernel driver in use: snd_hda_intel
	Kernel modules: snd_hda_intel

# USB 3.1コントローラー ←これではないらしい
08:00.2 USB controller: NVIDIA Corporation TU116 USB 3.1 Host Controller (rev a1) (prog-if 30 [XHCI])
	Subsystem: Micro-Star International Co., Ltd. [MSI] Device 8d90
	Flags: fast devsel, IRQ 64
	Memory at f2000000 (64-bit, prefetchable) [size=256K]
	Memory at f2040000 (64-bit, prefetchable) [size=64K]
	Capabilities: <access denied>
	Kernel driver in use: xhci_hcd
	Kernel modules: xhci_pci

# シリアルバスコントローラー ←これらしい
08:00.3 Serial bus controller [0c80]: NVIDIA Corporation TU116 [GeForce GTX 1650 SUPER] (rev a1)
	Subsystem: Micro-Star International Co., Ltd. [MSI] TU116 [GeForce GTX 1650 SUPER]
	Flags: bus master, fast devsel, latency 0, IRQ 42
	Memory at f6084000 (32-bit, non-prefetchable) [size=4K]
	Capabilities: <access denied>
	Kernel driver in use: nvidia-gpu
	Kernel modules: i2c_nvidia_gpu

ucsiってなに?

CONFIG_UCSI: USB Type-C Connector System Software Interface driver

USB Type-C Connector System Software Interface (UCSI)
specification for an interface that allows the Operating System to control the USB Type-C ports on a system.
Things the need controlling include the USB Data Role (host or device), and when USB Power Delivery is supported, the Power Role (source or sink).
(USBType-Cポートを制御できるようにするインターフェイスの仕様。データ送受信やUSB給電がサポートされてる場合は給電も制御します。<意訳>)

i2c_nvidia_gpu ucsi_ccg らをブラックリストに入れる

touch /etc/modprobe.d/blacklist-i2c-nvidia-gpu.conf
cat 'blacklist i2c_nvidia_gpu' > /etc/modprobe.d/blacklist-i2c-nvidia-gpu.conf

touch /etc/modprobe.d/blacklist-ucsi_ccg.conf
cat 'blacklist ucsi_ccg' > /etc/modprobe.d/blacklist-ucsi_ccg.conf

update-initramfs -u

再起動後ログをチェック。

$ journalctl -ab -p err
-- Logs begin at Fri 2022-03-25 12:25:45 JST, end at Fri 2022-04-01 23:09:06 JST. --
 4月 01 23:08:48 user-comp gdm-password][1813]: gkr-pam: unable to locate daemon control file

ナイス。

後半のエラー

nvidia-powerd.serviceが起動していません。

$ systemctl status
● user-comp
    State: degraded
     Jobs: 0 queued
   Failed: 1 units
    Since: Sat 2022-04-02 09:23:46 JST; 7h ago
   CGroup: /
           ├─368 bpfilter_umh
           ├─user.slice 
           │ ├─user-125.slice 
           │ │ ├─session-c2.scope 
           │ │ │ ├─10923 gdm-session-worker [pam/gdm-launch-environment]
$ systemctl --failed
  UNIT                  LOAD   ACTIVE SUB    DESCRIPTION          
● nvidia-powerd.service loaded failed failed nvidia-powerd service

LOAD   = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB    = The low-level unit activation state, values depend on unit type.

1 loaded units listed.

nvidia-powerd.serviceの中身を確認します。
WantedBy=multi-user.targetであることがわかります。
これってもしかしてgraphical.targetって書いてないといけないのでしょうか??
う〜ん、よくわからないしいじりたくないなぁ…。

$ systemctl show nvidia-powerd
Type=dbus
Restart=no
NotifyAccess=none
RestartUSec=100ms
...

ここにあるようにRestart=noには意図的な意味があるのかもしれません。[5]

$ /lib/systemd/system  cat ./nvidia-powerd.service 
[Unit]
Description=nvidia-powerd service

[Service]
Type=dbus
BusName=nvidia.powerd.server
ExecStart=/usr/bin/nvidia-powerd

[Install]
WantedBy=multi-user.target
$ /lib/systemd/system  cat ./multi-user.target
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the user of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.

[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes

なぜ起動しないかは以下を確認するとわかります。

$ cat /proc/driver/nvidia/gpus/0000\:08\:00.0/power 
Runtime D3 status:          Not supported
Video Memory:               Active

GPU Hardware Support:
 Video Memory Self Refresh: Supported
 Video Memory Off:          Supported

Power Limits:
 Default:                   N/A milliwatts
 GPU Boost:                 N/A milliwatts

仕様

In addition to that, if the PCI PM Spec is implemented by the device, it must support D3hot as well as D0.
https://docs.kernel.org/power/pci.html

少なくとも電源管理したいのならばデバイス側で実装してね、ということかと思います。
Runtime D3 status: Not supported
先に書きましたが、NVIDIA的には意図を理解した上で実行してね、ということなんでしょう。

補足

PCI電源管理仕様
デバイスならD0-D3 (値が大きいほど電力使用量は小さい)(バスならB0-B3)

ACPI
S0 通常の稼働状態
S1 省電力モード (プロセッサー、チップセットは共に電源オン)
S2 省電力モード (プロセッサーは電源オフ、チップセットは電源オン)
S3 スタンバイ状態
S4 休止状態
S5 ソフトウェアによる電源オフ

systemctl disable nvidia-powerd.service

サービスをdisableします。

$ /lib/systemd/system  sudo systemctl disable nvidia-powerd.service 
[sudo] user のパスワード: 
Removed /etc/systemd/system/multi-user.target.wants/nvidia-powerd.service.

$ /lib/systemd/system  sudo reboot

再起動後ログ等のチェック。

$ journalctl -b -a -p err
-- Logs begin at Fri 2022-03-25 12:25:45 JST, end at Sat 2022-04-02 17:19:01 JST. --
 402 17:17:52 user-comp kernel: 
 402 17:18:06 user-comp gdm-password][1849]: gkr-pam: unable to locate daemon control file
● user-comp
    State: running
     Jobs: 0 queued
   Failed: 0 units
    Since: Sat 2022-04-02 17:17:51 JST; 1min 52s ago
   CGroup: /
           ├─368 bpfilter_umh
           ├─user.slice 
           │ ├─user-125.slice 
$ systemctl --failed
  UNIT LOAD ACTIVE SUB DESCRIPTION
0 loaded units listed.

ナイス。

pm-utils

最初に書いた回避策です。

sudo apt install -y pm-utils
sudo pm-suspend

特に不具合なく動作しています。

あとがき

NVIDIAドライバーやライブラリについてのクレーム?ですが、510は駄目だけど470ならトラブルが少ない、いや470でも全然駄目だとか、MATEだと解決法があるよ、とかかなりの量があります。起動しないパターンだと阿鼻叫喚になるのもわかります。

さてNVIDIAのドライバーダウンロードサイトに以下のように載っていました。

Updated nvidia-bug-report.sh to search the systemd journal for nvidia-powerd logs.

パッケージマネージャからのインストールですが確かに/usr/bin/nvidia-bug-report.shは存在します。掘り下げてみたい方はこれを使うと良いことが起こるかもしれません。

同じサイトのAdditional informationには

One of the last installation steps will offer to update your X configuration file. Either accept that offer, edit your X configuration file manually so that the NVIDIA X driver will be used, or run nvidia-xconfig (Xコンフィグファイルを手作業でいじくるか、nvidia-xconfigを実行するか選べ。)

と記載があります。確かに実行ファイルが存在しました。

$ which nvidia-xconfig 
/usr/bin/nvidia-xconfig

このファイルってディストリビューションのパッケージマネージャでドライバーをインストールした人は関係ないかと思っているのですが、理解が違っているかもしれません。

こういうのは専門の人をたてて任せてしまうのが一番ですけど、そうできない環境だから辛いなぁ。

追記

2022年4月3日

 journalctl -ab -p err
-- Logs begin at Fri 2022-03-25 12:25:45 JST, end at Sun 2022-04-03 17:51:21 JST. --
 403 15:42:33 user kernel: [drm:nv_drm_master_set [nvidia_drm]] *ERROR* [nvidia-drm] [GPU ID 0x00000800] Failed to grab modeset ownership

上記エラーが発生しました。これについてNVIDIAから「無視して大丈夫」と書かれています。

HI All,
The warning message is expected. When a client (such as the modesetting driver) attempts to open our DRM device node while modesetting permission is already acquired by something else (like the NVIDIA X driver), it has to fail, but the kernel won’t let us return a failure after v5.9-rc1, so we print this message. It won’t impact functionality of the NVIDIA X driver that already has modesetting permission. Safe to ignore as long as long as you didn’t need the other client to actually get modesetting permission. If you want to suppress the error, you would need to find which client is attempting to open the NVIDIA DRM device node and prevent it from doing so.
https://forums.developer.nvidia.com/t/ubuntu-21-10-failed-to-grab-modeset-ownership-with-495-44/193867/37

脚注
  1. Device Power Management BasicsCPUだけ考えてもこれを自分が理解するのは難しい ↩︎

  2. ノートPCに限った話かもしれません ↩︎

  3. Fedraの記事ですがこんなことも書いてあります。
    Driver 510+ requires nvidia-powerd for dynamic GPU frequency boost and other advanced performance-improving features.
    It's going to make a big improvement in game framerates.
    Don't uninstall it. Don't disable the service either. You need nvidia-powerd (xorg-x11-drv-nvidia-power).
    If it causes any issues with suspend on your system (as I've heard from 1 or 2 people), then simply disable suspend on your system in GNOME Settings: Power: Automatic Suspend: Off.
    Then wait for a fixed driver which doesn't have suspend-issues.
    https://www.reddit.com/r/Fedora/comments/sy52ov/i_think_nvidia_driver_isnt_installed_properly_on/hxxe6w0/
    I also don't agree with your final advice whatsoever, because disabling the service could be harmful (read on below).
    https://www.reddit.com/r/Fedora/comments/sy52ov/i_think_nvidia_driver_isnt_installed_properly_on/hxzs1n5/ ↩︎

  4. いつの間にかSysV initからsystemdになった…という感覚の人間なのでこの機会にsystemdについて色々と読んでみました。長いなぁ…。 ↩︎

  5. Maybe there isn't a better way to do it though. Systemd has a lot of startup features, but I don't think "probe the physical hardware features and only start the service if found" is one of them. I've written a few service files and don't think I've ever seen such a feature.
    Here's how NVIDIA decided to achieve the "only start on hardware that needs it" ↩︎

Discussion