about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2018-06-08T15·14-0700
committerGennadiy Civil <misterg@google.com>2018-06-08T15·24-0400
commit92020a042c0cd46979db9f6f0cb32783dc07765e (patch)
tree5f4ebb5a8b0a8c4f0e5e2a061e63665b2071d92f
parent7aacab8ae05d7115049923da9cfbf584dc1f8338 (diff)
- 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
-rw-r--r--absl/base/exception_safety_testing_test.cc71
-rw-r--r--absl/base/internal/exception_safety_testing.cc31
-rw-r--r--absl/base/internal/exception_safety_testing.h182
-rw-r--r--absl/base/internal/spinlock.cc30
-rw-r--r--absl/base/optimization.h4
-rw-r--r--absl/numeric/BUILD.bazel12
-rw-r--r--absl/numeric/int128_benchmark.cc221
-rw-r--r--absl/strings/BUILD.bazel16
-rw-r--r--absl/strings/internal/memutil_benchmark.cc323
-rw-r--r--absl/time/BUILD.bazel20
-rw-r--r--absl/time/clock_benchmark.cc72
-rw-r--r--absl/time/duration_benchmark.cc361
-rw-r--r--absl/time/duration_test.cc20
-rw-r--r--absl/time/format_benchmark.cc63
-rw-r--r--absl/time/internal/cctz/src/time_zone_format_test.cc13
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup_test.cc17
-rw-r--r--absl/time/time.h88
-rw-r--r--absl/time/time_benchmark.cc316
-rw-r--r--absl/types/BUILD.bazel15
-rw-r--r--absl/types/optional_exception_safety_test.cc84
-rw-r--r--absl/types/span.h2
-rw-r--r--absl/types/variant_exception_safety_test.cc121
22 files changed, 1804 insertions, 278 deletions
diff --git a/absl/base/exception_safety_testing_test.cc b/absl/base/exception_safety_testing_test.cc
index a8b82b73daf1..97c8d6f83189 100644
--- a/absl/base/exception_safety_testing_test.cc
+++ b/absl/base/exception_safety_testing_test.cc
@@ -168,8 +168,58 @@ TEST(ThrowingValueTest, ThrowingCompoundAssignmentOps) {
 TEST(ThrowingValueTest, ThrowingStreamOps) {
   ThrowingValue<> bomb;
 
-  TestOp([&]() { std::cin >> bomb; });
-  TestOp([&]() { std::cout << bomb; });
+  TestOp([&]() {
+    std::istringstream stream;
+    stream >> bomb;
+  });
+  TestOp([&]() {
+    std::stringstream stream;
+    stream << bomb;
+  });
+}
+
+// Tests the operator<< of ThrowingValue by forcing ConstructorTracker to emit
+// a nonfatal failure that contains the std::string representation of the Thrower
+TEST(ThrowingValueTest, StreamOpsOutput) {
+  using ::testing::TypeSpec;
+  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
+
+  // Test default spec list (kEverythingThrows)
+  EXPECT_NONFATAL_FAILURE(
+      {
+        using Thrower = ThrowingValue<TypeSpec{}>;
+        auto thrower = Thrower(123);
+        thrower.~Thrower();
+      },
+      "ThrowingValue<>(123)");
+
+  // Test with one item in spec list (kNoThrowCopy)
+  EXPECT_NONFATAL_FAILURE(
+      {
+        using Thrower = ThrowingValue<TypeSpec::kNoThrowCopy>;
+        auto thrower = Thrower(234);
+        thrower.~Thrower();
+      },
+      "ThrowingValue<kNoThrowCopy>(234)");
+
+  // Test with multiple items in spec list (kNoThrowMove, kNoThrowNew)
+  EXPECT_NONFATAL_FAILURE(
+      {
+        using Thrower =
+            ThrowingValue<TypeSpec::kNoThrowMove | TypeSpec::kNoThrowNew>;
+        auto thrower = Thrower(345);
+        thrower.~Thrower();
+      },
+      "ThrowingValue<kNoThrowMove | kNoThrowNew>(345)");
+
+  // Test with all items in spec list (kNoThrowCopy, kNoThrowMove, kNoThrowNew)
+  EXPECT_NONFATAL_FAILURE(
+      {
+        using Thrower = ThrowingValue<static_cast<TypeSpec>(-1)>;
+        auto thrower = Thrower(456);
+        thrower.~Thrower();
+      },
+      "ThrowingValue<kNoThrowCopy | kNoThrowMove | kNoThrowNew>(456)");
 }
 
 template <typename F>
@@ -653,20 +703,20 @@ struct BasicGuaranteeWithExtraInvariants : public NonNegative {
 };
 constexpr int BasicGuaranteeWithExtraInvariants::kExceptionSentinel;
 
-TEST(ExceptionCheckTest, BasicGuaranteeWithInvariants) {
+TEST(ExceptionCheckTest, BasicGuaranteeWithExtraInvariants) {
   auto tester_with_val =
       tester.WithInitialValue(BasicGuaranteeWithExtraInvariants{});
   EXPECT_TRUE(tester_with_val.Test());
   EXPECT_TRUE(
       tester_with_val
-          .WithInvariants([](BasicGuaranteeWithExtraInvariants* w) {
-            if (w->i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) {
+          .WithInvariants([](BasicGuaranteeWithExtraInvariants* o) {
+            if (o->i == BasicGuaranteeWithExtraInvariants::kExceptionSentinel) {
               return testing::AssertionSuccess();
             }
             return testing::AssertionFailure()
                    << "i should be "
                    << BasicGuaranteeWithExtraInvariants::kExceptionSentinel
-                   << ", but is " << w->i;
+                   << ", but is " << o->i;
           })
           .Test());
 }
@@ -846,29 +896,28 @@ TEST(ConstructorTrackerTest, NotDestroyedAfter) {
         new (&storage) Tracked;
       },
       "not destroyed");
-
-  // Manual destruction of the Tracked instance is not required because
-  // ~ConstructorTracker() handles that automatically when a leak is found
 }
 
 TEST(ConstructorTrackerTest, DestroyedTwice) {
+  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
   EXPECT_NONFATAL_FAILURE(
       {
         Tracked t;
         t.~Tracked();
       },
-      "destroyed improperly");
+      "re-destroyed");
 }
 
 TEST(ConstructorTrackerTest, ConstructedTwice) {
+  exceptions_internal::ConstructorTracker ct(exceptions_internal::countdown);
   absl::aligned_storage_t<sizeof(Tracked), alignof(Tracked)> storage;
   EXPECT_NONFATAL_FAILURE(
       {
         new (&storage) Tracked;
         new (&storage) Tracked;
+        reinterpret_cast<Tracked*>(&storage)->~Tracked();
       },
       "re-constructed");
-  reinterpret_cast<Tracked*>(&storage)->~Tracked();
 }
 
 TEST(ThrowingValueTraitsTest, RelationalOperators) {
diff --git a/absl/base/internal/exception_safety_testing.cc b/absl/base/internal/exception_safety_testing.cc
index d3e94074b822..f1d081f7e50d 100644
--- a/absl/base/internal/exception_safety_testing.cc
+++ b/absl/base/internal/exception_safety_testing.cc
@@ -21,16 +21,14 @@ namespace testing {
 
 exceptions_internal::NoThrowTag nothrow_ctor;
 
-bool nothrow_guarantee(const void*) {
-  return ::testing::AssertionFailure()
-         << "Exception thrown violating NoThrow Guarantee";
-}
 exceptions_internal::StrongGuaranteeTagType strong_guarantee;
 
 namespace exceptions_internal {
 
 int countdown = -1;
 
+ConstructorTracker* ConstructorTracker::current_tracker_instance_ = nullptr;
+
 void MaybeThrow(absl::string_view msg, bool throw_bad_alloc) {
   if (countdown-- == 0) {
     if (throw_bad_alloc) throw TestBadAllocException(msg);
@@ -43,6 +41,31 @@ testing::AssertionResult FailureMessage(const TestException& e,
   return testing::AssertionFailure() << "Exception thrown from " << e.what();
 }
 
+std::string GetSpecString(TypeSpec spec) {
+  std::string out;
+  absl::string_view sep;
+  const auto append = [&](absl::string_view s) {
+    absl::StrAppend(&out, sep, s);
+    sep = " | ";
+  };
+  if (static_cast<bool>(TypeSpec::kNoThrowCopy & spec)) {
+    append("kNoThrowCopy");
+  }
+  if (static_cast<bool>(TypeSpec::kNoThrowMove & spec)) {
+    append("kNoThrowMove");
+  }
+  if (static_cast<bool>(TypeSpec::kNoThrowNew & spec)) {
+    append("kNoThrowNew");
+  }
+  return out;
+}
+
+std::string GetSpecString(AllocSpec spec) {
+  return static_cast<bool>(AllocSpec::kNoThrowAllocate & spec)
+             ? "kNoThrowAllocate"
+             : "";
+}
+
 }  // namespace exceptions_internal
 
 }  // namespace testing
diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h
index c3ff34c50abc..8c2f5093fc4d 100644
--- a/absl/base/internal/exception_safety_testing.h
+++ b/absl/base/internal/exception_safety_testing.h
@@ -62,6 +62,9 @@ constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) {
 
 namespace exceptions_internal {
 
+std::string GetSpecString(TypeSpec);
+std::string GetSpecString(AllocSpec);
+
 struct NoThrowTag {};
 struct StrongGuaranteeTagType {};
 
@@ -101,70 +104,96 @@ void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
 testing::AssertionResult FailureMessage(const TestException& e,
                                         int countdown) noexcept;
 
-class ConstructorTracker;
+struct TrackedAddress {
+  bool is_alive;
+  std::string description;
+};
 
-class TrackedObject {
+// Inspects the constructions and destructions of anything inheriting from
+// TrackedObject. This allows us to safely "leak" TrackedObjects, as
+// ConstructorTracker will destroy everything left over in its destructor.
+class ConstructorTracker {
  public:
-  TrackedObject(const TrackedObject&) = delete;
-  TrackedObject(TrackedObject&&) = delete;
+  explicit ConstructorTracker(int count) : countdown_(count) {
+    assert(current_tracker_instance_ == nullptr);
+    current_tracker_instance_ = this;
+  }
 
- protected:
-  explicit TrackedObject(const char* child_ctor) {
-    if (!GetInstanceMap().emplace(this, child_ctor).second) {
-      ADD_FAILURE() << "Object at address " << static_cast<void*>(this)
-                    << " re-constructed in ctor " << child_ctor;
+  ~ConstructorTracker() {
+    assert(current_tracker_instance_ == this);
+    current_tracker_instance_ = nullptr;
+
+    for (auto& it : address_map_) {
+      void* address = it.first;
+      TrackedAddress& tracked_address = it.second;
+      if (tracked_address.is_alive) {
+        ADD_FAILURE() << "Object at address " << address
+                      << " with countdown of " << countdown_
+                      << " was not destroyed [" << tracked_address.description
+                      << "]";
+      }
     }
   }
 
-  ~TrackedObject() noexcept {
-    if (GetInstanceMap().erase(this) == 0) {
-      ADD_FAILURE() << "Object at address " << static_cast<void*>(this)
-                    << " destroyed improperly";
+  static void ObjectConstructed(void* address, std::string description) {
+    if (!CurrentlyTracking()) return;
+
+    TrackedAddress& tracked_address =
+        current_tracker_instance_->address_map_[address];
+    if (tracked_address.is_alive) {
+      ADD_FAILURE() << "Object at address " << address << " with countdown of "
+                    << current_tracker_instance_->countdown_
+                    << " was re-constructed. Previously: ["
+                    << tracked_address.description << "] Now: [" << description
+                    << "]";
     }
+    tracked_address = {true, std::move(description)};
+  }
+
+  static void ObjectDestructed(void* address) {
+    if (!CurrentlyTracking()) return;
+
+    auto it = current_tracker_instance_->address_map_.find(address);
+    // Not tracked. Ignore.
+    if (it == current_tracker_instance_->address_map_.end()) return;
+
+    TrackedAddress& tracked_address = it->second;
+    if (!tracked_address.is_alive) {
+      ADD_FAILURE() << "Object at address " << address << " with countdown of "
+                    << current_tracker_instance_->countdown_
+                    << " was re-destroyed or created prior to construction "
+                    << "tracking [" << tracked_address.description << "]";
+    }
+    tracked_address.is_alive = false;
   }
 
  private:
-  using InstanceMap = std::unordered_map<TrackedObject*, absl::string_view>;
-  static InstanceMap& GetInstanceMap() {
-    static auto* instance_map = new InstanceMap();
-    return *instance_map;
+  static bool CurrentlyTracking() {
+    return current_tracker_instance_ != nullptr;
   }
 
-  friend class ConstructorTracker;
+  std::unordered_map<void*, TrackedAddress> address_map_;
+  int countdown_;
+
+  static ConstructorTracker* current_tracker_instance_;
 };
 
-// Inspects the constructions and destructions of anything inheriting from
-// TrackedObject. This allows us to safely "leak" TrackedObjects, as
-// ConstructorTracker will destroy everything left over in its destructor.
-class ConstructorTracker {
+class TrackedObject {
  public:
-  explicit ConstructorTracker(int c)
-      : init_count_(c), init_instances_(TrackedObject::GetInstanceMap()) {}
-  ~ConstructorTracker() {
-    auto& cur_instances = TrackedObject::GetInstanceMap();
-    for (auto it = cur_instances.begin(); it != cur_instances.end();) {
-      if (init_instances_.count(it->first) == 0) {
-        ADD_FAILURE() << "Object at address " << static_cast<void*>(it->first)
-                      << " constructed from " << it->second
-                      << " where the exception countdown was set to "
-                      << init_count_ << " was not destroyed";
-        // Erasing an item inside an unordered_map invalidates the existing
-        // iterator. A new one is returned for iteration to continue.
-        it = cur_instances.erase(it);
-      } else {
-        ++it;
-      }
-    }
+  TrackedObject(const TrackedObject&) = delete;
+  TrackedObject(TrackedObject&&) = delete;
+
+ protected:
+  explicit TrackedObject(std::string description) {
+    ConstructorTracker::ObjectConstructed(this, std::move(description));
   }
 
- private:
-  int init_count_;
-  TrackedObject::InstanceMap init_instances_;
+  ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); }
 };
 
 template <typename Factory, typename Operation, typename Invariant>
 absl::optional<testing::AssertionResult> TestSingleInvariantAtCountdownImpl(
-    const Factory& factory, Operation operation, int count,
+    const Factory& factory, const Operation& operation, int count,
     const Invariant& invariant) {
   auto t_ptr = factory();
   absl::optional<testing::AssertionResult> current_res;
@@ -229,7 +258,6 @@ inline absl::optional<testing::AssertionResult> TestAllInvariantsAtCountdown(
 
 extern exceptions_internal::NoThrowTag nothrow_ctor;
 
-bool nothrow_guarantee(const void*);
 extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
 
 // A test class which is convertible to bool.  The conversion can be
@@ -283,17 +311,18 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
     return static_cast<bool>(Spec & spec);
   }
 
+  static constexpr int kDefaultValue = 0;
   static constexpr int kBadValue = 938550620;
 
  public:
-  ThrowingValue() : TrackedObject(ABSL_PRETTY_FUNCTION) {
+  ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) {
     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
-    dummy_ = 0;
+    dummy_ = kDefaultValue;
   }
 
   ThrowingValue(const ThrowingValue& other) noexcept(
       IsSpecified(TypeSpec::kNoThrowCopy))
-      : TrackedObject(ABSL_PRETTY_FUNCTION) {
+      : TrackedObject(GetInstanceString(other.dummy_)) {
     if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
       exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
     }
@@ -302,20 +331,20 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
 
   ThrowingValue(ThrowingValue&& other) noexcept(
       IsSpecified(TypeSpec::kNoThrowMove))
-      : TrackedObject(ABSL_PRETTY_FUNCTION) {
+      : TrackedObject(GetInstanceString(other.dummy_)) {
     if (!IsSpecified(TypeSpec::kNoThrowMove)) {
       exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
     }
     dummy_ = other.dummy_;
   }
 
-  explicit ThrowingValue(int i) : TrackedObject(ABSL_PRETTY_FUNCTION) {
+  explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) {
     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
     dummy_ = i;
   }
 
   ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept
-      : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(i) {}
+      : TrackedObject(GetInstanceString(i)), dummy_(i) {}
 
   // absl expects nothrow destructors
   ~ThrowingValue() noexcept = default;
@@ -548,9 +577,9 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
   void operator&() const = delete;  // NOLINT(runtime/operator)
 
   // Stream operators
-  friend std::ostream& operator<<(std::ostream& os, const ThrowingValue&) {
+  friend std::ostream& operator<<(std::ostream& os, const ThrowingValue& tv) {
     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
-    return os;
+    return os << GetInstanceString(tv.dummy_);
   }
 
   friend std::istream& operator>>(std::istream& is, const ThrowingValue&) {
@@ -606,6 +635,12 @@ class ThrowingValue : private exceptions_internal::TrackedObject {
   const int& Get() const noexcept { return dummy_; }
 
  private:
+  static std::string GetInstanceString(int dummy) {
+    return absl::StrCat("ThrowingValue<",
+                        exceptions_internal::GetSpecString(Spec), ">(", dummy,
+                        ")");
+  }
+
   int dummy_;
 };
 // While not having to do with exceptions, explicitly delete comma operator, to
@@ -658,26 +693,30 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
   using propagate_on_container_swap = std::true_type;
   using is_always_equal = std::false_type;
 
-  ThrowingAllocator() : TrackedObject(ABSL_PRETTY_FUNCTION) {
+  ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) {
     exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
     dummy_ = std::make_shared<const int>(next_id_++);
   }
 
   template <typename U>
   ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept  // NOLINT
-      : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {}
+      : TrackedObject(GetInstanceString(*other.State())),
+        dummy_(other.State()) {}
 
   // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of
   // allocator shall not exit via an exception, thus they are marked noexcept.
   ThrowingAllocator(const ThrowingAllocator& other) noexcept
-      : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {}
+      : TrackedObject(GetInstanceString(*other.State())),
+        dummy_(other.State()) {}
 
   template <typename U>
   ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept  // NOLINT
-      : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(std::move(other.State())) {}
+      : TrackedObject(GetInstanceString(*other.State())),
+        dummy_(std::move(other.State())) {}
 
   ThrowingAllocator(ThrowingAllocator&& other) noexcept
-      : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(std::move(other.State())) {}
+      : TrackedObject(GetInstanceString(*other.State())),
+        dummy_(std::move(other.State())) {}
 
   ~ThrowingAllocator() noexcept = default;
 
@@ -758,6 +797,12 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject {
   friend class ThrowingAllocator;
 
  private:
+  static std::string GetInstanceString(int dummy) {
+    return absl::StrCat("ThrowingAllocator<",
+                        exceptions_internal::GetSpecString(Spec), ">(", dummy,
+                        ")");
+  }
+
   const std::shared_ptr<const int>& State() const { return dummy_; }
   std::shared_ptr<const int>& State() { return dummy_; }
 
@@ -801,6 +846,29 @@ void TestThrowingCtor(Args&&... args) {
   }
 }
 
+// Tests the nothrow guarantee of the provided nullary operation. If the an
+// exception is thrown, the result will be AssertionFailure(). Otherwise, it
+// will be AssertionSuccess().
+template <typename Operation>
+testing::AssertionResult TestNothrowOp(const Operation& operation) {
+  struct Cleanup {
+    Cleanup() { exceptions_internal::SetCountdown(); }
+    ~Cleanup() { exceptions_internal::UnsetCountdown(); }
+  } c;
+  try {
+    operation();
+    return testing::AssertionSuccess();
+  } catch (exceptions_internal::TestException) {
+    return testing::AssertionFailure()
+           << "TestException thrown during call to operation() when nothrow "
+              "guarantee was expected.";
+  } catch (...) {
+    return testing::AssertionFailure()
+           << "Unknown exception thrown during call to operation() when "
+              "nothrow guarantee was expected.";
+  }
+}
+
 namespace exceptions_internal {
 
 // Dummy struct for ExceptionSafetyTester<> partial state.
diff --git a/absl/base/internal/spinlock.cc b/absl/base/internal/spinlock.cc
index 28a2059f3287..1b97efbccc58 100644
--- a/absl/base/internal/spinlock.cc
+++ b/absl/base/internal/spinlock.cc
@@ -18,10 +18,12 @@
 #include <atomic>
 #include <limits>
 
+#include "absl/base/attributes.h"
 #include "absl/base/internal/atomic_hook.h"
 #include "absl/base/internal/cycleclock.h"
 #include "absl/base/internal/spinlock_wait.h"
 #include "absl/base/internal/sysinfo.h" /* For NumCPUs() */
+#include "absl/base/call_once.h"
 
 // Description of lock-word:
 //  31..00: [............................3][2][1][0]
@@ -54,30 +56,10 @@
 namespace absl {
 namespace base_internal {
 
-static int adaptive_spin_count = 0;
-
-namespace {
-struct SpinLock_InitHelper {
-  SpinLock_InitHelper() {
-    // On multi-cpu machines, spin for longer before yielding
-    // the processor or sleeping.  Reduces idle time significantly.
-    if (base_internal::NumCPUs() > 1) {
-      adaptive_spin_count = 1000;
-    }
-  }
-};
-
-// Hook into global constructor execution:
-// We do not do adaptive spinning before that,
-// but nothing lock-intensive should be going on at that time.
-static SpinLock_InitHelper init_helper;
-
 ABSL_CONST_INIT static base_internal::AtomicHook<void (*)(const void *lock,
                                                           int64_t wait_cycles)>
     submit_profile_data;
 
-}  // namespace
-
 void RegisterSpinLockProfiler(void (*fn)(const void *contendedlock,
                                          int64_t wait_cycles)) {
   submit_profile_data.Store(fn);
@@ -120,6 +102,14 @@ void SpinLock::InitLinkerInitializedAndCooperative() {
 // from the lock is returned from the method.
 uint32_t SpinLock::SpinLoop(int64_t initial_wait_timestamp,
                             uint32_t *wait_cycles) {
+  // We are already in the slow path of SpinLock, initialize the
+  // adaptive_spin_count here.
+  ABSL_CONST_INIT static absl::once_flag init_adaptive_spin_count;
+  ABSL_CONST_INIT static int adaptive_spin_count = 0;
+  base_internal::LowLevelCallOnce(&init_adaptive_spin_count, []() {
+    adaptive_spin_count = base_internal::NumCPUs() > 1 ? 1000 : 1;
+  });
+
   int c = adaptive_spin_count;
   uint32_t lock_value;
   do {
diff --git a/absl/base/optimization.h b/absl/base/optimization.h
index aaaffa495a9a..2fddfc800c1d 100644
--- a/absl/base/optimization.h
+++ b/absl/base/optimization.h
@@ -158,8 +158,8 @@
 #define ABSL_PREDICT_FALSE(x) (__builtin_expect(x, 0))
 #define ABSL_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
 #else
-#define ABSL_PREDICT_FALSE(x) x
-#define ABSL_PREDICT_TRUE(x) x
+#define ABSL_PREDICT_FALSE(x) (x)
+#define ABSL_PREDICT_TRUE(x) (x)
 #endif
 
 #endif  // ABSL_BASE_OPTIMIZATION_H_
diff --git a/absl/numeric/BUILD.bazel b/absl/numeric/BUILD.bazel
index 0791145d0f89..f49571ebb3e1 100644
--- a/absl/numeric/BUILD.bazel
+++ b/absl/numeric/BUILD.bazel
@@ -53,3 +53,15 @@ cc_test(
         "@com_google_googletest//:gtest_main",
     ],
 )
+
+cc_test(
+    name = "int128_benchmark",
+    srcs = ["int128_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    deps = [
+        ":int128",
+        "//absl/base:config",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
diff --git a/absl/numeric/int128_benchmark.cc b/absl/numeric/int128_benchmark.cc
new file mode 100644
index 000000000000..1cb7d0ed87e0
--- /dev/null
+++ b/absl/numeric/int128_benchmark.cc
@@ -0,0 +1,221 @@
+// Copyright 2017 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/numeric/int128.h"
+
+#include <algorithm>
+#include <cstdint>
+#include <random>
+#include <vector>
+
+#include "benchmark/benchmark.h"
+#include "absl/base/config.h"
+
+namespace {
+
+constexpr size_t kSampleSize = 1000000;
+
+std::mt19937 MakeRandomEngine() {
+  std::random_device r;
+  std::seed_seq seed({r(), r(), r(), r(), r(), r(), r(), r()});
+  return std::mt19937(seed);
+}
+
+std::vector<std::pair<absl::uint128, absl::uint128>>
+GetRandomClass128SampleUniformDivisor() {
+  std::vector<std::pair<absl::uint128, absl::uint128>> values;
+  std::mt19937 random = MakeRandomEngine();
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    absl::uint128 a =
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+    absl::uint128 b =
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+    values.emplace_back(std::max(a, b),
+                        std::max(absl::uint128(2), std::min(a, b)));
+  }
+  return values;
+}
+
+void BM_DivideClass128UniformDivisor(benchmark::State& state) {
+  auto values = GetRandomClass128SampleUniformDivisor();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first / pair.second);
+    }
+  }
+}
+BENCHMARK(BM_DivideClass128UniformDivisor);
+
+std::vector<std::pair<absl::uint128, uint64_t>>
+GetRandomClass128SampleSmallDivisor() {
+  std::vector<std::pair<absl::uint128, uint64_t>> values;
+  std::mt19937 random = MakeRandomEngine();
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    absl::uint128 a =
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random));
+    uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
+    values.emplace_back(std::max(a, absl::uint128(b)), b);
+  }
+  return values;
+}
+
+void BM_DivideClass128SmallDivisor(benchmark::State& state) {
+  auto values = GetRandomClass128SampleSmallDivisor();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first / pair.second);
+    }
+  }
+}
+BENCHMARK(BM_DivideClass128SmallDivisor);
+
+std::vector<std::pair<absl::uint128, absl::uint128>> GetRandomClass128Sample() {
+  std::vector<std::pair<absl::uint128, absl::uint128>> values;
+  std::mt19937 random = MakeRandomEngine();
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    values.emplace_back(
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)),
+        absl::MakeUint128(uniform_uint64(random), uniform_uint64(random)));
+  }
+  return values;
+}
+
+void BM_MultiplyClass128(benchmark::State& state) {
+  auto values = GetRandomClass128Sample();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first * pair.second);
+    }
+  }
+}
+BENCHMARK(BM_MultiplyClass128);
+
+void BM_AddClass128(benchmark::State& state) {
+  auto values = GetRandomClass128Sample();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first + pair.second);
+    }
+  }
+}
+BENCHMARK(BM_AddClass128);
+
+#ifdef ABSL_HAVE_INTRINSIC_INT128
+
+// Some implementations of <random> do not support __int128 when it is
+// available, so we make our own uniform_int_distribution-like type.
+class UniformIntDistribution128 {
+ public:
+  // NOLINTNEXTLINE: mimicking std::uniform_int_distribution API
+  unsigned __int128 operator()(std::mt19937& generator) {
+    return (static_cast<unsigned __int128>(dist64_(generator)) << 64) |
+           dist64_(generator);
+  }
+
+ private:
+  std::uniform_int_distribution<uint64_t> dist64_;
+};
+
+std::vector<std::pair<unsigned __int128, unsigned __int128>>
+GetRandomIntrinsic128SampleUniformDivisor() {
+  std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
+  std::mt19937 random = MakeRandomEngine();
+  UniformIntDistribution128 uniform_uint128;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    unsigned __int128 a = uniform_uint128(random);
+    unsigned __int128 b = uniform_uint128(random);
+    values.emplace_back(
+        std::max(a, b),
+        std::max(static_cast<unsigned __int128>(2), std::min(a, b)));
+  }
+  return values;
+}
+
+void BM_DivideIntrinsic128UniformDivisor(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128SampleUniformDivisor();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first / pair.second);
+    }
+  }
+}
+BENCHMARK(BM_DivideIntrinsic128UniformDivisor);
+
+std::vector<std::pair<unsigned __int128, uint64_t>>
+GetRandomIntrinsic128SampleSmallDivisor() {
+  std::vector<std::pair<unsigned __int128, uint64_t>> values;
+  std::mt19937 random = MakeRandomEngine();
+  UniformIntDistribution128 uniform_uint128;
+  std::uniform_int_distribution<uint64_t> uniform_uint64;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    unsigned __int128 a = uniform_uint128(random);
+    uint64_t b = std::max(uint64_t{2}, uniform_uint64(random));
+    values.emplace_back(std::max(a, static_cast<unsigned __int128>(b)), b);
+  }
+  return values;
+}
+
+void BM_DivideIntrinsic128SmallDivisor(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128SampleSmallDivisor();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first / pair.second);
+    }
+  }
+}
+BENCHMARK(BM_DivideIntrinsic128SmallDivisor);
+
+std::vector<std::pair<unsigned __int128, unsigned __int128>>
+      GetRandomIntrinsic128Sample() {
+  std::vector<std::pair<unsigned __int128, unsigned __int128>> values;
+  std::mt19937 random = MakeRandomEngine();
+  UniformIntDistribution128 uniform_uint128;
+  values.reserve(kSampleSize);
+  for (size_t i = 0; i < kSampleSize; ++i) {
+    values.emplace_back(uniform_uint128(random), uniform_uint128(random));
+  }
+  return values;
+}
+
+void BM_MultiplyIntrinsic128(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128Sample();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first * pair.second);
+    }
+  }
+}
+BENCHMARK(BM_MultiplyIntrinsic128);
+
+void BM_AddIntrinsic128(benchmark::State& state) {
+  auto values = GetRandomIntrinsic128Sample();
+  while (state.KeepRunningBatch(values.size())) {
+    for (const auto& pair : values) {
+      benchmark::DoNotOptimize(pair.first + pair.second);
+    }
+  }
+}
+BENCHMARK(BM_AddIntrinsic128);
+
+#endif  // ABSL_HAVE_INTRINSIC_INT128
+
+}  // namespace
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index d1c6878c41e4..f06bdc0d01cf 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -158,6 +158,22 @@ cc_test(
 )
 
 cc_test(
+    name = "memutil_benchmark",
+    srcs = [
+        "internal/memutil.h",
+        "internal/memutil_benchmark.cc",
+    ],
+    copts = ABSL_TEST_COPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":strings",
+        "//absl/base:core_headers",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_test(
     name = "memutil_test",
     size = "small",
     srcs = [
diff --git a/absl/strings/internal/memutil_benchmark.cc b/absl/strings/internal/memutil_benchmark.cc
new file mode 100644
index 000000000000..77915adb958e
--- /dev/null
+++ b/absl/strings/internal/memutil_benchmark.cc
@@ -0,0 +1,323 @@
+// 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/strings/internal/memutil.h"
+
+#include <algorithm>
+#include <cstdlib>
+
+#include "benchmark/benchmark.h"
+#include "absl/strings/ascii.h"
+
+// We fill the haystack with aaaaaaaaaaaaaaaaaa...aaaab.
+// That gives us:
+// - an easy search: 'b'
+// - a medium search: 'ab'.  That means every letter is a possible match.
+// - a pathological search: 'aaaaaa.......aaaaab' (half as many a's as haytack)
+// We benchmark case-sensitive and case-insensitive versions of
+// three memmem implementations:
+// - memmem() from memutil.h
+// - search() from STL
+// - memmatch(), a custom implementation using memchr and memcmp.
+// Here are sample results:
+//
+// Run on (12 X 3800 MHz CPU s)
+// CPU Caches:
+//   L1 Data 32K (x6)
+//   L1 Instruction 32K (x6)
+//   L2 Unified 256K (x6)
+//   L3 Unified 15360K (x1)
+// ----------------------------------------------------------------
+// Benchmark                           Time          CPU Iterations
+// ----------------------------------------------------------------
+// BM_Memmem                        3583 ns      3582 ns     196469  2.59966GB/s
+// BM_MemmemMedium                 13743 ns     13742 ns      50901  693.986MB/s
+// BM_MemmemPathological        13695030 ns  13693977 ns         51  713.133kB/s
+// BM_Memcasemem                    3299 ns      3299 ns     212942  2.82309GB/s
+// BM_MemcasememMedium             16407 ns     16406 ns      42170  581.309MB/s
+// BM_MemcasememPathological    17267745 ns  17266030 ns         41  565.598kB/s
+// BM_Search                        1610 ns      1609 ns     431321  5.78672GB/s
+// BM_SearchMedium                 11111 ns     11110 ns      63001  858.414MB/s
+// BM_SearchPathological        12117390 ns  12116397 ns         58  805.984kB/s
+// BM_Searchcase                    3081 ns      3081 ns     229949  3.02313GB/s
+// BM_SearchcaseMedium             16003 ns     16001 ns      44170  595.998MB/s
+// BM_SearchcasePathological    15823413 ns  15821909 ns         44  617.222kB/s
+// BM_Memmatch                       197 ns       197 ns    3584225  47.2951GB/s
+// BM_MemmatchMedium               52333 ns     52329 ns      13280  182.244MB/s
+// BM_MemmatchPathological        659799 ns    659727 ns       1058  14.4556MB/s
+// BM_Memcasematch                  5460 ns      5460 ns     127606  1.70586GB/s
+// BM_MemcasematchMedium           32861 ns     32857 ns      21258  290.248MB/s
+// BM_MemcasematchPathological  15154243 ns  15153089 ns         46  644.464kB/s
+// BM_MemmemStartup                    5 ns         5 ns  150821500
+// BM_SearchStartup                    5 ns         5 ns  150644203
+// BM_MemmatchStartup                  7 ns         7 ns   97068802
+//
+// Conclusions:
+//
+// The following recommendations are based on the sample results above. However,
+// we have found that the performance of STL search can vary significantly
+// depending on compiler and standard library implementation. We recommend you
+// run the benchmarks for yourself on relevant platforms.
+//
+// If you need case-insensitive, STL search is slightly better than memmem for
+// all cases.
+//
+// Case-sensitive is more subtle:
+// Custom memmatch is _very_ fast at scanning, so if you have very few possible
+// matches in your haystack, that's the way to go. Performance drops
+// significantly with more matches.
+//
+// STL search is slightly faster than memmem in the medium and pathological
+// benchmarks. However, the performance of memmem is currently more dependable
+// across platforms and build configurations.
+
+namespace {
+
+constexpr int kHaystackSize = 10000;
+constexpr int64_t kHaystackSize64 = kHaystackSize;
+const char* MakeHaystack() {
+  char* haystack = new char[kHaystackSize];
+  for (int i = 0; i < kHaystackSize - 1; ++i) haystack[i] = 'a';
+  haystack[kHaystackSize - 1] = 'b';
+  return haystack;
+}
+const char* const kHaystack = MakeHaystack();
+
+void BM_Memmem(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memmem(kHaystack, kHaystackSize, "b", 1));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Memmem);
+
+void BM_MemmemMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memmem(kHaystack, kHaystackSize, "ab", 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemmemMedium);
+
+void BM_MemmemPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memmem(
+        kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2,
+        kHaystackSize - kHaystackSize / 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemmemPathological);
+
+void BM_Memcasemem(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memcasemem(kHaystack, kHaystackSize, "b", 1));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Memcasemem);
+
+void BM_MemcasememMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memcasemem(kHaystack, kHaystackSize, "ab", 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemcasememMedium);
+
+void BM_MemcasememPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memcasemem(
+        kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2,
+        kHaystackSize - kHaystackSize / 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemcasememPathological);
+
+bool case_eq(const char a, const char b) {
+  return absl::ascii_tolower(a) == absl::ascii_tolower(b);
+}
+
+void BM_Search(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize - 1,
+                                         kHaystack + kHaystackSize));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Search);
+
+void BM_SearchMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize - 2,
+                                         kHaystack + kHaystackSize));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_SearchMedium);
+
+void BM_SearchPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize / 2,
+                                         kHaystack + kHaystackSize));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_SearchPathological);
+
+void BM_Searchcase(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize - 1,
+                                         kHaystack + kHaystackSize, case_eq));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Searchcase);
+
+void BM_SearchcaseMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize - 2,
+                                         kHaystack + kHaystackSize, case_eq));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_SearchcaseMedium);
+
+void BM_SearchcasePathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(std::search(kHaystack, kHaystack + kHaystackSize,
+                                         kHaystack + kHaystackSize / 2,
+                                         kHaystack + kHaystackSize, case_eq));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_SearchcasePathological);
+
+char* memcasechr(const char* s, int c, size_t slen) {
+  c = absl::ascii_tolower(c);
+  for (; slen; ++s, --slen) {
+    if (absl::ascii_tolower(*s) == c) return const_cast<char*>(s);
+  }
+  return nullptr;
+}
+
+const char* memcasematch(const char* phaystack, size_t haylen,
+                         const char* pneedle, size_t neelen) {
+  if (0 == neelen) {
+    return phaystack;  // even if haylen is 0
+  }
+  if (haylen < neelen) return nullptr;
+
+  const char* match;
+  const char* hayend = phaystack + haylen - neelen + 1;
+  while ((match = static_cast<char*>(
+              memcasechr(phaystack, pneedle[0], hayend - phaystack)))) {
+    if (absl::strings_internal::memcasecmp(match, pneedle, neelen) == 0)
+      return match;
+    else
+      phaystack = match + 1;
+  }
+  return nullptr;
+}
+
+void BM_Memmatch(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memmatch(kHaystack, kHaystackSize, "b", 1));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Memmatch);
+
+void BM_MemmatchMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        absl::strings_internal::memmatch(kHaystack, kHaystackSize, "ab", 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemmatchMedium);
+
+void BM_MemmatchPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memmatch(
+        kHaystack, kHaystackSize, kHaystack + kHaystackSize / 2,
+        kHaystackSize - kHaystackSize / 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemmatchPathological);
+
+void BM_Memcasematch(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize, "b", 1));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_Memcasematch);
+
+void BM_MemcasematchMedium(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize, "ab", 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemcasematchMedium);
+
+void BM_MemcasematchPathological(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(memcasematch(kHaystack, kHaystackSize,
+                                          kHaystack + kHaystackSize / 2,
+                                          kHaystackSize - kHaystackSize / 2));
+  }
+  state.SetBytesProcessed(kHaystackSize64 * state.iterations());
+}
+BENCHMARK(BM_MemcasematchPathological);
+
+void BM_MemmemStartup(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memmem(
+        kHaystack + kHaystackSize - 10, 10, kHaystack + kHaystackSize - 1, 1));
+  }
+}
+BENCHMARK(BM_MemmemStartup);
+
+void BM_SearchStartup(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(
+        std::search(kHaystack + kHaystackSize - 10, kHaystack + kHaystackSize,
+                    kHaystack + kHaystackSize - 1, kHaystack + kHaystackSize));
+  }
+}
+BENCHMARK(BM_SearchStartup);
+
+void BM_MemmatchStartup(benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(absl::strings_internal::memmatch(
+        kHaystack + kHaystackSize - 10, 10, kHaystack + kHaystackSize - 1, 1));
+  }
+}
+BENCHMARK(BM_MemmatchStartup);
+
+}  // namespace
diff --git a/absl/time/BUILD.bazel b/absl/time/BUILD.bazel
index 64cb99f73716..fe55fe1f9bf6 100644
--- a/absl/time/BUILD.bazel
+++ b/absl/time/BUILD.bazel
@@ -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",
+    ],
+)
diff --git a/absl/time/clock_benchmark.cc b/absl/time/clock_benchmark.cc
new file mode 100644
index 000000000000..3d3cd9d5c42c
--- /dev/null
+++ b/absl/time/clock_benchmark.cc
@@ -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
diff --git a/absl/time/duration_benchmark.cc b/absl/time/duration_benchmark.cc
new file mode 100644
index 000000000000..54f89a1f000d
--- /dev/null
+++ b/absl/time/duration_benchmark.cc
@@ -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
diff --git a/absl/time/duration_test.cc b/absl/time/duration_test.cc
index 7918e1677052..704684edb34e 100644
--- a/absl/time/duration_test.cc
+++ b/absl/time/duration_test.cc
@@ -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))); \
diff --git a/absl/time/format_benchmark.cc b/absl/time/format_benchmark.cc
new file mode 100644
index 000000000000..ee53d71c6854
--- /dev/null
+++ b/absl/time/format_benchmark.cc
@@ -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
diff --git a/absl/time/internal/cctz/src/time_zone_format_test.cc b/absl/time/internal/cctz/src/time_zone_format_test.cc
index 3a5f19ac8b1f..7d5b02ad3a68 100644
--- a/absl/time/internal/cctz/src/time_zone_format_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_format_test.cc
@@ -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");
 }
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index f97eab0227eb..06b172a80323 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -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) {
diff --git a/absl/time/time.h b/absl/time/time.h
index c50d69a5689f..99c12bbd87ed 100644
--- a/absl/time/time.h
+++ b/absl/time/time.h
@@ -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 EnableIfIntegral = typename std::enable_if<
+    std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
 template <typename T>
-using IsFloatingPoint =
+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);
 }
diff --git a/absl/time/time_benchmark.cc b/absl/time/time_benchmark.cc
new file mode 100644
index 000000000000..e1009946cd58
--- /dev/null
+++ b/absl/time/time_benchmark.cc
@@ -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
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel
index c26c68d0b35f..1fc4c098e9bd 100644
--- a/absl/types/BUILD.bazel
+++ b/absl/types/BUILD.bazel
@@ -28,7 +28,7 @@ licenses(["notice"])  # Apache 2.0
 cc_library(
     name = "any",
     hdrs = ["any.h"],
-    copts = ABSL_DEFAULT_COPTS + ABSL_EXCEPTIONS_FLAG,
+    copts = ABSL_DEFAULT_COPTS,
     deps = [
         ":bad_any_cast",
         "//absl/base:config",
@@ -40,9 +40,19 @@ cc_library(
 
 cc_library(
     name = "bad_any_cast",
-    srcs = ["bad_any_cast.cc"],
     hdrs = ["bad_any_cast.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    deps = [":bad_any_cast_impl"],
+)
+
+cc_library(
+    name = "bad_any_cast_impl",
+    srcs = [
+        "bad_any_cast.cc",
+        "bad_any_cast.h",
+    ],
     copts = ABSL_EXCEPTIONS_FLAG + ABSL_DEFAULT_COPTS,
+    visibility = ["//visibility:private"],
     deps = [
         "//absl/base",
         "//absl/base:config",
@@ -206,7 +216,6 @@ cc_test(
     ],
 )
 
-
 cc_library(
     name = "variant",
     srcs = ["internal/variant.h"],
diff --git a/absl/types/optional_exception_safety_test.cc b/absl/types/optional_exception_safety_test.cc
index 7f6348e1b8e1..d2ef04b8d1b0 100644
--- a/absl/types/optional_exception_safety_test.cc
+++ b/absl/types/optional_exception_safety_test.cc
@@ -170,25 +170,22 @@ TEST(OptionalExceptionSafety, EverythingThrowsSwap) {
 
 TEST(OptionalExceptionSafety, NoThrowMoveSwap) {
   // Tests the nothrow guarantee for optional of T with non-throwing move
-  auto nothrow_test =
-      MakeExceptionSafetyTester().WithInvariants(testing::nothrow_guarantee);
-  auto nothrow_test_empty = nothrow_test.WithInitialValue(MoveOptional());
-  auto nothrow_test_nonempty =
-      nothrow_test.WithInitialValue(MoveOptional(kInitialInteger));
-
-  auto swap_empty = [](MoveOptional* optional_ptr) {
+  {
     auto empty = MoveOptional();
-    optional_ptr->swap(empty);
-  };
-  EXPECT_TRUE(nothrow_test_nonempty.Test(swap_empty));
-
-  auto swap_nonempty = [](MoveOptional* optional_ptr) {
-    auto nonempty =
-        MoveOptional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
-    optional_ptr->swap(nonempty);
-  };
-  EXPECT_TRUE(nothrow_test_empty.Test(swap_nonempty));
-  EXPECT_TRUE(nothrow_test_nonempty.Test(swap_nonempty));
+    auto nonempty = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty.swap(empty); }));
+  }
+  {
+    auto nonempty = MoveOptional(kUpdatedInteger);
+    auto empty = MoveOptional();
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { empty.swap(nonempty); }));
+  }
+  {
+    auto nonempty_from = MoveOptional(kUpdatedInteger);
+    auto nonempty_to = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(
+        testing::TestNothrowOp([&]() { nonempty_to.swap(nonempty_from); }));
+  }
 }
 
 TEST(OptionalExceptionSafety, CopyAssign) {
@@ -251,32 +248,33 @@ TEST(OptionalExceptionSafety, MoveAssign) {
 
 TEST(OptionalExceptionSafety, NothrowMoveAssign) {
   // Tests the nothrow guarantee for optional of T with non-throwing move
-  auto nothrow_test =
-      MakeExceptionSafetyTester().WithInvariants(testing::nothrow_guarantee);
-  auto nothrow_test_empty = nothrow_test.WithInitialValue(MoveOptional());
-  auto nothrow_test_nonempty =
-      nothrow_test.WithInitialValue(MoveOptional(kInitialInteger));
-
-  auto moveassign_empty = [](MoveOptional* optional_ptr) {
+  {
     auto empty = MoveOptional();
-    *optional_ptr = std::move(empty);
-  };
-  EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_empty));
-
-  auto moveassign_nonempty = [](MoveOptional* optional_ptr) {
-    auto nonempty =
-        MoveOptional(absl::in_place, kUpdatedInteger, testing::nothrow_ctor);
-    *optional_ptr = std::move(nonempty);
-  };
-  EXPECT_TRUE(nothrow_test_empty.Test(moveassign_nonempty));
-  EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_nonempty));
-
-  auto moveassign_thrower = [](MoveOptional* optional_ptr) {
-    auto thrower = MoveThrower(kUpdatedInteger, testing::nothrow_ctor);
-    *optional_ptr = std::move(thrower);
-  };
-  EXPECT_TRUE(nothrow_test_empty.Test(moveassign_thrower));
-  EXPECT_TRUE(nothrow_test_nonempty.Test(moveassign_thrower));
+    auto nonempty = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { nonempty = std::move(empty); }));
+  }
+  {
+    auto nonempty = MoveOptional(kInitialInteger);
+    auto empty = MoveOptional();
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(nonempty); }));
+  }
+  {
+    auto nonempty_from = MoveOptional(kUpdatedInteger);
+    auto nonempty_to = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(testing::TestNothrowOp(
+        [&]() { nonempty_to = std::move(nonempty_from); }));
+  }
+  {
+    auto thrower = MoveThrower(kUpdatedInteger);
+    auto empty = MoveOptional();
+    EXPECT_TRUE(testing::TestNothrowOp([&]() { empty = std::move(thrower); }));
+  }
+  {
+    auto thrower = MoveThrower(kUpdatedInteger);
+    auto nonempty = MoveOptional(kInitialInteger);
+    EXPECT_TRUE(
+        testing::TestNothrowOp([&]() { nonempty = std::move(thrower); }));
+  }
 }
 
 }  // namespace
diff --git a/absl/types/span.h b/absl/types/span.h
index f781353c2347..76be819ecca2 100644
--- a/absl/types/span.h
+++ b/absl/types/span.h
@@ -279,7 +279,7 @@ class Span {
   using size_type = size_t;
   using difference_type = ptrdiff_t;
 
-  static const size_type npos = ~size_type{0};
+  static const size_type npos = ~(size_type(0));
 
   constexpr Span() noexcept : Span(nullptr, 0) {}
   constexpr Span(pointer array, size_type length) noexcept
diff --git a/absl/types/variant_exception_safety_test.cc b/absl/types/variant_exception_safety_test.cc
index 377e4afac572..27c0b96ca6f3 100644
--- a/absl/types/variant_exception_safety_test.cc
+++ b/absl/types/variant_exception_safety_test.cc
@@ -27,8 +27,8 @@ namespace absl {
 namespace {
 
 using ::testing::MakeExceptionSafetyTester;
-using ::testing::nothrow_guarantee;
 using ::testing::strong_guarantee;
+using ::testing::TestNothrowOp;
 using ::testing::TestThrowingCtor;
 
 using Thrower = testing::ThrowingValue<>;
@@ -120,7 +120,11 @@ testing::AssertionResult CheckInvariants(ThrowingVariant* v) {
   return AssertionSuccess();
 }
 
-Thrower ExpectedThrower() { return Thrower(42); }
+template <typename... Args>
+Thrower ExpectedThrower(Args&&... args) {
+  return Thrower(42, args...);
+}
+
 ThrowerVec ExpectedThrowerVec() { return {Thrower(100), Thrower(200)}; }
 ThrowingVariant ValuelessByException() {
   ThrowingVariant v;
@@ -193,18 +197,14 @@ TEST(VariantExceptionSafetyTest, CopyAssign) {
   {
     // - neither *this nor rhs holds a value
     const ThrowingVariant rhs = ValuelessByException();
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(ValuelessByException())
-                    .WithInvariants(nothrow_guarantee)
-                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+    ThrowingVariant lhs = ValuelessByException();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
   }
   {
     // - *this holds a value but rhs does not
     const ThrowingVariant rhs = ValuelessByException();
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithInvariants(nothrow_guarantee)
-                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
   }
   // - index() == j
   {
@@ -237,10 +237,8 @@ TEST(VariantExceptionSafetyTest, CopyAssign) {
     // should not throw because emplace() invokes Tj's copy ctor
     // which should not throw.
     const ThrowingVariant rhs(CopyNothrow{});
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithInvariants(nothrow_guarantee)
-                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
   }
   {
     // is_nothrow_copy_constructible<Tj> == false &&
@@ -281,23 +279,14 @@ TEST(VariantExceptionSafetyTest, MoveAssign) {
   {
     // - neither *this nor rhs holds a value
     ThrowingVariant rhs = ValuelessByException();
-
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(ValuelessByException())
-                    .WithInvariants(nothrow_guarantee)
-                    .Test([rhs](ThrowingVariant* lhs) mutable {
-                      *lhs = std::move(rhs);
-                    }));
+    ThrowingVariant lhs = ValuelessByException();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
   }
   {
     // - *this holds a value but rhs does not
     ThrowingVariant rhs = ValuelessByException();
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithInvariants(nothrow_guarantee)
-                    .Test([rhs](ThrowingVariant* lhs) mutable {
-                      *lhs = std::move(rhs);
-                    }));
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
   }
   {
     // - index() == j
@@ -310,13 +299,14 @@ TEST(VariantExceptionSafetyTest, MoveAssign) {
     // Since Thrower's move assignment has basic guarantee, so should variant's.
     auto tester = MakeExceptionSafetyTester()
                       .WithInitialValue(WithThrower())
-                      .WithOperation([rhs](ThrowingVariant* lhs) mutable {
-                        *lhs = std::move(rhs);
+                      .WithOperation([&](ThrowingVariant* lhs) {
+                        auto copy = rhs;
+                        *lhs = std::move(copy);
                       });
     EXPECT_TRUE(tester
                     .WithInvariants(
                         CheckInvariants,
-                        [j](ThrowingVariant* lhs) { return lhs->index() == j; })
+                        [&](ThrowingVariant* lhs) { return lhs->index() == j; })
                     .Test());
     EXPECT_FALSE(tester.WithInvariants(strong_guarantee).Test());
   }
@@ -332,8 +322,9 @@ TEST(VariantExceptionSafetyTest, MoveAssign) {
                                     [](ThrowingVariant* lhs) {
                                       return lhs->valueless_by_exception();
                                     })
-                    .Test([rhs](ThrowingVariant* lhs) mutable {
-                      *lhs = std::move(rhs);
+                    .Test([&](ThrowingVariant* lhs) {
+                      auto copy = rhs;
+                      *lhs = std::move(copy);
                     }));
   }
 }
@@ -365,8 +356,9 @@ TEST(VariantExceptionSafetyTest, ValueAssign) {
     // move assign
     auto move_tester = MakeExceptionSafetyTester()
                            .WithInitialValue(WithThrower())
-                           .WithOperation([rhs](ThrowingVariant* lhs) mutable {
-                             *lhs = std::move(rhs);
+                           .WithOperation([&](ThrowingVariant* lhs) {
+                             auto copy = rhs;
+                             *lhs = std::move(copy);
                            });
     EXPECT_TRUE(move_tester
                     .WithInvariants(CheckInvariants,
@@ -388,19 +380,13 @@ TEST(VariantExceptionSafetyTest, ValueAssign) {
   // invokes the copy/move constructor and it should not throw.
   {
     const CopyNothrow rhs;
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithInvariants(nothrow_guarantee)
-                    .Test([&rhs](ThrowingVariant* lhs) { *lhs = rhs; }));
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = rhs; }));
   }
   {
     MoveNothrow rhs;
-    EXPECT_TRUE(MakeExceptionSafetyTester()
-                    .WithInitialValue(WithThrower())
-                    .WithInvariants(nothrow_guarantee)
-                    .Test([rhs](ThrowingVariant* lhs) mutable {
-                      *lhs = std::move(rhs);
-                    }));
+    ThrowingVariant lhs = WithThrower();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs = std::move(rhs); }));
   }
   // if is_nothrow_constructible_v<Tj, T> == false &&
   // is_nothrow_move_constructible<Tj> == false
@@ -423,8 +409,8 @@ TEST(VariantExceptionSafetyTest, ValueAssign) {
     // move
     auto move_tester = MakeExceptionSafetyTester()
                            .WithInitialValue(WithCopyNoThrow())
-                           .WithOperation([rhs](ThrowingVariant* lhs) mutable {
-                             *lhs = std::move(rhs);
+                           .WithOperation([](ThrowingVariant* lhs) {
+                             *lhs = ExpectedThrower(testing::nothrow_ctor);
                            });
     EXPECT_TRUE(move_tester
                     .WithInvariants(CheckInvariants,
@@ -477,21 +463,20 @@ TEST(VariantExceptionSafetyTest, Swap) {
   // if both are valueless_by_exception(), no effect
   {
     ThrowingVariant rhs = ValuelessByException();
-    EXPECT_TRUE(
-        MakeExceptionSafetyTester()
-            .WithInitialValue(ValuelessByException())
-            .WithInvariants(nothrow_guarantee)
-            .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+    ThrowingVariant lhs = ValuelessByException();
+    EXPECT_TRUE(TestNothrowOp([&]() { lhs.swap(rhs); }));
   }
   // if index() == rhs.index(), calls swap(get<i>(*this), get<i>(rhs))
   // where i is index().
   {
     ThrowingVariant rhs = ExpectedThrower();
-    EXPECT_TRUE(
-        MakeExceptionSafetyTester()
-            .WithInitialValue(WithThrower())
-            .WithInvariants(CheckInvariants)
-            .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithThrower())
+                    .WithInvariants(CheckInvariants)
+                    .Test([&](ThrowingVariant* lhs) {
+                      auto copy = rhs;
+                      lhs->swap(copy);
+                    }));
   }
   // Otherwise, exchanges the value of rhs and *this. The exception safety
   // involves variant in moved-from state which is not specified in the
@@ -499,19 +484,23 @@ TEST(VariantExceptionSafetyTest, Swap) {
   // overall strong guarantee. So, we are only checking basic guarantee here.
   {
     ThrowingVariant rhs = ExpectedThrower();
-    EXPECT_TRUE(
-        MakeExceptionSafetyTester()
-            .WithInitialValue(WithCopyNoThrow())
-            .WithInvariants(CheckInvariants)
-            .Test([rhs](ThrowingVariant* lhs) mutable { lhs->swap(rhs); }));
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithCopyNoThrow())
+                    .WithInvariants(CheckInvariants)
+                    .Test([&](ThrowingVariant* lhs) {
+                      auto copy = rhs;
+                      lhs->swap(copy);
+                    }));
   }
   {
     ThrowingVariant rhs = ExpectedThrower();
-    EXPECT_TRUE(
-        MakeExceptionSafetyTester()
-            .WithInitialValue(WithCopyNoThrow())
-            .WithInvariants(CheckInvariants)
-            .Test([rhs](ThrowingVariant* lhs) mutable { rhs.swap(*lhs); }));
+    EXPECT_TRUE(MakeExceptionSafetyTester()
+                    .WithInitialValue(WithCopyNoThrow())
+                    .WithInvariants(CheckInvariants)
+                    .Test([&](ThrowingVariant* lhs) {
+                      auto copy = rhs;
+                      copy.swap(*lhs);
+                    }));
   }
 }