mirror of https://github.com/grpc/grpc.git
grpc_millis -> Timestamp/Duration (#28119)
* wip * Automated change: Fix sanity tests * fixes * progress * progress * grpc compiles * Automated change: Fix sanity tests * fixing tests * x * progress * better code * Automated change: Fix sanity tests * progress * progress * windows fix * Make Duration metadata trivial * better message * fix * Automated change: Fix sanity tests * fix * fix * fix * fix * Automated change: Fix sanity tests * Automated change: Fix sanity tests * fix * progress * fixes * fix * fix * spam * un-disable errantly disabled tests * gain insight * Automated change: Fix sanity tests * fixes * fixes * fix * debug * tweak * fix * fix timeout * fix comment * fixes * x * better test * tests * Automated change: Fix sanity tests * missed file * fix * x * fix * fix * fix * fix * Automated change: Fix sanity tests * fix * merge * Automated change: Fix sanity tests * fix Co-authored-by: ctiller <ctiller@users.noreply.github.com>pull/28968/head^2
parent
0966536dc1
commit
5fc3ff8203
205 changed files with 2285 additions and 1580 deletions
@ -0,0 +1,186 @@ |
|||||||
|
// Copyright 2021 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gprpp/time.h" |
||||||
|
|
||||||
|
#include <atomic> |
||||||
|
#include <cstdint> |
||||||
|
#include <limits> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <grpc/impl/codegen/gpr_types.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
std::atomic<int64_t> g_process_epoch_seconds; |
||||||
|
std::atomic<gpr_cycle_counter> g_process_epoch_cycles; |
||||||
|
|
||||||
|
GPR_ATTRIBUTE_NOINLINE std::pair<int64_t, gpr_cycle_counter> InitTime() { |
||||||
|
gpr_cycle_counter cycles_start; |
||||||
|
gpr_cycle_counter cycles_end; |
||||||
|
int64_t process_epoch_seconds; |
||||||
|
|
||||||
|
// Check the current time... if we end up with zero, try again after 100ms.
|
||||||
|
// If it doesn't advance after sleeping for 1100ms, crash the process.
|
||||||
|
for (int i = 0; i < 11; i++) { |
||||||
|
cycles_start = gpr_get_cycle_counter(); |
||||||
|
gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); |
||||||
|
cycles_end = gpr_get_cycle_counter(); |
||||||
|
process_epoch_seconds = now.tv_sec - 1; |
||||||
|
if (process_epoch_seconds != 0) { |
||||||
|
break; |
||||||
|
} |
||||||
|
gpr_sleep_until(gpr_time_add(now, gpr_time_from_millis(100, GPR_TIMESPAN))); |
||||||
|
} |
||||||
|
|
||||||
|
// Time does not seem to be increasing from zero...
|
||||||
|
GPR_ASSERT(process_epoch_seconds != 0); |
||||||
|
int64_t expected = 0; |
||||||
|
gpr_cycle_counter process_epoch_cycles = (cycles_start + cycles_end) / 2; |
||||||
|
GPR_ASSERT(process_epoch_cycles != 0); |
||||||
|
if (!g_process_epoch_seconds.compare_exchange_strong( |
||||||
|
expected, process_epoch_seconds, std::memory_order_relaxed, |
||||||
|
std::memory_order_relaxed)) { |
||||||
|
process_epoch_seconds = expected; |
||||||
|
do { |
||||||
|
process_epoch_cycles = |
||||||
|
g_process_epoch_cycles.load(std::memory_order_relaxed); |
||||||
|
} while (process_epoch_cycles == 0); |
||||||
|
} else { |
||||||
|
g_process_epoch_cycles.store(process_epoch_cycles, |
||||||
|
std::memory_order_relaxed); |
||||||
|
} |
||||||
|
return std::make_pair(process_epoch_seconds, process_epoch_cycles); |
||||||
|
} |
||||||
|
|
||||||
|
gpr_timespec StartTime() { |
||||||
|
int64_t sec = g_process_epoch_seconds.load(std::memory_order_relaxed); |
||||||
|
if (GPR_UNLIKELY(sec == 0)) sec = InitTime().first; |
||||||
|
return {sec, 0, GPR_CLOCK_MONOTONIC}; |
||||||
|
} |
||||||
|
|
||||||
|
gpr_cycle_counter StartCycleCounter() { |
||||||
|
gpr_cycle_counter cycles = |
||||||
|
g_process_epoch_cycles.load(std::memory_order_relaxed); |
||||||
|
if (GPR_UNLIKELY(cycles == 0)) cycles = InitTime().second; |
||||||
|
return cycles; |
||||||
|
} |
||||||
|
|
||||||
|
gpr_timespec MillisecondsAsTimespec(int64_t millis, gpr_clock_type clock_type) { |
||||||
|
// special-case infinities as Timestamp can be 32bit on some
|
||||||
|
// platforms while gpr_time_from_millis always takes an int64_t.
|
||||||
|
if (millis == std::numeric_limits<int64_t>::max()) { |
||||||
|
return gpr_inf_future(clock_type); |
||||||
|
} |
||||||
|
if (millis == std::numeric_limits<int64_t>::min()) { |
||||||
|
return gpr_inf_past(clock_type); |
||||||
|
} |
||||||
|
|
||||||
|
if (clock_type == GPR_TIMESPAN) { |
||||||
|
return gpr_time_from_millis(millis, GPR_TIMESPAN); |
||||||
|
} |
||||||
|
return gpr_time_add(gpr_convert_clock_type(StartTime(), clock_type), |
||||||
|
gpr_time_from_millis(millis, GPR_TIMESPAN)); |
||||||
|
} |
||||||
|
|
||||||
|
int64_t TimespanToMillisRoundUp(gpr_timespec ts) { |
||||||
|
GPR_ASSERT(ts.clock_type == GPR_TIMESPAN); |
||||||
|
double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) + |
||||||
|
static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS + |
||||||
|
static_cast<double>(GPR_NS_PER_SEC - 1) / |
||||||
|
static_cast<double>(GPR_NS_PER_SEC); |
||||||
|
if (x <= static_cast<double>(std::numeric_limits<int64_t>::min())) { |
||||||
|
return std::numeric_limits<int64_t>::min(); |
||||||
|
} |
||||||
|
if (x >= static_cast<double>(std::numeric_limits<int64_t>::max())) { |
||||||
|
return std::numeric_limits<int64_t>::max(); |
||||||
|
} |
||||||
|
return static_cast<int64_t>(x); |
||||||
|
} |
||||||
|
|
||||||
|
int64_t TimespanToMillisRoundDown(gpr_timespec ts) { |
||||||
|
GPR_ASSERT(ts.clock_type == GPR_TIMESPAN); |
||||||
|
double x = GPR_MS_PER_SEC * static_cast<double>(ts.tv_sec) + |
||||||
|
static_cast<double>(ts.tv_nsec) / GPR_NS_PER_MS; |
||||||
|
if (x <= static_cast<double>(std::numeric_limits<int64_t>::min())) { |
||||||
|
return std::numeric_limits<int64_t>::min(); |
||||||
|
} |
||||||
|
if (x >= static_cast<double>(std::numeric_limits<int64_t>::max())) { |
||||||
|
return std::numeric_limits<int64_t>::max(); |
||||||
|
} |
||||||
|
return static_cast<int64_t>(x); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
Timestamp Timestamp::FromTimespecRoundUp(gpr_timespec ts) { |
||||||
|
return FromMillisecondsAfterProcessEpoch(TimespanToMillisRoundUp(gpr_time_sub( |
||||||
|
gpr_convert_clock_type(ts, GPR_CLOCK_MONOTONIC), StartTime()))); |
||||||
|
} |
||||||
|
|
||||||
|
Timestamp Timestamp::FromTimespecRoundDown(gpr_timespec ts) { |
||||||
|
return FromMillisecondsAfterProcessEpoch( |
||||||
|
TimespanToMillisRoundDown(gpr_time_sub( |
||||||
|
gpr_convert_clock_type(ts, GPR_CLOCK_MONOTONIC), StartTime()))); |
||||||
|
} |
||||||
|
|
||||||
|
Timestamp Timestamp::FromCycleCounterRoundUp(gpr_cycle_counter c) { |
||||||
|
return Timestamp::FromMillisecondsAfterProcessEpoch( |
||||||
|
TimespanToMillisRoundUp(gpr_cycle_counter_sub(c, StartCycleCounter()))); |
||||||
|
} |
||||||
|
|
||||||
|
Timestamp Timestamp::FromCycleCounterRoundDown(gpr_cycle_counter c) { |
||||||
|
return Timestamp::FromMillisecondsAfterProcessEpoch( |
||||||
|
TimespanToMillisRoundDown(gpr_cycle_counter_sub(c, StartCycleCounter()))); |
||||||
|
} |
||||||
|
|
||||||
|
gpr_timespec Timestamp::as_timespec(gpr_clock_type clock_type) const { |
||||||
|
return MillisecondsAsTimespec(millis_, clock_type); |
||||||
|
} |
||||||
|
|
||||||
|
std::string Timestamp::ToString() const { |
||||||
|
return "@" + std::to_string(millis_) + "ms"; |
||||||
|
} |
||||||
|
|
||||||
|
gpr_timespec Duration::as_timespec() const { |
||||||
|
return MillisecondsAsTimespec(millis_, GPR_TIMESPAN); |
||||||
|
} |
||||||
|
|
||||||
|
Duration Duration::FromTimespec(gpr_timespec t) { |
||||||
|
return Duration::Milliseconds(TimespanToMillisRoundUp(t)); |
||||||
|
} |
||||||
|
|
||||||
|
std::string Duration::ToString() const { |
||||||
|
return std::to_string(millis_) + "ms"; |
||||||
|
} |
||||||
|
|
||||||
|
void TestOnlySetProcessEpoch(gpr_timespec epoch) { |
||||||
|
g_process_epoch_seconds.store( |
||||||
|
gpr_convert_clock_type(epoch, GPR_CLOCK_MONOTONIC).tv_sec); |
||||||
|
} |
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Timestamp timestamp) { |
||||||
|
return out << timestamp.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Duration duration) { |
||||||
|
return out << duration.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,292 @@ |
|||||||
|
// Copyright 2021 gRPC authors.
|
||||||
|
//
|
||||||
|
// Licensed 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_CORE_LIB_GPRPP_TIME_H |
||||||
|
#define GRPC_CORE_LIB_GPRPP_TIME_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <limits> |
||||||
|
#include <ostream> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include <grpc/support/time.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gpr/time_precise.h" |
||||||
|
#include "src/core/lib/gpr/useful.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
|
||||||
|
namespace time_detail { |
||||||
|
|
||||||
|
inline int64_t MillisAdd(int64_t a, int64_t b) { |
||||||
|
if (a == std::numeric_limits<int64_t>::max() || |
||||||
|
b == std::numeric_limits<int64_t>::max()) { |
||||||
|
return std::numeric_limits<int64_t>::max(); |
||||||
|
} |
||||||
|
if (a == std::numeric_limits<int64_t>::min() || |
||||||
|
b == std::numeric_limits<int64_t>::min()) { |
||||||
|
return std::numeric_limits<int64_t>::min(); |
||||||
|
} |
||||||
|
return SaturatingAdd(a, b); |
||||||
|
} |
||||||
|
|
||||||
|
constexpr inline int64_t MillisMul(int64_t millis, int64_t mul) { |
||||||
|
return millis >= std::numeric_limits<int64_t>::max() / mul |
||||||
|
? std::numeric_limits<int64_t>::max() |
||||||
|
: millis <= std::numeric_limits<int64_t>::min() / mul |
||||||
|
? std::numeric_limits<int64_t>::min() |
||||||
|
: millis * mul; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace time_detail
|
||||||
|
|
||||||
|
class Duration; |
||||||
|
|
||||||
|
// Timestamp represents a discrete point in time.
|
||||||
|
class Timestamp { |
||||||
|
public: |
||||||
|
constexpr Timestamp() = default; |
||||||
|
// Constructs a Timestamp from a gpr_timespec.
|
||||||
|
static Timestamp FromTimespecRoundDown(gpr_timespec t); |
||||||
|
static Timestamp FromTimespecRoundUp(gpr_timespec t); |
||||||
|
|
||||||
|
// Construct a Timestamp from a gpr_cycle_counter.
|
||||||
|
static Timestamp FromCycleCounterRoundUp(gpr_cycle_counter c); |
||||||
|
static Timestamp FromCycleCounterRoundDown(gpr_cycle_counter c); |
||||||
|
|
||||||
|
static constexpr Timestamp FromMillisecondsAfterProcessEpoch(int64_t millis) { |
||||||
|
return Timestamp(millis); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Timestamp ProcessEpoch() { return Timestamp(0); } |
||||||
|
|
||||||
|
static constexpr Timestamp InfFuture() { |
||||||
|
return Timestamp(std::numeric_limits<int64_t>::max()); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Timestamp InfPast() { |
||||||
|
return Timestamp(std::numeric_limits<int64_t>::min()); |
||||||
|
} |
||||||
|
|
||||||
|
constexpr bool operator==(Timestamp other) const { |
||||||
|
return millis_ == other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator!=(Timestamp other) const { |
||||||
|
return millis_ != other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator<(Timestamp other) const { |
||||||
|
return millis_ < other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator<=(Timestamp other) const { |
||||||
|
return millis_ <= other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator>(Timestamp other) const { |
||||||
|
return millis_ > other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator>=(Timestamp other) const { |
||||||
|
return millis_ >= other.millis_; |
||||||
|
} |
||||||
|
Timestamp& operator+=(Duration duration); |
||||||
|
|
||||||
|
bool is_process_epoch() const { return millis_ == 0; } |
||||||
|
|
||||||
|
uint64_t milliseconds_after_process_epoch() const { return millis_; } |
||||||
|
|
||||||
|
gpr_timespec as_timespec(gpr_clock_type type) const; |
||||||
|
|
||||||
|
std::string ToString() const; |
||||||
|
|
||||||
|
private: |
||||||
|
explicit constexpr Timestamp(int64_t millis) : millis_(millis) {} |
||||||
|
|
||||||
|
int64_t millis_ = 0; |
||||||
|
}; |
||||||
|
|
||||||
|
// Duration represents a span of time.
|
||||||
|
class Duration { |
||||||
|
public: |
||||||
|
constexpr Duration() : millis_(0) {} |
||||||
|
|
||||||
|
static Duration FromTimespec(gpr_timespec t); |
||||||
|
static Duration FromSecondsAndNanoseconds(int64_t seconds, int32_t nanos); |
||||||
|
static Duration FromSecondsAsDouble(double seconds); |
||||||
|
|
||||||
|
static constexpr Duration Zero() { return Duration(0); } |
||||||
|
|
||||||
|
// Smallest representatable positive duration.
|
||||||
|
static constexpr Duration Epsilon() { return Duration(1); } |
||||||
|
|
||||||
|
static constexpr Duration NegativeInfinity() { |
||||||
|
return Duration(std::numeric_limits<int64_t>::min()); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration Infinity() { |
||||||
|
return Duration(std::numeric_limits<int64_t>::max()); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration Hours(int64_t hours) { |
||||||
|
return Minutes(time_detail::MillisMul(hours, 60)); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration Minutes(int64_t minutes) { |
||||||
|
return Seconds(time_detail::MillisMul(minutes, 60)); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration Seconds(int64_t seconds) { |
||||||
|
return Milliseconds(time_detail::MillisMul(seconds, GPR_MS_PER_SEC)); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration Milliseconds(int64_t millis) { |
||||||
|
return Duration(millis); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration MicrosecondsRoundDown(int64_t micros) { |
||||||
|
return Duration(micros / GPR_US_PER_MS); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration NanosecondsRoundDown(int64_t nanos) { |
||||||
|
return Duration(nanos / GPR_NS_PER_MS); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration MicrosecondsRoundUp(int64_t micros) { |
||||||
|
return Duration(micros / GPR_US_PER_MS + (micros % GPR_US_PER_MS != 0)); |
||||||
|
} |
||||||
|
|
||||||
|
static constexpr Duration NanosecondsRoundUp(int64_t nanos) { |
||||||
|
return Duration(nanos / GPR_NS_PER_MS + (nanos % GPR_NS_PER_MS != 0)); |
||||||
|
} |
||||||
|
|
||||||
|
constexpr bool operator==(Duration other) const { |
||||||
|
return millis_ == other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator!=(Duration other) const { |
||||||
|
return millis_ != other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator<(Duration other) const { |
||||||
|
return millis_ < other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator<=(Duration other) const { |
||||||
|
return millis_ <= other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator>(Duration other) const { |
||||||
|
return millis_ > other.millis_; |
||||||
|
} |
||||||
|
constexpr bool operator>=(Duration other) const { |
||||||
|
return millis_ >= other.millis_; |
||||||
|
} |
||||||
|
Duration& operator/=(int64_t divisor) { |
||||||
|
if (millis_ == std::numeric_limits<int64_t>::max()) { |
||||||
|
*this = divisor < 0 ? NegativeInfinity() : Infinity(); |
||||||
|
} else if (millis_ == std::numeric_limits<int64_t>::min()) { |
||||||
|
*this = divisor < 0 ? Infinity() : NegativeInfinity(); |
||||||
|
} else { |
||||||
|
millis_ /= divisor; |
||||||
|
} |
||||||
|
return *this; |
||||||
|
} |
||||||
|
Duration& operator+=(Duration other) { |
||||||
|
millis_ += other.millis_; |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
constexpr int64_t millis() const { return millis_; } |
||||||
|
double seconds() const { return static_cast<double>(millis_) / 1000.0; } |
||||||
|
|
||||||
|
gpr_timespec as_timespec() const; |
||||||
|
|
||||||
|
std::string ToString() const; |
||||||
|
|
||||||
|
private: |
||||||
|
explicit constexpr Duration(int64_t millis) : millis_(millis) {} |
||||||
|
|
||||||
|
int64_t millis_; |
||||||
|
}; |
||||||
|
|
||||||
|
inline Duration operator+(Duration lhs, Duration rhs) { |
||||||
|
return Duration::Milliseconds( |
||||||
|
time_detail::MillisAdd(lhs.millis(), rhs.millis())); |
||||||
|
} |
||||||
|
|
||||||
|
inline Duration operator-(Duration lhs, Duration rhs) { |
||||||
|
return Duration::Milliseconds( |
||||||
|
time_detail::MillisAdd(lhs.millis(), -rhs.millis())); |
||||||
|
} |
||||||
|
|
||||||
|
inline Timestamp operator+(Timestamp lhs, Duration rhs) { |
||||||
|
return Timestamp::FromMillisecondsAfterProcessEpoch(time_detail::MillisAdd( |
||||||
|
lhs.milliseconds_after_process_epoch(), rhs.millis())); |
||||||
|
} |
||||||
|
|
||||||
|
inline Timestamp operator-(Timestamp lhs, Duration rhs) { |
||||||
|
return Timestamp::FromMillisecondsAfterProcessEpoch(time_detail::MillisAdd( |
||||||
|
lhs.milliseconds_after_process_epoch(), -rhs.millis())); |
||||||
|
} |
||||||
|
|
||||||
|
inline Timestamp operator+(Duration lhs, Timestamp rhs) { return rhs + lhs; } |
||||||
|
|
||||||
|
inline Duration operator-(Timestamp lhs, Timestamp rhs) { |
||||||
|
return Duration::Milliseconds( |
||||||
|
time_detail::MillisAdd(lhs.milliseconds_after_process_epoch(), |
||||||
|
-rhs.milliseconds_after_process_epoch())); |
||||||
|
} |
||||||
|
|
||||||
|
inline Duration operator*(Duration lhs, double rhs) { |
||||||
|
if (lhs == Duration::Infinity()) { |
||||||
|
return rhs < 0 ? Duration::NegativeInfinity() : Duration::Infinity(); |
||||||
|
} |
||||||
|
if (lhs == Duration::NegativeInfinity()) { |
||||||
|
return rhs < 0 ? Duration::Infinity() : Duration::NegativeInfinity(); |
||||||
|
} |
||||||
|
return Duration::FromSecondsAsDouble(lhs.millis() * rhs / 1000.0); |
||||||
|
} |
||||||
|
|
||||||
|
inline Duration operator*(double lhs, Duration rhs) { return rhs * lhs; } |
||||||
|
|
||||||
|
inline Duration operator/(Duration lhs, int64_t rhs) { |
||||||
|
lhs /= rhs; |
||||||
|
return lhs; |
||||||
|
} |
||||||
|
|
||||||
|
inline Duration Duration::FromSecondsAndNanoseconds(int64_t seconds, |
||||||
|
int32_t nanos) { |
||||||
|
return Seconds(seconds) + NanosecondsRoundDown(nanos); |
||||||
|
} |
||||||
|
|
||||||
|
inline Duration Duration::FromSecondsAsDouble(double seconds) { |
||||||
|
double millis = seconds * 1000.0; |
||||||
|
if (millis >= static_cast<double>(std::numeric_limits<int64_t>::max())) { |
||||||
|
return Infinity(); |
||||||
|
} |
||||||
|
if (millis <= static_cast<double>(std::numeric_limits<int64_t>::min())) { |
||||||
|
return NegativeInfinity(); |
||||||
|
} |
||||||
|
return Milliseconds(static_cast<int64_t>(millis)); |
||||||
|
} |
||||||
|
|
||||||
|
inline Timestamp& Timestamp::operator+=(Duration duration) { |
||||||
|
return *this = (*this + duration); |
||||||
|
} |
||||||
|
|
||||||
|
void TestOnlySetProcessEpoch(gpr_timespec epoch); |
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& out, Timestamp timestamp); |
||||||
|
std::ostream& operator<<(std::ostream& out, Duration duration); |
||||||
|
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif // GRPC_CORE_LIB_GPRPP_TIME_H
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue