| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| |
| #include "kudu/util/monotime.h" |
| |
| #include <sys/time.h> |
| |
| #include <ctime> |
| #include <limits> |
| |
| #include <glog/logging.h> |
| |
| #include "kudu/gutil/integral_types.h" |
| #include "kudu/gutil/port.h" |
| #include "kudu/gutil/stringprintf.h" |
| #include "kudu/gutil/sysinfo.h" |
| #include "kudu/util/thread_restrictions.h" |
| #if defined(__APPLE__) |
| #include "kudu/gutil/walltime.h" |
| #endif |
| |
| namespace kudu { |
| |
| #define MAX_MONOTONIC_SECONDS \ |
| (((1ULL<<63) - 1ULL) /(int64_t)MonoTime::kNanosecondsPerSecond) |
| |
| |
| /// |
| /// MonoDelta |
| /// |
| |
| const int64_t MonoDelta::kUninitialized = kint64min; |
| |
| MonoDelta MonoDelta::FromSeconds(double seconds) { |
| int64_t delta = seconds * MonoTime::kNanosecondsPerSecond; |
| return MonoDelta(delta); |
| } |
| |
| MonoDelta MonoDelta::FromMilliseconds(int64_t ms) { |
| return MonoDelta(ms * MonoTime::kNanosecondsPerMillisecond); |
| } |
| |
| MonoDelta MonoDelta::FromMicroseconds(int64_t us) { |
| return MonoDelta(us * MonoTime::kNanosecondsPerMicrosecond); |
| } |
| |
| MonoDelta MonoDelta::FromNanoseconds(int64_t ns) { |
| return MonoDelta(ns); |
| } |
| |
| MonoDelta::MonoDelta() |
| : nano_delta_(kUninitialized) { |
| } |
| |
| bool MonoDelta::Initialized() const { |
| return nano_delta_ != kUninitialized; |
| } |
| |
| bool MonoDelta::LessThan(const MonoDelta &rhs) const { |
| DCHECK(Initialized()); |
| DCHECK(rhs.Initialized()); |
| return nano_delta_ < rhs.nano_delta_; |
| } |
| |
| bool MonoDelta::MoreThan(const MonoDelta &rhs) const { |
| DCHECK(Initialized()); |
| DCHECK(rhs.Initialized()); |
| return nano_delta_ > rhs.nano_delta_; |
| } |
| |
| bool MonoDelta::Equals(const MonoDelta &rhs) const { |
| DCHECK(Initialized()); |
| DCHECK(rhs.Initialized()); |
| return nano_delta_ == rhs.nano_delta_; |
| } |
| |
| std::string MonoDelta::ToString() const { |
| return StringPrintf("%.3fs", ToSeconds()); |
| } |
| |
| MonoDelta::MonoDelta(int64_t delta) |
| : nano_delta_(delta) { |
| } |
| |
| double MonoDelta::ToSeconds() const { |
| DCHECK(Initialized()); |
| double d(nano_delta_); |
| d /= MonoTime::kNanosecondsPerSecond; |
| return d; |
| } |
| |
| int64_t MonoDelta::ToNanoseconds() const { |
| DCHECK(Initialized()); |
| return nano_delta_; |
| } |
| |
| int64_t MonoDelta::ToMicroseconds() const { |
| DCHECK(Initialized()); |
| return nano_delta_ / MonoTime::kNanosecondsPerMicrosecond; |
| } |
| |
| int64_t MonoDelta::ToMilliseconds() const { |
| DCHECK(Initialized()); |
| return nano_delta_ / MonoTime::kNanosecondsPerMillisecond; |
| } |
| |
| void MonoDelta::ToTimeVal(struct timeval *tv) const { |
| DCHECK(Initialized()); |
| tv->tv_sec = nano_delta_ / MonoTime::kNanosecondsPerSecond; |
| tv->tv_usec = (nano_delta_ - (tv->tv_sec * MonoTime::kNanosecondsPerSecond)) |
| / MonoTime::kNanosecondsPerMicrosecond; |
| |
| // tv_usec must be between 0 and 999999. |
| // There is little use for negative timevals so wrap it in PREDICT_FALSE. |
| if (PREDICT_FALSE(tv->tv_usec < 0)) { |
| --(tv->tv_sec); |
| tv->tv_usec += 1000000; |
| } |
| |
| // Catch positive corner case where we "round down" and could potentially set a timeout of 0. |
| // Make it 1 usec. |
| if (PREDICT_FALSE(tv->tv_usec == 0 && tv->tv_sec == 0 && nano_delta_ > 0)) { |
| tv->tv_usec = 1; |
| } |
| |
| // Catch negative corner case where we "round down" and could potentially set a timeout of 0. |
| // Make it -1 usec (but normalized, so tv_usec is not negative). |
| if (PREDICT_FALSE(tv->tv_usec == 0 && tv->tv_sec == 0 && nano_delta_ < 0)) { |
| tv->tv_sec = -1; |
| tv->tv_usec = 999999; |
| } |
| } |
| |
| void MonoDelta::ToTimeSpec(struct timespec* ts) const { |
| DCHECK(Initialized()); |
| NanosToTimeSpec(nano_delta_, ts); |
| } |
| |
| void MonoDelta::NanosToTimeSpec(int64_t nanos, struct timespec* ts) { |
| ts->tv_sec = nanos / MonoTime::kNanosecondsPerSecond; |
| ts->tv_nsec = nanos - (ts->tv_sec * MonoTime::kNanosecondsPerSecond); |
| |
| // tv_nsec must be between 0 and 999999999. |
| // There is little use for negative timespecs so wrap it in PREDICT_FALSE. |
| if (PREDICT_FALSE(ts->tv_nsec < 0)) { |
| --(ts->tv_sec); |
| ts->tv_nsec += MonoTime::kNanosecondsPerSecond; |
| } |
| } |
| |
| MonoDelta& MonoDelta::operator+=(const MonoDelta& delta) { |
| nano_delta_ += delta.nano_delta_; |
| return *this; |
| } |
| |
| MonoDelta& MonoDelta::operator-=(const MonoDelta& delta) { |
| nano_delta_ -= delta.nano_delta_; |
| return *this; |
| } |
| |
| /// |
| /// MonoTime |
| /// |
| |
| MonoTime MonoTime::Now() { |
| #if defined(__APPLE__) |
| return MonoTime(walltime_internal::GetMonoTimeNanos()); |
| # else |
| struct timespec ts; |
| PCHECK(clock_gettime(CLOCK_MONOTONIC, &ts) == 0); |
| return MonoTime(ts); |
| #endif // defined(__APPLE__) |
| } |
| |
| MonoTime MonoTime::Max() { |
| return MonoTime(std::numeric_limits<int64_t>::max()); |
| } |
| |
| MonoTime MonoTime::Min() { |
| return MonoTime(1); |
| } |
| |
| const MonoTime& MonoTime::Earliest(const MonoTime& a, const MonoTime& b) { |
| if (b.nanos_ < a.nanos_) { |
| return b; |
| } |
| return a; |
| } |
| |
| MonoTime::MonoTime() KUDU_MONOTIME_NOEXCEPT |
| : nanos_(0) { |
| } |
| |
| bool MonoTime::Initialized() const { |
| return nanos_ != 0; |
| } |
| |
| MonoDelta MonoTime::GetDeltaSince(const MonoTime &rhs) const { |
| return rhs - *this; |
| } |
| |
| void MonoTime::AddDelta(const MonoDelta &delta) { |
| DCHECK(Initialized()); |
| nanos_ += delta.nano_delta_; |
| } |
| |
| bool MonoTime::ComesBefore(const MonoTime &rhs) const { |
| DCHECK(Initialized()); |
| DCHECK(rhs.Initialized()); |
| return nanos_ < rhs.nanos_; |
| } |
| |
| std::string MonoTime::ToString() const { |
| return StringPrintf("%.3fs", ToSeconds()); |
| } |
| |
| void MonoTime::ToTimeSpec(struct timespec* ts) const { |
| DCHECK(Initialized()); |
| MonoDelta::NanosToTimeSpec(nanos_, ts); |
| } |
| |
| bool MonoTime::Equals(const MonoTime& other) const { |
| return nanos_ == other.nanos_; |
| } |
| |
| MonoTime& MonoTime::operator+=(const MonoDelta& delta) { |
| this->AddDelta(delta); |
| return *this; |
| } |
| |
| MonoTime& MonoTime::operator-=(const MonoDelta& delta) { |
| this->AddDelta(MonoDelta(-1 * delta.nano_delta_)); |
| return *this; |
| } |
| |
| MonoTime::MonoTime(const struct timespec& ts) KUDU_MONOTIME_NOEXCEPT { |
| // Monotonic time resets when the machine reboots. The 64-bit limitation |
| // means that we can't represent times larger than 292 years, which should be |
| // adequate. |
| CHECK_LT(ts.tv_sec, MAX_MONOTONIC_SECONDS); |
| nanos_ = ts.tv_sec; |
| nanos_ *= MonoTime::kNanosecondsPerSecond; |
| nanos_ += ts.tv_nsec; |
| } |
| |
| MonoTime::MonoTime(int64_t nanos) KUDU_MONOTIME_NOEXCEPT |
| : nanos_(nanos) { |
| } |
| |
| double MonoTime::ToSeconds() const { |
| double d(nanos_); |
| d /= MonoTime::kNanosecondsPerSecond; |
| return d; |
| } |
| |
| void SleepFor(const MonoDelta& delta) { |
| ThreadRestrictions::AssertWaitAllowed(); |
| base::SleepForNanoseconds(delta.ToNanoseconds()); |
| } |
| |
| bool operator==(const MonoDelta &lhs, const MonoDelta &rhs) { |
| return lhs.Equals(rhs); |
| } |
| |
| bool operator!=(const MonoDelta &lhs, const MonoDelta &rhs) { |
| return !lhs.Equals(rhs); |
| } |
| |
| bool operator<(const MonoDelta &lhs, const MonoDelta &rhs) { |
| return lhs.LessThan(rhs); |
| } |
| |
| bool operator<=(const MonoDelta &lhs, const MonoDelta &rhs) { |
| return lhs.LessThan(rhs) || lhs.Equals(rhs); |
| } |
| |
| bool operator>(const MonoDelta &lhs, const MonoDelta &rhs) { |
| return lhs.MoreThan(rhs); |
| } |
| |
| bool operator>=(const MonoDelta &lhs, const MonoDelta &rhs) { |
| return lhs.MoreThan(rhs) || lhs.Equals(rhs); |
| } |
| |
| MonoDelta operator-(const MonoDelta &lhs, const MonoDelta &rhs) { |
| return MonoDelta(lhs.nano_delta_ - rhs.nano_delta_); |
| } |
| |
| MonoDelta operator+(const MonoDelta &lhs, const MonoDelta &rhs) { |
| return MonoDelta(lhs.nano_delta_ + rhs.nano_delta_); |
| } |
| |
| bool operator==(const MonoTime& lhs, const MonoTime& rhs) { |
| return lhs.Equals(rhs); |
| } |
| |
| bool operator!=(const MonoTime& lhs, const MonoTime& rhs) { |
| return !lhs.Equals(rhs); |
| } |
| |
| bool operator<(const MonoTime& lhs, const MonoTime& rhs) { |
| return lhs.ComesBefore(rhs); |
| } |
| |
| bool operator<=(const MonoTime& lhs, const MonoTime& rhs) { |
| return lhs.ComesBefore(rhs) || lhs.Equals(rhs); |
| } |
| |
| bool operator>(const MonoTime& lhs, const MonoTime& rhs) { |
| return rhs.ComesBefore(lhs); |
| } |
| |
| bool operator>=(const MonoTime& lhs, const MonoTime& rhs) { |
| return rhs.ComesBefore(lhs) || rhs.Equals(lhs); |
| } |
| |
| MonoTime operator+(const MonoTime& t, const MonoDelta& delta) { |
| MonoTime tmp(t); |
| tmp.AddDelta(delta); |
| return tmp; |
| } |
| |
| MonoTime operator-(const MonoTime& t, const MonoDelta& delta) { |
| MonoTime tmp(t); |
| tmp.AddDelta(MonoDelta::FromNanoseconds(-delta.ToNanoseconds())); |
| return tmp; |
| } |
| |
| MonoDelta operator-(const MonoTime& t_end, const MonoTime& t_beg) { |
| DCHECK(t_beg.Initialized()); |
| DCHECK(t_end.Initialized()); |
| int64_t delta(t_end.nanos_); |
| delta -= t_beg.nanos_; |
| return MonoDelta(delta); |
| } |
| |
| } // namespace kudu |