GPUとCPUのパフォーマンスを比較しようとしています。 NVIDIA GPUの場合、cudaEvent_t
を入力して、非常に正確なタイミングを取得します。
CPUには、次のコードを使用しています。
// Timers
clock_t start, stop;
float elapsedTime = 0;
// Capture the start time
start = clock();
// Do something here
.......
// Capture the stop time
stop = clock();
// Retrieve time elapsed in milliseconds
elapsedTime = (float)(stop - start) / (float)CLOCKS_PER_SEC * 1000.0f;
どうやら、そのコードは数秒で数えている場合にのみ有効です。また、結果は時々非常に奇妙になります。
Linuxで高解像度タイマーを作成する方法を知っている人はいますか?
clock_gettime
を確認してください。これは、高解像度タイマーへのPOSIXインターフェイスです。
マンページを読んで、CLOCK_REALTIME
とCLOCK_MONOTONIC
の違いについて疑問に思っている場合は、 CLOCK_REALTIMEとCLOCK_MONOTONICの違い? を参照してください。
完全な例については、次のページを参照してください。 http://www.guyrutenberg.com/2007/09/22/profiling-code-using-clock_gettime/
#include <iostream>
#include <time.h>
using namespace std;
timespec diff(timespec start, timespec end);
int main()
{
timespec time1, time2;
int temp;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
for (int i = 0; i< 242000000; i++)
temp+=temp;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
cout<<diff(time1,time2).tv_sec<<":"<<diff(time1,time2).tv_nsec<<endl;
return 0;
}
timespec diff(timespec start, timespec end)
{
timespec temp;
if ((end.tv_nsec-start.tv_nsec)<0) {
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
}
return temp;
}
これまでに提示された情報を要約すると、これらは一般的なアプリケーションに必要な2つの機能です。
#include <time.h>
// call this function to start a nanosecond-resolution timer
struct timespec timer_start(){
struct timespec start_time;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time);
return start_time;
}
// call this function to end a timer, returning nanoseconds elapsed as a long
long timer_end(struct timespec start_time){
struct timespec end_time;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time);
long diffInNanos = (end_time.tv_sec - start_time.tv_sec) * (long)1e9 + (end_time.tv_nsec - start_time.tv_nsec);
return diffInNanos;
}
以下に、入力リストの分散を計算するのにかかる時間を計る方法の例を示します。
struct timespec vartime = timer_start(); // begin a timer called 'vartime'
double variance = var(input, MAXLEN); // perform the task we want to time
long time_elapsed_nanos = timer_end(vartime);
printf("Variance = %f, Time taken (nanoseconds): %ld\n", variance, time_elapsed_nanos);
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
cLOCK_REALTIME_HRもありますが、違いがあるかどうかはわかりません。
このスレッドを読んだ後、c ++ 11のクロノに対するclock_gettimeのコードのテストを開始しましたが、一致していないようです。
それらの間には大きなギャップがあります!
std :: chrono :: seconds(1)はclock_gettimeの〜30,0と同等のようです
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <thread>
#include <chrono>
#include <iomanip>
#include <vector>
timespec diff(timespec start, timespec end);
timespec get_cpu_now_time();
std::vector<timespec> get_start_end_pairs();
void output_deltas(const std::vector<timespec> &start_end_pairs);
//=============================================================
int main()
{
std::cout << "Hello waiter" << std::endl; // flush is intentional
std::vector<timespec> start_end_pairs = get_start_end_pairs();
output_deltas(start_end_pairs);
return EXIT_SUCCESS;
}
//=============================================================
std::vector<timespec> get_start_end_pairs()
{
std::vector<timespec> start_end_pairs;
for (int i = 0; i < 20; ++i)
{
start_end_pairs.Push_back(get_cpu_now_time());
std::this_thread::sleep_for(std::chrono::seconds(1));
start_end_pairs.Push_back(get_cpu_now_time());
}
return start_end_pairs;
}
//=============================================================
void output_deltas(const std::vector<timespec> &start_end_pairs)
{
for (auto it_start = start_end_pairs.begin(); it_start != start_end_pairs.end(); it_start += 2)
{
auto it_end = it_start + 1;
auto delta = diff(*it_start, *it_end);
std::cout
<< "Waited ("
<< delta.tv_sec
<< "\ts\t"
<< std::setw(9)
<< std::setfill('0')
<< delta.tv_nsec
<< "\tns)"
<< std::endl;
}
}
//=============================================================
timespec diff(timespec start, timespec end)
{
timespec temp;
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
if (temp.tv_nsec < 0) {
++temp.tv_sec;
temp.tv_nsec += 1000000000;
}
return temp;
}
//=============================================================
timespec get_cpu_now_time()
{
timespec now_time;
memset(&now_time, 0, sizeof(timespec));
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now_time);
return now_time;
}
出力:
Waited (0 s 000064802 ns)
Waited (0 s 000028512 ns)
Waited (0 s 000030664 ns)
Waited (0 s 000041233 ns)
Waited (0 s 000013458 ns)
Waited (0 s 000024068 ns)
Waited (0 s 000027591 ns)
Waited (0 s 000028148 ns)
Waited (0 s 000033783 ns)
Waited (0 s 000022382 ns)
Waited (0 s 000027866 ns)
Waited (0 s 000028085 ns)
Waited (0 s 000028012 ns)
Waited (0 s 000028172 ns)
Waited (0 s 000022121 ns)
Waited (0 s 000052940 ns)
Waited (0 s 000032138 ns)
Waited (0 s 000028082 ns)
Waited (0 s 000034486 ns)
Waited (0 s 000018875 ns)
ウォール時間(実際に経過する時間)またはサイクル数(サイクル数)に興味がありますか?最初のケースでは、gettimeofday
のようなものを使用する必要があります。
最高解像度のタイマーは、RDTSC
x86 Assembly命令を使用します。ただし、これはクロックティックを測定するため、省電力モードが無効になっていることを確認する必要があります。
TSCのWikiページにはいくつかの例があります。 http://en.wikipedia.org/wiki/Time_Stamp_Counter
epollの実装: https://github.com/ielife/simple-timer-for-c-language
次のように使用します:
timer_server_handle_t *timer_handle = timer_server_init(1024);
if (NULL == timer_handle) {
fprintf(stderr, "timer_server_init failed\n");
return -1;
}
ctimer timer1;
timer1.count_ = 3;
timer1.timer_internal_ = 0.5;
timer1.timer_cb_ = timer_cb1;
int *user_data1 = (int *)malloc(sizeof(int));
*user_data1 = 100;
timer1.user_data_ = user_data1;
timer_server_addtimer(timer_handle, &timer1);
ctimer timer2;
timer2.count_ = -1;
timer2.timer_internal_ = 0.5;
timer2.timer_cb_ = timer_cb2;
int *user_data2 = (int *)malloc(sizeof(int));
*user_data2 = 10;
timer2.user_data_ = user_data2;
timer_server_addtimer(timer_handle, &timer2);
sleep(10);
timer_server_deltimer(timer_handle, timer1.fd);
timer_server_deltimer(timer_handle, timer2.fd);
timer_server_uninit(timer_handle);