open-vm-toolsと%stealについて

前の記事の「[LinuxのCPU使用率の%stealについて(KVM以外の場合)](http://qiita.com/thatsdone/items/2810d531f381a6be08cf)」で、ESXiの場合の Linux の kernel や user land と hypervisor の間の情報のやりとりについて書いたのだが、2008年頃から状況の変化や記憶違いがあったので、現状について少しまとめておきたい。

* open-vm-tools とは
* vmGuestLib とは
    * VMware Guest SDK で、いつから StolenMs が採取できるようになったのか？
    * vmGuestLib を使ってみる
    * vmGuestLib の処理構造

# open-vm-tools とは

ざっくり一言でいえば、VMware Tools のオープンソース版である。

VMwareとしても、distro として open-vm-tools を提供しているものについては、VMware Tools ではなく open-vm-tools を使うのが推奨になっているようだ。

## 何ができるのか？

VMware Tools がカバーしている範囲に対応するので、機能範囲はとても広い。また、user land のプログラムだけでなく、各種kernel用のdevivce driver等も含まれている。

できることの説明は、

https://github.com/vmware/open-vm-tools/blob/master/README.md

に書いてあるのだが、これってよく読んでみると、featureレベルの説明と実装レベルの説明がちゃんとマッピングがとれていない上に、説明のカバレッジもいまいちなようだ。:(
featureレベルの説明だけ引用して日本語をつけてみたのだが、あくまでご参考ということで。

なお、open-vm-tools のサービスのログを見ていると、以下のような機能が plugin として読み込まれているのがわかる。

* balloon driver
* hgfs
* time sync
* powerOps
* vmbackup
* vix
* deployPkg

VIXはVM操作の自動化のためのしくみで、他はだいたい名前がそのまま機能を表しているように思う。
上記に加えて(少なくとも)

* vmGuestLib

がついてくる。

---
以下、README.md 冒頭部より。

* The ability to perform virtual machine power operations gracefully.
    * VMの電源操作をgracefulに実行する昨日。例えば、電源Offに先だってナニカするとか。
* Execution of VMware provided or user configured scripts in guests during various power operations.
    * VMの電源操作中に、VMware提供またはユーザが設定したスクリプトをゲストの中で実行する。
* The ability to run programs, commands and file system operation in guests to enhance guest automation.
    * ゲストの中でコマンドやファイルシステム操作を実行する機能により、ゲストの自動化を強化する。
* Authentication for guest operations.
    * VM内の操作に必要な認証機能を提供する。
* Periodic collection of network, disk, and memory usage information from the guest.
    * VMのリソース利用状況を定期的に取得する。(本題の vmGuestLib とは逆の操作のようだ) 
* Generation of heartbeat from guests to hosts so VMware's HA solution can determine guests' availability.
    * ESXiへの生存通知。VMware HAで使われるようだ。
* Clock synchronization between guests and hosts or client desktops.
    * ホストとVMの間の時刻同期
* Quiescing guest file systems to allow hosts to capture file-system- consistent guest snapshots.
    * VMのスナップショットをとる際にファイルシステムのdirty dataをフラッシュするとか？
* Execution of pre-freeze and post-thaw scripts while quiescing guest file systems.
    * ゲストのファイルシステムを静止させる際に事前/事後処理を行う
* The ability to customize guest operating systems immediately after powering on virtual machines.
    * VMの電源On直後にゲストOSのカスタマイズを可能にする。
* Enabling shared folders between host and guest file systems on VMware Workstation and VMware Fusion.
    * ホストとVMの間でファイルシステム共有を実現する。いわゆる hgfs のこと。
* Copying and pasting text, graphics, and files between guests and hosts or client desktops.
    * ゲストとホストの間で、テキスト/グラフィック/ファイルのcopy & paste 等を実現する。

ブツの性質上しかたないのだけど、雑多だよね(笑)

# vmGuestLib とは

もちろん、VMware Guest SDK の(open-vm-toolsに含まれる)OSS版ということである。

## StolenMs サポートの追加時期

さて、元々の本題は、%Ready の元ネタの StolenMs をゲストOS側から取得できるようになったのはいつからなのか？だった。

結論から言うと、2009年の5月にリリースされた ESX4.0用の Guest SDK 4.0 から StolenMs を取得できるようになったらしい。前の記事のうち「2008年当時でもVMの中から%Ready相当の情報、つまりStolenMsを採取できた」云々というのは誤りだった。申し訳ないorz

本家のマニュアルを調べてみたところ、 StolenMs の記述は2007/11にリリースされた Guest SDK 3.5 には存在せず、ESX 4.1 に対応して 2010/7にリリースされた Guest SDK 4.0(のマイナーアップデート？)には記述があった。

* https://www.vmware.com/support/developer/guest-sdk/guest_sdk_35.pdf
    * Revision: 20071129 (ESX3.5まで)
* https://www.vmware.com/support/developer/guest-sdk/guest_sdk_40.pdf
    * Revision: 13JUL2010 (ESX 4.1まで)

単純にGuest SDK側の開発方針の変更かもしれないが、もしかしたらESX 4.x以降、ハイパーバイザが値を返せるようになったのかもしれない。
なお、本稿執筆時点の最新版は、Guest SDK 10.1 (2016/11リリース)である。


## vmGuestLibを使ってみる

前の記事でも触れたように、拙作が以下においてある。

https://github.com/thatsdone/kusanagi/tree/master/user/vgstat

これは、mode によって以下のいずれかをを定期的に表示し続けるだけのプログラムである。

1. 自分が動いているVMが、ESXi 上で使用しているCPU使用率(%Used)および待たされたCPU使用率(%Ready)を表示する(standard mode)
2. 単純に Guest SDK (open-vm-tools では vmGuestLib)から取得できる値をすべて表示する(raw mode)

README.md に実行例を載せてあるのだが、standard mode の例を引用してみたのが以下である。

```
|$ ./vgstat -c 10 -i 10
|Timestamp                intvl(g) intvl(h)     used   stolen    %used   %ready
|2017-03-12T01:06:20+0900    10001    10001       30       14     0.30     0.14
|2017-03-12T01:06:30+0900    10000    10001       30       13     0.30     0.13
|2017-03-12T01:06:40+0900    10000    10001     9189       11    91.88     0.11
|2017-03-12T01:06:50+0900    10000    10000     9142       11    91.42     0.11
|2017-03-12T01:07:00+0900    10000    10001       29       13     0.29     0.13
|2017-03-12T01:07:10+0900    10000    10001     7052       11    70.51     0.11
|2017-03-12T01:07:20+0900    10000    10000    12316       11   123.16     0.11
|2017-03-12T01:07:30+0900    10000    10001     5244       12    52.43     0.12
|2017-03-12T01:07:40+0900    10000    10000       19       13     0.19     0.13
|2017-03-12T01:07:50+0900    10000    10001       19       11     0.19     0.11
```

各カラムの意味は以下の通り。
Timestamp : タイムスタンプ
intvl(g) : 前回の情報取得からの経過時間(ゲスト上での計測)
intvl(h) : 前回の情報取得からの経過時間。ElapsedMsから算出(ESXiでの計測)
used : UsedMs の差分値。実際にCPUを使った時間(ミリ秒単位)
stolen : StolenMs の差分値。Ready状態でCPUを待っていた時間(ミリ秒単位) 
%used : 分母に intvl(h)を使って計算した %used。nVCPUなら最大n00%
%ready : 分母に intvl(h)を使って計算した %ready。nVCPUなら最大n00%

最後の %ready が Linuxでいうところの%steal相当の量である。

この測定では、ESXi 6.5 を使用し、1VCPUのVMの上で、Ubuntu Xenial (amd64)を使っている。サンプリングは10秒間隔で行い、負荷は、stress を使ってCPUのみの負荷を断続的にかけた。

ところで、この条件と結果を見て、何か気付かないだろうか？
%ready の値として0ではない値が出ていることよりも、1VCPUであるにもかかわらず、%used の値が100%を大きく超えている!? ((((；ﾟДﾟ))))

これは、どういうことだろうか？

Guest SDK 10.1 のマニュアル[^1]の VMGuestLib_GetCpuUsedMs() の説明のところには以下のような記述がある。

[^1]: Guest and HA Application Monitoring SDK Programming Guide - vSphere Guest SDK 10.1 and vSphere HA Application Monitoring for vSphere 6.5 (EN-002081-00)

>  Retrieves the number of milliseconds during which the virtual machine
has used the CPU. This value includes the time used by the guest
operating system and the time used by virtualization code for tasks for this
virtual machine. You can combine this value with the elapsed time
(VMGuestLib_GetElapsedMs) to estimate the effective virtual machine
CPU speed. This value is a subset of elapsedMs.

この計算では、分母に elapsedMs、分子に usedMs を使い、それぞれ連続する2回のサンプリング値の差分を求めて割っている。
上記の最後の文では分子の usedMs が分母の elapsedMs のサブセットであると述べられているので、もしこの通りなら1VCPUなら100%を超えるはずはないのだが...
実際のコードでいうと[このあたり](https://github.com/thatsdone/kusanagi/blob/master/user/vgstat/vgstat.c#L333)である。(何か見落としているかなぁ？)

ここから先は想像になる。
察するに、usedMs は本来のVMの処理以外の分のCPU時間もカウントされているのではないかという気がする。実際、上記の2つ目の分で、OSがつかった分だけでなくこのVMのための仮想化コードが使った分も含むとあるので、最後の1文はあくまでコンセプトであって、厳密にはサブセットにはなっていないのではないだろうか？

以下、esxtop の結果なのだが、見てわかるとおり、esxtop でも1VCPUなのに100%を超えることがあるので、当たらずとも遠からず…といったところではないだろうか。

![esxtop-example.png](https://qiita-image-store.s3.amazonaws.com/0/155831/aec465f2-ac9c-5473-7057-c12ad284b40c.png)

(一部、白消ししてあるところはご容赦願いたい...)

## vmGuestLibの処理構造

詳細はTBD。

VMCI device (/dev/vmci) 経由で、RPCで hypervisor (ESXi の vmkernel ...というよりは、システムプロセス?)と通信して、情報を取得しているようだ。
…が、追いかけていくと、inline assember で outsb を使っている backdoor 云々なんていう紛らわしい(笑)名前のついた関数もあり、memory mapped I/O が使えればそちらを使って高速に情報をやりとりするルートもあるようだ。

# まとめ

* open-vm-tools は VMware Tools のOSS版であり、distro (UbuntuとかCentOSとか...)が提供しているのであれば open-vm-tools のほうを使うのが推奨。
* 2009年5月以降、Linux でいう %steal 相当の情報をVMの中でハイパーバイザから取得できるようになっている。
* vmGuestLib が返すリソース利用情報には、若干注意が必要なものもある。