// Measure how long it takes to read the various timers available on Linux. // Adam Sampson #include #include #include const int turns = 5; const int cycles = 1000000; enum modes { MODE_CONTROL = 0, MODE_RDTSC, MODE_GETTIMEOFDAY, MODE_GETITIMER, MODE_CGT_REALTIME, MODE_CGT_MONOTONIC, MODE_TGT_REALTIME, MODE_TGT_MONOTONIC, NUM_MODES }; const char *mode_names[] = { "(none)", "RDTSC", "gtod", "gitREAL", "cgtREAL", "cgtMONO", "tgtREAL", "tgtMONO", NULL }; #ifdef IA32 int cpufactor = 123456; static inline int rdtsc (void) { int time_in_us; __asm__ __volatile__ (" \n" \ " pushl %%edx \n" \ " pushl %%ebx \n" \ " pushl %%eax \n" \ " \n" \ " rdtsc \n" \ " movl %%edx, %%ebx \n" \ " mull cpufactor \n" \ " movl %%ebx, %%eax \n" \ " movl %%edx, %%ebx \n" \ " mull cpufactor \n" \ " addl %%ebx, %%eax \n" \ " movl %%eax, (%%ecx) \n" \ " \n" \ " popl %%eax \n" \ " popl %%ebx \n" \ " popl %%edx \n" \ : : "c" (&time_in_us) : "cc", "memory"); return time_in_us; } #endif #ifdef PPC64 static inline int rdtsc (void) { unsigned long long int tbr; __asm__ __volatile__("mftb %[tbr]" : [tbr] "=r" (tbr):); return tbr / 123456; } #endif double benchmark (int mode) { struct timeval start, end; int t; struct timeval tv; struct itimerval itv; struct timespec ts; timer_t tim; struct itimerspec its; switch (mode) { case MODE_TGT_REALTIME: case MODE_TGT_MONOTONIC: if (timer_create (mode == MODE_TGT_REALTIME ? CLOCK_REALTIME : CLOCK_MONOTONIC, NULL, &tim) < 0) return -1.0L; break; case MODE_CGT_REALTIME: case MODE_CGT_MONOTONIC: if (clock_gettime (mode == MODE_CGT_REALTIME ? CLOCK_REALTIME : CLOCK_MONOTONIC, &ts) < 0) return -1.0L; break; } gettimeofday (&start, NULL); for (int i = 0; i < cycles; i++) { switch (mode) { case MODE_CONTROL: // Do nothing -- just measure overhead. break; case MODE_RDTSC: t = rdtsc (); break; case MODE_GETTIMEOFDAY: gettimeofday (&tv, NULL); break; case MODE_GETITIMER: getitimer (ITIMER_REAL, &itv); break; case MODE_CGT_REALTIME: clock_gettime (CLOCK_REALTIME, &ts); break; case MODE_CGT_MONOTONIC: clock_gettime (CLOCK_MONOTONIC, &ts); break; case MODE_TGT_REALTIME: case MODE_TGT_MONOTONIC: timer_gettime (tim, &its); break; } } gettimeofday (&end, NULL); switch (mode) { case MODE_TGT_REALTIME: case MODE_TGT_MONOTONIC: timer_delete (tim); break; } double usecs = ((end.tv_sec * 1000000.0L) + end.tv_usec) - ((start.tv_sec * 1000000.0L) + start.tv_usec); return usecs * 1000.0L / cycles; } int main (int argc, char **argv) { double results[NUM_MODES][turns]; for (int turn = 0; turn < turns; turn++) { printf ("turn %d\n", turn); for (int mode = 0; mode < NUM_MODES; mode++) { results[mode][turn] = benchmark (mode); } } for (int mode = 0; mode < NUM_MODES; mode++) { printf ("%9s", mode_names[mode]); } printf ("\n"); for (int mode = 0; mode < NUM_MODES; mode++) { double r = 0.0L; for (int i = 0; i < turns; i++) { r += results[mode][i]; } r /= turns; printf ("%9.2f", r); } printf ("\n"); }