ここにはいくつかの問題があります。1つ目は、機能に移行するときに、明らかに開始時刻と停止時刻を切り替えたことですdiffclock()
。2番目の問題は最適化です。最適化が有効になっている適度にスマートなコンパイラーは、副作用がないため、ループ全体を単純に破棄します。しかし、上記の問題を修正しても、プログラムはおそらく0を出力します。1秒あたり数十億の操作を実行することを想像しようとすると、最新のCPUで採用されている高度なアウトオブオーダー実行、予測、およびその他のテクノロジーを大量に投入します。ループを最適化します。ただし、そうでない場合でも、実行時間を長くするには、10Kを超える反復が必要になります。clock()
何かを反映させるには、おそらくプログラムを1、2秒実行する必要があります。
しかし、最も重要な問題はclock()
それ自体です。この機能は、パフォーマンス測定のどの時点にも適していません。これにより、プログラムで使用されるプロセッサ時間の概算が得られます。特定の実装で使用される可能性のある近似方法のあいまいな性質は別として(標準では特定のものを必要としないため)、POSIX標準も実際の解像度とは無関係である必要CLOCKS_PER_SEC
があります。1000000
言い換えると、クロックがどれほど正確であるかは関係ありません。CPUが実行されている周波数は関係ありません。簡単に言えば、これはまったく役に立たない数値であるため、まったく役に立たない関数です。それがまだ存在する唯一の理由は、おそらく歴史的な理由によるものです。なので、使わないでください。
あなたが探しているものを達成するために、人々はそれを読むために使用される対応するCPU命令の名前で「RDTSC」としても知られているCPUタイムスタンプを読んでいました。ただし、最近では、これもほとんど役に立たない理由があります。
- 最新のオペレーティングシステムでは、プログラムを1つのCPUから別のCPUに簡単に移行できます。別のCPUで1秒間実行した後、別のCPUでタイムスタンプを読み取ることはあまり意味がないことを想像できます。最新のIntelCPUでのみ、カウンターはCPUコア間で同期されます。全体として、これを行うことはまだ可能ですが、多くの特別な注意を払う必要があります(つまり、プロセスへのアフィニティを一度設定できるなど)。
- プログラムのCPU命令を測定しても、実際に使用されている時間を正確に把握できないことがよくあります。これは、実際のプログラムでは、プロセスに代わってOSカーネルによって作業が実行されるシステムコールが発生する可能性があるためです。その場合、その時間は含まれません。
- また、OSがプロセスの実行を長時間中断することもあります。そして、実行するのにほんの数命令しかかかりませんでしたが、ユーザーにとっては1秒のように見えました。したがって、このようなパフォーマンス測定は役に立たない場合があります。
じゃあ何をすればいいの?
プロファイリングに関しては、のようなツールをperf
使用する必要があります。これは、CPUクロックの数、キャッシュミス、取得された分岐、欠落した分岐、プロセスが1つのCPUから別のCPUに移動された回数などを追跡できます。ツールとして使用することも、アプリケーションに埋め込むこともできます(PAPIなど)。
そして、質問が実際に費やされた時間についてである場合、人々は壁掛け時計を使用します。好ましくは、高精度のものであり、これもまたNTP調整(単調)の対象ではない。これは、何が起こっていても、正確にどれだけの時間が経過したかを示しています。その目的のためclock_gettime()
に使用することができます。これは、SUSv2、POSIX.1-2001標準の一部です。getch()
ターミナルを開いたままにするためにあなたを使用することを考えると、私はあなたがWindowsを使用していると思います。残念ながら、そこにはありませんclock_gettime()
。最も近いのはパフォーマンスカウンターAPIです。
BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);
ポータブルソリューションの場合、最善の策はにありstd::chrono::high_resolution_clock()
ます。これはC++11で導入されましたが、ほとんどの産業用グレードのコンパイラ(GCC、Clang、MSVC)でサポートされています。
以下はその使用例です。私のCPUはミリ秒よりも整数の10000増分を実行することがわかっているので、マイクロ秒に変更したことに注意してください。volatile
また、コンパイラーがカウンターを最適化しないことを期待して、カウンターを宣言しました。
#include <ctime>
#include <chrono>
#include <iostream>
int main()
{
volatile int i = 0; // "volatile" is to ask compiler not to optimize the loop away.
auto start = std::chrono::steady_clock::now();
while (i < 10000) {
++i;
}
auto end = std::chrono::steady_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "It took me " << elapsed.count() << " microseconds." << std::endl;
}
コンパイルして実行すると、次のように出力されます。
$ g++ -std=c++11 -Wall -o test ./test.cpp && ./test
It took me 23 microseconds.
それが役に立てば幸い。幸運を!