NVIDIA GPU の X11 headless setup + X11VNC/RDP 接続のメモ

## 背景

* OpenGL や Vulkan アプリをリモート(ディスプレイ接続の無いサーバ)で動かしたい
* `nvidia-settings` で GPU clock offset とかしたい
  * `nvidia-settings` を動かすには X11 が必要(`nvidia-settings` 自体は nv-control? という機能を呼んでおり GPU でコード公開されているので, いろいろ頑張れば直接 `/sys` あたりで制御レジスタ設定というのもできるかもしれない) 
* nvidia proprietary driver 440 以降(確認したのは 455)とする


## とりあえずのまとめ

* x11vnc を使う
  * **lightdm を使う**(gdm3 は x11vnc に未対応)
  * [x] OpenGL, Vulkan が動く
  * [x] `nvidia-settings` 動く
  * [x] OptiX optixPathTracer sample 動く
  * [ ] 画面サイズ変更に制約がある(EDID を取得して xorg.conf を編集の必要がある)
* xrdp(RDP) を使う
  * gdm3, lightdm どちらでもよい
    * lightdm だと最初真っ黒なので起動スクリプト追加が必要 
  * [x] OpenGL が動く
  * [ ] Vulkan 動かない(画面に出す場合. present queue がうまく作れない)
  * [ ] `nvidia-settings` 動かない(Prime な環境として認識されてしまう)
  * [ ] OptiX optixPathTracer sample 動かない(denoiser 関連?)
  * 画面転送は VNC より少し効率な気がする
  * 画面のサイズ変更などやりやすい
  * コピペもやりやすい... はず.

今までの手元環境をそのまま headless 環境で再現したい場合は, x11vnc(+ lightdm) を使いましょう.
RDP は画面など細かく制御できてよいですが, Vulkan と `nvidia-settings` 動かないなど制約があります. 

## 情報

https://virtualgl.org/Documentation/HeadlessNV

https://unix.stackexchange.com/questions/367584/how-to-adjust-nvidia-gpu-fan-speed-on-a-headless-node

https://7me.nobiki.com/2019/11/11/xorg-virtual-screen-with-nvidia-gpu/

https://askubuntu.com/questions/1119542/headless-ubuntu-server-with-desktop-gui-with-working-gpu

## セットアップ

Ubuntu 16.04 or later とする(Desktop 版で gdm/lightdm をインストールしているとする)

### lightdm

gdm3 では x11vnc に対応していないため(なぜかは不明), lightdm に切り替えます.

`lightdm` を apt で入れます.

すでに lightdm, gdm3 両方インストールしている場合は,

`sudo dpkg-reconfigure gdm3`

or 

`sudo dpkg-reconfigure lightdm`


で, gdm3 or lightdm を選択できるようになるので, lightdm を選択します.

gdm3 を使っているかどうかは `ps aux | grep Xorg` して `-auth` が gdm のを使っているかどうかでわかります.

### xorg.conf

```
sudo nvidia-xconfig --allow-empty-initial-configuration --enable-all-gpus --cool-bits=28
```

でまずは `/etc/X11/xorg.conf` を作ります.
(ちなみに Ubuntu だとデフォルトでは `/etc/X11/xorg.conf` が存在せず, `/usr/share/X11/xorg.conf.d/***` のファイル(テンプレート設定?)を読み込む)

x11vnc や VirtualGL など動かしたいときは `--virtual=1920x1200 --busid {busid}` でダミーのディスプレイを作るとよさそうである.

`--use-display-device=None` も入れておくといいかも...?

RDP で接続する場合はダミーのディスプレイとして `DPF-0` を指定するとよさそう(デフォルトだと CRT display に設定されてしまう)

```
sudo nvidia-xconfig --allow-empty-initial-configuration --cool-bits=28 --use-display-device="DFP-0" --connected-monitor="DFP-0" --enable-all-gpus
```

再起動します.


## X11 アプリを動かす.


あとは以下のようにして DISPLAY と XAUTHORITY を設定して動かせばいけます!
(`~/.ssh/config` でリモートマシンに `ForwardX11 yes` を設定していたら外しておくとよいでしょう)

```
$ DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 nvidia-settings -q fans
```

greeter(Ubuntu では lightdm がデフォルト) を使っているばあい, Authority ファイルへのアクセスのため sudo 必要でした(`/var/run/lightdm/` が root 権限になっている)

### nvidia-settings のクロックオフセットメモ

`-q all` で出てくる PerfLevel に合わせて `GPUMemoryTransferRateOffset[N]` の N を設定しますが, query で出てくる current perf level の値に設定してもはなぜか設定できないときがあるようです. 以下のように N +- 1 の設定もしておくのがよさそうです(通常はだいたい performance level `3` )

```
sudo DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 nvidia-settings -a '[gpu:0]/GPUMemoryTransferRateOffset[2]=1200'
sudo DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 nvidia-settings -a '[gpu:0]/GPUMemoryTransferRateOffset[3]=1200'
sudo DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 nvidia-settings -a '[gpu:0]/GPUMemoryTransferRateOffset[4]=1200'
```

## x11vnc

リモートで GUI 画面を開きたいときもあります.
普通に vnc 接続ですと GPU が有効にならないため, GPU が使える x11vnc を使います(描画をすべてサーバで行い仮想の画面に描画して VNC 画面転送みたいな).

VNC 接続用パスワードを生成します.

```
sudo x11vnc -storepasswd /etc/x11vnc.passwd
```

生成されるファイルの permission は root のみ読み書きできる `600` になっています.

```
sudo x11vnc -auth guess -display :0 -rfbauth /etc/x11vnc.passwd -rfbport 5900  -forever -loop -noxdamage -repeat -shared
```

のようにして起動します.

`-ncache 10` も追加するといくらか画面描画が速くなるかもしれません.


```
...
08/11/2020 15:36:59 -auth guess: using 'XAUTHORITY=/var/run/lightdm/root/:0' for disp=':0'
...
08/11/2020 15:36:59 Default visual ID: 0x21
08/11/2020 15:37:00 Read initial data from X display into framebuffer.
08/11/2020 15:37:00 initialize_screen: fb_depth/fb_bpp/fb_Bpl 24/32/7680
08/11/2020 15:37:00 
08/11/2020 15:37:00 X display :0 is 32bpp depth=24 true color
08/11/2020 15:37:00 
08/11/2020 15:37:00 Listening for VNC connections on TCP port 5900
08/11/2020 15:37:00 Listening for VNC connections on TCP6 port 5900
```

`guess` で XAUTHORITY がうまく見つからなかったら手動で設定してみましょう.
 
あとは VNC クライアントで接続し, `glxinfo` あたり実行してリモートで nvidia ドライバ(GPU HW accelerated) で動いているのを確認する.

Ubuntu では Remmia という RDP/VNC クライアントが標準であるのでそれを使うとよい(tightvnc viewer とか使いづらいため)

ただ, VNC は仕組み上, 非圧縮としても全画面転送は遅い(ローカル接続時でも)ためもっさりしてつらいです.
(OpenGL で vsync off? だと, ティアリングはするが 1024x1024 くらいまでであれば 1GbE でもそこそこの速度で動きはする)

### 画面サイズの変更

デフォルトでは 1024x768 サイズです. Ubuntu 側の Display 設定で `1600x1200` まで上げることができますが, 手元 PC のディスプレイが 4K or larger だと画面サイズが小さいです.

また, x11vnc で `-geometry` でサイズ設定だとスケーリングがかかるだけです.

仮想のディスプレイをでっち上げる必要があります.

そのためには EDID というディスプレイのデータを xorg.conf で指定する必要があります.

headless ubuntu server with desktop gui with working gpu
https://askubuntu.com/questions/1119542/headless-ubuntu-server-with-desktop-gui-with-working-gpu

ただし, EDID 指定した状態で, 別の物理的なモニタにつないでしまうと画面が出ないので注意です(X11 が動かない).

EDID のデータはネットを漁れば手にいれることもできますし, 手元 PC で NVIDIA GPU 使っていれば `nvidia-settings` で `Acquire EDID` で手元 Display の設定を取得してそれを流用できます.

![Screenshot from 2020-11-10 17-55-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/de8b881c-ea8c-3808-6186-a1661f2adb4a.png)

参考までに Dell 27 inch 4K ディスプレイの EDID データ(base64)です. `base64 -d file` などとしてバイナリにしてください.

```
AP///////wAQrCehTDVSMCEdAQOAPSN47u6Vo1RMmSYPUFSlSwBxT4GAqcCpQNHA4QABAQEBCOgA
MPJwWoCwWIoAYV0hAAAaAAAA/wBLV0hGMjk4RTBSNUwKAAAA/ABERUxMIFUyNzE4UU0KAAAA/QAx
VgqJPAAKICAgICAgARECAz7xWGFgX15dEAUEAgcWARQfEhMnICEiAwYRFSMJHweDAQAAbQMMABAA
MEQgAGADAgFn2F3EAXiAAeIPA1ZeAKCgoClQMCA1AGFdIQAAGgR0ADDycFqAsFiKAGFdIQAAHr8W
AKCAOBNAMCA6AGFdIQAAGgAAAAAAAAAAAAAApA==
```

最終的に, NVIDIA headless 用の xorg.conf 生成は以下のようになります.

```
sudo nvidia-xconfig -a --allow-empty-initial-configuration --cool-bits=28 --enable-all-gpus \
--use-display-device="DFP-0" --connected-monitor="DFP-0" \
--custom-edid="DFP-0:/etc/X11/dellfpd-4k-edid.bin"
```

`DFP-0` は flat panel display であることを示すものです(指定しないと CRT display が割り当たる模様).
`DFP-0` に, ディスプレイの設定(EDID)を指定しています.

必要であれば `--virtual=1920x1200 --busid {busid}` も指定してみてください
(virtual はデフォルトでの画面サイズ(greeter での画面サイズ)を設定するっぽい))

これで x11vnc で画面サイズを変更できるようになります!

![Screenshot from 2020-11-10 18-08-51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36275/a8268c53-c978-4e36-9b9c-6781ea86905a.png)


リモート接続先の Display 設定で画面サイズを変えたら VNC 再接続必要です.



## RDP(Ubuntu version により対応違いあり)

おまけとして, 全画面転送が RDP だと早くなるかなとおもって RDP を試します.
RDP だと X11 headless 設定は不要かもしれません.


WindowsのRDPを使ってクラウド上のLinuxインスタンスに接続する
https://qiita.com/yamada-hakase/items/a8efe626f598c5eb6f8c

Ubuntu では, リモートマシンに `xrdp` を apt で入れます.


https://linuxize.com/post/how-to-install-xrdp-on-ubuntu-18-04/

上記記事を参考に xrdp ユーザを `ssl-cert` に登録しておくとよいかも?

```
sudo adduser xrdp ssl-cert 
```

ちなみに 20.04 では特に extra な設定をせずに xrdp 動くようです.

第621回　Ubuntu 20.04 LTSでxrdpを使用する
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0621

また, RDP では gdm3, lightdm のどちらでも OK ですが, lightdm だと最初真っ黒(なにもデスクトップマネージャが起動していない)なので, いろいろスクリプトセットアップが必要になります.

### Linux client から Linux server(RDP sever) へつなぐ

残念ながら client 18.04 -> server 16.04 はうまくいきませんでした(接続しようとすると Remmia client が落ちてしまう. Windows の RDP client ではうまくいくようだが...)

client 18.04 -> server 20.04.1 はうまく行きました.
ただし Desktop session(Dock?) は動いてくれませんでした. 上記 Gihyo のページにあるようにセッションの設定などすればいけます.

画面のレスポンスはやはり RDP がよいです.

<blockquote class="twitter-tweet"><p lang="en" dir="ltr">NVIDIA headless + RDP(xrdp) + Server-side OptiX ray tracing for the win!!!!! 🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🥰🥰🥰🥰🥰🥰🥰🥰😻😻😻😻😻😻😻 It makes GPU Ray tracing development on thin client possible! ☺️☺️☺️☺️😊😊😊😊😊😍😍😍😍 <a href="https://t.co/KYmlpLxN2P">pic.twitter.com/KYmlpLxN2P</a></p>&mdash; Syoyo Fujita 🌸 レイトラ 🐯 2 周年 🎉 (@syoyo) <a href="https://twitter.com/syoyo/status/1325396539263524864?ref_src=twsrc%5Etfw">November 8, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> 

GPU 積んだマシンをリモート(e.g. 別部屋)に置いての Graphics app 開発がやりやすくなります!

1 GbE では画面転送さすがにぬるぬるというわけにはいきませんでした.
10 GbE or InfiniBand でつなげばぬるぬるいけるかも?

### 問題点

RDP だと `nvidia-settings` がうごきません(Prime な環境と認識されてしまうが, 物理画面が無いのでいろいろ不都合が出て動かないっぽい).
Vulkan も画面出すのは動きません(これも原因は Window system 周りっぽい). compute は動きます.


## TODO

* [x] x11vnc の動作を確認する
* [x] RDP 接続を確認する
* [x] RDP 接続時に `nvidia-settings` が動かない原因を調べる
* [ ] VirtualGL の動作を確認する
* [ ] 10 GbE or InfiniBand(e.g. IB QDR 40 GbE)で画面転送が早くなるか確認する.