C++ で、特定のプログラムまたはルーチンを CPU 時間で実行するのにかかる時間を計算する方法はありますか?
Windows 7 で実行されている Visual Studio 2008 を使用しています。
C++ で、特定のプログラムまたはルーチンを CPU 時間で実行するのにかかる時間を計算する方法はありますか?
Windows 7 で実行されている Visual Studio 2008 を使用しています。
プロセスによって使用される CPU 時間の合計量を知りたい場合、どちらclock
もrdtsc
(直接またはコンパイラ組み込みを介して) 実際には最良の選択ではありません (少なくとも IMO)。コードを移植可能にする必要がある場合、できることは を使用し、システムをできるだけ静止させてテストし、最善を期待することです (ただし、そうする場合は、 の解像度がであることclock
に注意してください。1000 ではなく、たとえそうであったとしても、実際のタイミングの解像度はあまり良くないことがよくあります。時間はミリ秒単位で表示される場合がありますが、少なくとも通常は一度に数十ミリ秒進みます)。clock
CLOCKS_PER_SEC
ただし、コードが Windows に固有であることを気にしていないように見えるので、かなり改善することができます。少なくとも、あなたが探しているものについての私の理解が正しければ、あなたが本当に欲しいのはおそらく ですGetProcessTimes
。これにより、プロセスのカーネルモードとユーザーモードの両方の CPU 使用率 (および開始時間と必要に応じて、使用された壁時間を計算できます)。またQueryProcessCycleTime
、プロセスによって使用される CPU クロック サイクルの合計数 (すべてのスレッドのユーザー モードとカーネル モードの合計) を示す もあります。個人的には、後者の多くの用途を想像するのに苦労していますが、個々のクロックサイクルを数えることは小さなコードのセクションは集中的な最適化の対象となりますが、それを完全なプロセスにどのように適用するかについてはあまり確信が持てません. GetProcessTimes
は、100 ナノ秒の解像度をサポートする FILETIME 構造を使用しますが、実際にはほとんどの場合、スケジューラのタイム スライスの倍数になります (ウィンドウのバージョンによって異なりますが、ミリ秒から数十ミリ秒のオーダーです)。
いずれにせよ、最初から最後まで時間が本当に必要な場合は、それを実行GetProcessTimes
できます。プログラムを生成する場合 (たとえば、を使用CreateProcess
)、子プロセスが終了したときに通知されるプロセスへのハンドルを取得します。 . 次に、そのハンドルを呼び出しGetProcessTimes
て、子が既に終了していても時間を取得できます。プロセスへのハンドルが少なくとも 1 つ開いている限り、ハンドルは有効なままです。
これが1つの方法です。ルーチンの実行時間をミリ秒単位で測定します。
clock_t begin=clock();
ルートが実行される前にclock_t end=clock();
開始し、ルーチンが終了した直後に開始します。
次に、2つの時間セットが互いに減算され、結果はミリ秒単位の値になります。
#include <stdio.h>
#include <iostream>
#include <time.h>
using namespace std;
double get_CPU_time_usage(clock_t clock1,clock_t clock2)
{
double diffticks=clock1-clock2;
double diffms=(diffticks*1000)/CLOCKS_PER_SEC;
return diffms;
}
void test_CPU_usage()
{
cout << "Standby.. measuring exeution time: ";
for (int i=0; i<10000;i++)
{
cout << "\b\\" << std::flush;
cout << "\b|" << std::flush;
cout << "\b/" << std::flush;
cout << "\b-" << std::flush;
}
cout << " \n\n";
}
int main (void)
{
clock_t begin=clock();
test_CPU_usage();
clock_t end=clock();
cout << "Time elapsed: " << double(get_CPU_time_usage(end,begin)) << " ms ("<<double(get_CPU_time_usage(end,begin))/1000<<" sec) \n\n";
return 0;
}
[Visual C++ 2008 で提供される] clock() 関数は、プログラムが使用するプロセッサ時間を返しませんが、(C 標準および/または C++ 標準に従って) 必要があります。つまり、Windows で CPU 時間を測定するために、次のヘルパー クラスがあります (これは必然的に移植性がありません)。
class ProcessorTimer
{
public:
ProcessorTimer() { start(); }
void start() { ::GetProcessTimes(::GetCurrentProcess(), &ft_[3], &ft_[2], &ft_[1], &ft_[0]); }
std::tuple<double, double> stop()
{
::GetProcessTimes(::GetCurrentProcess(), &ft_[5], &ft_[4], &ft_[3], &ft_[2]);
ULARGE_INTEGER u[4];
for (size_t i = 0; i < 4; ++i)
{
u[i].LowPart = ft_[i].dwLowDateTime;
u[i].HighPart = ft_[i].dwHighDateTime;
}
double user = (u[2].QuadPart - u[0].QuadPart) / 10000000.0;
double kernel = (u[3].QuadPart - u[1].QuadPart) / 10000000.0;
return std::make_tuple(user, kernel);
}
private:
FILETIME ft_[6];
};
class ScopedProcessorTimer
{
public:
ScopedProcessorTimer(std::ostream& os = std::cerr) : timer_(ProcessorTimer()), os_(os) { }
~ScopedProcessorTimer()
{
std::tuple<double, double> t = timer_.stop();
os_ << "user " << std::get<0>(t) << "\n";
os_ << "kernel " << std::get<1>(t) << "\n";
}
private:
ProcessorTimer timer_;
std::ostream& os_;
}
たとえば、{} ブロックの先頭に ScopedProcessorTimer を定義することで、ブロックの実行にかかる時間を測定できます。
組み込み関数は、__rdtscp
CPU サイクルで時間を示しますが、注意が必要です。MSDNの記事はこちら
何を測定したいかによって異なります。より良い結果を得るには、平均して数百万回 (10 億回ではないにしても) の反復を行います。