ProxmoxVE メモリーHugePage設定方法

## HugePageとは
HugePageは特定の用途用にロックダウンしたメモリ範囲を用意する。HugePageの名の通り、通常4KBのページサイズが2MB、1GBに増えるため処理するページ数が少なくなりCPUの負荷を抑えることができる。仮想マシンを動作させるなど大量のメモリーを使用する場合。HugePageを利用することでパフォーマンスの低下を抑えられる。

## 実施環境
物理マシン
* ProxmoxVE 7.0-11
* CPU AMD Ryzen 5 1600 12コア
* RAM 16GB

ゲストマシン
* Windows 10 Home
* CPU 10コア
* RAM 8GB
* PCI-Passthrough等の設定済み（今回の話とは直接関係ないです）

## 初期状態の確認

CPUの確認。「pse」もしくは「pdpe1gb」の文字列が含まれていればHugePage対応CPU。「pse」であれば2MB、「pdpe1gb」であれば1GBサイズのページが作成できる。

```bash
cat /proc/cpuinfo | egrep -o pse | head -n 1
# pse
```

```bash
cat /proc/cpuinfo | egrep -o pdpe1gb | head -n 1
# pdpe1gb
```

使用しているRyzen 1600は両方とも対応していた。

メモリの確認

```bash
cat /proc/meminfo | grep -i huge
AnonHugePages:   8271872 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
```
「Hugepagesize:2048 kB」の箇所に注目。現在のHugePageのページあたりの容量の設定は2MBということがわかる。1GBの設定の場合は下記のようになる。

```bash
root@kiyoura:~# cat /proc/meminfo | grep -i huge
略
Hugepagesize:    1048576 kB
```

## GRUBの設定変更

8GBのページをゲスト専用に用意するケースを考える。

### 2MB設定の場合

「/etc/default/grub」を編集する。
「hugepagesz=1G default_hugepagesz=2M hugepages=4096 transparent_hugepage=never"」を後ろに書き足す。「2M」の部分が先程確認した数値。仮想マシンで使用しているメモリの容量が8GB。8192MB/2MBでページ数は4096必要。

```bash
GRUB_CMDLINE_LINUX_DEFAULT="quiet 〜略〜 hugepagesz=1G default_hugepagesz=2M hugepages=4096 transparent_hugepage=never"
```

### 1GB設定の場合

8GB/1GBで8ページ必要

```bash
GRUB_CMDLINE_LINUX_DEFAULT="quiet 〜略〜 hugepagesz=1G default_hugepagesz=1G hugepages=8 transparent_hugepage=never"
```

default_hugepageszの部分でmeminfoで表示されるページサイズ設定が変更される。

編集後はgrubを更新し再起動。

```bash
update-grub
```

起動後にHugePageの状態を確認。4096ページと表示されるはず。

```bash
cat /proc/meminfo | grep -i huge
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:    4096
HugePages_Free:     4096
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:         8388608 kB
```

## 仮想マシンの設定

仮想マシンのCPU設定で、「NUMAを有効化」をチェック。「pdpe1gb」フラグをOnにする。

![aaaスクリーンショット 0003-10-15 10.52.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/f66713b7-4f8c-5c06-fe0d-b9c0c4fa2262.png)

仮想マシンの設定ファイルを編集する。パスは「/etc/pve/qemu-server/（仮想マシン番号）.conf」

「hugepages: 2」の行を追記。場所はどこでもいい。1ページ1GBの場合は1024と記入。

```bash
hotplug: 0
hugepages: 2
ide0: none,media=cdrom
```

## ゲスト起動後

「HugePages_Free」が0になっていることが確認できる。

```bash
cat /proc/meminfo | grep -i huge
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:    4096
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:     4096
Hugepagesize:       2048 kB
Hugetlb:         8388608 kB
```

サマリで、ゲストのメモリ利用状況を確認するとほぼ0になっている。

![スクリーンショット 0003-10-15 11.29.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/479ea952-7a73-7ba9-1c75-51c31c43761f.png)

仮想マシンを完全にシャットダウンした場合、利用されたHugePageは開放されてしまうようで、再度ゲストの起動を試みた際にHugePageがなくAllocation Errorとなってしまう。Windowsの再起動ではHugePageは維持され問題なかった。

```bash
cat /proc/meminfo | grep -i huge
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
```

## ゲストシャットダウン後に再度HugePage作成

以下のコマンドで再度HugePageを用意できる。

```bash
echo 4096 > /proc/sys/vm/nr_hugepages
```

実行後

```
cat /proc/meminfo | grep -i huge
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:    4096
HugePages_Free:     4096
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:         8388608 kB
```

作成後は再度ゲストを起動することができた。

ちなみに1GBの設定の場合、

```bash
echo 8 > /proc/sys/vm/nr_hugepages
```

## 起動前のHugePage作成自動化

いちいち上記のコマンドを実行するのは面倒なため、自動化する。ProxmoxVEにはhookscript機能があり、ゲストマシンの起動・シャットダウンのタイミングで任意のperlスクリプトを実行させることができる。

「スニペット」をlocalで有効化する。これで「/var/lib/vz/snippets/」ディレクトリが作成される。
![スクリーンショット 0003-10-15 12.26.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/a2f171d8-8756-a867-9be7-abbea4a647cc.png)

hookscriptのサンプルが「/usr/share/pve-docs/examples/guest-example-hookscript.pl」にあるため、これをコピーする。

```bash
cp /usr/share/pve-docs/examples/guest-example-hookscript.pl /var/lib/vz/snippets/make_4096_hugepage.pl
```

![スクリーンショット 0003-10-15 12.29.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/d14f4783-9ca4-e5aa-f74d-6bdaac30a21d.png)

「/var/lib/vz/snippets/make_4096_hugepage.pl」を編集する。
起動直前のタイミング「pre-start」の場合に「echo 4096 > /proc/sys/vm/nr_hugepages」コマンドが打たれるようにする。

```perl
if ($phase eq 'pre-start') {

    # First phase 'pre-start' will be executed before the guest
    # ist started. Exiting with a code != 0 will abort the start

    print "$vmid is starting, doing preparations.\n";

    # ここから
    my $command = "echo 4096 > /proc/sys/vm/nr_hugepages";
    system($command);
    # ここまで

    # print "preparations failed, aborting."
    # exit(1);
```

ゲストマシンの設定「/etc/pve/qemu-server/（仮想マシン番号）.conf」に以下を追記

```bash
hookscript: local:snippets/make_4096_hugepage.pl
```

これで起動とシャットダウンを繰り返しても正常に動作するようになる。


## WindowsでのHugePageの利用

メモリーの測定にSandraというベンチマークソフトが良さそうなので、使用してみたところHugePageが使用できていないことがわかった。

[Sandra Lite](https://www.sisoftware.co.uk/download-lite/)

![スクリーンショット 0004-01-26 15.55.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/d007bc66-c30f-043a-bb25-b64672f0334c.png)

>「特権の不足により、大きなメモリーページを使用できません」

グループポリシーの設定変更が必要なことがわかった。Windows10のHome版ではgpeditが使用できないため、下記の記事を参考にgpeditを使用できるようにした。

https://tanweb.net/2021/01/06/38190/

そして下記手順を参考にポリシーを変更した。ページロック可能対象ユーザーとして「Everyone」を指定した。

https://yaneuraou.yaneu.com/2020/05/31/%E3%82%84%E3%81%AD%E3%81%86%E3%82%89%E7%8E%8B%E3%80%81large-page%E5%AF%BE%E5%BF%9C%E3%81%A710%E6%95%B0%E9%80%9F%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%9F%E4%BB%B6/

再起動後、警告は消えたためHugePageが使用できるようになったと思われる。

![スクリーンショット 0004-01-26 16.16.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65278/ab89f45b-00cb-d0c0-017c-162ff8683b73.png)