仮想化通信

日本仮想化技術株式会社の公式エンジニアブログ

GPUパススルーを利用したKVM仮想マシンが不安定なときのチェックポイント

前回は、KVM環境でGPUパススルーをする方法について構築手順を紹介しました。

しかしながら、環境によってはいくつかの要因が重なり手順どおりにはいかないことがあります。

ここでは、KVM仮想マシンでGPUパススルーが動作しない または 不安定なときの確認ポイントを紹介いたします。

BIOSのバージョン確認

BIOSの不具合等により最新のGPUカードが正しく認識しないことがあります。メーカーのリリースノート等を確認し、該当しそうな不具合が見つかったら最新版のBIOSへアップデートします。

BIOSの設定確認

複数のGPUを利用する場合、4GB以上のMemory mapped I/O addressがサポートされていないとホストシステム上でGPUカードが正しく認識されないことがあります。

BIOSの設定にabove 4G decodingという項目がある場合は設定を有効にします。

KVM仮想マシンのチップセット設定

仮想マシンのOSがLinuxでGPUパススルーを利用する場合はQ35が安定すると言われています。仮想マシンを作成するとき、特別な理由がない限りチップセットはQ35を選択することを推奨します。

(参考:https://wiki.lime-technology.com/UnRAID_Manual_6#Creating_Your_Own_Virtual_Machines

KVM仮想マシンのCPUモード設定

仮想マシンのCPUモードが適切なものに設定されていないと仮想マシン上でGPUが正しくに動作しない場合があります。ライブマイグレーション機能を利用しない場合は "host-model" にすることを推奨します。

$ virsh edit [仮想マシン名]

### CPU Mode 設定例 ###
 <cpu mode='host-model'>
   <model fallback='allow'/>
 </cpu>

KVMホスト側の設定

PCI Expressでのデータ破損を防止するACS(Access Control Service)が有効になっていると、KVM環境では逆に不具合の要因となる場合があります。動作が不安定なときは /etc/libvirt/qemu.conf (Ubuntu 16.04の場合)を開き、以下の設定を加えてACSを無効化してみます。

relaxed_acs_check = 1

認識されているPCI Expressの世代の確認

GPUが想定していたほど性能を出していないときは、ホスト上でPCI Expressの世代が低く認識されていたり、何らかの理由でPCI Expressの転送速度が落ちている場合があります。まずは PCI Express の世代が正しく認識されているか確認します。

$ nvidia-smi -q

--- コマンド結果から抜粋 --- 
        GPU Link Info
            PCIe Generation
                Max                 : 3
                Current             : 3
            Link Width
                Max                 : 16x
                Current             : 16x
        Bridge Chip
            Type                    : N/A
            Firmware                : N/A
        Replays since reset         : 0
        Tx Throughput               : 0 KB/s
        Rx Throughput               : 0 KB/s

ここで仮想マシン上の環境では結果がGen1となっていた場合でも、物理マシン上では本来の世代で認識されていて、転送スピードを測定するとGen1の規定値以上になることがあります。次項を参考にバススピードも測ってみます。

GPUバススピードの確認方法

バススピードの実測値を測定して適切な値となるか確認します。 前回も軽く触れましたが、バススピード測定ツールはCUDAに添付されているサンプルプログラムに含まれているので、それを実行してみます。

### サンプルプログラムをまだコンパイルしていない場合は make を実行
$ cd ~/NVIDIA_CUDA-8.0_Sample
$ make

### バススピードの測定
$ cd ~/NVIDIA_CUDA-8.0_Samples/bin/x86_64/linux/release/
$ ./bandwidthTest

<出力例>
[CUDA Bandwidth Test] - Starting...
Running on...

 Device 0: Tesla P40
 Quick Mode

 Host to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         11537.8

 Device to Host Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         12961.7

 Device to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)    Bandwidth(MB/s)
   33554432         240433.7

Result = PASS

NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.

実測値が1世代前の制限値より低い場合は、ハードウェアやソフトウェアに何らかの問題が起きている可能性があります(ハードウェアの相性問題であることもあります)。

各世代の制限値(一方向)

  • Gen1: 4.0 GB/sec
  • Gen2: 8.0 GB/sec
  • Gen3: 16.0 GB/sec
  • Gen4: 32.0 GB/sec

(参考:https://ja.wikipedia.org/wiki/PCI_Express

ベンチマーク

バススピードに問題がない場合は、GPUへ直接負荷をかけてみます。ベンチマークを長時間稼働させたとき、処理数が一定量で増えない場合はなんらかの問題が発生していると考えられます。ベンチマークツールの一つとして、GPU Burnを紹介します。

なお、実行する際にはGPUの温度の変化に注意して下さい。

<実行例>

$ ./gpu_burn 60

GPU 0: Tesla P40 (UUID: GPU-1f4d9f28-51e7-065d-2db9-af4397809c49)
Initialized device 0 with 22912 MB of memory (22552 MB available, using 20297 MB of it), using FLOATS
13.3%  proc'd: 3798 (9453 Gflop/s)   errors: 0   temps: 51 C
    Summary at:   Tue Dec 19 11:47:57 JST 2017

25.0%  proc'd: 7596 (9443 Gflop/s)   errors: 0   temps: 54 C
    Summary at:   Tue Dec 19 11:48:04 JST 2017

40.0%  proc'd: 12660 (9438 Gflop/s)   errors: 0   temps: 58 C
    Summary at:   Tue Dec 19 11:48:13 JST 2017

51.7%  proc'd: 16458 (9444 Gflop/s)   errors: 0   temps: 60 C
    Summary at:   Tue Dec 19 11:48:20 JST 2017

63.3%  proc'd: 20256 (9451 Gflop/s)   errors: 0   temps: 60 C
    Summary at:   Tue Dec 19 11:48:27 JST 2017

75.0%  proc'd: 24054 (9441 Gflop/s)   errors: 0   temps: 61 C
    Summary at:   Tue Dec 19 11:48:34 JST 2017

90.0%  proc'd: 29118 (9446 Gflop/s)   errors: 0   temps: 63 C
    Summary at:   Tue Dec 19 11:48:43 JST 2017

100.0%  proc'd: 32916 (9440 Gflop/s)   errors: 0   temps: 64 C
Killing processes.. done

Tested 1 GPUs:
    GPU 0: OK

Kernelログの調査

NVIDIAドライバでなんらかしらの問題が発生したとき、syslogへXidメッセージが出力されることがあります。XidメッセージにはIDが振られており、そのIDを元に公式ドキュメントを調べることでメッセージの詳細を得ることができます。

<出力例>
NVRM: Xid (PCI:0000:00:09): 32, Channel ID 0000000e intr 00008000

上記の場合、Xidは32になります。

モジュールパラメーターの設定・確認

環境によってはNVIDIAドライバのモジュールパラメータを指定することで改善される場合があります。パラメーターの項目はNVIDIAドライバのヘッダーファイル内にドキュメントがあります。

現在のパラメータの設定は以下のコマンドで確認することができます

$ cat /proc/driver/nvidia/params

パラメータを任意の値に設定するにはUbuntuの場合、以下の手順で設定します。

1. パラメーターの指定

nvidiaモジュールの設定ファイルを新たに作成します。

  • ここでは、パラメータ NVreg_CheckPCIConfigSpace=0 と NVreg_EnableMSI=1 を設定しています。
  • XXXにはNVIDIAドライバーのバージョンが入ります。
$ vi /etc/modprobe.d/nvidia-params.conf  # ←ファイルは新規に作成します

--- ファイル内容 ---
options nvidia_XXX NVreg_CheckPCIConfigSpace=0 NVreg_EnableMSI=1
--- ここまで ---

2. Initramfsの更新

$ update-initramfs -u

3. VMの再起動

$ sudo shutdown -r now