diff --git a/src/common/mutex.h b/src/common/mutex.h index b29ba4942..46e89044f 100644 --- a/src/common/mutex.h +++ b/src/common/mutex.h @@ -120,10 +120,14 @@ class MutexLock { class CondVar { public: explicit CondVar(Mutex* mu) : mu_(mu) { - PthreadCall("init condvar", pthread_cond_init(&cond_, NULL)); + // use monotonic clock + PthreadCall("condattr init ", pthread_condattr_init(&attr_)); + PthreadCall("condattr setclock ", pthread_condattr_setclock(&attr_, CLOCK_MONOTONIC)); + PthreadCall("condvar init with attr", pthread_cond_init(&cond_, &attr_)); } ~CondVar() { - PthreadCall("destroy condvar", pthread_cond_destroy(&cond_)); + PthreadCall("condvar destroy", pthread_cond_destroy(&cond_)); + PthreadCall("condattr destroy", pthread_condattr_destroy(&attr_)); } void Wait(const char* msg = NULL) { int64_t msg_threshold = mu_->msg_threshold_; @@ -134,12 +138,13 @@ class CondVar { // Time wait in us // timeout < 0 would cause ETIMEOUT and return false immediately bool TimeWaitInUs(int timeout, const char* msg = NULL) { - timespec ts; - struct timeval tv; - gettimeofday(&tv, NULL); - int64_t usec = tv.tv_usec + timeout; - ts.tv_sec = tv.tv_sec + usec / 1000000; - ts.tv_nsec = (usec % 1000000) * 1000; + // ref: http://www.qnx.com/developers/docs/6.5.0SP1.update/com.qnx.doc.neutrino_lib_ref/p/pthread_cond_timedwait.html + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + int64_t nsec = ((int64_t)timeout) * 1000 + ts.tv_nsec; + ts.tv_sec += nsec / 1000000000; + ts.tv_nsec = nsec % 1000000000; + int64_t msg_threshold = mu_->msg_threshold_; mu_->BeforeUnlock(); int ret = pthread_cond_timedwait(&cond_, &mu_->mu_, &ts); @@ -163,6 +168,7 @@ class CondVar { void operator=(const CondVar&); Mutex* mu_; pthread_cond_t cond_; + pthread_condattr_t attr_; }; } // namespace common diff --git a/src/common/timer.h b/src/common/timer.h index 14ec8d62c..073711fcf 100644 --- a/src/common/timer.h +++ b/src/common/timer.h @@ -27,17 +27,15 @@ static inline std::string get_curtime_str() { } static inline int64_t get_micros() { - struct timeval tv; - gettimeofday(&tv, NULL); - return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast(ts.tv_sec) * 1000000 + static_cast(ts.tv_nsec) / 1000; } static inline int64_t get_unique_micros(int64_t ref) { - struct timeval tv; int64_t now; do { - gettimeofday(&tv, NULL); - now = static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + now = get_micros(); } while (now == ref); return now; } diff --git a/src/leveldb/bench/tera_bench.cc b/src/leveldb/bench/tera_bench.cc index 53ed6a01a..ea7ffe93b 100644 --- a/src/leveldb/bench/tera_bench.cc +++ b/src/leveldb/bench/tera_bench.cc @@ -222,8 +222,8 @@ class Benchmark { snprintf(msg, sizeof(msg), "(%d ops)", num_entries); message_ = msg; } - char ts[10]; - snprintf(ts, sizeof(ts), "%d", FLAGS_value_seed); + char ts[20]; + snprintf(ts, sizeof(ts), "%lld", ((long long int)FLAGS_value_seed) * 1000000); // Write to database int i = FLAGS_start_key; diff --git a/src/leveldb/port/port_posix.cc b/src/leveldb/port/port_posix.cc index 37ba0c3bb..0ad21d620 100644 --- a/src/leveldb/port/port_posix.cc +++ b/src/leveldb/port/port_posix.cc @@ -50,32 +50,39 @@ void Mutex::Unlock() { PthreadCall("unlock", pthread_mutex_unlock(&mu_)); } CondVar::CondVar(Mutex* mu) : mu_(mu) { - PthreadCall("init cv", pthread_cond_init(&cv_, NULL)); + // use monotonic clock + PthreadCall("condattr init ", pthread_condattr_init(&attr_)); + PthreadCall("condattr setclock ", pthread_condattr_setclock(&attr_, CLOCK_MONOTONIC)); + PthreadCall("condvar init with attr", pthread_cond_init(&cond_, &attr_)); } -CondVar::~CondVar() { PthreadCall("destroy cv", pthread_cond_destroy(&cv_)); } +CondVar::~CondVar() { + PthreadCall("condvar destroy", pthread_cond_destroy(&cond_)); + PthreadCall("condattr destroy", pthread_condattr_destroy(&attr_)); +} void CondVar::Wait() { - PthreadCall("wait", pthread_cond_wait(&cv_, &mu_->mu_)); + PthreadCall("condvar wait", pthread_cond_wait(&cond_, &mu_->mu_)); } +// wait in ms bool CondVar::Wait(int64_t wait_millisec) { assert(wait_millisec >= 0); + // ref: http://www.qnx.com/developers/docs/6.5.0SP1.update/com.qnx.doc.neutrino_lib_ref/p/pthread_cond_timedwait.html struct timespec ts; - struct timeval tp; - gettimeofday(&tp, NULL); - uint64_t usec = tp.tv_usec + wait_millisec * 1000; - ts.tv_sec = tp.tv_sec + usec / 1000000; - ts.tv_nsec = (usec % 1000000) * 1000; - return (0 == pthread_cond_timedwait(&cv_, &mu_->mu_, &ts)); + clock_gettime(CLOCK_MONOTONIC, &ts); + int64_t nsec = ((int64_t)wait_millisec) * 1000000 + ts.tv_nsec; + ts.tv_sec += nsec / 1000000000; + ts.tv_nsec = nsec % 1000000000; + return (0 == pthread_cond_timedwait(&cond_, &mu_->mu_, &ts)); } void CondVar::Signal() { - PthreadCall("signal", pthread_cond_signal(&cv_)); + PthreadCall("signal", pthread_cond_signal(&cond_)); } void CondVar::SignalAll() { - PthreadCall("broadcast", pthread_cond_broadcast(&cv_)); + PthreadCall("broadcast", pthread_cond_broadcast(&cond_)); } void InitOnce(OnceType* once, void (*initializer)()) { diff --git a/src/leveldb/port/port_posix.h b/src/leveldb/port/port_posix.h index bb80c31f9..ed19e222f 100644 --- a/src/leveldb/port/port_posix.h +++ b/src/leveldb/port/port_posix.h @@ -113,7 +113,8 @@ class CondVar { void Signal(); void SignalAll(); private: - pthread_cond_t cv_; + pthread_cond_t cond_; + pthread_condattr_t attr_; Mutex* mu_; }; diff --git a/src/leveldb/util/env_posix.cc b/src/leveldb/util/env_posix.cc index 2918a73f1..4e6682cc0 100644 --- a/src/leveldb/util/env_posix.cc +++ b/src/leveldb/util/env_posix.cc @@ -809,9 +809,9 @@ class PosixEnv : public Env { } virtual uint64_t NowMicros() { - struct timeval tv; - gettimeofday(&tv, NULL); - return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast(ts.tv_sec) * 1000000 + static_cast(ts.tv_nsec) / 1000; } virtual void SleepForMicroseconds(int micros) { diff --git a/src/leveldb/util/raw_key_operator_test.cc b/src/leveldb/util/raw_key_operator_test.cc index 1704822eb..17c51ea7a 100644 --- a/src/leveldb/util/raw_key_operator_test.cc +++ b/src/leveldb/util/raw_key_operator_test.cc @@ -19,9 +19,9 @@ void print_bytes(const char* str, int len) { } int64_t get_micros() { - struct timeval tv; - gettimeofday(&tv, NULL); - return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast(ts.tv_sec) * 1000000 + static_cast(ts.tv_nsec) / 1000; } class RawKeyOperatorTest {}; diff --git a/src/utils/timer.h b/src/utils/timer.h index 4cae24137..ecb96974a 100644 --- a/src/utils/timer.h +++ b/src/utils/timer.h @@ -27,23 +27,19 @@ static inline std::string get_curtime_str_plain() { } static inline int64_t get_micros() { - struct timeval tv; - gettimeofday(&tv, NULL); - return static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return static_cast(ts.tv_sec) * 1000000 + static_cast(ts.tv_nsec) / 1000; } static inline int64_t get_millis() { - struct timeval tv; - gettimeofday(&tv, NULL); - return static_cast(tv.tv_sec) * 1000 + tv.tv_usec / 1000; + return get_micros() / 1000; } static inline int64_t get_unique_micros(int64_t ref) { - struct timeval tv; int64_t now; do { - gettimeofday(&tv, NULL); - now = static_cast(tv.tv_sec) * 1000000 + tv.tv_usec; + now = get_micros(); } while (now == ref); return now; }