kazubits のすべての投稿

準仮想化クロックの更新の頻度

***本記事にはプロモーションが含まれています。***

以前、準仮想化クロック(kvm-clock)は起動してからの時間とTSCの値をメモリに書き込んでいることがわかりました。

また、その書き込むタイミングはホストOSからゲストOSに制御が移る前だということもわかりました。

ただ、書き込む頻度についてはよくわかりませんでした。

そこで、LinuxのKVMのソースコードを読んで詳しく調べてみました。

ソースコードはarch/x86/kvm/x86.cで、kvm_guest_time_update()でシステムタイムとTSCのメモリの値を更新しています。

この関数は、vcpu_enter_guest()で呼ばれます。ホストOSからゲストOSに制御を移す関数です。

ただ、KVM_REQ_CLOCK_UPDATEという名前のリクエストがあったときのみkvm_guest_time_update()は呼ばれますので、どういう条件か探してみます。

わかったところを列挙すると次のようになります。

  • システムが立ち上がったとき
  • TSCの周波数が変更されたとき
  • プロセスのCPU間での移動があったとき
  • マイグレーションのとき
  • MSR_KVM_SYSTEM_TIMEをセットしたとき
  • CPUのホットプラグでロードされたとき

現在のパソコンのシステムを考えると、最初の3つくらいがよく起こることだと思います。でも、思いのほか準仮想化クロックの値の更新がなされません。Core iシリーズ以降の最近のCPUでは、CPUの周波数が変わったときでもTSCの周波数は変わらないです。プロセスの移動もそう頻繁にはないです。システムが起動してから、あまり頻繁には準仮想化クロックは更新されていないということがわかります。

実際に、ホストOSの時刻を変更してもゲストOSの時刻が同期して変わることはありません。

このことから準仮想化クロックは頻繁には更新されず、主にTSCによって現在時刻を計算していることがわかりました。

VirtualBox 5.0の準仮想化クロックが遅れるときの対処法

***本記事にはプロモーションが含まれています。***

準仮想化クロックの遅れの原因を追究してみます

前回、準仮想化クロックが5分で6秒くらい遅れることがわかりました。

少し細かな話になりますが、ソースコードを探索して原因の追究ととりあえずの対処法を紹介します。

VirtualBoxのソースコードを見てみる

まずはVirtualBoxのソースコードをダウンロードします。以前いじったときから5年ほど時間がたっていました。

Googleの検索でparavirtualizationを検索しているとき、VirtualBox 5.0 Beta2 releasedのリリースノートに

VMM: added support for using Paravirtualization providers with raw-mode VMs

とありました。

raw-mode VMsはなんだろうということで、svn logでraw-modeを検索してみます。

すると、

r55068 disble GIM for raw-mode VMs

とあって、GIMは何だろうということになりました。そこでソースコードを検索してみると、

vbox/src/VBox/VMM/VMMR3/GIM.cppに説明がありました。

GIM providerはparavirtualization interfaceとして参照される。

準仮想化インターフェースはソースコードではGIMと呼ばれているんですね。GIMとは、Guest Interface Manager Deviceの略で準仮想化インターフェースのすべてを扱っています。

ソースコードには次のような説明があります。

準仮想化の1つのゴールはゲストをもっと正確に、もっと効率的にすることです。たとえばゲストOSは、ホストプロセッサの正しいTSCの周波数がGIM providerから供給されることに依存します。これによりゲストはTSC自身をキャリブレートすることを避けることができ、正確さと効率がよくなります。

ということは、VirtualBoxがTSCの周波数を供給していることになります。

また、ゲストOSの設定ファイルのところにあるVBox.logというログを眺めて、TSCを探します。すると、TSCモードをVirtTscEmulatedからRealTSCOffsetに変えると出ています。このRealTSCOffsetがあやしいです。

これは、vbox/src/VBox/VMM/VMMR3/TM.cppにあります。

このファイルを見てみると、u64CpuHzがCPUの周波数を設定しているようです。また、tmR3CalibrateTSC()という関数がTSCのキャリブレーションをしていそうです。

また、kvm-clockはメモリーにTSCと、それをシステム時間に変換するスケールファクターを保存していたことを頼りに、どこで設定しているかを探します。

すると、vbox/src/VBox/VMM/include/GIMKvmInternal.hにstruct GIMKVMSYSTEMTIMEという構造体のu32TscScaleがTSCをシステム時間に変換するスケールファクターであることがわかります。今度は、u32TscScaleを設定しているところをソースコードで探します。

u32TscScaleは、vbox/src/VBox/VMM/VMMR3/GIMKvm.cppでpVM->cTscTicksPerSecondを代入しています。

また、いろいろな情報をログファイルに出力していることに気づき、VirtualBoxのゲストの設定ファイルのところにあるVBox.logをGIMやTSCを目安に眺めてみるとcTscTicksPerSecondも数値が記録されていることがわかります。

このように、関連するであろうファイル、変数やマクロ名をソースコードをから探し出しました。

完全に理解するところまでは行かなかったのですが、重要と思われる変数などは抜き出せたように思います。

VMware Playerで気づいたこと

VirtualBoxと平行して使っていたVMware Playerでdmesg |grep tscとdmesg |grep TSCをやると次のように出ます。

kazu@Mars:~$ dmesg |grep tsc
[ 0.000000] tsc: Detected 3400.109 MHz processor
[ 1.595236] Switched to clocksource tsc
kazu@Mars:~$ dmesg |grep TSC
[ 0.000000] TSC freq read from hypervisor : 3400.109 MHz

CPUの周波数3400MHzとでて、TSCの周波数はhypervisorから供給されていると出ています。これは、今使っているCPUの定格の周波数です。

じゃあVirtualBoxの場合はどうなんだとなりました。ログファイルでcTscTicksPerSecondを見てみると、

00:00:01.277674 TM: cTSCTicksPerSecond=3 478 274 491 (0xcf5241bb) enmTSCMode=1 (VirtTscEmulated)

3478274491Hzということみたいです。3478MHzということで、VMware Playerより大きいです。

また、この違いが1分でどれくらいの差になるのか計算すると、

60 * 3400109000 / 3478274491 = 58.65 (秒)

となりました。ほぼ、5分で6から7秒の遅れということで、前回の計測とあっています。

ここまでわかっていること

  • ゲストOSのクロックソースがkvm-clockとtscの場合時計が遅れる。遅れるのは5分で6秒ほど。
  • 準仮想化クロックでは、TSCの周波数はハイパバイザーがゲストOSに伝える。ゲストOSではキャリブレートしない。
  • VMware Playerとの比較では、cTSCTicksPerSecondの値が大きい。その値は、時計の遅れと一致している。

ということがわかりました。

とりあえずの対処法

VirtualBoxのフォーラムをGoogleでcTSCTicksPerSecondを検索すると、VBoxManageでゲストOSのTSCTicksPerSecondを設定する項目があるという情報を見つけました。

[solved] detected frequency

この項目が、準仮想化にも関係するのかよくわかりませんでしたが、次のように設定してから立ち上げました。

VBoxManage setextradata "[VMName]" "VBoxInternal/TM/TSCTicksPerSecond" 3400109000

周波数の値は、VMware Playerの値を使っています。わからなければ、CPUの定格の周波数でいいと思います。すると、時計の遅れはなくなりました。

これは、とりあえずの対処になります。TSCの周波数を決め打ちしています。TSCの周波数がCPUの電源管理状態によらず一定でないとできない対処です。最近のCore iシリーズ以降であれば使えると思います。でもこれで、VirtualBoxのTSCの周波数を決めるところにバグがあることがわかりました。

原因がつかめたようでよかったです。早くバグが修正されるといいなと思います。

VirtualBox 5.0の準仮想化クロックの精度

***本記事にはプロモーションが含まれています。***

このところずっとVirtualBoxを使っていて、ゲストOSの時計が遅れていることに気がつきました。なんか変だということで、精度を簡単に測ってみることにしました。

クロックソースによる時計のおくれの違い

準仮想化クロックkvm-clockは、/sys/devices/system/clocksource/clocksource0/current_clocksourceでクロックソースとして指定しています。その他にも変えられるものがあるので、準仮想化ではなくなってしまいますがクロックソースを変えてみます。

$ sudo sh -c "echo tsc >/sys/devices/system/clocksource/clocksource0/current_clocksource"

で変えられます。

変えられるのは、cat /sys/devices/system/clocksource/clocksource0/available_clocksourceで確認できます。

tsc(Time Stamp Counter)というのは、CPUの刻む時計です。acpi_pm(ACPI Power Management Timer)というのは、ACPIというパソコンの規格で定められている精度の高いタイマーです。

また、VirtualBoxの準仮想化インターフェースでKVMのほかに、Legacyと”なし”にしたときも同様に測ってみます。

計測は手元のストップウォッチで5分を計測して、dateコマンドで秒単位の変化を見ました。

ホストWindows 7 x86_64 ultimate、ゲストUbuntu 12.04 x86_64です。VirtualBoxは5.0で、GuestAdditionsを入れてあります。

準仮想化インターフェースがKVMのとき

準仮想化インターフェースをKVMにしてかかった時間を計測します。

実時間 kvm-clock tsc acpi_pm
5分00秒 4分54秒 4分54秒 5分00秒

kvm-clockとtscのときは、5分経過したとき6秒も時計が遅れていました。acpi_pmにしたときは、ほぼ5分になります。

kvm-clockはtscをつかっているので、kvm-clockがずれているのはtscが原因だと思います。

準仮想化インターフェースがLegacyのとき

準仮想化インターフェースのLegacyがよくわからなかったので、計測してみました。

実時間 tsc acpi_pm
5分00秒 5分00秒 5分00秒

tsc、acpi_pmの両方とも正確に測れています。

準仮想化インターフェースがなしのとき

準仮想化インターフェースをなしにしたときも測定してみました。

実時間 tsc acpi_pm
5分00秒 5分00秒 5分00秒

tsc、acpi_pmともに時計は正確でした。

KVMでkvm-clockを使ったとき

時計の遅れがゲストOSのkvm-clockドライバーの問題なのか、VirtualBoxの準仮想化インターフェースの問題なのかはっきりさせるため、KVMを使ってみました。
LinuxのホストマシンがないのでVMware Playerを使ってKVMを仮想環境で動かしました。

ホストOSは、Windows 7 x64 Ultimate上でVMware Player 7.1.2のIntel VT-x/EPTまたはAMD-V/RVIを仮想化という機能を使ってUbuntu 14.04 x86_64を動かしました。
Ubuntu 14.04 x86_64上でQEMUの開発バージョンでKVMを使います。
ゲストOSは、Ubuntu 12.04 x86_64です。

実時間 kvm-clock
5分00秒 5分00秒

とくに大きな遅れは見られなかったです。ホストOSが複雑なので難しいのですが、kvm-clockが遅れの原因ではなさそうです。

準仮想化クロックを使っても時計が正確にならない

残念ですね。せっかく準仮想化クロックを導入しても時計が正確ではないです。VirtualBoxが1分で1秒以上遅れてしまうのは問題ですね。

マニュアルを読むとGuestAdditionsが時計を補正するとあります。どういう場合に補正されるのかが気になります。少なくとも準仮想化クロックをKVMにしたときは、補正されていないです。

準仮想化インターフェースのLegacyは、VBoxManageのヘルプを読むとVirtualBox 5.0以前に作られた仮想マシンを5.0以降で起動すると自動的に設定されるとあります。VirtualBoxのログを読むとLegacyが選ばれたときは準仮想化インターフェースとしてnone(なし)が選ばれています。そのため、Legacyとnoneは実質的な違いはないと思います。

何が原因で時計が遅れているのかを調べるため、次回ソースコードを追いかけて検討しようと思います。

Hyper-Vの準仮想化クロックのしくみ

***本記事にはプロモーションが含まれています。***

準仮想化クロックについていろいろ調べてみて、Hyper-Vでは何をやっているのだろうと疑問に思いました。

そこで、LinuxのHyper-V用準仮想化クロックのドライバを見てみることにしました。

準仮想化クロックは、ソースコードLinux/arch/x86/kernel/cpu/mshyperv.cで、hyperv_clocksourceという名前で登録されています。

しくみについて簡単にコメントがありました。MSRというCPU内部のレジスタにHV_X64_MSR_TIME_REF_COUNTという名前のレジスタがあります。そのレジスタを読むとパーティションカウンターという数値が読めます。これは、子パーティション(ゲスト)が作られてからのtick countという値です。このcountは、子パーティションが作られたとき0になり、100 nanosecond単位で増加します。

要するに子パーティションができてからの時間が分かります。

これで、ゲスト起動時に時刻が設定されていれば現在時刻を計算することができます。

後はどれくらいの頻度で値が更新され、どれくらいの頻度で見に行くのかですが、Windowsで何をやっているのかですね。

意外にシンプルなことをやっていますね。その分kvm-clockと比べて少し精度は落ちるのかもしれません。起動してからの経過時間を使って時計を正確にしようとしているのは、LinuxとWindowsで似ていて面白かったです。

Hyper-Vについて書かれたKVMの資料
KVM as a Microsoft-compatible hypervisor.

Hyper-Vのインターフェースについて書かれた公式資料
Requirements for implementing the Microsoft Hypervisor interface

準仮想化クロックを使用しているときのUbuntuゲストのNTP使用とSUSEの場合について

***本記事にはプロモーションが含まれています。***

準仮想化クロック(kvm-clock)を使用しているとき、UbuntuゲストでNTPを使用しなくてもいいというような記事がありました。

それでいろいろ調べてみました。ところが、よく見るとUbuntuのWikiのヘルプページはひんぱんに書き換えられているらしいです。最近のヘルプではUbuntuをゲストOSに使っているときもNTPを使ったほうがよいと書いてあります。ゲストでNTPを使わなくてもkvm-clockは正確だそうです。

KVM/FAQ

kvm-clockだけ正確でもシステムクロックが正確にならないと意味ないと思うのですが、後は自分でやってねというスタンスでしょう。

kvm-clockは、システムが起動してからの経過時間を供給しますが、閏秒などの情報を供給しません。

というわけで、kvm-clockを使っているときも時計を正確にしたければNTPを使いましょう。

SUSEのマニュアルだと、ゲストに使ったときはNTPを使わないようにという説明があるのですが、理由がはっきりしません。

Xenの場合はカーネルパラメータにxen.independent_wallclockがあります。これを使う場合はNTPを使うと2重に時計を管理することになり不具合が出るという報告があります。

また、Xenを使っているときでも、xen.independent_wallclock=1にしてNTPを使ったほうがいいというメールもあります。

sistemad telling me "Time has been changed", only on xen guests?

システムクロックを同期する方法が他にあるかと思いましたが、いくら検索してみても情報が出てきません。NTPなしで使用してみて問題が出るようであればNTPを使ったほうがいいと思います。kvm-clockのしくみから見ても、そのほうが自然です。

準仮想化クロックkvmclockのしくみ

***本記事にはプロモーションが含まれています。***

準仮想化クロックのしくみについて解説してるブログがありました。

KVM pvclock

まず、ゲストOSが読めるメモリーをMSRを使って登録しておきます。そこへKVMがホストの起動してからの時間とTSC(Time Stamp Counter)を書き込みます。ゲストOSは時間を知りたいときに、まず現在のTSCを読みます。そして、メモリー上の起動してからの時間とTSCの差分の値を使って現在時間を割り出します。

ホストの起動したときの時刻は別に保存してあるそうです。

メモリーを使って値のやり取りをしていることと、TSCを使っているのが特徴かなと思います。

メモリーの値がアップデートされるのはホストOSからゲストOSに制御が移るVM eventの前だそうです。

時計がどれだけ正確化は、ゲストOSがどういうタイミングで時計をチェックして更新するかによります。
Linuxのシステムクロックについては、こちらの解説がくわしいです。4回の連載になっていて、kvm-clockについてもpvclockとして解説があります。
kvm-clockはRTCのようにハードウェアクロックの1種とされているようですが。

ハードウェアの時計とシステムクロックの同期は、システムの起動時とサスペンド、レジューム時に行われるそうです。その他に、getnstimeofday()/ktime_get_real()はハードウェアの時計も参照するとなっています。、gettimeofday()はハードウェアの時計を参照するようです。

カーネルにおけるタイマー事情 ~第3回 IAマシンのもつ各種計時ハードウェア~

準仮想化クロックを使っているときは、ホストOSにNTPを動かしていることが大切ですね。ゲストOSで動かしたほうがいいかどうかはディストリビューションによって意見が分かれるようです。

KVMにおいて ホストとゲストの時間管理はNTPを用いるべきか?

ゲストOSでNTPを使わなかった場合、ハードウェアの時計であるkvm-clockをゲストOSのシステムクロックに反映させる必要があります。UbuntuやSUSEにそういう仕組みがありましたっけ。確認が必要です。

以上簡単ですが準仮想化クロックについて調べてみました。

追記
ハードウェアクロックというとRTC(Real Time Clock)のことを指すそうです。kvm-clockは、ハードウェアの時計と書き直しました。

追記(2015/08/09)
KVMがメモリに値を書き込む頻度についてLinuxのカーネルソースを調べたところ、そう頻繁には値が更新されていないことがわかりました。

VirtualBox 5.0の準仮想化クロックの速度測定

***本記事にはプロモーションが含まれています。***

VirtualBox 5.0の準仮想化クロックをgettimeofday()を使って測定された方がいらっしゃいました。

VirtualBox 5 で利用可能になった Paravirtualization 機能 kvmclock を使う

kvm-clockは、TSC(Time Stamp Counter)より2倍くらい遅いそうです。

TSCはCPUが刻んでいるタイマーです。タイマーとしては一定のリズムを刻んでほしいのです。しかし、昔のCPUではCPUがスリープモードになったりして周波数を落とすと、一緒になって遅くなってしまうことがあったそうです。最近のCPUでは大丈夫なようですが。また、TSCの値がCPUのコアごとに少しずつずれてしまうのです。それで、なかなか安定したタイマーとしては使いにくいのです。

調べてみると、kvm-clockもTSCを使っています。詳しくは次の記事に書きます。

VirtualBox 5.0のSMPスピンロックの確認

***本記事にはプロモーションが含まれています。***

VirtualBox 5.0では、Linuxゲストに対してKVMタイプとして準仮想化クロックとSMPスピンロックが提供されます。

今回は、SMPスピンロックを確認してみます。

ベンチマークとしてUnixBench 5.1.3を用いました。

準仮想化インターフェースで”なし”と”KVM”を選んでそれぞれUnixBenchを走らせます。

ゲストOSはUbuntu 12.04で仮想CPUを2CPUで行いました。

まずはUnixBenchをダウンロードしてきて解凍しベンチマークを走らせます。
-iというオプションは測定を各項目で1回に制限するものです。そうしないと、10回やってしまい30分くらい時間がかかります。

wget https://byte-unixbench.googlecode.com/files/UnixBench5.1.3.tgz
tar xvzf UnixBench5.1.3.tgz
cd UnixBench
./Run -i 1

準仮想化インターフェースを変えても結果はあまり変わらなかったのですが、Index Scoreと特に値が大きく変わったPipe-based context switchingをまとめました。

Index Score

準仮想化インターフェース 1CPU 2CPU
なし 1739.7 2912.0
KVM 1910.0 3278.5

Pipe-based context switching

準仮想化インターフェース 1CPU 2CPU
なし 329.3 565.5
KVM 919.5 1814.0

Pipe-based context switchingというのは、プロセスのコンテキストスイッチを起こさせることでOSとCPUの性能の違いを見るものです。コンテキストスイッチとは、複数のスレッドやプロセスの実行の順番を変えて実行することです。

準仮想化インターフェースにKVMを選ぶことで565.5から1814.0と3倍くらい性能が上がっていることが分かります。

Index Scoreの値が変わったのは主にPipe-based context switchingが変わったことによるものです。

ただ、実際にこの違いが分かるかというと、マルチスレッドのプログラムをぶん回したりサーバーで複数のプロセスを高負荷で動かすことをしないと実感できないと思います。

以上、VirtualBox 5.0のSMPスピンロックについて確認してみました。

OpenStackでできること、変わること

***本記事にはプロモーションが含まれています。***

OpenStackのセミナーの様子が報告されています。

「分かる、できる、本当に使える、OpenStack超入門」セミナーリポート~ユーザー、ベンダーが本音で語った「できること、変わること」~ (1/3)

報告をピックアップしてみると次のようになります。

バージョンアップは負担になる。まずは使ってみること。

コスト意識は大切。OpenStack APIが使えればベンダーロックインは避けられる。

小さく始めて大きく育てること。

とにかく自動化すること。とにかくテストすること。手動で行わないことが大切です。

バージョンアップの問題は実例がそろい出したところです。

企業文化を変えることが必要です。

導入にはそれなりに学習コストがかかることが分かります。企業文化を変えることも思わぬ障害になるかもしれません。今まで慣れてきた「動いているものは触るな」という文化にはそぐわないものですので。まずは使ってみることというのが一番初めにやることかなという気がします。

VirtualBox 5.0の準仮想化クロック

***本記事にはプロモーションが含まれています。***

VirtualBox 5.0が登場しました。

VirtualBox

プレスリリースによると次のような特徴があります。

  • WindowsとLinuxゲストの準仮想化のサポート
  • CPU使用の改善。CPUの命令が増えています。
  • USB 3.0のサポート
  • Windowsのドラッグアンドドロップのサポート
  • ディスクイメージの暗号化

Linuxゲストの準仮想化をサポートするというので、早速インストールしてみました。

前回にも書きましたが、Linuxゲストの準仮想化はXenのように準仮想化専用のカーネルを動かすのではなく、準仮想化インターフェースに機能を提供してエミュレーションの精度をあげるものです。

Linuxゲストには、KVMタイプとして準仮想化クロックとSMPスピンロックが提供されます。この準仮想化クロックを確認してみます。

今回はUbuntu 12.04ゲストで確認しました。

まずは順番にインストールしていきます。

  • VirtualBox 5.0のインストール
  • Extenstion Packのインストール
  • ゲストOSを起動してGuest AdditionsをゲストOSにインストール
  • 一度シャットダウンして、仮想マシンの設定で、システムー>アクセラレーション準仮想化インターフェースで、KVMもしくはデフォルトを選びます。デフォルトはゲストOSのタイプによって提供するインターフェースを変えてくれます。
  • ゲストOSの起動

起動したら、dmesgで起動時のメッセージを確認します。

$ dmesg |grep KVM
[ 4.515926] Booting paravirtualized kernel on KVM

このようにon KVMとでていれば成功です。

同様にkvm-clockを確認することで準仮想化クロックを使っていることが分かります。

$ dmesg |grep kvm-clock
[ 0.000000] kvm-clock: Using msrs 4b564d01 and 4b564d00
[ 0.000000] kvm-clock: cpu 0, msr 0:1cf9781, boot clock
[ 4.516128] kvm-clock: cpu 0, msr 0:7fc12781, primary cpu clock
[ 4.730889] kvm-clock: cpu 1, msr 0:7fd12781, secondary cpu clock
[ 4.798499] Switching to clocksource kvm-clock

もし、kvm-clockなんて出てこなかったらkvm-clockがシステムに存在するか次のように調べます。

$ cat /sys/devices/system/clocksource/clocksource0/available_clocksource
kvm-clock tsc acpi_pm

もし、なければカーネルにCONFIG_PARAVIRT_CLOCKが設定されていたか調べます。

$ less /boot/config-hogehoge
CONFIG_PARAVIRT=y
CONFIG_PARAVIRT_SPINLOCKS=y
CONFIG_PARAVIRT_CLOCK=y

こうなっていなければ、準仮想化クロックは使えません。CONFIG_PARAVIRT_CLOCKがあって、kvm-clockがないときは、VirtualBoxがインターフェースを提供できていないです。

準仮想化クロックを使うことで時間の精度が上がります。でも、ゲストOS上でもNTPを使ったほうがよいようです。

KVMにおいて ホストとゲストの時間管理はNTPを用いるべきか?

準仮想化クロックと共に提供されるSMPスピンロックはマルチCPUでたくさんのプロセスを同時に起動したときの効率を高めてくれるものです。

ベンチマークを取らないと確認できないと思います。

ネットワークやディスクのアクセスも改善されるのかも確認が必要ですね。

以上、準仮想化クロックについて確認してみました。