#include #include #include #include #include #include #include #include #include #include const unsigned futex_wait_op = 0; const unsigned futex_wait_bitset_op = 9; const unsigned futex_clock_monotonic_flag = 0; const unsigned futex_clock_realtime_flag = 256; const unsigned futex_bitset_match_any = ~0; const unsigned futex_wake_op = 1; static int futex(int *uaddr, int futex_op, int val, const struct timespec *timeout, int *uaddr2, int val3) { return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr, val3); } std::chrono::nanoseconds test_futex_realtime() { int word = 1; struct timespec timeout{0,0}; const auto start = std::chrono::steady_clock::now(); int rc = futex(&word, futex_wait_bitset_op | futex_clock_realtime_flag, 1, &timeout, nullptr, futex_bitset_match_any); if (rc != -1) { fprintf(stderr, "Unexpected return value from futex: %d\n", rc); exit(1); } if (errno != ETIMEDOUT) { fprintf(stderr, "Unexpected error from futex: %m\n"); exit(1); } const auto duration = std::chrono::steady_clock::now() - start; return duration; } std::chrono::nanoseconds test_futex_monotonic() { int word = 1; struct timespec timeout{0,0}; const auto start = std::chrono::steady_clock::now(); int rc = futex(&word, futex_wait_bitset_op | futex_clock_monotonic_flag, 1, &timeout, nullptr, futex_bitset_match_any); if (rc != -1) { fprintf(stderr, "Unexpected return value from futex: %d\n", rc); exit(1); } if (errno != ETIMEDOUT) { fprintf(stderr, "Unexpected error from futex: %m\n"); exit(1); } const auto duration = std::chrono::steady_clock::now() - start; return duration; } std::chrono::nanoseconds test_futex_relative() { int word = 1; struct timespec timeout{0,0}; const auto start = std::chrono::steady_clock::now(); int rc = futex(&word, futex_wait_op, 1, &timeout, nullptr, 0); if (rc != -1) { fprintf(stderr, "Unexpected return value from futex: %d\n", rc); exit(1); } if (errno != ETIMEDOUT) { fprintf(stderr, "Unexpected error from futex: %m\n"); exit(1); } const auto duration = std::chrono::steady_clock::now() - start; return duration; } std::chrono::nanoseconds test_clock_gettime() { const auto start = std::chrono::steady_clock::now(); struct timespec timeout; clock_gettime(CLOCK_REALTIME, &timeout); const auto duration = std::chrono::steady_clock::now() - start; return duration; } pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond_realtime = PTHREAD_COND_INITIALIZER; std::chrono::nanoseconds test_cond_realtime() { int rc = pthread_mutex_lock(&mut); if (rc != 0) { fprintf(stderr, "pthread_mutex_lock: %m\n"); exit(1); } const auto start = std::chrono::steady_clock::now(); struct timespec timeout{0,0}; rc = pthread_cond_timedwait(&cond_realtime, &mut, &timeout); if (rc != ETIMEDOUT) { fprintf(stderr, "Unexpected return value from cond wait: %d\n", rc); exit(1); } const auto duration = std::chrono::steady_clock::now() - start; pthread_mutex_unlock(&mut); return duration; } pthread_cond_t cond_monotonic; std::chrono::nanoseconds test_cond_monotonic() { int rc = pthread_mutex_lock(&mut); if (rc != 0) { fprintf(stderr, "pthread_mutex_lock: %m\n"); exit(1); } const auto start = std::chrono::steady_clock::now(); struct timespec timeout{0,0}; rc = pthread_cond_timedwait(&cond_monotonic, &mut, &timeout); if (rc != ETIMEDOUT) { fprintf(stderr, "Unexpected return value from cond wait: %d\n", rc); exit(1); } const auto duration = std::chrono::steady_clock::now() - start; pthread_mutex_unlock(&mut); return duration; } void show_mean(const char *name, std::chrono::nanoseconds (*f)()) { // warm up for(int i = 0; i < 10; ++i) f(); // calculate mean const int count = 5000; std::chrono::nanoseconds total{0}; for(int i = 0; i < count; ++i) { total += f(); std::this_thread::sleep_for(std::chrono::milliseconds(1)); } printf("%s mean duration %" PRId64 "ns\n", name, (total/count).count()); } int main() { pthread_condattr_t condattr_monotonic; pthread_condattr_init(&condattr_monotonic); pthread_condattr_setclock(&condattr_monotonic, CLOCK_MONOTONIC); pthread_cond_init(&cond_monotonic, &condattr_monotonic); show_mean("futex_realtime", test_futex_realtime); show_mean("futex_monotonic", test_futex_monotonic); show_mean("futex_relative", test_futex_relative); show_mean("clock_gettime", test_clock_gettime); show_mean("cond_realtime", test_cond_realtime); show_mean("cond_monotonic", test_cond_monotonic); }