Core2 Quad で VMware Server の時刻が進む件は解決した

VMware Server 1.0.4 on Core2Quad で guest の時刻が進みまくり - daily dayflowerという現象があったのですが,なんとか解決にこぎつけることができました。

原因

  • NEC Express 5800 / 110Gd の BIOS が(EIST をきちんとサポートしていないためか)おかしな CPU frequency を返す
  • EIST 無効時は Core2 Quad Q6600 は 2.4GHz で動いている
  • ホスト側は(自力でキャリブレーションしているのか)2.4GHz であると認識している(∴ホストの時刻は狂わない)
  • VMware Server は ACPI 経由で CPU frequency を取得している
  • 先に上げたように ACPI 経由の CPU frequency 取得がおかしいので(フルパワー時)900MHz であると認識される
  • VMware Server は guest も host も 900MHz で動いているとみなす
  • 実際には 2.4GHz をベースとして割り込みが発生しているので 2.4GHz / 900MHz(≒2.67倍)の割り込みが guest に伝達する
  • このため clocksource を何にしたところで,最悪 2.67 倍のスピードで時刻が進んでいく(実際には割り込みのとりこぼし lost ticks が発生するのでそこまで早くはならない)

対策

  • host のクロック変動を避けるため host の cpuspeed サービスを停止しておく
  • Host Power Management Causes Problems with Guest Timekeeping on Linux Hosts に従って /etc/vmware/config に正しい host CPU frequency を設定しておく
  • guest のカーネルパラメータに notsc clocksource=pit を追加し,guest の kernel サイドのアグレッシブな時刻補正を無効にしておく((お好みで nosmp noapic nolapic 等を追加することで,割り込みハードウェアを IO-APIC ではなく XT-PIC にして割り込み負荷を軽減させることもできます))
  • guest に VMware Tools をインストールして syncTime を有効にする

以下調査経過が長々と続きます。

調査結果

まずは /proc/cpuinfo を見てみます。


# cat /proc/cpuinfo

processor : 0
vendor_id : GenuineIntel
cpu family : 6
model : 15
model name : Intel(R) Core(TM)2 Quad CPU Q6600 @ 2.40GHz
stepping : 11
cpu MHz : 600.000
cache size : 4096 KB
physical id : 0
siblings : 4
core id : 0
cpu cores : 4
fpu : yes
fpu_exception : yes
cpuid level : 10
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov
pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm syscall nx lm constant_tsc
pni monitor ds_cpl vmx est tm2 cx16 xtpr lahf_lm
bogomips : 4803.45
clflush size : 64
cache_alignment : 64
address sizes : 36 bits physical, 48 bits virtual
power management:

CPU が EIST をサポートしていること,また現在のクロックが 600MHz である(と認識されている)ことがわかります。

ひょっとすると cpuspeed サービスが自動的にクロックを落としているのでしょうか。

# service cpuspeed status

Frequency scaling enabled using ondemand governor

ondemand という governor によってクロック周波数が決まっていることがわかります。どのような governor があり,どのような意味をもつかについては cpufreq-selectorのメモ (blog@browncat.org)が詳しいです。

さて,この環境ではどのような周波数レンジがサポートされているのでしょうか。/sys/devices/system/cpu/cpu0/cpufreq を覗くといろいろわかります。

# cd /sys/devices/system/cpu/cpu0/cpufreq

# ls -F

affected_cpus     ondemand/                      scaling_driver
cpuinfo_cur_freq  scaling_available_frequencies  scaling_governor
cpuinfo_max_freq  scaling_available_governors    scaling_max_freq
cpuinfo_min_freq  scaling_cur_freq               scaling_min_freq

# for f (*); [ -f $f ] && ( echo -n "$f: "; cat $f )

affected_cpus: 0 1 2 3
cpuinfo_cur_freq: 600000
cpuinfo_max_freq: 900000
cpuinfo_min_freq: 600000
scaling_available_frequencies: 900000 600000 
scaling_available_governors: ondemand userspace performance 
scaling_cur_freq: 600000
scaling_driver: centrino
scaling_governor: ondemand
scaling_max_freq: 900000
scaling_min_freq: 600000

これだけでもある程度の情報はわかりますが,これらの情報を見やすく整形してくれるのが cpufreq-info というコマンドです(標準ではインストールされていません)。

# yum install cpufreq-utils

# cpufreq-info

cpufrequtils 002: cpufreq-info (C) Dominik Brodowski 2004-2006
Report errors and bugs to linux@brodo.de, please.
analyzing CPU 0:
  driver: centrino
  CPUs which need to switch frequency at the same time: 0 1 2 3
  hardware limits: 600 MHz - 900 MHz
  available frequency steps: 900 MHz, 600 MHz
  available cpufreq governors: ondemand, userspace, performance
  current policy: frequency should be within 600 MHz and 900 MHz.
                  The governor "ondemand" may decide which speed to use
                  within this range.
  current CPU frequency is 600 MHz (asserted by call to hardware).

...... snip ......

現状で ondemand, userspace, performance の3種類の governor があり,CPU clock は 600MHz と 9000MHz の2種類が設定されうる,ということがわかります。

えっ?最高で 900MHz なの?

念のために dmesg で確認してみると……

# dmesg

...... snip ......
time.c: Using 14.318180 MHz WALL HPET GTOD HPET timer.
time.c: Detected 2400.089 MHz processor.
...... snip ......

一応 2.4GHz のプロセッサであることが認識されています。これで host の時刻が狂うことはないはずです。


ですがなぜ 600MHz, 900MHz なのでしょう。実力をフルに発揮できていないのでしょうか。

と思って調べたところ,まったく同じような現象に遭遇している例を発見しました。

なぜ表示されるクロックが900MHz、600MHzという奇妙な値なのか、ということに関して、Intel社に在籍しているacpi-cpufreqの開発者の方にメールで質問を送ってみたところ、BIOSがエクスポートしている値がおかしいのではないか、との回答を得ました。

このマザーボードで使用しているBIOSではEISTで指定可能な周波数の値を設定することは出来ないことと、周波数とベンチマークの比率に整合性がとれているということを考えると、BIOSに問題があると推測されます。現時点ではそれ以上のことは分かっていません。

http://www.clustcom.com/content/view/88/32/

うーむ BIOS が怪しいのですか。たしかに Q6600 は 110Gd で正式にサポートされている CPU ではありませんし,EIST の項目もないので怪しい。ただ引用元の情報を見ていただければわかると思いますが,表示上おかしいだけで,実際には 900MHz のときに 2.4GHz で動いているようです。

引用元によると acpi-cpufreq を disable すると OK になるそうですが,手元の環境で cpuspeed を disable してリブートをかけてみても,900MHz にはなるものの 2.4GHz にはなりませんでした。


この誤認識がどのような弊害をもたらしているかですが。

VMware Server の vmware.log から抜粋します。

Dec 06 18:04:09: vmx| KHZEstimate 900000
Dec 06 18:04:09: vmx| MHZEstimate 900

このように 900MHz だと推定されています。それで guest の dmesg の結果ですが,

time.c: Using 3.579545 MHz WALL PM GTOD PM timer.
time.c: Detected 899.923 MHz processor.

やはり,guest も 900MHz のクロックで動作しているとみなされているようです。このせいで時刻がどんどん先にすすんでいるようです。


では,対策は,というと VMware の Knowledge Base にありました。

To prevent guest clocks from running too quickly, specify the correct maximum host CPU speed in your global configuration file, /etc/vmware/config. If this file exists, edit it with a text editor, adding the lines described below. The file may not exist. If it does not exist, create it as a plain text file.

The example presented here assumes that the host computer has a maximum speed of 1700MHz. The first line is the most important one. It should be your host computer's maximum speed in kHz -- that is, its speed in MHz times 1000, or its speed in GHz times 1000000. Add the following lines to your global configuration file:

  host.cpukHz = 1700000
  host.noTSC = TRUE
  ptsc.noTSC = TRUE
Host Power Management Causes Problems with Guest Timekeeping on Linux Hosts

本来は SpeedStep(や EIST や PowerNow や Cool'n'Quiet)で host CPU のクロックが変動する際に用いるものですが,今回のように誤認識されている場合にもこのクロック数強制設定が使えそうです。


そこで上記設定を /etc/vmware/config に書き足し,念のために guest の kernel options で notscclocksource=pit を追加,そして VMware Tools の時刻同期機能を使ってみました。

その結果。

まず vmware.log ですが,

...... snip ......

Dec 07 10:23:19: vmx| DICT --- CONFIGURATION

...... snip ......

Dec 07 10:23:19: vmx| DICT --- USER PREFERENCES
Dec 07 10:23:19: vmx| DICT --- USER DEFAULTS
Dec 07 10:23:19: vmx| DICT --- HOST DEFAULTS

...... snip ......

Dec 07 10:23:19: vmx| DICT               host.cpukHz = 2400000
Dec 07 10:23:19: vmx| DICT                host.noTSC = TRUE
Dec 07 10:23:19: vmx| DICT                ptsc.noTSC = TRUE
Dec 07 10:23:19: vmx| DICT --- SITE DEFAULTS

...... snip ......

Dec 07 10:23:19: vmx| KHZEstimate 2400000
Dec 07 10:23:19: vmx| MHZEstimate 2400

...... snip ......

Dec 07 10:23:19: vmx| TimeTracker host to guest rate conversion 3949280226459 @ 
2400000000Hz -> 3949280226459 @ 2400000000Hz

...... snip ......

見事に 2.4GHz と認識されています。

さて,guest の dmesg です。

time.c: Using 3.579545 MHz WALL PM GTOD PM timer.
time.c: Detected 2399.846 MHz processor.

おお,こちらでも無事 2.4GHz として認識されたことがわかります。

念のために guest で一度 ntpdate しておいて,しばらくしてから時刻を調べてみます。

% /sbin/hwclock && date
2007年12月07日 10時38分44秒  -0.981510 秒
2007年 12月  7日 金曜日 10:38:44 JST

hwclock というのは RTC の時刻を調べるもので実質 host 側の時刻を調べるものだと思って下さい*1。後者の date については文字通り local time source の時刻を調べるものです。

結果をみると,ほぼ同じ時刻を刻んでいることがわかります。無事きちんと時刻を同期させることができるようになりました。

*1:厳密にいうと異なります。このへんはいつか続きを書きます