C++でコード実行時間をナノ秒(ns)単位で計測する場合は、通常 std::chrono::steady_clock を使います。
関数化
使用例:
注意点
極めて短いコード(数ns~100ns程度)を計測する場合、
1回だけの計測ではタイマ精度やOS割込みの影響が大きくなります。
そのため、
のように大量ループして1回当たりの時間を求める方が正確です。
さらにSIMD命令やCPUサイクル単位で測るなら、RDTSC/RDTSCP を使う方法もあります。
ただし __rdtsc() は命令の並べ替えの影響を受けるため、ベンチマーク用途では通常
のように LFENCE + RDTSC + RDTSCP + LFENCE を組み合わせます。
SSE/AVXレベルの最適化を評価するなら、chrono よりも RDTSCP で「サイクル数」を測定する方が有用です。例えば _mm_store_si128 と memcmp の比較などでは、nsよりcyclesの方が差が見えやすくなります。
CPUサイクル数から時間への換算は、
時間[s]=CPU周波数[Hz]cyclesです。
例えば 4.0GHz のCPUで、
なら
400/(4.0×109)=100nsとなります。
nsへ直接換算
時間[ns]=CPU周波数[Hz]cycles×1094GHzなら
になります。
なぜなら4 GHz = 4 cycles/ns
だからです。
実際にはTurboで周波数が変わる
最近のCPUは
のように動的に変化します。
そのため
で計算しても誤差があります。
ベンチマークでは通常、
のまま比較します。
TSCがInvariantの場合
最近のIntel/AMDでは TSC(Time Stamp Counter) が一定速度です。
例えば
なら
です。
TSC周波数は実クロックとは異なり、
に固定されていることが多いです。
正確な換算方法
chrono と rdtsc を同時に計測して較正します。
すると
で高精度に換算できます。
SIMDコード(_mm_store_si128、memcmp、8byte比較など)の性能評価なら、ユーザーさんの用途では ns換算せず cycles のまま比較するのが一般的 です。CPU周波数変動の影響を受けず、
のように直接性能差が分かります。さらに命令単位で評価する場合は、ループ展開して「cycles/iteration」または「cycles/op」を見るのが定番です。
0 件のコメント:
コメントを投稿