最近の仮想マシンはTickタイムも案外正確で感心した次第

１年に１回ぐらい、「そういえば仮想マシンではTickタイムが不正確だから、パフォーマンス試験を仮想マシン上の時計で計るのは不適切なんだったか？」と思いだすものの、実際どのくらい不正確なのかねというのは未検証で１０年ぐらい過ごしてきたのだが、今回は簡単に確認するところまではたどり着き、認識を新たにした。

思いのほか正確である。constant_tscとかnonstop_tscとか、難しいことはわからないが最近の進歩の結果らしい。
要らん心配事が減るのは大変良いことだ。

# 検証の仕方

１．手元のWindows 10 PC(物理)で現在時刻を表示する。

２．Windows 10 PCからcurl.exeで、Linux仮想マシン上のプログラムにhttpでアクセスする。プログラムはsleepで10分(600秒)待った後、応答を返す。

３．再度、手元のWindows 10 PC(物理)で現在時刻を表示する。

４．Windows 10 PCからcurl.exeで、Linux仮想マシン上のプログラムにhttpでアクセスする。プログラムはアクセス開始からtickカウントが10分(600秒)増えたら、応答を返す。

５．最後にまた、手元のWindows 10 PC(物理)で現在時刻を表示する。


Windowsで実行する具体的なコマンドは以下。

```
> powershell "get-date; curl.exe http://＜仮想マシンのIPアドレス＞/sleep; get-date; curl.exe http://＜仮想マシンのIPアドレス＞/ticktime; get-date;
```

Linux仮想マシン上で実行し、httpリクエストを受け付けるプログラム。Ruby+sinatra。

```ruby:time.rb
require "sinatra"
set :bind => "0.0.0.0"
set :port => "80"

get "/sleep" do
  res = ""
  res += Time.now().to_s() + "\n"
  res += `date`
  res += "sleep\n"
  `sleep 600`
  res += Time.now().to_s() + "\n"
  res += `date`
end

get "/ticktime" do
  res = ""
  res += Time.now().to_s() + "\n"
  res += `date`
  res += "ticktime\n"
  start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  while (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) <= 600.0; end
  res += Time.now().to_s() + "\n"
  res += `date`
end
```

# 検証１：Windows 10 PC＆VMware Workstation上のCentOS 8
Windows 10 PC(物理)で動作するVMWare Workstation 16 Proに、CentOS 8.3のゲストOSを導入して実行した結果。

```
2021年1月29日 0:40:17       → 「１．」の時間
2021-01-28 10:40:16 -0500
Thu Jan 28 10:40:16 EST 2021
sleep
2021-01-28 10:50:16 -0500
Thu Jan 28 10:50:16 EST 2021
2021年1月29日 0:50:17       → 「３．」の時間
2021-01-28 10:50:16 -0500
Thu Jan 28 10:50:16 EST 2021
ticktime
2021-01-28 11:00:16 -0500
Thu Jan 28 11:00:16 EST 2021
2021年1月29日 1:00:17       → 「５．」の時間
```

一応、OSで取得した/proc/cpuinfoのCPUフラグ。

```
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon nopl xtopology tsc_reliable nonstop_tsc cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 invpcid rdseed adx smap clflushopt xsaveopt xsavec xgetbv1 xsaves arat md_clear flush_l1d arch_capabilities
```

# 検証２：Amazon Lightsail上のCentOS 7
Sleepのところで一秒ずれるが、プログラム起動やhttpのオーバーヘッドもあるし、許容出来る。

```
2021年1月28日 23:49:21       → 「１．」の時間
2021-01-28 14:49:21 +0000
Thu Jan 28 14:49:21 UTC 2021
sleep
2021-01-28 14:59:21 +0000
Thu Jan 28 14:59:21 UTC 2021
2021年1月28日 23:59:22       → 「３．」の時間
2021-01-28 14:59:21 +0000
Thu Jan 28 14:59:21 UTC 2021
ticktime
2021-01-28 15:09:21 +0000
Thu Jan 28 15:09:21 UTC 2021
2021年1月29日 0:09:22       → 「５．」の時間
```

```
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm fsgsbase bmi1 avx2 smep bmi2 erms invpcid xsaveopt
```

# 検証３：IBM Cloud(Classic)上のRHEL 8
LocationをTokyoとして仮想マシン作ったのに時刻がCSTとはこれ如何に、という事に気が付いたが、まあ、時間の精度は申し分ない。

```
2021年1月29日 0:00:14       → 「１．」の時間
2021-01-28 09:00:13 -0600
Thu Jan 28 09:00:13 CST 2021
sleep
2021-01-28 09:10:13 -0600
Thu Jan 28 09:10:13 CST 2021
2021年1月29日 0:10:14       → 「３．」の時間
2021-01-28 09:10:14 -0600
Thu Jan 28 09:10:14 CST 2021
ticktime
2021-01-28 09:20:14 -0600
Thu Jan 28 09:20:14 CST 2021
2021年1月29日 0:20:14       → 「５．」の時間
```

```
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush acpi mmx fxsr sse sse2 ht syscall pdpe1gb rdtscp lm constant_tsc rep_good nopl cpuid pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb stibp fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt clwb xsaveopt xsavec xgetbv1 xsaves pku ospke md_clear flush_l1d
```