「クラウド」カテゴリーアーカイブ

AWSのIoTサポート

AWSのre:invent 2015でIoTのサポートが発表されましたね。

Amazon Web Servicesで膨大なIoTデバイスを司る「AWS IoT」発表

AWS IoT ButtonでAWS IoTを体験してみた! #reinvent

会場で配布されたデバイスでは、ボタンを押すと電圧値が送信される物のようです。

[速報]AWS re:Invent 2日目は、IoT、コンテナ―、Lambdaなどで発表が相次ぐ

かかる費用は100万メッセージあたり8ドルということです。これって安いのでしょうか。すごくたくさんメッセージをやり取りすることを想定しているようですね。

たとえば心拍数に応じてメッセージを送ることを想定しているのでしょうか。

IoTの数が多くなればこのくらいの値段でないとやっていけないのかな。

IoTのための通信の課金のしくみ

格安SIMで通信の料金はずい分下がってきましたが、IoTのためにはもう1段下がらないといけないだろうなと思っていました。

そしたら、次のようなサービスが出てきました。

格安SIMによるドコモ回線をAmazonクラウド上でプログラマブルに制御。ソラコムがネットデバイス向けの新通信サービスを提供開始

基本使用量1日10円、1MBあたり0.2円ということでまさにIoT向けのものになっています。Amazon AWSを使うことで通信制御もできるそうです。これからこういうサービスが増えそうな気がします。

ティックレスLinuxカーネルと準仮想化クロック

ゲストOSの時計の遅れにはティックレスLinuxカーネルが関係していた

このところVirtualBoxを契機として、準仮想化クロックについて調べてきました。
ところが、SUSEのマニュアルがゲストOSでNTPを使わないことを推奨していることの理由がどうしてもわかりませんでした。
昔QEMUにかかわったとき、Linuxの割り込み頻度が1000Hzから250Hzに変わったことを思い出しました。

すると、こんな記事が見つかりました。

仮想化しても時刻ずれが発生しないCentOS6

最近のLinuxカーネルはティックレスになっていて、仮想化しても時刻がずれないというのです。そこで、ティックレスカーネルについて調べてみました。

Linuxの割り込み頻度の変遷

VMwareのサイトにLinuxの割り込み頻度の変遷がまとめられています。

Linuxの2.4ではHZ=100Hzだったのが、2.6ではHZ=1000Hzに変わり、2.6.14以降はHZ=250Hzになっています。

ティックレスカーネルのサポートはLinux 2.6.18より始まっています。

ティックレスカーネルのしくみ

昔はPIT(Programmable Interval Timer)を使って定期的に割り込みをかけていました。100Hzなら10msに一度カーネルに割り込みが発生するようにプログラムします。割り込みが発生したら10msたったとして時計を進めていたわけです。

Linuxの割り込み頻度は、多いほうが時計の精度が高いように思います。しかし割り込みの時間内に処理が終わらず次の割り込みが起こってしまうと割り込みが失われた状態になり時計が狂ってきます。

仮想化環境で時計の狂いが大きかったのはこれが大きな原因です。

ティックレスカーネルは時間を決めて定期的に割り込みをかけることをやめてしまうものです。その代わり1度きりのone shot timerというタイマーを使って割り込みまでの時間を設定して割り込みをかけます。動いているプロセスが少ないときは長い時間割り込まないようにします。動いているときは、定期的に割り込みます。

時間があらかじめ決まっていないので、カーネルがsleepしてどれくらい時間がかかったかを毎度ハードウェアをチェックする必要があります。それをクロックソースと呼んでいます。

クロックソースとして代表的なものが、TSC(Time Stamp Counter)、ACPI PM(ACPI Power Management timer)、HPET(High Precision Event Timer)などがあります。

ティックレスカーネルの適用状況

Linuxのディストリビューションがティックレスカーネルを採用した時期はまちまちです。以下にまとめてみました。

ディストリビューション バージョン 時期
Red Hat Enterprise Linux 6 2010-11-09
CentOS 6 2011-07-10
Fedora 7 x86 2007-05-31
Fedora 8 x86_64 2007-11-8
Ubuntu 7.10 2007-10-18
SUSE Linux Enterprise Server 12 2014-10-28

UbuntuとFedoraが同時期で、Red HatとCentOSが次で、SUSEの順番です。

使っている人が多いと思われるCentOSは6からのサポートです。最近になって時計の話題を見かけることが少なくなったことはこのためだと思われます。

また、Ubuntuの方が時計が正確だという報告があったのですがティックレスカーネルの採用時期が早かったためでしょう。

SUSEは本当に最近のサポートですね。

ティックレスカーネルと準仮想化クロックと組み合わせると

ティックレスカーネルになってクロックソースを指定できるようになりました。最近のディストリビューションでは準仮想化クロックを採用しているところばかりです。準仮想化クロックといってもこれまで調べたようにその中身はTSCを使っています。ゲストOSの時計が正確になったのは、CPUの周波数の変化によってTSCの周波数が変化しなくなっていることも大きいと思います。

Linuxカーネルの進化とCPUの進化によって時計の正確さが増したということでしょう。

VirtualBoxのゲストの時計の補正を停止する方法

ゲストの時計の補正を止める

VirtualBoxは、準仮想化インターフェースが”なし”のとき、ゲストOSとホストOSの時計は同期しています。でも、何かのときにゲストとホストの時計の同期を止めたいことがあると思います。

こちらを参考に紹介します。ゲストOSがWindowsの場合が載っています。

なお、TSCTiedToExecutionというのはTSCに関する別の設定ですので今回は設定しません。

VirtualBoxがホストの時計をゲストに供給するのを止める

時計の補正を止めたいゲストOSをシャットダウンします。

設定でシステム―>アクセラレーション―>準仮想化インターフェースで”なし”を選びます。

Legacyを選んでも”なし”と同じです。他を選ぶと自動的に補正されなくなります。

VirtualBoxのインストールされているフォルダに行きます。

cd "C:\Program Files\Oracle\VirtualBox"

次のコマンドでゲストOSのリストを見ることができます。

C:\Program Files\Oracle\VirtualBox> VBoxManage list vms

その名前を使って次のようにするとゲストがホストの時計を参照することを止めることができます。"Guest Name"というのは自分の設定したいゲストの名前です。

C:\Program Files\Oracle\VirtualBox> VBoxManage setextradata "Guest Name" "VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled" "1"

このコマンドで、ゲストOSのところにある設定ファイル"Guest Name".vboxに設定が書き込まれます。

この後で、ゲストOSを再起動するとゲストOSの時計ががホストに同期するのは停止されます。

GuestAdditionsの時計の同期を止める

上記だけでも時計が同期しなくなります。
ゲストOS上でも、Guest Additionsが同期しようとしていますので、念のためそれを止める方法です。

ゲストOSがUbuntu 12.04 x64の場合です。

現在動いているVBoxServiceを止めます。

sudo service vboxadd-service stop

タイマーの同期をとめたままGuest Additionsを動かします。

sudo /usr/sbin/VBoxService --disable-timesync

これでゲストとホストの時計の同期は止まるはずです。この方法だと、ゲストOSを再起動するとまた--disable-timesyncなしでサービスが動きます。

ゲストとホストの時計の同期を再開する

VBoxManageの最後の"1"をなくして実行することで設定のエントリーをなくすことができます。"0"とすることでも再開できます。

C:\Program Files\Oracle\VirtualBox> VBoxManage setextradata "Guest Name" "VBoxInternal/Devices/VMMDev/0/Config/GetHostTimeDisabled"

ゲストの実行中でもコマンドを実行できますが、再起動しないと有効になりません。

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

以前、準仮想化クロック(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のカーネルソースを調べたところ、そう頻繁には値が更新されていないことがわかりました。