#include #include #include #include #include #include #include uint64_t my_get_time_us() { struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); return ts.tv_sec * 1000000 + ts.tv_nsec / 1000; } uint64_t *records; int pos = 0; int iterations = 0; void record_time() { if (pos < iterations) records[pos ++] = my_get_time_us(); } void report(const char *name) { printf("'%s': [", name); int i; for (i = 0; i < iterations; ++i) { printf("%llu, ", (unsigned long long)records[i]); } printf("],\n"); memset(records, 0, iterations * sizeof(uint64_t)); pos = 0; } void my_sleep_1(uint64_t us) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = us * 1000; clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); } void my_sleep_2(uint64_t us) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = us * 1000; nanosleep(&ts, NULL); } void my_sleep_3(uint64_t us) { usleep(us); } void my_sleep_4(uint64_t us) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = us; select(0, NULL, NULL, NULL, &tv); } struct timespec abs_start; void my_sleep_abs_init() { clock_gettime(CLOCK_MONOTONIC, &abs_start); } void my_sleep_abs(uint64_t us) { struct timespec ts = abs_start; ts.tv_sec += (us / 1000000); ts.tv_nsec += (us % 1000000 * 1000); if (ts.tv_nsec >= 1000000000) { ts.tv_sec += 1; ts.tv_nsec -= 1000000000; } clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL); } timer_t timer_id; void my_timer_handler(int sig, siginfo_t *si, void *uc) { record_time(); } void my_timer_init() { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = my_timer_handler; sigemptyset(&sa.sa_mask); sigaction(SIGRTMIN, &sa, NULL); struct sigevent sig; sig.sigev_notify = SIGEV_SIGNAL; sig.sigev_signo = SIGRTMIN; sig.sigev_value.sival_ptr = &timer_id; timer_create(CLOCK_MONOTONIC, &sig, &timer_id); } void my_timer_set(uint64_t us) { struct itimerspec its; its.it_value.tv_sec = 0; its.it_value.tv_nsec = us * 1000; its.it_interval.tv_sec = its.it_value.tv_sec; its.it_interval.tv_nsec = its.it_value.tv_nsec; timer_settime(timer_id, 0, &its, NULL); } void run_sleep(void (* sleep_func)(uint64_t us), uint64_t us) { uint64_t ts = my_get_time_us(); int i; for (i = 0; i < iterations; ++i) { ts += us; uint64_t now = my_get_time_us(); if (ts > now) sleep_func(ts - now); record_time(); } } void run_sleep_abs(uint64_t us) { uint64_t ts = 0; int i; my_sleep_abs_init(); for (i = 0; i < iterations; ++i) { ts += us; my_sleep_abs(ts); record_time(); } } void run_timer(uint64_t us) { my_timer_init(); my_timer_set(us); int i; for (i = 0; i < iterations; ++i) { pause(); } my_timer_set(0); } void run(int us) { run_sleep(my_sleep_1, us); report("clock_nanosleep"); run_sleep(my_sleep_2, us); report("nanosleep"); run_sleep(my_sleep_4, us); report("select"); run_sleep_abs(us); report("clock_nanosleep_TIMER_ABSTIME"); run_timer(us); report("signal"); } int main(int argc, char **argv) { uint64_t interval = argc > 1 ? atoi(argv[1]) : 1000; iterations = argc > 2 ? atoi(argv[2]) : 1000; records = calloc(iterations, sizeof(uint64_t)); run(interval); return 0; }