blob: b5ad60f91af31a4f969cc41a5e8fed59b5544c54 [file] [log] [blame]
#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;
}