| #define __STDC_FORMAT_MACROS |
| |
| #include <sys/time.h> |
| #include <time.h> |
| #include <stdlib.h> |
| #include <sys/syscall.h> |
| #include <unistd.h> |
| #include <dlfcn.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <inttypes.h> |
| |
| typedef int (*vgettime_t)(clockid_t, timespec *); |
| |
| void describe_clock(const char *name, int id) |
| { |
| struct timespec res; |
| int ret = clock_getres(id, &res); |
| if (ret < 0) { |
| printf(" %d (%s) [failed to query resolution]\n", |
| id, name); |
| } else { |
| printf(" %d (%s) resolution = %" PRIu64 ".%09u\n", |
| id, name, |
| (uint64_t)res.tv_sec, (unsigned)res.tv_nsec); |
| } |
| } |
| |
| int main(int argc, char **argv) |
| { |
| if (argc < 3) { |
| printf("Usage: time <Miters> <mode> [POSIX clock id]\n"); |
| printf("\nClocks are:\n"); |
| describe_clock("CLOCK_REALTIME", CLOCK_REALTIME); |
| describe_clock("CLOCK_MONOTONIC", CLOCK_MONOTONIC); |
| describe_clock("CLOCK_REALTIME_COARSE", CLOCK_REALTIME_COARSE); |
| describe_clock("CLOCK_MONOTONIC_COARSE", CLOCK_MONOTONIC_COARSE); |
| return 1; |
| } |
| |
| void *vdso = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); |
| if (!vdso) |
| vdso = dlopen("linux-gate.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); |
| if (!vdso) |
| printf("dlopen failed\n");; |
| |
| vgettime_t vgettime = (vgettime_t)dlsym(vdso, "__vdso_clock_gettime"); |
| if (!vgettime) |
| printf("dlsym failed: %s", dlerror()); |
| |
| size_t loops = (size_t)atol(argv[1]) * 1000000; |
| clockid_t c = argc > 3 ? atoi(argv[3]) : 0; |
| const char *mode = argv[2]; |
| |
| timespec start; |
| clock_gettime(CLOCK_MONOTONIC, &start); |
| |
| timespec t; |
| if (!strcmp(mode, "clock_gettime")) { |
| for (size_t i = 0; i < loops; ++i) |
| clock_gettime(c, &t); |
| } else if (!strcmp(mode, "rdtsc")) { |
| for (size_t i = 0; i < loops; ++i) { |
| unsigned int a, d; |
| asm volatile ("rdtsc" : "=a" (a), "=d" (d)); |
| } |
| } else if (!strcmp(mode, "lfence_rdtsc")) { |
| for (size_t i = 0; i < loops; ++i) { |
| unsigned int a, d; |
| asm volatile ("lfence;rdtsc" : "=a" (a), "=d" (d)); |
| } |
| } else if (!strcmp(mode, "lfence_rdtsc_lfence")) { |
| for (size_t i = 0; i < loops; ++i) { |
| unsigned int a, d; |
| asm volatile (""); |
| asm volatile ("lfence;rdtsc;lfence" : "=a" (a), "=d" (d)); |
| } |
| } else if (!strcmp(mode, "mfence_rdtsc_mfence")) { |
| for (size_t i = 0; i < loops; ++i) { |
| unsigned int a, d; |
| asm volatile ("mfence;rdtsc;mfence" : "=a" (a), "=d" (d)); |
| } |
| } else if (!strcmp(mode, "rdtscp")) { |
| for (size_t i = 0; i < loops; ++i) { |
| unsigned int a, c, d; |
| asm volatile ("rdtscp" : "=a" (a), "=c" (c), "=d" (d)); |
| } |
| } else if (!strcmp(mode, "gettimeofday")) { |
| struct timeval tv; |
| for (size_t i = 0; i < loops; ++i) |
| gettimeofday(&tv, 0); |
| } else if (!strcmp(mode, "sys_clock_gettime")) { |
| for (size_t i = 0; i < loops; ++i) |
| syscall(__NR_clock_gettime, c, &t); |
| } else if (!strcmp(mode, "vclock_gettime")) { |
| for (size_t i = 0; i < loops; ++i) |
| vgettime(c, &t); |
| } else if (!strcmp(mode, "getpid")) { |
| for (size_t i = 0; i < loops; ++i) |
| syscall(SYS_getpid); |
| } else if (!strcmp(mode, "rdpmc")) { |
| // Unlikely to work. |
| unsigned int eax, edx; |
| unsigned int ecx = 0; |
| for (size_t i = 0; i < loops; ++i) |
| asm volatile ("rdpmc" : "=a" (eax), "=d" (edx) : "c" (ecx)); |
| } else { |
| printf("Unknown mode %s\n", mode); |
| return 1; |
| } |
| |
| timespec end; |
| clock_gettime(CLOCK_MONOTONIC, &end); |
| unsigned long long duration = (end.tv_nsec - start.tv_nsec) + 1000000000ULL * (end.tv_sec - start.tv_sec); |
| printf("%ld loops in %.5fs = %.2f nsec / loop\n", |
| (long)loops, float(duration) * 1e-9, |
| float(duration) / loops); |
| return 0; |
| } |