- abacaab4b11a69dd4db627bd183571d7cabb8def Refinement to previous time.h edit (in this same github p... by Greg Falcon <gfalcon@google.com>

- 64db19b773134c6c8004e3b23c9ca892efbf8bae Move SpinLock's adaptive spin count computation from a st... by Derek Mauro <dmauro@google.com>
  - 6f9533fb44a52485a7c2bbb9b4efc7bf8d6c359a Import of CCTZ from GitHub. by Abseil Team <absl-team@google.com>
  - a211d7255c986e8dd4ceada362c0d054a6a1969a Cleanup exception flags by Abseil Team <absl-team@google.com>
  - babdb29c590126fe9bba5229fe91034b5b5c358a Release time benchmarks. by Alex Strelnikov <strel@google.com>
  - 5803b32a3ff123d1fb57a0c471d199c818357c9f Release memutil microbenchmarks. by Alex Strelnikov <strel@google.com>
  - 5357d4890d30e80c53beb05af32500fb20e9402b Add parens around expansion of ABSL_PREDICT_{FALSE,TRUE} ... by Abseil Team <absl-team@google.com>
  - 32023f61a239a5f6b1c59e577bfe81b179bbcd2d Reformat build rule tag. by Alex Strelnikov <strel@google.com>
  - 833758ecf2b0cf7a42bbd50b5b127e416425c168 Release uint128 microbenchmarks. by Alex Strelnikov <strel@google.com>
  - c115a9bca1f944b90fdc78a56b2de176466b124f Disambiguate bitwise-not of size_type by Abseil Team <absl-team@google.com>
  - f6905f5b5f6e425792de646edafde440548d9346 Updates ConstructorTracker and TrackedObjects with 1) a m... by Abseil Team <absl-team@google.com>
  - 147c553bdd5d2db20a38f75c4d1ef973d6c709c5 Changes the absl::Duration factory functions to disallow ... by Greg Miller <jgm@google.com>
  - dba2b96d11b5264546b283ba452f2de1303b0f07 White space fix by Alex Strelnikov <strel@google.com>

GitOrigin-RevId: abacaab4b11a69dd4db627bd183571d7cabb8def
Change-Id: I6fa34f20d0b2f898e7b5475a603111413bb80a67
This commit is contained in:
Abseil Team 2018-06-08 08:14:48 -07:00 committed by Gennadiy Civil
parent 7aacab8ae0
commit 92020a042c
22 changed files with 1808 additions and 282 deletions

View file

@ -93,3 +93,23 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "time_benchmark",
srcs = [
"clock_benchmark.cc",
"duration_benchmark.cc",
"format_benchmark.cc",
"time_benchmark.cc",
],
copts = ABSL_TEST_COPTS,
tags = [
"benchmark",
],
deps = [
":test_util",
":time",
"//absl/base",
"@com_github_google_benchmark//:benchmark_main",
],
)

View file

@ -0,0 +1,72 @@
// Copyright 2018 The Abseil 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 "absl/time/clock.h"
#if !defined(_WIN32)
#include <sys/time.h>
#endif // _WIN32
#include <cstdio>
#include "absl/base/internal/cycleclock.h"
#include "benchmark/benchmark.h"
namespace {
void BM_Clock_Now_AbslTime(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::Now());
}
}
BENCHMARK(BM_Clock_Now_AbslTime);
void BM_Clock_Now_GetCurrentTimeNanos(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::GetCurrentTimeNanos());
}
}
BENCHMARK(BM_Clock_Now_GetCurrentTimeNanos);
void BM_Clock_Now_AbslTime_ToUnixNanos(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToUnixNanos(absl::Now()));
}
}
BENCHMARK(BM_Clock_Now_AbslTime_ToUnixNanos);
void BM_Clock_Now_CycleClock(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::base_internal::CycleClock::Now());
}
}
BENCHMARK(BM_Clock_Now_CycleClock);
#if !defined(_WIN32)
static void BM_Clock_Now_gettimeofday(benchmark::State& state) {
struct timeval tv;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(gettimeofday(&tv, nullptr));
}
}
BENCHMARK(BM_Clock_Now_gettimeofday);
static void BM_Clock_Now_clock_gettime(benchmark::State& state) {
struct timespec ts;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(clock_gettime(CLOCK_REALTIME, &ts));
}
}
BENCHMARK(BM_Clock_Now_clock_gettime);
#endif // _WIN32
} // namespace

View file

@ -0,0 +1,361 @@
// Copyright 2018 The Abseil 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 <cmath>
#include <cstddef>
#include <cstdint>
#include <ctime>
#include <string>
#include "absl/time/time.h"
#include "benchmark/benchmark.h"
namespace {
//
// Factory functions
//
void BM_Duration_Factory_Nanoseconds(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::Nanoseconds(1));
}
}
BENCHMARK(BM_Duration_Factory_Nanoseconds);
void BM_Duration_Factory_Microseconds(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::Microseconds(1));
}
}
BENCHMARK(BM_Duration_Factory_Microseconds);
void BM_Duration_Factory_Milliseconds(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::Milliseconds(1));
}
}
BENCHMARK(BM_Duration_Factory_Milliseconds);
void BM_Duration_Factory_Seconds(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::Seconds(1));
}
}
BENCHMARK(BM_Duration_Factory_Seconds);
void BM_Duration_Factory_Minutes(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::Minutes(1));
}
}
BENCHMARK(BM_Duration_Factory_Minutes);
void BM_Duration_Factory_Hours(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::Hours(1));
}
}
BENCHMARK(BM_Duration_Factory_Hours);
//
// Arithmetic
//
void BM_Duration_Addition(benchmark::State& state) {
absl::Duration d = absl::Nanoseconds(1);
absl::Duration step = absl::Milliseconds(1);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(d += step);
}
}
BENCHMARK(BM_Duration_Addition);
void BM_Duration_Subtraction(benchmark::State& state) {
absl::Duration d = absl::Seconds(std::numeric_limits<int64_t>::max());
absl::Duration step = absl::Milliseconds(1);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(d -= step);
}
}
BENCHMARK(BM_Duration_Subtraction);
void BM_Duration_Multiplication_Fixed(benchmark::State& state) {
absl::Duration d = absl::Milliseconds(1);
absl::Duration s;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(s += d * (i + 1));
++i;
}
}
BENCHMARK(BM_Duration_Multiplication_Fixed);
void BM_Duration_Multiplication_Double(benchmark::State& state) {
absl::Duration d = absl::Milliseconds(1);
absl::Duration s;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(s += d * (i + 1.0));
++i;
}
}
BENCHMARK(BM_Duration_Multiplication_Double);
void BM_Duration_Division_Fixed(benchmark::State& state) {
absl::Duration d = absl::Seconds(1);
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(d /= i + 1);
++i;
}
}
BENCHMARK(BM_Duration_Division_Fixed);
void BM_Duration_Division_Double(benchmark::State& state) {
absl::Duration d = absl::Seconds(1);
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(d /= i + 1.0);
++i;
}
}
BENCHMARK(BM_Duration_Division_Double);
void BM_Duration_FDivDuration_Nanoseconds(benchmark::State& state) {
double d = 1;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(
d += absl::FDivDuration(absl::Milliseconds(i), absl::Nanoseconds(1)));
++i;
}
}
BENCHMARK(BM_Duration_FDivDuration_Nanoseconds);
void BM_Duration_IDivDuration_Nanoseconds(benchmark::State& state) {
int64_t a = 1;
absl::Duration ignore;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(a +=
absl::IDivDuration(absl::Nanoseconds(i),
absl::Nanoseconds(1), &ignore));
++i;
}
}
BENCHMARK(BM_Duration_IDivDuration_Nanoseconds);
void BM_Duration_IDivDuration_Microseconds(benchmark::State& state) {
int64_t a = 1;
absl::Duration ignore;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(a += absl::IDivDuration(absl::Microseconds(i),
absl::Microseconds(1),
&ignore));
++i;
}
}
BENCHMARK(BM_Duration_IDivDuration_Microseconds);
void BM_Duration_IDivDuration_Milliseconds(benchmark::State& state) {
int64_t a = 1;
absl::Duration ignore;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(a += absl::IDivDuration(absl::Milliseconds(i),
absl::Milliseconds(1),
&ignore));
++i;
}
}
BENCHMARK(BM_Duration_IDivDuration_Milliseconds);
void BM_Duration_IDivDuration_Seconds(benchmark::State& state) {
int64_t a = 1;
absl::Duration ignore;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(
a += absl::IDivDuration(absl::Seconds(i), absl::Seconds(1), &ignore));
++i;
}
}
BENCHMARK(BM_Duration_IDivDuration_Seconds);
void BM_Duration_IDivDuration_Minutes(benchmark::State& state) {
int64_t a = 1;
absl::Duration ignore;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(
a += absl::IDivDuration(absl::Minutes(i), absl::Minutes(1), &ignore));
++i;
}
}
BENCHMARK(BM_Duration_IDivDuration_Minutes);
void BM_Duration_IDivDuration_Hours(benchmark::State& state) {
int64_t a = 1;
absl::Duration ignore;
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(
a += absl::IDivDuration(absl::Hours(i), absl::Hours(1), &ignore));
++i;
}
}
BENCHMARK(BM_Duration_IDivDuration_Hours);
void BM_Duration_ToInt64Nanoseconds(benchmark::State& state) {
absl::Duration d = absl::Seconds(100000);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToInt64Nanoseconds(d));
}
}
BENCHMARK(BM_Duration_ToInt64Nanoseconds);
void BM_Duration_ToInt64Microseconds(benchmark::State& state) {
absl::Duration d = absl::Seconds(100000);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToInt64Microseconds(d));
}
}
BENCHMARK(BM_Duration_ToInt64Microseconds);
void BM_Duration_ToInt64Milliseconds(benchmark::State& state) {
absl::Duration d = absl::Seconds(100000);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToInt64Milliseconds(d));
}
}
BENCHMARK(BM_Duration_ToInt64Milliseconds);
void BM_Duration_ToInt64Seconds(benchmark::State& state) {
absl::Duration d = absl::Seconds(100000);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToInt64Seconds(d));
}
}
BENCHMARK(BM_Duration_ToInt64Seconds);
void BM_Duration_ToInt64Minutes(benchmark::State& state) {
absl::Duration d = absl::Seconds(100000);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToInt64Minutes(d));
}
}
BENCHMARK(BM_Duration_ToInt64Minutes);
void BM_Duration_ToInt64Hours(benchmark::State& state) {
absl::Duration d = absl::Seconds(100000);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToInt64Hours(d));
}
}
BENCHMARK(BM_Duration_ToInt64Hours);
//
// To/FromTimespec
//
void BM_Duration_ToTimespec_AbslTime(benchmark::State& state) {
absl::Duration d = absl::Seconds(1);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToTimespec(d));
}
}
BENCHMARK(BM_Duration_ToTimespec_AbslTime);
ABSL_ATTRIBUTE_NOINLINE timespec DoubleToTimespec(double seconds) {
timespec ts;
ts.tv_sec = seconds;
ts.tv_nsec = (seconds - ts.tv_sec) * (1000 * 1000 * 1000);
return ts;
}
void BM_Duration_ToTimespec_Double(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(DoubleToTimespec(1.0));
}
}
BENCHMARK(BM_Duration_ToTimespec_Double);
void BM_Duration_FromTimespec_AbslTime(benchmark::State& state) {
timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
while (state.KeepRunning()) {
if (++ts.tv_nsec == 1000 * 1000 * 1000) {
++ts.tv_sec;
ts.tv_nsec = 0;
}
benchmark::DoNotOptimize(absl::DurationFromTimespec(ts));
}
}
BENCHMARK(BM_Duration_FromTimespec_AbslTime);
ABSL_ATTRIBUTE_NOINLINE double TimespecToDouble(timespec ts) {
return ts.tv_sec + (ts.tv_nsec / (1000 * 1000 * 1000));
}
void BM_Duration_FromTimespec_Double(benchmark::State& state) {
timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
while (state.KeepRunning()) {
if (++ts.tv_nsec == 1000 * 1000 * 1000) {
++ts.tv_sec;
ts.tv_nsec = 0;
}
benchmark::DoNotOptimize(TimespecToDouble(ts));
}
}
BENCHMARK(BM_Duration_FromTimespec_Double);
//
// String conversions
//
const char* const kDurations[] = {
"0", // 0
"123ns", // 1
"1h2m3s", // 2
"-2h3m4.005006007s", // 3
"2562047788015215h30m7.99999999975s", // 4
};
const int kNumDurations = sizeof(kDurations) / sizeof(kDurations[0]);
void BM_Duration_FormatDuration(benchmark::State& state) {
const std::string s = kDurations[state.range(0)];
state.SetLabel(s);
absl::Duration d;
absl::ParseDuration(kDurations[state.range(0)], &d);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::FormatDuration(d));
}
}
BENCHMARK(BM_Duration_FormatDuration)->DenseRange(0, kNumDurations - 1);
void BM_Duration_ParseDuration(benchmark::State& state) {
const std::string s = kDurations[state.range(0)];
state.SetLabel(s);
absl::Duration d;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ParseDuration(s, &d));
}
}
BENCHMARK(BM_Duration_ParseDuration)->DenseRange(0, kNumDurations - 1);
} // namespace

View file

@ -330,18 +330,10 @@ TEST(Duration, ToChrono) {
EXPECT_EQ(hours::max(), absl::ToChronoHours(inf));
}
// Used for testing the factory overloads.
template <typename T>
struct ImplicitlyConvertible {
T n_;
explicit ImplicitlyConvertible(T n) : n_(n) {}
// Marking this conversion operator with 'explicit' will cause the test to
// fail (as desired).
operator T() { return n_; }
};
TEST(Duration, FactoryOverloads) {
enum E { kOne = 1 };
#define TEST_FACTORY_OVERLOADS(NAME) \
EXPECT_EQ(1, NAME(kOne) / NAME(kOne)); \
EXPECT_EQ(1, NAME(static_cast<int8_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(static_cast<int16_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(static_cast<int32_t>(1)) / NAME(1)); \
@ -350,14 +342,6 @@ TEST(Duration, FactoryOverloads) {
EXPECT_EQ(1, NAME(static_cast<uint16_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(static_cast<uint32_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(static_cast<uint64_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<int8_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<int16_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<int32_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<int64_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint8_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint16_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint32_t>(1)) / NAME(1)); \
EXPECT_EQ(1, NAME(ImplicitlyConvertible<uint64_t>(1)) / NAME(1)); \
EXPECT_EQ(NAME(1) / 2, NAME(static_cast<float>(0.5))); \
EXPECT_EQ(NAME(1) / 2, NAME(static_cast<double>(0.5))); \
EXPECT_EQ(1.5, absl::FDivDuration(NAME(static_cast<float>(1.5)), NAME(1))); \

View file

@ -0,0 +1,63 @@
// Copyright 2018 The Abseil 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 <cstddef>
#include <string>
#include "absl/time/internal/test_util.h"
#include "absl/time/time.h"
#include "benchmark/benchmark.h"
namespace {
namespace {
const char* const kFormats[] = {
absl::RFC1123_full, // 0
absl::RFC1123_no_wday, // 1
absl::RFC3339_full, // 2
absl::RFC3339_sec, // 3
"%Y-%m-%dT%H:%M:%S", // 4
"%Y-%m-%d", // 5
};
const int kNumFormats = sizeof(kFormats) / sizeof(kFormats[0]);
} // namespace
void BM_Format_FormatTime(benchmark::State& state) {
const std::string fmt = kFormats[state.range(0)];
state.SetLabel(fmt);
const absl::TimeZone lax =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
const absl::Time t =
absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::FormatTime(fmt, t, lax).length());
}
}
BENCHMARK(BM_Format_FormatTime)->DenseRange(0, kNumFormats - 1);
void BM_Format_ParseTime(benchmark::State& state) {
const std::string fmt = kFormats[state.range(0)];
state.SetLabel(fmt);
const absl::TimeZone lax =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
absl::Time t =
absl::FromDateTime(1977, 6, 28, 9, 8, 7, lax) + absl::Nanoseconds(1);
const std::string when = absl::FormatTime(fmt, t, lax);
std::string err;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ParseTime(fmt, when, lax, &t, &err));
}
}
BENCHMARK(BM_Format_ParseTime)->DenseRange(0, kNumFormats - 1);
} // namespace

View file

@ -463,13 +463,12 @@ TEST(Format, ExtendedSecondOffset) {
EXPECT_TRUE(load_time_zone("Europe/Moscow", &tz));
tp = convert(civil_second(1919, 6, 30, 23, 59, 59), utc);
if (tz.lookup(tp).offset == 4 * 60 * 60) {
// We're likely dealing with zoneinfo that doesn't support really old
// timestamps, so Europe/Moscow never looks to be on local mean time.
} else {
TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19");
TestFormatSpecifier(tp, tz, "%Ez", "+04:31");
}
#if defined(__ANDROID__) && __ANDROID_API__ < 25
// Only Android 'N'.1 and beyond have this tz2016g transition.
#else
TestFormatSpecifier(tp, tz, "%E*z", "+04:31:19");
TestFormatSpecifier(tp, tz, "%Ez", "+04:31");
#endif
tp += seconds(1);
TestFormatSpecifier(tp, tz, "%E*z", "+04:00:00");
}

View file

@ -693,7 +693,14 @@ TEST(TimeZones, LoadZonesConcurrently) {
// Allow a small number of failures to account for skew between
// the contents of kTimeZoneNames and the zoneinfo data source.
#if defined(__ANDROID__)
// Cater to the possibility of using an even older zoneinfo data
// source when running on Android, where it is difficult to override
// the bionic tzdata provided by the test environment.
const std::size_t max_failures = 20;
#else
const std::size_t max_failures = 3;
#endif
std::set<std::string> failures;
for (const auto& thread_failure : thread_failures) {
failures.insert(thread_failure.begin(), thread_failure.end());
@ -839,7 +846,7 @@ TEST(TimeZoneImpl, LocalTimeInFixed) {
const time_zone tz = fixed_time_zone(offset);
const auto tp = system_clock::from_time_t(0);
ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false,
"UTC-083347");
"-083347");
EXPECT_EQ(weekday::wednesday, get_weekday(civil_day(convert(tp, tz))));
}
@ -1098,6 +1105,9 @@ TEST(TimeZoneEdgeCase, PacificApia) {
TEST(TimeZoneEdgeCase, AfricaCairo) {
const time_zone tz = LoadZone("Africa/Cairo");
#if defined(__ANDROID__) && __ANDROID_API__ < 21
// Only Android 'L' and beyond have this tz2014c transition.
#else
// An interesting case of midnight not existing.
//
// 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET)
@ -1106,11 +1116,15 @@ TEST(TimeZoneEdgeCase, AfricaCairo) {
ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET");
tp += seconds(1);
ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST");
#endif
}
TEST(TimeZoneEdgeCase, AfricaMonrovia) {
const time_zone tz = LoadZone("Africa/Monrovia");
#if defined(__ANDROID__) && __ANDROID_API__ < 26
// Only Android 'O' and beyond have this tz2017b transition.
#else
// Strange offset change -00:44:30 -> +00:00:00 (non-DST)
//
// 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT)
@ -1119,6 +1133,7 @@ TEST(TimeZoneEdgeCase, AfricaMonrovia) {
ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
tp += seconds(1);
ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
#endif
}
TEST(TimeZoneEdgeCase, AmericaJamaica) {

View file

@ -82,8 +82,15 @@ constexpr Duration MakeDuration(int64_t hi, uint32_t lo);
constexpr Duration MakeDuration(int64_t hi, int64_t lo);
constexpr int64_t kTicksPerNanosecond = 4;
constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond;
template <std::intmax_t N>
constexpr Duration FromInt64(int64_t v, std::ratio<1, N>);
constexpr Duration FromInt64(int64_t v, std::ratio<60>);
constexpr Duration FromInt64(int64_t v, std::ratio<3600>);
template <typename T>
using IsFloatingPoint =
using EnableIfIntegral = typename std::enable_if<
std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
template <typename T>
using EnableIfFloat =
typename std::enable_if<std::is_floating_point<T>::value, int>::type;
} // namespace time_internal
@ -178,15 +185,15 @@ inline Duration operator-(Duration lhs, Duration rhs) { return lhs -= rhs; }
// Multiplicative Operators
template <typename T>
inline Duration operator*(Duration lhs, T rhs) {
Duration operator*(Duration lhs, T rhs) {
return lhs *= rhs;
}
template <typename T>
inline Duration operator*(T lhs, Duration rhs) {
Duration operator*(T lhs, Duration rhs) {
return rhs *= lhs;
}
template <typename T>
inline Duration operator/(Duration lhs, T rhs) {
Duration operator/(Duration lhs, T rhs) {
return lhs /= rhs;
}
inline int64_t operator/(Duration lhs, Duration rhs) {
@ -322,27 +329,27 @@ constexpr Duration Hours(int64_t n);
// Example:
// auto a = absl::Seconds(1.5); // OK
// auto b = absl::Milliseconds(1500); // BETTER
template <typename T, time_internal::IsFloatingPoint<T> = 0>
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Nanoseconds(T n) {
return n * Nanoseconds(1);
}
template <typename T, time_internal::IsFloatingPoint<T> = 0>
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Microseconds(T n) {
return n * Microseconds(1);
}
template <typename T, time_internal::IsFloatingPoint<T> = 0>
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Milliseconds(T n) {
return n * Milliseconds(1);
}
template <typename T, time_internal::IsFloatingPoint<T> = 0>
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Seconds(T n) {
return n * Seconds(1);
}
template <typename T, time_internal::IsFloatingPoint<T> = 0>
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Minutes(T n) {
return n * Minutes(1);
}
template <typename T, time_internal::IsFloatingPoint<T> = 0>
template <typename T, time_internal::EnableIfFloat<T> = 0>
Duration Hours(T n) {
return n * Hours(1);
}
@ -1154,10 +1161,16 @@ constexpr Duration FromInt64(int64_t v, std::ratio<1, N>) {
v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N);
}
constexpr Duration FromInt64(int64_t v, std::ratio<60>) {
return Minutes(v);
return (v <= std::numeric_limits<int64_t>::max() / 60 &&
v >= std::numeric_limits<int64_t>::min() / 60)
? MakeDuration(v * 60)
: v > 0 ? InfiniteDuration() : -InfiniteDuration();
}
constexpr Duration FromInt64(int64_t v, std::ratio<3600>) {
return Hours(v);
return (v <= std::numeric_limits<int64_t>::max() / 3600 &&
v >= std::numeric_limits<int64_t>::min() / 3600)
? MakeDuration(v * 3600)
: v > 0 ? InfiniteDuration() : -InfiniteDuration();
}
// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is
@ -1220,6 +1233,24 @@ T ToChronoDuration(Duration d) {
}
} // namespace time_internal
constexpr Duration Nanoseconds(int64_t n) {
return time_internal::FromInt64(n, std::nano{});
}
constexpr Duration Microseconds(int64_t n) {
return time_internal::FromInt64(n, std::micro{});
}
constexpr Duration Milliseconds(int64_t n) {
return time_internal::FromInt64(n, std::milli{});
}
constexpr Duration Seconds(int64_t n) {
return time_internal::FromInt64(n, std::ratio<1>{});
}
constexpr Duration Minutes(int64_t n) {
return time_internal::FromInt64(n, std::ratio<60>{});
}
constexpr Duration Hours(int64_t n) {
return time_internal::FromInt64(n, std::ratio<3600>{});
}
constexpr bool operator<(Duration lhs, Duration rhs) {
return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
@ -1261,39 +1292,6 @@ constexpr Duration operator-(Duration d) {
time_internal::GetRepLo(d));
}
constexpr Duration Nanoseconds(int64_t n) {
return time_internal::MakeNormalizedDuration(
n / (1000 * 1000 * 1000),
n % (1000 * 1000 * 1000) * time_internal::kTicksPerNanosecond);
}
constexpr Duration Microseconds(int64_t n) {
return time_internal::MakeNormalizedDuration(
n / (1000 * 1000),
n % (1000 * 1000) * (1000 * time_internal::kTicksPerNanosecond));
}
constexpr Duration Milliseconds(int64_t n) {
return time_internal::MakeNormalizedDuration(
n / 1000, n % 1000 * (1000 * 1000 * time_internal::kTicksPerNanosecond));
}
constexpr Duration Seconds(int64_t n) { return time_internal::MakeDuration(n); }
constexpr Duration Minutes(int64_t n) {
return (n <= std::numeric_limits<int64_t>::max() / 60 &&
n >= std::numeric_limits<int64_t>::min() / 60)
? time_internal::MakeDuration(n * 60)
: n > 0 ? InfiniteDuration() : -InfiniteDuration();
}
constexpr Duration Hours(int64_t n) {
return (n <= std::numeric_limits<int64_t>::max() / 3600 &&
n >= std::numeric_limits<int64_t>::min() / 3600)
? time_internal::MakeDuration(n * 3600)
: n > 0 ? InfiniteDuration() : -InfiniteDuration();
}
constexpr Duration InfiniteDuration() {
return time_internal::MakeDuration(std::numeric_limits<int64_t>::max(), ~0U);
}

316
absl/time/time_benchmark.cc Normal file
View file

@ -0,0 +1,316 @@
// Copyright 2018 The Abseil 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 "absl/time/time.h"
#if !defined(_WIN32)
#include <sys/time.h>
#endif // _WIN32
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstring>
#include <ctime>
#include <memory>
#include <string>
#include "absl/time/clock.h"
#include "absl/time/internal/test_util.h"
#include "benchmark/benchmark.h"
namespace {
//
// Addition/Subtraction of a duration
//
void BM_Time_Arithmetic(benchmark::State& state) {
const absl::Duration nano = absl::Nanoseconds(1);
const absl::Duration sec = absl::Seconds(1);
absl::Time t = absl::UnixEpoch();
while (state.KeepRunning()) {
benchmark::DoNotOptimize(t += nano);
benchmark::DoNotOptimize(t -= sec);
}
}
BENCHMARK(BM_Time_Arithmetic);
//
// Time difference
//
void BM_Time_Difference(benchmark::State& state) {
absl::Time start = absl::Now();
absl::Time end = start + absl::Nanoseconds(1);
absl::Duration diff;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(diff += end - start);
}
}
BENCHMARK(BM_Time_Difference);
//
// ToDateTime
//
// In each "ToDateTime" benchmark we switch between two instants
// separated by at least one transition in order to defeat any
// internal caching of previous results (e.g., see local_time_hint_).
//
// The "UTC" variants use UTC instead of the Google/local time zone.
//
void BM_Time_ToDateTime_Absl(benchmark::State& state) {
const absl::TimeZone tz =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
absl::Time t = absl::FromUnixSeconds(1384569027);
absl::Time t2 = absl::FromUnixSeconds(1418962578);
while (state.KeepRunning()) {
std::swap(t, t2);
t += absl::Seconds(1);
benchmark::DoNotOptimize(t.In(tz));
}
}
BENCHMARK(BM_Time_ToDateTime_Absl);
void BM_Time_ToDateTime_Libc(benchmark::State& state) {
// No timezone support, so just use localtime.
time_t t = 1384569027;
time_t t2 = 1418962578;
while (state.KeepRunning()) {
std::swap(t, t2);
t += 1;
struct tm tm;
#if !defined(_WIN32)
benchmark::DoNotOptimize(localtime_r(&t, &tm));
#else // _WIN32
benchmark::DoNotOptimize(localtime_s(&tm, &t));
#endif // _WIN32
}
}
BENCHMARK(BM_Time_ToDateTime_Libc);
void BM_Time_ToDateTimeUTC_Absl(benchmark::State& state) {
const absl::TimeZone tz = absl::UTCTimeZone();
absl::Time t = absl::FromUnixSeconds(1384569027);
while (state.KeepRunning()) {
t += absl::Seconds(1);
benchmark::DoNotOptimize(t.In(tz));
}
}
BENCHMARK(BM_Time_ToDateTimeUTC_Absl);
void BM_Time_ToDateTimeUTC_Libc(benchmark::State& state) {
time_t t = 1384569027;
while (state.KeepRunning()) {
t += 1;
struct tm tm;
#if !defined(_WIN32)
benchmark::DoNotOptimize(gmtime_r(&t, &tm));
#else // _WIN32
benchmark::DoNotOptimize(gmtime_s(&tm, &t));
#endif // _WIN32
}
}
BENCHMARK(BM_Time_ToDateTimeUTC_Libc);
//
// FromUnixMicros
//
void BM_Time_FromUnixMicros(benchmark::State& state) {
int i = 0;
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::FromUnixMicros(i));
++i;
}
}
BENCHMARK(BM_Time_FromUnixMicros);
void BM_Time_ToUnixNanos(benchmark::State& state) {
const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(ToUnixNanos(t));
}
}
BENCHMARK(BM_Time_ToUnixNanos);
void BM_Time_ToUnixMicros(benchmark::State& state) {
const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(ToUnixMicros(t));
}
}
BENCHMARK(BM_Time_ToUnixMicros);
void BM_Time_ToUnixMillis(benchmark::State& state) {
const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(ToUnixMillis(t));
}
}
BENCHMARK(BM_Time_ToUnixMillis);
void BM_Time_ToUnixSeconds(benchmark::State& state) {
const absl::Time t = absl::UnixEpoch() + absl::Seconds(123);
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToUnixSeconds(t));
}
}
BENCHMARK(BM_Time_ToUnixSeconds);
//
// FromDateTime
//
// In each "FromDateTime" benchmark we switch between two YMDhms
// values separated by at least one transition in order to defeat any
// internal caching of previous results (e.g., see time_local_hint_).
//
// The "UTC" variants use UTC instead of the Google/local time zone.
// The "Day0" variants require normalization of the day of month.
//
void BM_Time_FromDateTime_Absl(benchmark::State& state) {
const absl::TimeZone tz =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
int i = 0;
while (state.KeepRunning()) {
if ((i & 1) == 0) {
absl::FromDateTime(2014, 12, 18, 20, 16, 18, tz);
} else {
absl::FromDateTime(2013, 11, 15, 18, 30, 27, tz);
}
++i;
}
}
BENCHMARK(BM_Time_FromDateTime_Absl);
void BM_Time_FromDateTime_Libc(benchmark::State& state) {
// No timezone support, so just use localtime.
int i = 0;
while (state.KeepRunning()) {
struct tm tm;
if ((i & 1) == 0) {
tm.tm_year = 2014 - 1900;
tm.tm_mon = 12 - 1;
tm.tm_mday = 18;
tm.tm_hour = 20;
tm.tm_min = 16;
tm.tm_sec = 18;
} else {
tm.tm_year = 2013 - 1900;
tm.tm_mon = 11 - 1;
tm.tm_mday = 15;
tm.tm_hour = 18;
tm.tm_min = 30;
tm.tm_sec = 27;
}
tm.tm_isdst = -1;
mktime(&tm);
++i;
}
}
BENCHMARK(BM_Time_FromDateTime_Libc);
void BM_Time_FromDateTimeUTC_Absl(benchmark::State& state) {
const absl::TimeZone tz = absl::UTCTimeZone();
while (state.KeepRunning()) {
FromDateTime(2014, 12, 18, 20, 16, 18, tz);
}
}
BENCHMARK(BM_Time_FromDateTimeUTC_Absl);
void BM_Time_FromDateTimeDay0_Absl(benchmark::State& state) {
const absl::TimeZone tz =
absl::time_internal::LoadTimeZone("America/Los_Angeles");
int i = 0;
while (state.KeepRunning()) {
if ((i & 1) == 0) {
absl::FromDateTime(2014, 12, 0, 20, 16, 18, tz);
} else {
absl::FromDateTime(2013, 11, 0, 18, 30, 27, tz);
}
++i;
}
}
BENCHMARK(BM_Time_FromDateTimeDay0_Absl);
void BM_Time_FromDateTimeDay0_Libc(benchmark::State& state) {
// No timezone support, so just use localtime.
int i = 0;
while (state.KeepRunning()) {
struct tm tm;
if ((i & 1) == 0) {
tm.tm_year = 2014 - 1900;
tm.tm_mon = 12 - 1;
tm.tm_mday = 0;
tm.tm_hour = 20;
tm.tm_min = 16;
tm.tm_sec = 18;
} else {
tm.tm_year = 2013 - 1900;
tm.tm_mon = 11 - 1;
tm.tm_mday = 0;
tm.tm_hour = 18;
tm.tm_min = 30;
tm.tm_sec = 27;
}
tm.tm_isdst = -1;
mktime(&tm);
++i;
}
}
BENCHMARK(BM_Time_FromDateTimeDay0_Libc);
//
// To/FromTimespec
//
void BM_Time_ToTimespec(benchmark::State& state) {
absl::Time now = absl::Now();
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::ToTimespec(now));
}
}
BENCHMARK(BM_Time_ToTimespec);
void BM_Time_FromTimespec(benchmark::State& state) {
timespec ts = absl::ToTimespec(absl::Now());
while (state.KeepRunning()) {
if (++ts.tv_nsec == 1000 * 1000 * 1000) {
++ts.tv_sec;
ts.tv_nsec = 0;
}
benchmark::DoNotOptimize(absl::TimeFromTimespec(ts));
}
}
BENCHMARK(BM_Time_FromTimespec);
//
// Comparison with InfiniteFuture/Past
//
void BM_Time_InfiniteFuture(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::InfiniteFuture());
}
}
BENCHMARK(BM_Time_InfiniteFuture);
void BM_Time_InfinitePast(benchmark::State& state) {
while (state.KeepRunning()) {
benchmark::DoNotOptimize(absl::InfinitePast());
}
}
BENCHMARK(BM_Time_InfinitePast);
} // namespace