窓とかペンギンとか

インフラエンジニアの色々備忘録 少しでも情報を発信できたらなと思いブログを作ってみました。 このブログの内容は個人の見解であり、所属する組織の公式見解ではありません. 趣味のこと等も書きます(たぶん)

AMDの仮想グラフィックス「MxGPU」を使って、KVMのVMに仮想GPUリソースを割り当ててみた。

f:id:lezoid:20201005132217p:plain
※上記画像はAMD.com MxGPU公式より引用

GPUの仮想化周りで比較的手軽に触れる技術といえば、「NVIDIA GRID」や「Intel GVT-g」が存在しますが、
AMDでもSR-IOVに対応した「MxGPU」という技術があります。
今回はMxGPUに対応したGPUを入手したのでOpenStack + KVMな環境で仮想GPUリソースを使ってみました。

  1. AMD MxGPUとは
  2. Kernelドライバーのインストール
  3. nova.confの設定(VFを利用する)
  4. 動作確認
  5. 参考サイト

1. AMD MxGPUとは

AMDのGPUカード(RADEON , FirePro , Instinct)でSR-IOVの機能を利用して、
1つのGPUを複数の別個の物理デバイスとして認識されるようにできます。
AMD MxGPUを利用したプロダクトとしてはMicrosoft Azureで提供されている、Microsoft Azure® NVv4インスタンスなどがあります。

デバイスとしては非常に扱いやすく、NVIDIA GRIDのように高価なライセンスも不要で、ライセンスコストをかけずにGPUリソースをVMに割り当てることができます。
その上でリモート接続プロトコル(RDPやCitrixやVMware)でVMにアサインしたvGPUをハードウェアアクセラレータとして利用できるので、VDIのパフォーマンス向上を図ることができます。

このように…非常に素晴らしい技術なのですが、難点がいくつかあります。

  1. 対応カードが非常に限定的で日本国内では入手することが難しい。
  2. 現行のSR-IOV対応カード(InstinctMi25など)は現時点では仮想GPUとして利用する方法がない。

2020年現在対応カードのマトリックス表は以下の通りです。

GPU Linux KVM Citrix Xen VMware 備考
FirePro S7150 EoL 型落ちなのでスペックが低い ebayで安い
FirePro S7150 X2 EoL 型落ちなのでスペックが低い ebayで安い
RADEON Pro V340 × 入手すること自体が困難
Instinct MI25 × × × ドライバが対応していない。Azureが使っている

間違いあればご指摘頂けますと幸いです

今回はFirePro S7150 x2を検証カードとして利用しています。
f:id:lezoid:20201005140157p:plain

2.MxGPU用のカーネルモジュール GIMの導入

前項で説明したように、MxGPUとして利用するには対応したカーネルモジュールを導入することが必要です。
Linux KVMの場合はAMDからGIMモジュールが提供されており、そちらを利用することでMxGPUとして利用することができます。
github.com
全てのカードに対応していたら良いのですが…現状はAMD S7150 seriesしか対応していません。
試しにInstinct MI25でも試しましたが、動きませんでした。

GIM導入手順

FirePro S7150 x2がデバイスとして認識されているか確認する
[root@ ~]# lspci -nn |grep AMD
b1:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XT GL [FirePro S7150] [1002:6929]
b4:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XT GL [FirePro S7150] [1002:6929]
# gim導入前はSR-IOVのデバイスは見えてこないので、2つのみ表示される
デフォルトのAMD GPUカーネルモジュールをロードしないようにする。
## blacklist.confの編集
vim /etc/modprobe.d/blacklist.conf
## 内容確認 
[root@3 ~]# cat /etc/modprobe.d/nouveau_blacklist.conf
blacklist nouveau
options nouveau modeset=0
blacklist radeon
blacklist amdgpu
blacklist amdkfd
## 再起動
# reboot
gimのソースコードをダウンロードとインストール
git clone https://github.com/GPUOpen-LibrariesAndSDKs/MxGPU-Virtualization
cd MxGPU-Virtualization/drv/
make
make install
modprobe gim
# modprobe時フリーズするときはLinux Kernelをアップデートすると解決した。
# 当環境は以下の通り
[root@~]# uname -r
3.10.0-1127.19.1.el7.x86_64
[root@~]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
SR-IOVデバイスが認識されているか確認する。
#合計32個の仮想VFが認識されていることがわかる。
[root@ ~]# lspci -nn |grep AMD
b1:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XT GL [FirePro S7150] [1002:6929]
b1:02.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:02.1 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:02.2 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:02.3 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:02.4 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:02.5 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:02.6 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:02.7 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:03.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:03.1 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:03.2 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:03.3 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:03.4 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:03.5 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:03.6 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b1:03.7 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XT GL [FirePro S7150] [1002:6929]
b4:02.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:02.1 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:02.2 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:02.3 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:02.4 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:02.5 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:02.6 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:02.7 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:03.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:03.1 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:03.2 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:03.3 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:03.4 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:03.5 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:03.6 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
b4:03.7 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga XTV GL [FirePro S7150V] [1002:692f]
OpenStack nova-compute側でFirePro S7150を扱えるようにする。
#alias設定とpassthrough_whiteリストにS7150のカード情報を追加する。
#Vender_IdとProduct_IDはlspciの結果を入れる形となる。nameはnova flavorのプロパティに利用します。
[root@ ~]# vim /etc/nova/nova.conf
......下記を[pci]セクションに追加
# GPU Assign AMD FirePro S7150 x2 MxGPUs
alias={"vendor_id":"1002","product_id":"692f","device_type":"type-VF","name":"amdMxGPU_S7150V"}

# GPU Assign AMD FirePro S7150 x2 MxGPUs
passthrough_whitelist= [{ "name":"amdMxGPU_S7150V" , "vendor_id":"1002", "product_id":"692f" }]
........

# nova-api , scheduler , computeサービスを再起動

novaのflavor情報を追加

GPUリソースを付けたいflavorにextra_specにpci_passthorugh:aliasを下記を参考に追加する。
aliasの値が先ほどnovaに追加したnameになる。

[root@rdo ~(keystone_admin)]# nova flavor-show 6e701757-0bf2-4b47-ad91-6a091735a048
+----------------------------+------------------------------------------------+
| Property                   | Value                                          |
+----------------------------+------------------------------------------------+
| OS-FLV-DISABLED:disabled   | False                                          |
| OS-FLV-EXT-DATA:ephemeral  | 0                                              |
| description                | -                                              |
| disk                       | 100                                            |
| extra_specs                | {"pci_passthrough:alias": "amdMxGPU_S7150V:1"} |
| id                         | 6e701757-0bf2-4b47-ad91-6a091735a048           |
| name                       | 4Core_8GB_100GB_AMD-MxGPU-S7150                |
| os-flavor-access:is_public | True                                           |
| ram                        | 8192                                           |
| rxtx_factor                | 1.0                                            |
| swap                       |                                                |
| vcpus                      | 4                                              |
+----------------------------+------------------------------------------------+


該当flavorを使ってVMを作成すると、MxGPU付きのInstanceが作成される。

f:id:lezoid:20201005145411p:plain


3. 動作確認

OpenStack上からVMを作成すると、VFが接続されたVMが作成される。

参考1) Libvirtの定義を見てみる

libvirtのXMLは下記のようになっている。
もしOpenStackなどを用いず手動でlibvirt xmlを定義してVMを作成したい場合は下記をご参照ください。

<domain type='kvm' id='1'>
  <name>instance-000000cd</name>
  <uuid>645270f0-b840-4c4b-a4ac-955a6d64ea91</uuid>
  <metadata>
    <nova:instance xmlns:nova="http://openstack.org/xmlns/libvirt/nova/1.0">
      <nova:package version="17.0.13-1.el7"/>
      <nova:name>mxgpu-vm</nova:name>
      <nova:creationTime>2020-10-01 05:13:00</nova:creationTime>
      <nova:flavor name="4Core_8GB_100GB_AMD-MxGPU-S7150">
        <nova:memory>8192</nova:memory>
        <nova:disk>100</nova:disk>
        <nova:swap>0</nova:swap>
        <nova:ephemeral>0</nova:ephemeral>
        <nova:vcpus>4</nova:vcpus>
      </nova:flavor>
      <nova:owner>
        <nova:user uuid="4cfbced8a22742ee9c0cb85434c5cf1c">admin</nova:user>
        <nova:project uuid="16d8bbfc828b40109fa6d0b780ccca00">admin</nova:project>
      </nova:owner>
      <nova:root type="image" uuid="402ae9f3-e5ee-4ba3-807d-7a69d3fb91a5"/>
    </nova:instance>
  </metadata>
  <memory unit='KiB'>8388608</memory>
  <currentMemory unit='KiB'>8388608</currentMemory>
  <vcpu placement='static'>4</vcpu>
  <cputune>
    <shares>4096</shares>
  </cputune>
  <resource>
    <partition>/machine</partition>
  </resource>
  <sysinfo type='smbios'>
    <system>
      <entry name='manufacturer'>RDO</entry>
      <entry name='product'>OpenStack Compute</entry>
      <entry name='version'>17.0.13-1.el7</entry>
      <entry name='serial'>d2647a1e-9ee2-46b4-b9b5-fbd166664f4e</entry>
      <entry name='uuid'>645270f0-b840-4c4b-a4ac-955a6d64ea91</entry>
      <entry name='family'>Virtual Machine</entry>
    </system>
  </sysinfo>
  <os>
    <type arch='x86_64' machine='pc-q35-rhel7.6.0'>hvm</type>
    <boot dev='hd'/>
    <smbios mode='sysinfo'/>
  </os>
  <features>
    <acpi/>
    <apic/>
  </features>
  <cpu mode='host-passthrough' check='none'>
    <topology sockets='4' cores='1' threads='1'/>
  </cpu>
  <clock offset='utc'>
    <timer name='pit' tickpolicy='delay'/>
    <timer name='rtc' tickpolicy='catchup'/>
    <timer name='hpet' present='no'/>
  </clock>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/libexec/qemu-kvm</emulator>
    <disk type='file' device='disk'>
      <driver name='qemu' type='qcow2' cache='none'/>
      <source file='/var/lib/nova/instances/645270f0-b840-4c4b-a4ac-955a6d64ea91/disk'/>
      <backingStore type='file' index='1'>
        <format type='raw'/>
        <source file='/var/lib/nova/instances/_base/5739657f125a79d1b97e7d90950cefac80119a8b'/>
        <backingStore/>
      </backingStore>
      <target dev='vda' bus='virtio'/>
      <alias name='virtio-disk0'/>
      <address type='pci' domain='0x0000' bus='0x03' slot='0x00' function='0x0'/>
    </disk>
    <controller type='usb' index='0' model='qemu-xhci'>
      <alias name='usb'/>
      <address type='pci' domain='0x0000' bus='0x02' slot='0x00' function='0x0'/>
    </controller>
    <controller type='sata' index='0'>
      <alias name='ide'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
    </controller>
    <controller type='pci' index='0' model='pcie-root'>
      <alias name='pcie.0'/>
    </controller>
    <controller type='pci' index='1' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='1' port='0x10'/>
      <alias name='pci.1'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0' multifunction='on'/>
    </controller>
    <controller type='pci' index='2' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='2' port='0x11'/>
      <alias name='pci.2'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x1'/>
    </controller>
    <controller type='pci' index='3' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='3' port='0x12'/>
      <alias name='pci.3'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x2'/>
    </controller>
    <controller type='pci' index='4' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='4' port='0x13'/>
      <alias name='pci.4'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x3'/>
    </controller>
    <controller type='pci' index='5' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='5' port='0x14'/>
      <alias name='pci.5'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x4'/>
    </controller>
    <controller type='pci' index='6' model='pcie-root-port'>
      <model name='pcie-root-port'/>
      <target chassis='6' port='0x15'/>
      <alias name='pci.6'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x5'/>
    </controller>
    <interface type='bridge'>
      <mac address='fa:16:3e:14:3a:4f'/>
      <source bridge='qbr70911c88-80'/>
      <target dev='tap70911c88-80'/>
      <model type='virtio'/>
      <mtu size='1500'/>
      <alias name='net0'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
    </interface>
    <serial type='pty'>
      <source path='/dev/pts/1'/>
      <log file='/var/lib/nova/instances/645270f0-b840-4c4b-a4ac-955a6d64ea91/console.log' append='off'/>
      <target type='isa-serial' port='0'>
        <model name='isa-serial'/>
      </target>
      <alias name='serial0'/>
    </serial>
    <console type='pty' tty='/dev/pts/1'>
      <source path='/dev/pts/1'/>
      <log file='/var/lib/nova/instances/645270f0-b840-4c4b-a4ac-955a6d64ea91/console.log' append='off'/>
      <target type='serial' port='0'/>
      <alias name='serial0'/>
    </console>
    <input type='tablet' bus='usb'>
      <alias name='input0'/>
      <address type='usb' bus='0' port='1'/>
    </input>
    <input type='mouse' bus='ps2'>
      <alias name='input1'/>
    </input>
    <input type='keyboard' bus='ps2'>
      <alias name='input2'/>
    </input>
    <graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0' keymap='ja'>
      <listen type='address' address='0.0.0.0'/>
    </graphics>
    <video>
      <model type='cirrus' vram='16384' heads='1' primary='yes'/>
      <alias name='video0'/>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0'/>
    </video>
    <hostdev mode='subsystem' type='pci' managed='yes'>
      <driver name='vfio'/>
      <source>
        <address domain='0x0000' bus='0xb4' slot='0x03' function='0x7'/>
      </source>
      <alias name='hostdev0'/>
      <address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
    </hostdev>
    <memballoon model='virtio'>
      <stats period='10'/>
      <alias name='balloon0'/>
      <address type='pci' domain='0x0000' bus='0x05' slot='0x00' function='0x0'/>
    </memballoon>
  </devices>
  <seclabel type='dynamic' model='dac' relabel='yes'>
    <label>+107:+107</label>
    <imagelabel>+107:+107</imagelabel>
  </seclabel>
</domain>

vfioのセクションでnodedevの情報を書いてデバイスを渡してあげている感じですね。

[root@ ~]# virsh nodedev-dumpxml pci_0000_b4_03_7
<device>
  <name>pci_0000_b4_03_7</name>
  <path>/sys/devices/pci0000:ae/0000:ae:00.0/0000:af:00.0/0000:b0:10.0/0000:b4:03.7</path>
  <parent>pci_0000_b0_10_0</parent>
  <driver>
    <name>vfio-pci</name>
  </driver>
  <capability type='pci'>
    <domain>0</domain>
    <bus>180</bus>
    <slot>3</slot>
    <function>7</function>
    <product id='0x692f'>Tonga XTV GL [FirePro S7150V]</product>
    <vendor id='0x1002'>Advanced Micro Devices, Inc. [AMD/ATI]</vendor>
    <capability type='phys_function'>
      <address domain='0x0000' bus='0xb4' slot='0x00' function='0x0'/>
    </capability>
    <iommuGroup number='158'>
      <address domain='0x0000' bus='0xb4' slot='0x03' function='0x7'/>
    </iommuGroup>
    <numa node='1'/>
    <pci-express>
      <link validity='cap' port='16' speed='8' width='16'/>
      <link validity='sta' width='0'/>
    </pci-express>
  </capability>
</device>
    <iommuGroup number='151'>
      <address domain='0x0000' bus='0xb4' slot='0x03' function='0x0'/>
    </iommuGroup>
    <numa node='1'/>
    <pci-express>
      <link validity='cap' port='16' speed='8' width='16'/>
      <link validity='sta' width='0'/>
    </pci-express>
  </capability>
</device>

実際のVMからデバイス情報を見てみる

VMにドライバーを当てるとAMD MxGPUとして認識される。

f:id:lezoid:20201005145543p:plain

dxdiag(DirectX12が扱えるデバイスとして認識される)

f:id:lezoid:20201005145628p:plain

性能

リモート接続の支援用としては問題なく使えます。
DirectXやOpenCL APIを求めるアプリケーションも動くようになります
が、、、GPU自体は何世代も前の物なので性能はお察しです(´・ω・`)
ハイスペックをお求めの方はパススルーするか現行TeslaカードとGRIDライセンスをお買い求めください!
快適に動きます!


MxGPUは非常に素晴らしい技術なので新しいカードでサポートされることを願ってます…(‐人‐)