Ubuntu でコマンドラインで nvidia-settings でクロックオフセットやファン速度を変えるメモ

## 背景

GPU マイニングなり GPU レイトレなりで複数 PC を headless で管理している.
nvidia-smi で powerlimit に加えて, nvidia-settings でクロックのオフセットやファン速度を変えたい
(GeForce 系はクロックオフセットとファン速度を変更するには `nvidia-settings` を利用する必要がある. nvidia-smi では変更できない)

しかし一度 graphical login してからでないと, `nvidia-settings` はユーザー権限で動かない.

* XAUTHORITY 指定で sudo で設定
* autologin しておく

の２つの方法がありました.

## 方法1

Ubuntu における nVidia GPU に対する各種設定方法
https://geraniums.hatenablog.com/entry/2018/01/23/165704

グラフィカルログインしなくとも `DISPLAY` `XAUTHORITY` 指定して sudo でいけました.


## 手順

クロックオフセットやファンを制御するには, xorg の設定と coolbits などの設定が必要になります.

NVIDIA GPU の X11 headless setup + X11VNC/RDP 接続のメモ
https://qiita.com/syoyo/items/a14fa891b80bb82a4485

あたりを参考にしてセットアップしておきます.

あとは最初のリンクにありますように,

```bash
sudo DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 \
nvidia-settings -a GPUPowerMizerMode=1
sudo DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 \
nvidia-settings -a GPUFanControlState=1
sudo DISPLAY=:0 XAUTHORITY=/var/run/lightdm/root/:0 \
nvidia-settings -a GPUTargetFanSpeed=100
```

のような感じでいけます!

一応 `nvidia-settings -c 0:` で `-c` で DISPLAY 設定もできますが, ssh ログインしている場合は `-c` 指定はうまくいかないようでした. 

## clock offset の level

ClockOffset は

```
nvidia-settings -a "GPUGraphicsClockOffset[level]=delta1"
```

のようにレベルを指定しますが, 通常は 2, 3 あたりになります
(`nvidia-smi` で出てくる P state とは別っぽい?)

GUI で用意されている全レベルに設定という機能は無いようなので, 

```
DISPLAY=:0 nvidia-settings -a "[gpu:0]/GPUGraphicsClockOffset[4]=-450"
DISPLAY=:0 nvidia-settings -a "[gpu:0]/GPUMemoryTransferRateOffset[4]=1200"
DISPLAY=:0 nvidia-settings -a "[gpu:0]/GPUGraphicsClockOffset[3]=-450"
DISPLAY=:0 nvidia-settings -a "[gpu:0]/GPUMemoryTransferRateOffset[3]=1200"
DISPLAY=:0 nvidia-settings -a "[gpu:0]/GPUGraphicsClockOffset[2]=-450"
DISPLAY=:0 nvidia-settings -a "[gpu:0]/GPUMemoryTransferRateOffset[2]=1200"
```

のように並べて記載することになるでしょう.

(Pascal 世代から?)メモリのクロックは 2 倍の値を設定します. たとえば 1200 だと `+600` されることになります.


sudo 権限は sudoers に記述してパスワードなし実行がよいでしょうか.


```
syoyo ALL=NOPASSWD: /usr/bin/nvidia-smi
syoyo ALL=NOPASSWD: /usr/bin/nvidia-settings
```

GPU が変更にならないのであれば,

https://forums.developer.nvidia.com/t/nvidia-settings-graphics-clock-report/45244/6

にあるように xinit.d に記載でもいいかもしれません.

## 方法2

autologin しておけば, ユーザー権限で `nvidia-settings` いけました.
こちらのほうが楽ですね.

クラスタ管理用になにかユーザーを作っておくといいかもしれません.

この場合, `DISPLAY` だけ設定でいけます.

```bash
DISPLAY=:0 nvidia-settings -a GPUTargetFanSpeed=100
```

autologin 設定は最近の Ubuntu(18.04 or later)であれば gdm, lightdm どちらでもできました.

GUI であれば Ubuntu の Settings panel からいけます. 


https://vitux.com/how-to-enable-disable-automatic-login-in-ubuntu-18-04-lts/

How do I enable auto-login in LightDM?
https://askubuntu.com/questions/51086/how-do-i-enable-auto-login-in-lightdm

### ログイン時に実行する

(自動)ログイン時に, ユーザー権限でスクリプト実行(Gnome desktop)は,

`~/.config/autostart/` に `.destop` でスクリプトを置けば実行してくれます.

たとえば `~/.config/autostart/gputune.desktop` を作り,

```
[Desktop Entry]
Exec=/bin/bash /home/gpuuser/gputune.sh
Type=Application
```

として, `gputune.sh` に nvidia-settings などのスクリプト書いておくとよいでしょう.

## GPU 温度に応じてファン速度を変える

nvidia-settingsでGPU温度に応じてFan速度を変える
https://qiita.com/tttamaki/items/96f2f0ed49249982ff1b

ありがとうございます. ユーザ権限での cron でいけますね.

注意点として, 複数 GPU および GPU につき fan が複数(e.g. 3080)ある場合, fan の番号は sequential に指定しないといけませんでした.

https://gist.github.com/squadbox/e5b5f7bcd86259d627ed#gistcomment-3083750

たとえば 3080 が二個合った場合, `fan:0`, `fan:1` は最初の GPU, `fan:2`, `fan:3` が二番目の GPU に対応します.
(正確には Xorg での Display ごとに番号割当しているっぽい?)

### ampere 世代のファン速度

3080 or higher ですと, どうも 85% あたりを超えると GPU 温度にかかわらず, 負荷がかかっていると判断されるようでクロックが下がり性能が落ちます.

だいたい 70 ~ 80 % の間でうまく冷却できるようにするとよいでしょう.
(fan speed に応じてのクロックの設定のテーブルが編集できるっぽいようであるが...)


### TODO

* [ ] GPU fan の数を nvidia-settings で取得する方法を探す