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