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

※上記画像はAMD.com MxGPU公式より引用
GPUの仮想化周りで比較的手軽に触れる技術といえば、「NVIDIA GRID」や「Intel GVT-g」が存在しますが、
AMDでもSR-IOVに対応した「MxGPU」という技術があります。
今回はMxGPUに対応したGPUを入手したのでOpenStack + KVMな環境で仮想GPUリソースを使ってみました。
- AMD MxGPUとは
- Kernelドライバーのインストール
- nova.confの設定(VFを利用する)
- 動作確認
- 参考サイト
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のパフォーマンス向上を図ることができます。
このように…非常に素晴らしい技術なのですが、難点がいくつかあります。
- 対応カードが非常に限定的で日本国内では入手することが難しい。
- 現行の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を検証カードとして利用しています。

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が作成される。

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として認識される。

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

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