NVIDIAドライバーでUbuntuのサスペンドが効かなくなったときの対処法

PC
この記事は約10分で読めます。

CPU内蔵GPUからNVIDIA製グラフィックボードに映像出力を変えたらサスペンドが効かなくなり、いろいろ調査した結果対処が分かったので備忘録として残します。OSはUbuntu 20.04です。

NVIDIAドライバーを導入する

UbuntuでNVIDIA製GPUを使う場合、ドライバーはオープンソースのnouveauだとエクスペリエンスが劣るのでNVIDIAドライバーを入れることを選択する人が多いと思います。UbuntuはそのためにNVIDIAドライバーを簡単に導入するための方法を提供しています。

ソフトウェアとアップデートから追加のドライバータブを選択すれば以下のようにNVIDIA製ドライバーを導入することが出来ます。

nouveauよりも動画再生、3D表示、Webの表示などあらゆる面でパフォーマンスが上がって快適に使用できます。

CUDAが使いたい

UbuntuでNVIDIA製ドライバーを導入するもう一つの理由は、CUDAでGPGPUや機械学習を動かしたいがあると思います。むしろ最近はこのためにUbuntu (Linux)を使うことが多くなっていると思います。ゲームをするためだったらWindowsを使うと思いますので。

NVIDIAドライバーはUbuntu管理とNVIDIA管理の2つがある

CUDAを導入する場合、Ubuntuにも nvidia-cuda-toolkit が用意されていますが、バージョンが古い(10.1)ので、nvidiaのサイトからインストールをする方が大勢だと思います。現時点だとNVIDIAのサイトからインストールすれば最新の11.6をインストールできます。私もNVIDIAのaptソースを設定してcudaの11系をインストールしました。どうやらこの変更がUbuntuをサスペンドできないようにしてしまったようです。

NVIDIAのサイトからcudaをインストールするとnvidia-driverが更新されます。この更新されたnvidia-driverはNVIDIA管理のもので、ソフトウェアアップデートの上記画面からインストールできるUbuntu管理のものと別物です。ややこしいことにパッケージ名が同じ名前です。

dpkg -l | grep nvidia-driver
ii  nvidia-driver-470                          470.86-0ubuntu0.20.04.2                     amd64        NVIDIA driver metapackage

上記コマンドを打って ubuntu0.20.04.2 みたいにバージョンがなっているとUbuntu管理で ubuntu1 みたいなバージョンになっているとNVIDIA管理です。NVIDIA管理のドライバーだとサスペンドが出来ません。

対処

  • NVIDIA管理のドライバーを消して、Ubuntu管理のドライバーに入れ替えるが1つ。
  • もう1つはNVIDIA管理のドライバーを使用しつつ足りないファイルを追加する。

1つ目の方法は、依存関係によりせっかくインストールしたcudaを削除しなければいけないデメリットがあります。

2つ目の方法はスマートではないですが、最新のCUDAも使えるメリットがあります。

NVIDIA管理のドライバーにサスペンドするためのファイルを追加する。

以下のサイトを参考にしましたが、私の環境に合わないところもあったので省略しているステップがあります。https://gist.github.com/bmcbm/375f14eaa17f88756b4bdbbebbcfd029

足らなかったファイルは以下。

  • /lib/systemd/system/nvidia-hibernate.service
  • /lib/systemd/system/nvidia-resume.service
  • /lib/systemd/system/nvidia-suspend.service
  • /lib/systemd/system-sleep/nvidia
  • /usr/bin/nvidia-sleep.sh

それぞれのファイルの内容はUbuntu管理のNVIDIAドライバーから頂戴してきます。

nvidia-driver-495 495.46-0ubuntu0.20.04.1 の場合。

/lib/systemd/system/nvidia-hibernate.service
[Unit]
Description=NVIDIA system hibernate actions
Before=systemd-hibernate.service

[Service]
Type=oneshot
ExecStart=/usr/bin/logger -t hibernate -s "nvidia-hibernate.service"
ExecStart=/usr/bin/nvidia-sleep.sh "hibernate"

[Install]
RequiredBy=systemd-hibernate.service
/lib/systemd/system/nvidia-resume.service
[Unit]
Description=NVIDIA system resume actions
After=systemd-suspend.service
After=systemd-hibernate.service

[Service]
Type=oneshot
ExecStart=/usr/bin/logger -t suspend -s "nvidia-resume.service"
ExecStart=/usr/bin/nvidia-sleep.sh "resume"

[Install]
RequiredBy=systemd-suspend.service
RequiredBy=systemd-hibernate.service
/lib/systemd/system/nvidia-suspend.service
[Unit]
Description=NVIDIA system suspend actions
Before=systemd-suspend.service

[Service]
Type=oneshot
ExecStart=/usr/bin/logger -t suspend -s "nvidia-suspend.service"
ExecStart=/usr/bin/nvidia-sleep.sh "suspend"

[Install]
RequiredBy=systemd-suspend.service
/lib/systemd/system-sleep/nvidia
#!/bin/sh

case "$1" in
    post)
        /usr/bin/nvidia-sleep.sh "resume"
        ;;
esac
/usr/bin/nvidia-sleep.sh
#!/bin/bash

if [ ! -f /proc/driver/nvidia/suspend ]; then
    exit 0
fi

RUN_DIR="/var/run/nvidia-sleep"
XORG_VT_FILE="${RUN_DIR}"/Xorg.vt_number

PATH="/bin:/usr/bin"

case "$1" in
    suspend|hibernate)
        mkdir -p "${RUN_DIR}"
        fgconsole > "${XORG_VT_FILE}"
        chvt 63
        if [[ $? -ne 0 ]]; then
            exit $?
        fi
        echo "$1" > /proc/driver/nvidia/suspend
        exit $?
        ;;
    resume)
        echo "$1" > /proc/driver/nvidia/suspend 
        #
        # Check if Xorg was determined to be running at the time
        # of suspend, and whether its VT was recorded.  If so,
        # attempt to switch back to this VT.
        #
        if [[ -f "${XORG_VT_FILE}" ]]; then
            XORG_PID=$(cat "${XORG_VT_FILE}")
            rm "${XORG_VT_FILE}"
            chvt "${XORG_PID}"
        fi
        exit 0
        ;;
    *)
        exit 1
esac

上記のファイルを配置します。

次に以下のコマンドを打ってsystemdの状態をチェックします。

$ ls -l /etc/systemd/system/nvidia-*
lrwxrwxrwx 1 root root 9 nov.  25 10:55 nvidia-hibernate.service -> /dev/null
lrwxrwxrwx 1 root root 9 nov.  25 10:55 nvidia-resume.service -> /dev/null
lrwxrwxrwx 1 root root 9 nov.  25 10:55 nvidia-suspend.service -> /dev/null

上記のように /dev/null へシンボリックリンクが貼られている場合は削除します。

$ sudo rm -f /etc/systemd/system/nvidia-suspend.service
$ sudo rm -f /etc/systemd/system/nvidia-hibernate.service
$ sudo rm -f /etc/systemd/system/nvidia-resume.service

パーミッションの変更とsystemdを有効にします。

$ sudo chmod 755 /lib/systemd/system-sleep/nvidia
$ sudo chmod 755 /usr/bin/nvidia-sleep.sh

$ sudo systemctl enable nvidia-suspend.service
$ sudo systemctl enable nvidia-hibernate.service
$ sudo systemctl enable nvidia-resume.service

これで完了です。

追記 (2022-02-17)

Ubuntu管理のNVIDIAドライバーでも nvidia-driver-510 からはsystemd関連の上記の5ファイルは省かれるようになったみたいです。nvidia-driver-495まではあったのですが。サーバーではなくデスクトップ用途ではサスペンドは要ると思うんですがね。。

$ dpkg -l | grep nvidia-driver
ii  nvidia-driver-495                          510.47.03-0ubuntu0.20.04.1                 amd64        Transitional package for nvidia-driver-510
ii  nvidia-driver-510                          510.47.03-0ubuntu0.20.04.1                 amd64        NVIDIA driver metapackage

参考URL

  • https://gist.github.com/bmcbm/375f14eaa17f88756b4bdbbebbcfd029
  • https://forums.developer.nvidia.com/t/ubuntu-20-04-installing-cuda-changes-nvidia-drivers-and-breaks-suspend/196220

スポンサーリンク
PC
ヤマカワをフォローする
タイトルとURLをコピーしました