Intel iGPUをパススルーして利用する - vSphere VM編

この記事は [vExperts Advent Calendar 2023](https://adventar.org/calendars/8879) の12月21日分の投稿記事です。

https://adventar.org/calendars/8879

## はじめに

Intel NUC 13ではモバイル向け[第13世代Coreプロセッサ(Raptor Lake)](https://www.intel.co.jp/content/www/jp/ja/products/docs/processors/core/13th-gen-processors.html)がCPUとして利用されています。第12世代Coreプロセッサ(Alder Lake)から、高性能コア(P-Core)と高効率コア(E-Core)の2種類のCPUを搭載するPerformance Hybrid Architectureで構成されており、内蔵GPU(iGPU)として[Iris Xe Graphics](https://www.intel.com/content/www/us/en/products/docs/discrete-gpus/iris-xe-integrated-graphics/overview.html)が搭載されています。
Intel NUC 13(IntelCore i7-1360P)にESXiをインストールし、パススルーしたIris XeをGPUを仮想マシンから使って、[OpenVINO](https://www.intel.co.jp/content/www/jp/ja/internet-of-things/openvino-toolkit.html)により[Stable Diffusion](https://huggingface.co/stabilityai/stable-diffusion-2-1-base)でText-to-Imageを試してみます。

::: note warn

VMware ESXiはIntel コンシューマー向けCPUのPerformance Hybrid Architectureをサポートしていません。本記事の内容はVMwareがサポートする内容ではありません。
:::

本記事は仮想マシンとしてIntel iGPUを利用する方法を説明しています。仮想マシン上のKubernetes Podから利用する場合はこちらの記事を参照してください。

https://qiita.com/masanara/items/6268294efceaa735aef6

## VMware ESXiのインストール

Raptor LakeにESXiをインストールしようとすると、ESXiがAlder Lakeから実装されたPerformance Hybrid Architectureに対応していないため、インストーラー起動時のチェックでPSODになってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/a7ec1334-cdce-672e-461b-57aad2dcf317.png)


カーネルオプションでE-Coreに対するチェックを無視するか、BIOSでE-Coreを無効化するか、どちらかでインストーラーの起動が可能です。ESXiとしてはコンシューマー向けCPUをサポートする予定はないようなので、E-Coreを無効化するのが推奨のようです。

### 参考 : Intel 12/13世代のCPUへの対応に関して

- [Video of ESXi install workaround for Fatal CPU mismatch on feature for Intel 12th Gen CPUs and newer](https://williamlam.com/2023/01/video-of-esxi-install-workaround-for-fatal-cpu-mismatch-on-feature-for-intel-12th-gen-cpus-and-newer.html)
- [ESXi PSOD due to GP Exception 13 in world with Intel 13th Generation CPU](https://williamlam.com/2023/04/esxi-psod-due-to-gp-exception-13-in-world-with-intel-13th-generation-cpu.html)

### オプション1 : 起動オプションの修正

- ESXiインストーラー起動時のカーネルオプションを指定して、インストール後にカーネルオプションを変更する。
  ```bash
  kernelopt=weaselInstalled autoPartition=FALSE cpuUniformityHardCheckPanic=FALSE
  ```
- インストール完了後、インストールしたESXiで以下の設定が必要。
  ```bash
  esxcli system settings kernel set -s cpuUniformityHardCheckPanic -v FALSE
  ```

### オプション2 : E-Coreの無効化

- [NUCのBIOSでE-Coreを無効化する。](https://williamlam.com/2023/03/how-to-disable-the-efficiency-cores-e-cores-on-an-intel-nuc.html)

## ESXi上のIris Xeの認識

ESXi 8.0u1をインストールすると、Iris Xeは「Intel Corporation VGE compatible Controller」として認識されます。このままでもパススルーデバイスとして構成し、仮想マシンに接続することが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/ff311bac-cde8-2585-f75b-d6882ea5211c.png)

[2023年10月リリースされたESXi 8.0u2](https://docs.vmware.com/jp/VMware-vSphere/8.0/rn/vsphere-esxi-802-release-notes/index.html)以降、「Intel Corporation Raptor Lake-P [Iris Xe Graphics]」として認識されるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/d2c62596-3eb9-207b-49d4-06a73c64fe79.png)

## 仮想マシンへのIris Xeの接続

ESXiでデバイスをパススルーデバイスとして設定すると、仮想マシン(4vCPU/16GB RAM)にPCIデバイスとして接続することが可能です。パススルーを利用するには仮想マシンの割当メモリーの「すべてのゲスト メモリを予約 (すべてロック)」をチェックする必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/b95c619c-a947-f5c0-749f-e51f79ea4c07.png)

## ゲストOSの設定

Ubuntu 22.04.3 LTSのデフォルトのカーネルとして 5.15 (5.15.0-89-generic) が利用されていますが、Raptor Lake-PのiGPUをカーネルが認識するには、[カーネル 5.19 以降](https://linux-hardware.org/?id=pci:8086-a7a0-8086-3037)であるためそのままでは利用できませんでした。HWE(Hardware Enablement)カーネルをインストールすることでカーネルとして 6.2(6.2.0-37-generic) の利用が可能になり、カーネルモジュールとしてi915が読み込まれます。

HWEカーネルインストール前はデバイスID 0xa7a0を「VGE compatible controller」として認識していますが、カーネルモジュールとして、i915がロードされていません。

```bash
root@ubuntu:~# uname -r
5.15.0-89-generic
root@ubuntu:~# lspci -k -s 02:05.0
02:05.0 VGA compatible controller: Intel Corporation Device a7a0 (rev 04)
        DeviceName: pciPassthru0
        Subsystem: Intel Corporation Device 3037
root@ubuntu:~# lsmod | grep i915
```

HWEカーネルをインストールして再起動します。

```bash
sudo apt-get install -y linux-image-generic-hwe-22.04 && sudo reboot
```

再起動後に確認するとカーネルとして 6.2.0-37-generic が利用されていて、デバイスID 0xa7a0をGPU(i915)として認識されてカーネルモジュールがロードされています。

```bash
root@ubuntu:~# uname -r
6.2.0-37-generic
root@ubuntu:~# lspci -k -s 02:05.0
02:05.0 VGA compatible controller: Intel Corporation Device a7a0 (rev 04)
        DeviceName: pciPassthru0
        Subsystem: Intel Corporation Device 3037
        Kernel driver in use: i915
        Kernel modules: i915
root@ubuntu:~# lsmod | grep i915
i915                 3899392  0
drm_buddy              20480  1 i915
i2c_algo_bit           16384  1 i915
drm_display_helper    212992  1 i915
cec                    94208  2 drm_display_helper,i915
ttm                   110592  3 vmwgfx,drm_ttm_helper,i915
drm_kms_helper        249856  5 vmwgfx,drm_display_helper,i915
video                  73728  1 i915
drm                   700416  9 vmwgfx,drm_kms_helper,drm_display_helper,drm_buddy,drm_ttm_helper,i915,ttm
```

## OpenCLランタイムのインストール

Intelのリポジトリを追加してGPUを使用するために[OpenCLランタイムをインストール](https://docs.openvino.ai/2023.2/openvino_docs_install_guides_configurations_for_intel_gpu.html)します。

```bash
wget -qO - https://repositories.intel.com/gpu/intel-graphics.key | \
  sudo gpg --dearmor --output /usr/share/keyrings/intel-graphics.gpg
echo "deb [arch=amd64,i386 signed-by=/usr/share/keyrings/intel-graphics.gpg] https://repositories.intel.com/gpu/ubuntu jammy client" | \
  sudo tee /etc/apt/sources.list.d/intel-gpu-jammy.list
sudo apt update
sudo apt-get install -y ocl-icd-libopencl1 intel-opencl-icd intel-level-zero-gpu level-zero
```

## OpenVINOのインストール

[PyPIでOpenVINOをインストール](https://docs.openvino.ai/2023.2/openvino_docs_install_guides_installing_openvino_pip.html)して、GPUが認識されていることを確認します。

```bash
apt-get install -y python3.10-venv
python3 -m venv openvino_env
source openvino_env/bin/activate
python -m pip install --upgrade pip
python -m pip install openvino
python -c "from openvino.runtime import Core; print(Core().available_devices)"
```

以下のような出力になれば、PythonからGPUが利用可能な状態です。

```bash
$ python -c "from openvino.runtime import Core; print(Core().available_devices)"
['CPU', 'GPU']
```

GPUにアクセスするためのデバイスである`/dev/dri/render*`のパーミッションが640となっているため、非rootユーザーはGPUを利用することができません。

```bash
root@ubuntu:~# ls -l /dev/dri/render*
crw-rw---- 1 root render 226, 128 Dec  7 22:19 /dev/dri/renderD128
crw-rw---- 1 root render 226, 129 Dec  7 22:19 /dev/dri/renderD129
```

GPUを利用するにはユーザーを`render`グループに追加するか、以下のようなudevルールを追加してデバイスのパーミッションを修正します。

```bash
echo 'KERNEL=="render*" GROUP="render", MODE="0666"' > /etc/udev/rules.d/99-render.rules
```

## Notebookの起動

Stable Diffusionの実行は[OpenVINO Notebooks](https://github.com/openvinotoolkit/openvino_notebooks)として公開されているので、今回はJupyter Notebookで実行します。

```bash
source $HOME/openvino_env/bin/activate
git clone --depth=1 https://github.com/openvinotoolkit/openvino_notebooks.git
cd openvino_notebooks
pip install wheel setuptools
pip install -r requirements.txt
jupyter lab --ip 0.0.0.0 notebooks
```

起動が完了すると、以下のようにTokenが含まれるURLが表示されるのでコピーしてブラウザで開きます。

```bash
[C 2023-12-07 22:43:35.426 ServerApp]

    To access the server, open this file in a browser:
        file:///home/ubuntu/.local/share/jupyter/runtime/jpserver-1343-open.html
    Or copy and paste one of these URLs:
        http://ubuntu:8888/lab?token=f0060167f4abffc3e4a0843c1c8e3b1248a1452b679f23fb
        http://127.0.0.1:8888/lab?token=f0060167f4abffc3e4a0843c1c8e3b1248a1452b679f23fb
```

ブラウザでアクセスしたら、[/236-stable-diffusion-v2/236-stable-diffusion-v2-text-to-image-demo.ipynb](https://github.com/openvinotoolkit/openvino_notebooks/blob/main/notebooks/236-stable-diffusion-v2/236-stable-diffusion-v2-text-to-image-demo.ipynb)を開いて実行します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/21253a24-8a16-6e47-7dc8-b84fc1c88022.png)

## Stable Diffusionによるイメージの生成

- Step 3.2: Select infrence device部分で推論デバイスをAUTO、GPU、CPUから選択することができます。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/a75c959f-6997-4f3b-4ebd-82ff5ad6caea.png)

- Step 3.3: Run Text-to-Image geenerationで`text_prompt`を変更して画像を作成することができます。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/aa2eaa73-02a2-9ce3-5eee-1cdf1690fb9f.png)

:::note info
text_prompt = "Shibuya city filled by many cats, epic vista, beautiful landscape, 4k, 8k"
:::

- 作成された画像はNotebook内に表示されます。
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/a8668d31-1cdf-294d-b198-6a1d5fd98f2d.png)


## GPUの効果測定

推論デバイスとしてGPUを利用した場合に本当に効果があるかどうか、時間を測ってみました。

|                  | CPU利用時  | GPU利用時 |
| ---------------- | ---------- | --------- |
| イメージ作成時間 | 312.26 sec | 74.51 sec |

GPUを使うことで、イメージ作成時間は1/4以上削減できました。

- CPU利用時
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/6a9a0435-22e6-0621-484d-d07021f10286.png)


- GPU利用時
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27668/e4086b5c-5560-cd02-dbe0-0eb51f9aee1b.png)


## まとめ

Intel CPUに統合されたGPUをVMware ESXiでパススルーして、仮想マシン上内のプログラムでGPUを使って画像生成することができました。
仮想マシンでKubernetesクラスターを構成して、コンテナからGPUを利用する方法については[こちら](https://qiita.com/masanara/items/6268294efceaa735aef6)の記事で説明してます。