blob: 748ba1f939139bfb10dcc6e14b3d1e79c090e612 [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>
#include <atomic>
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, "mfence")) {
for (size_t i = 0; i < loops; ++i) {
unsigned int a, d;
asm volatile ("mfence" : "=a" (a), "=d" (d));
}
} else if (!strcmp(mode, "sfence")) {
for (size_t i = 0; i < loops; ++i) {
unsigned int a, d;
asm volatile ("sfence" : "=a" (a), "=d" (d));
}
} else if (!strcmp(mode, "lock_addl")) {
std::atomic<unsigned int> x;
for (size_t i = 0; i < loops; ++i)
x += 2;
} 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, "lsl15")) {
for (size_t i = 0; i < loops; ++i) {
uint16_t index = (15 << 3) + 3;
uint32_t limit;
asm volatile ("lsl %[index], %[limit]"
: [limit] "=r" (limit)
: [index] "r" (index) : "cc");
}
} else if (!strcmp(mode, "lsl100")) {
for (size_t i = 0; i < loops; ++i) {
uint16_t index = (100 << 3) + 3;
uint32_t limit;
asm volatile ("lsl %[index], %[limit]"
: [limit] "=r" (limit)
: [index] "r" (index) : "cc");
}
} else if (!strcmp(mode, "sgdt")) {
struct {
unsigned short limit;
unsigned long base;
} __attribute__((packed)) val;
for (size_t i = 0; i < loops; ++i)
asm volatile ("sgdt %0" : "=m" (val));
} 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));
#ifdef __x86_64__
} else if (!strcmp(mode, "vsyscall_time")) {
auto vsyscall_time = (long (*)(long *))0xffffffffff600400;
for (size_t i = 0; i < loops; ++i)
vsyscall_time(nullptr);
#endif
} 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;
}