LinuxのCPU使用率の%stealについて(KVM以外の場合)

# はじめに

2017/03/04に書いた記事(「[LinuxのCPU使用率の%stealについて](http://qiita.com/thatsdone/items/e9592126ec0f8d445113)」)に思いのほか反響があったので、KVM以外で私が知っていることをダンプしておくことにした。

若干TBDが多いのはご容赦願いたい。

# Xenの場合

Xenの場合は普通に %steal にカウントされる。

Ubuntu Xenial の linux-4.4.0系の場合は、前回触れた ```account_steal_time()``` が少し違うルートから呼ばれる。こんな感じ。

```
timer割り込み =>
  =>xen_timer_interrupt() (arch/x86/xen/time.c)
    =>do_stolen_accounting() (arch/x86/xen/time.c)
      =>account_steal_ticks() (kernel/sched/cputime.c)
        =>account_steal_time() (kernel/sched/cputime.c)
```

見てわかるとおり、この時点ではXenの依存コードのtimer処理部分から直接呼び出される変則的な形になっている。ただし、[前の記事(の更新版)](http://qiita.com/thatsdone/items/e9592126ec0f8d445113)でコメントをいただいたように、現時点のLinusのtreeでは、Xen用の steal_clock ハンドラが実装されており、KVMと同じすっきりした call tree になっている。

余談だが、2008年くらいに Xen 上でWeb3層システムの検証をしていたときに、高負荷状態になるとVMの中で計測されるCPU使用率の値の精度が悪くなる現象を見たことがあった。おそらく Linus の tree を使えば sched_clock ハンドラ(```xen_clocksource_read()```)も実装されているため、改善されているのではないかと想像している。

# ESXiの場合

ESXi の場合は、現時点のLinusのtreeを使っても %steal に値は入らない。

(前述のXen上の検証と前後して)2007-2008年くらいに、ESXi (VI3の時代。当時はまだi(愛?)がなかった)上でLinuxベースのWeb3層システムの検証をしたことがあった。この当時、高負荷状態になるとVMの中で計測されるCPU使用率の値が狂うのでどうしようか検討していたのだが、%steal は0のままだったので意識していなかった。

では、%steal 相当の情報を得られないのか？と言われれば、実は当時でも可能だった。
まず、ESXiの vmkernel 側では、VMごとにCPU時間をaccountingしており、esxtop 等を使うと、VMごとの各種モードのCPU使用率も採取できる。この中に %Ready という値があり、これがVM側のLinuxの中でみた %steal に対応するものである。%Readyについては、今は広く知られているようだ。たとえば以下のような記事とか。

* https://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2019905 (日本語)
* https://kb.vmware.com/selfservice/search.do?cmd=displayKC&docType=kc&docTypeID=DT_KB_1_1&externalId=2001003 (英語の元記事)

ではさらに、ハイパーバイザに乗り込まないとこの情報は得られないのか？といえば、実はこれも可能である。VMware社から提供されている "vSphere vSphere Guest SDK" を使うと、VMの内部でハイパーバイザから自VMが使ったCPU時間の内訳を取得することができる。
(2017/03/18追記: 追跡調査の結果、2008年当時は以下で説明する StolenMsという量は得られなかったことがわかった。記憶違いをお詫びして訂正したい。この値が取得できるようになったのは2009年のESX4.x用の Guest SDK 4.0からである)

SDKの仕様としては、現行では

* https://www.vmware.com/support/developer/guest-sdk/

からたどれる、

* http://pubs.vmware.com/vsphere-65/index.jsp#com.vmware.guestsdk.pg.doc/guest_sdk_GuestApi.4.3.html?path=4_8_0_1_1_2#991587

あたりに関連APIの説明がある。
ざっくり使い方を説明すると、初期化APIの ``` VMGuestLib_OpenHandle()```でハイパーバイザと接続した後、定期的に ```VMGuestLib_UpdateInfo()``` で統計情報を取得更新した後、必要なアクセサAPIで情報を取り出す。
今回の話に関連するものとしては、たとえば以下の3つがある。

1. ```VMGuestLib_GetElapsedMs()```
    * VM起動以後の実経過時間の積算値(milisec単位)
2. ```VMGuestLib_GetCpuUsedMs()```
    * VM起動以後の実CPU使用時間の積算値(milisec単位)
3. ```VMGuestLib_GetCpuStolenMs()```
    * VM起動以後の時間泥棒さんに盗まれた(笑)実時間の積算値(milisec単位)

適当な間隔で2回情報を採取し、1. の差分を分母に、3.の差分を分子に使って前回説明した計算を行えば %steal 相当の値を得ることができるのがわかると思う。

若干手前味噌だが、当時作ったものが以下においてある。

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

VI3時代に作ったので、今はビルドにちょっと手直しが必要かもしれない。
(2017/03/11追記: 案の定動かなかったので、open-vm-tools 前提に手直ししておいた)

なお、こんなI/Fがあるのであれば、Linux kernel からも取得できるようにすればよいと思うかもしれない。しかし、この vSphere Guest SDK は user land から使うものである上にソースが公開されておらず、I/Fがわからない [^1] ので、VMwareの人にまかせるしかなさそうだ。

(2017/03/11追記: 実は、VMware Tools のOSS版の open-vm-tools には、Guest SDK相当のコードが含まれていることがわかった。別途記事を書きたいと思う)

(2017/03/12追記: 上記のvgstatを手直ししながら、2008年当時は ```VMGuestLib_GetCpuStolenMs()``` は提供されておらず、%Ready相当の値を知る方法はなかったのではないか？という気がしてきた。これも含めて別記事にまとめたい)

[^1]: リバースしても組み込めないので、それは言わない。

ちなみに、現時点のLinusのtreeでは、steal_clock ハンドラは存在しないが、sched_clock ハンドラ(```vmware_sched_clock()```)は実装されており、ハイパーバイザからTSCを取得できるようになっている。

# Hyper-Vの場合

Hyper-VでもESXiと事情は同じで、現状 Linus のツリーを持ってきても、%steal に値は入らない。

なお、白状しておくと、Hyper-Vについてはソースを追っただけで自分で検証していない。(ずっと、やりたいとは思っているのだが...)

ぐぐって出てきたのが以下の記事で、ずばり、Hyper-VでESXi の %Ready に対応するのって何よ？という記事である。

* https://www.sqlskills.com/blogs/jonathan/hyper-v-equivalent-to-vmware-cpu-ready-time/

これによると、少なくとも Windows Server 2012/2012R2 では、perfmon (?)に "Hyper-V Hypervisor Virtual Processor\CPU Wait Time Per Dispatch " というカウンタがあり、これが対応するらしい。名前からすると、百分率ではなく、積算値(vSphere Guest SDKで言うところの StolenMsに対応)のようだ。

そのほか、こんな記事もみつけたのだが、同じカウンタに触れているようだ。

* http://unix.stackexchange.com/questions/93168/measuring-cpu-steal-on-vmware-and-hyper-v-hypervisors/295186
* http://serverfault.com/questions/392216/is-there-a-windows-equivalent-of-unix-cpu-steal-time#455554

ところで、Ubuntu Xenial のlinux-4.4.0 系kernelの時点では、仮想デバイスまわりの対応のみ含まれているようだ。もうひとつ、KVMのHyper-V emulation なるコードが入っているのだが、あれはなんだろう？これはTBD。

また、本稿執筆時点のLinusのtreeを眺めると、 steal_clock ハンドラも sched_clock ハンドラも未実装のようだ。ただ、上記のようにHyper-V側では accounting を行っているため、いずれは実装されるものと思われる。

# s390の場合

[こんな書評]()を書いた都合上、s390に触れないわけにはいかないとは思うのだが、時間の都合で TBD。

# PowerPCの場合

kernelのソースを調べていた際に、PowerPCの場合も何か独自の考慮が入っていることに気づいたのだが、これも未調査。(需要があるのかどうかもわからないし)TBDということで。

# まとめ

* XenはだいたいKVMと同じ。
* ESXi と Hyper-V はハイパーバイザから%steal相当の時間泥棒情報を取得することが可能。現時点では、kernelでは未サポートだが、必要な情報はハイパーバイザ側にあるため、いずれ実装されるのではないかと思われる。
* 課題/TBD
    * s390 と powerpc はナニカをしている。
    * そのほかたくさん (fade out...)