けさらんぱの自由帳

とあるFF14プレイヤーがFF14のこととか関係ないことを書いていく予定のブログです。記載されている会社名・製品名・システム名などは、各社の商標、または登録商標です。

FF14をLinuxの仮想環境で動かす話・GVT-g編

以前、PCIパススルーを使ってGPUをゲストOS側に完全にパススルーしてFF14Linux上で動かす話をしました。今回は、完全なパススルーではなく、Mediated Passthroughというもので仮想GPUを作成し、それでFF14ベンチマークを動かしてみるお話です。GVT-gというのは、Intelによる仮想GPUの実装をそのように呼ぶみたいです。

ベンチマーク結果

まずは結果から。ベアメタル環境。 f:id:KesaranPa:20180502005244p:plain

GVT-gを使った仮想環境。CPUやメモリを半分しか割り当てていないこともあり、60%ぐらいに落ち込んでいます。 f:id:KesaranPa:20180502005255p:plain

前回の完全パススルーを使ったときは常用を目的にしていたし、実際に常用していますが、今回は元々非力なIntel NUC6i5SYH上で、しかも仮想環境で動かしているので、常用はかなり厳しいです。

テスト環境

ハードウェアは2世代ほど前のものですが、ソフトウェアはかなり最新で、LinuxカーネルQEmuもここ数週間にリリースされたものが必要です(この記事を書いている時点で、qemu-2.12.0-1はtestingにしかありません)。

手順

カーネルコマンドラインに以下のオプションを追加します。 i915.enable_gvt=1 はGVT-gを有効にします。 kvm.ignore_msrs=1 は特殊なレジスタへのアクセスを無視します(たまにアクセスするプログラムがあるらしい)。

i915.enable_gvt=1 kvm.ignore_msrs=1 intel_iommu=on

Linuxが起動したら、下記のようにして、Mediated Deviceを作成します。 echo の引数はUUIDです。 uuidgen とかで作成します。 i915-GVTg_V5_1 以外にもいくつかのディレクトリがありますが、vGPUに割り当たるメモリ量なんかが違うみたいです。ディレクトリ名の最後の数字は、作成できるvGPUの数を表しているようです。

% echo XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX | sudo tee /sys/class/mdev_bus/0000:00:02.0/mdev_supported_types/i915-GVTg_V5_1/create

次に、Libvirtの設定を書き換えます。自分が今回書き換えた箇所のうち、重要な部分は下記の部分です。QEmuのカスタム引数を使用しています。また海外サイトによると、OVMFでは問題があるようなので、SeaBIOSを使用しています。 x-igd-opregion=on は内蔵GPUのときに必要になるようです。

<domain type='kvm' xmlns:qemu='http://libvirt.org/schemas/domain/qemu/1.0'>
...
  <os>
    <type arch='x86_64' machine='q35'>hvm</type>
  </os>
...
  <devices>
...
    <graphics type='spice' keymap='en-us'>
      <listen type='none'/>
      <gl enable='yes' rendernode='/dev/dri/by-path/pci-0000:00:02.0-render'/>
    </graphics>
...
    <video>
      <model type='cirrus' vram='16384' heads='1' primary='yes'/>
      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x2'/>
    </video>
    <hostdev mode='subsystem' type='mdev' managed='no' model='vfio-pci'>
      <source>
        <address uuid='XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'/>
      </source>
      <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
    </hostdev>
...
  </devices>
  <qemu:commandline>
    <qemu:arg value='-set'/>
    <qemu:arg value='device.video0.driver=ne2k_pci'/>
    <qemu:arg value='-set'/>
    <qemu:arg value='device.hostdev0.x-igd-opregion=on'/>
  </qemu:commandline>
</domain>

他にゲームパッド等の必要なデバイスの設定も行い、virt-managerから起動します。

仮想環境のネットワーク接続をMACVLANとMACVTAPに切り替えてみた

今自分のメインPCでは、下記のOSが動いています。

OS 環境 用途
Arch Linux ホスト(物理マシン) デスクトップ
Debian GNU/Linux コンテナ(systemd-nspawn) サーバー
Windows 10 Pro 仮想マシンlibvirt ゲーム

今までDebian GNU/LinuxWindows 10 Proはソフトウェアブリッジ経由でネットワークに接続されていたのですが、これを性能が良いというMACVLAN/MACVTAP経由に切り替えてみることにしました。

systemd-nspawnでMACVLAN接続

設定ファイル中の下記のような記述を、

[Network]
Bridge=nm-bridge

次のように書き換えます。

[Network]
MACVLAN=eth0

libvirtでMACVTAP接続

設定ファイル中の下記のような記述を、

<interface type='bridge'>
  <mac address='xx:xx:xx:xx:xx:xx'/>
  <source bridge='br0'/>
  ...
</interface>

次のように書き換えます。

<interface type='direct'>
  <mac address='xx:xx:xx:xx:xx:xx'/>
  <source dev='eth0' mode='bridge'/>
  ...
</interface>

ホストと仮想環境での通信の設定

MACVLAN/MACVTAPで仮想環境をネットワークに接続する場合、そのままではホストと仮想環境の間の通信ができません。ただし、MACVLAN/MACVTAP同士の通信はできます。例えば今回の場合では、Arch LinuxDebian GNU/Linuxの間、Arch LinuxWindows 10 Proの間の通信ができませんが、Debian GNU/LinuxWindows 10 Proの間の通信は可能です。なので、ホストのArch LinuxもMACVLAN経由でネットワークで接続するようにしてしまえば、ホストと仮想環境の間で通信ができるようになります。

これをsystemd-networkdで実現する場合、下記のようにします。

#
# macvlan.netdev
#
[NetDev]
Name=macvlan0
Kind=macvlan

[MACVLAN]
Mode=bridge
#
# macvlan.network
#
[Match]
Name=macvlan0

[Network]
Address=192.168.x.y/24
...
#
# eth0.network
#
[Match]
MACAddress=xx:xx:xx:xx:xx:xx

[Network]
MACVLAN=macvlan0

画像の乗算、スクリーン、オーバーレイ

SSを撮ったときに、なんか暗いなあと思うと画像をコピーしてスクリーン処理をする、ということがよくあります。ですが、スクリーンとかオーバーレイって何をする処理だっけ?とたまになるので、そのあたりの覚え書きです。

乗算

かけ算です。ただし、画像ファイルのデータの255を1.0とみなします。1.0より小さい値同士のかけ算なので、必ず元の値以下になります。

上の画像の値をo、下の画像の値をb、結果の画像の値をrとすると、
{\displaystyle
r = ob
}
となります。

もしo=b、つまり自分自身に乗算処理をした場合、グラフは以下のようになります。青の実線がオレンジの破線(y=x)より下にあり、暗くなることがわかります。
f:id:KesaranPa:20180214183759j:plain

スクリーン

乗算とは逆の処理です。
{\displaystyle
r = 1 - (1 - o)(1 - b)
}
この処理は、2つの画像を反転して乗算処理をして、その結果をさらに反転する、という処理と等価になります。乗算とは逆に必ず元の値以上になります。

もしo=b、つまり自分自身にスクリーン処理をした場合、グラフは以下のようになります。青の実線がオレンジの破線より上にあり、明るくなることがわかります。
f:id:KesaranPa:20180214183818j:plain

オーバーレイ

乗算とスクリーンを合体させた処理です。下の画像が暗いと乗算、明るいとスクリーンになります。
{\displaystyle
r = \cases{
2ob \cr
1 - 2(1 - o)(1 - b) \cr
}\qquad\array{
b \lt 0.5 \cr
b \ge 0.5 \cr
}
}

もしo=b、つまり自分自身にオーバーレイ処理をした場合、グラフは以下のようになります。暗いところはより暗く、明るいところはより明るくなります。
f:id:KesaranPa:20180214183836j:plain

FF14のSSで試してみる

元の画像。
f:id:KesaranPa:20180214184303j:plain

自身に乗算処理。
f:id:KesaranPa:20180214184318j:plain

自身にスクリーン処理。
f:id:KesaranPa:20180214184335j:plain

自身にオーバーレイ処理。
f:id:KesaranPa:20180214184347j:plain

記載されている会社名・製品名・システム名などは、各社の商標、または登録商標です。