前回、QueryPerformanceCounterを実時間計測には使えないの記事で
つまり、負荷が変動するような環境でQueryPerformanceCounterを使っても正しい実時間は不明ということになります。
実時間でなくていい場合(計算にかかったクロック数を比較するような場合)では使用してもそれなりの効果を得られる「場合もある」わけです。
ということを書きましたが、drednoteさんの、.NETのStopwatchクラスは果たして常に正確か?の記事の中の一言
個人的には、そもそもSleep(1000)で正確に1秒きっかり停止しているかどうかから検証すべきな気もしてますが
をみて、う゛っ・・・と思いました・・・。
まあ、確かにそれを検証してからやるべき何でしょうね・・・。
というわけで、この問題を再検証してみました。コードは以下の通りです。
#include わかると思いますが、Sleep(1000)の正当性(つまり、Sleep(1000)は1000msの動作停止を行うこと)を確認するためにtimeGetTimeで時間計測を行うようにしたものです。 なお、timeBeginPeriod~timeEndPeriodは実行すると時間分解能が確保できるのですがその代わりCPUに負荷を与える(正確な時間を計ろうとするとその分割り込みが増えるのかな?)ので 本来はない方がいいのですが、そうなると時間の検証が弱くなるので入れるようにしてあります。 このソースコードで以下の条件で実行してその結果の8行目だけをピックアップして出してみたいと思います。 8行目なのは、10行ともほとんど同じ結果だったので結果例として出しています。 結果は以下の通りでした。 この結果からわかることは、私のPC環境では、 ・・・OSが違うと結果が違うのかい。・・・そうですかい・・・・・・。 もちろん、PC環境が違ってもQueryPerformanceCounterが使用する高分解能パフォーマンスカウンタは違うものになると思われるので一概に言えないと思います。 なお、.NET側の仕様(というより実装)はよくわかりませんが、対象としているSystem.Diagnostics.Stopwatch.Frequencyフィールドの説明にも Frequency 値は、基になるタイミング機構の解像力によって異なります。インストールされているハードウェアおよびオペレーティング システムが 高解像力のパフォーマンス カウンタをサポートする場合、Frequency 値はそのカウンタの頻度を反映します。それ以外の場合、Frequency 値はシステム タイマ頻度に基づきます。 と書いてあるので、おそらくはQueryPerformanceCounterを使うような実装なんだろうな~と思います。 こういう結果に結局なっちゃうんですね・・・。 ちなみに気になる人は上記のソースコードを適当なコンパイラ(VC++あたり?)でビルドとして実験してみればいいと思います。 ちょっと気になって じゃあ、高負荷時にツールを使ってオーバークロックするとどうなるの? という疑問を調べてみました。結果はこんな感じ。オーバークロック時のクロックは2.73GHz(約102.6%)でした。 やっぱりそうなのか・・・。(なお、QueryPerformanceFrequencyの値は一度再起動しているので変化しています)
#include
#include
#pragma comment(lib,”winmm.lib”)
#define _USE_TIMECAPS_
int main(void)
{
LARGE_INTEGER liBegin,liEnd,liFreq; DWORD dwBegin,dwEnd; int i;
#ifdef _USE_TIMECAPS_
TIMECAPS timeCaps;
timeGetDevCaps(&timeCaps,sizeof(timeCaps)); timeBeginPeriod(timeCaps.wPeriodMin);
#endif
dwBegin = dwEnd = 0;
for(i = 0;i < 10;i++){
dwBegin = timeGetTime();
QueryPerformanceCounter(&liBegin);
Sleep(1000);
QueryPerformanceCounter(&liEnd);
dwEnd = timeGetTime();
QueryPerformanceFrequency(&liFreq);
printf("%4d:%f(%lld)\n",dwEnd - dwBegin,(double)(liEnd.QuadPart - liBegin.QuadPart) / (double)liFreq.QuadPart,liFreq.QuadPart);
}
#ifdef _USE_TIMECAPS_
timeEndPeriod(timeCaps.wPeriodMin);
#endif
return 0;
}
[/cpp]
WinXP 32bit 無負荷
1000:0.634721(2666410000)
WinXP 32bit MPEG再生
1000:0.741520(2666410000)
WinXP 32bit CPUベンチ
1000:1.001017(2666410000)
Win7 64bit 無負荷
1000:0.999988(2603925)
Win7 64bit MPEG再生
1000:1.000035(2603925)
Win7 64bit CPUベンチ
1000:1.000019(2603925)
5/5 3:30追記
WinXP 32bit OC時
1000:1.025935(2666400000)
Win7 64bit OC時
1000:1.000026(2603886)