というわけで、昨日の記事を書いた後に思ったのは
ならばちゃんとC#版でコードを書いてみて同様の検証をすべきではないか?
との疑問が浮かび上がっちゃったのでさくっと書いてみました。
C#でコードを書くのは初めてなのでちょっと戸惑いましたが・・・。
using System; using System.Diagnostics; using System.Threading; namespace qpccs { class Program { static void Main(string[] args) { long lBegin,lEnd,lFreq; int i,nBegin,nEnd; for (i = 0; i < 10; i++) { nBegin = Environment.TickCount; lBegin = Stopwatch.GetTimestamp(); Thread.Sleep(1000); lEnd = Stopwatch.GetTimestamp(); nEnd = Environment.TickCount; lFreq = Stopwatch.Frequency; Console.WriteLine(nEnd - nBegin + ":" + ((double)lEnd - (double)lBegin) / (double)lFreq + "(" + lFreq + ")"); } } } }
時間検証用のタイマがtimeGetTimeからGetTickCountに変更されているので時間解像度がちょっと落ちていますが、これの目的はSleepの時間調整が正しいかを確認するためなのでこれで妥協です。
昨日のWinAPI版のコードとほぼ同じ動きをするはずです。(timeBeginPeriod~timeEndPeriodがなくなっているのでその影響はあるかもしれませんが)
これの検証結果がこんな感じです。実行条件は昨日と同じとします。C#.NETのランタイムバージョンはVisualStudio2005で作成した関係上、<v2.0>を使用しています。
WinXP 32bit 無負荷 | 1000:0.478172842136056(2666410000) |
WinXP 32bit MPEG再生 | 1000:0.851279321634707(2666410000) |
WinXP 32bit CPUベンチ | 1000:1.00184371345742(2666410000) |
WinXP 32bit OCベンチ | 1000:1.02587881683612(2666410000) |
Win7 64bit 無負荷 | 1014:1.01392907424462(2603906) |
Win7 64bit MPEG再生 | 1014:0.999912823273958(2603906) |
Win7 64bit CPUベンチ | 1014:1.01390411174597(2603906) |
Win7 64bit OCベンチ | 1014:1.01388951828522(2603906) |
ま、比較すればわかると思いますが、WinAPI版とほとんど同じ結果でした。
つまり、
System.Diagnostics.StopwatchクラスはQueryPerformanceCounterを使った実装となることがあり、
QueryPerformaceCounterが使う高分解能パフォーマンスカウンタがCPUクロックなら
C#になろうとも同様に時間への変換が正しくないことがある
という結論でした。
そのほかにどのような時間を計るクラスがあるかわからなかったので検証しませんでしたが・・・。
・・・こんなことC#だけでプログラムを作っている人がわかることってあんまりないような気がするのですが、どうなのでしょうか?