ラベル タイマー の投稿を表示しています。 すべての投稿を表示
ラベル タイマー の投稿を表示しています。 すべての投稿を表示

2012年1月5日木曜日

FreeBSDで使うLinux KVM準仮想化タイマ

こんにちわ。@hasegawです。あけましておめでとうございます。今年もよろしくお願いします!


かなり久々のブログ更新となりますが、本日は カーネル/VM Advent Calendar にてまたまた私の当番!ってことで、今回は FreeBSD 8.1-RELEASE に Linux KVM 用のタイムカウンタを実装してみたというネタでお話しようかと思います。


昨年のネタ: FreeBSD VIMAGEを使ったTCP/IPのルーティング デモンストレーション




■ Linux KVM のタイマ機能

まずバックグラウンドについて説明しておきましょう。 FreeBSD のはじめとする殆どの OS では、以下の計算式でシステム時間(年月日・時分秒)を把握しています。

システム時間 = システム起動時の時間 + システム起動後の経過時間

このうち「システム起動時の時間」はRTC(リアルタイムクロック)の値で初期化し、「システム起動後の経過時間」はOSが定期的にカウンタをインクリメントしています。しかし、仮想化環境ではこの仕組みをそのまま適用すると時刻ズレの原因となりやすいことは、この記事を読むような方であればご存じのことでしょう。

そこで、タイマの仮想化です。 Linux KVM でもタイマの準仮想化機能があります。

KVM PVclock
http://www.linux-kvm.org/page/KVMClock

これは、ゲスト OS が「おいら時間情報がほしいから、メモリのここに定期的に書いておいてちょ」と仮想マシンモニタにお願いすると、適当な間隔で仮想マシンモニタが指定されたメモリ上に時刻情報を書いておいてくれる、という仕組みです。

ただ、 KVM のサイトを見るとこの機能は Linux guests only. と書いてあります。

どうして
Linux でしか使えないの?
それは、ゲスト OS が KVM PV Clock に対応する必要があるからです。


しかし KVM の PV Clock は決して難しいものではありません。もともと Xen にインスパイアされて殆ど同じ汎用的なデータ構造を持っているので、すでに BSDL で Xen 対応のコードがある FreeBSD であれば私のヘナチョコがちょろちょろっとコピペして済むレベルです。対応するかしないかは仮想マシンモニタ開発側&ゲスト OS 開発側のモチベーション次第なだけなのです!よっしゃ、私は最近 FreeBSD 使っていないけど、やってみるかー。

ってことでとりあえず動くモノを作ってみましたとさ。



■ FreeBSD 用 timecounter: kvmclock 失敗編


時は 2011 年 10 月。今回のモノは FreeBSD の timecounter として実装しました。 Linux で言う clocksource ですね。システム起動時には以下のイメージで初期化されます。

Timecounter "kvmclock" frequency 1800000536 Hz quality 900


Pvclockgen1500px


このタイムカウンタは、 Linux KVM が定期的に TSC のカウンタをメモリに書いてくれるので、それを使って時を刻んでいます。

struct pvclock_vcpu_time_info {

        u32   version;

        u32   pad0;

        u64   tsc_timestamp;

        u64   system_time;

        u32   tsc_to_system_mul;

        s8    tsc_shift;

        u8    pad[3];

} __attribute__((__packed__)); /* 32 bytes */

とりあえず動いたのですが、しかし実際には問題が起きて使い物になりませんでした。理由は桁あふれです。1.8GHzでカウントアップされていくタイマだと、あっという間に32ビットのカウンタは一週してゼロに戻ります。この結果、アイドル時間が多いと時計が遅れるという最高にイケていないタイムカウンタになりました。なお while true; do date > /dev/null ; done とかしていると非常に精度が高いカウンタであったことは申し添えておきます!


■ FreeBSD用timecounter: kvmclock その2


時は2011年12月29日。年末年始はスノーボードに行くので今作らなかったら Advent Calendar のネタがありません。ってことで、とりあえずバージョンアップしました。

Timecounter "kvmclock" frequency 1000000 Hz quality 900


Pvclockgen2500px

このタイマはゲストOSに対して仮想的にマイクロ秒精度のタイマ機能を提供します。


前回は Linux KVM がシャドウしてくれた TSC の値を使って時を刻んでいましたが、今回は Linux KVM がシャドウしてくれたシステム時間をベースに時を刻みます。

struct pvclock_wall_clock {

        u32   version;

        u32   sec;

        u32   nsec;

} __attribute__((__packed__));


このデータ自体はナノ秒オーダーのものですが、 t = sec * 1000 + nsec / 1000 としてマイクロ秒のオーダーに変換し、これの情報を OS 側に食わせます。この形であればカーネルが気づかないうちに桁あふれなんてことがそうそう起きません。


■ 評価

早速作ったタイムカウンタで仮想マシンを動かしてみました。素人ハックの結果としては割と良好かと思います。


Pvclockcomparision


これは while true; do date; sleep 1; done の結果をゲスト(上)とホスト(下)で実行しっぱなしにした結果です。

5時8分0秒が飛んでいるので不安定っぽく見えますが、 sleep 1 の待ち時間がフラついているという問題はあるもののホスト OS から 1 秒以上時間がずれることは無くなりました。 sleep の精度が低い問題はありつつも gettimeofday は安定しているようです。

また、vCPUがアイドルの場合も、負荷をかけた場合でも、システムの時刻がホストとゲストの間で大きくズレることはないようです。


12 月 29 日から 1 月 4 日までの 5 日間放置しても、システム時間のずれは生じなかった

Pvclock_0105


■ もっと頑張らないといけないこと

とりあえず自覚している課題は以下の部分です。

  • 実はまだ KVM のプローブをしていない。 MSR を一発たたけばいいので、いつでもできます。

  • vCPU != 1 の場合を想定していないし、評価していない。vCPU ごとにカウンタを進める必要がありますので、今のコードのままではまずい。このままでも動くかもしれないけど。

  • sleep 1 が不安定 ゚+.(・ω・)゚+.゚ ヘボグラマなので細かい修正はエキスパートにお願いすればいいかなっと。

現時点のやるきのないコードの一部(試行錯誤の跡付き)



Pvclockcode_2





■ おわりに

というわけで、「タイマ作りました、動いてます」というとっても退屈な記事ですが、、こんな事してみましたよ、ってことで。私のようなヘボでもいじくれる所があるというのは有り難いものです。

Advent Calendar 参加者の皆さんの記事、楽しく読ませていただきました。今後ともよろしくお願いします。


2009年8月30日日曜日

hpetオプション

 High Precision Event Timer (HPET)をエミュレートします。 (HVMドメイン)





 HPETは、これまでのPC/AT互換機で標準搭載されていたPITと比較し、高精度・高機能を実現したタイマーデバイスです。HPETを利用するにはHPETに対応したOS(Windows Vista、Windows Server 2008、Linux 2.6など)が必要です。


■ 書式

hpet=<n>

■ <n>の値


  • 1 …… 有効

  • 0 …… 無効





■ 実行例

hpet=0の場合

hvm-domain$ sudo cat /sys/devices/system/clocksource/clocksource0/available_clocksource
hpet acpi_pm jiffies tsc
hvm-domain$ sudo cat /sys/devices/system/clocksource/clocksource0/current_clocksource
hpet

hpet=0の場合

hvm-domain$ sudo cat /sys/devices/system/clocksource/clocksource0/available_clocksource
acpi_pm jiffies tsc
hvm-domain$ sudo cat /sys/devices/system/clocksource/clocksource0/current_clocksource
acpi_pm

■ 注意点


  • HPETエミュレーションを利用した場合でも、タイマのエミュレーション精度が向上するとは限りません。

  • Xen 3.3以降

softtsc(TSCのエミュレーション)

最近のXenでは、Xen起動時にsofttscオプションを指定することで、HVMドメインにおいてTSCをエミュレーションできるようになります。この機能を使うことにより、HVMドメインの時刻のずれをある程度抑制できます。




■設定例

/boot/grub/menu.lst抜粋

title Xen-unstable + 2.6.18.8-xen, iommu=0
        root (hd0,0)
        kernel /xen-3.5.gz iommu=0 com1=9600,8n1 console=com1,vga softtsc
        module /vmlinuz-2.6.18.8-xen ro root=LABEL=/
        module /initrd-2.6.18.8-xen.img

■実行例

softtscオプションが有効な場合、HVMドメインがRDTSCインストラクションを発行すると、Xenが管理するドメインの実行時間を基にTSCカウンタの値が決定されます。また、HVMドメインは(CPUの実働クロックに関わらず)仮想CPUのクロックを1000MHzと報告します。

softtscオプションありの場合

root@vm245:~# cat /proc/cpuinfo
 processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Intel(R) Core(TM)2 Quad CPU    Q8400  @ 2.66GHz
stepping        : 10
cpu MHz         : 1000.005
……

デフォルト(softtscオプションなし)の場合は、HVMドメインがRDTSCインストラクションを発行すると、CPUが持つTSCカウンタの値をそのまま受け取ります。

softtscオプションなしの場合

hasegaw@vm245:~$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Intel(R) Core(TM)2 Quad CPU    Q8400  @ 2.66GHz
stepping        : 10
cpu MHz         : 2666.414
……

■注意点


  • softtscオプションを指定した場合、そのXenハイパーバイザ上で実行されるすべてのHVMドメインに機能します。

  • 将来的には仮想CPUのクロック速度、ドメイン単位での有効化/無効化が可能になると思われます。

  • マージ時期 2008年7月(xen-unstable)