about summary refs log tree commit diff
path: root/absl
diff options
context:
space:
mode:
Diffstat (limited to 'absl')
-rw-r--r--absl/algorithm/algorithm.h11
-rw-r--r--absl/base/BUILD.bazel41
-rw-r--r--absl/base/CMakeLists.txt27
-rw-r--r--absl/base/internal/periodic_sampler.cc50
-rw-r--r--absl/base/internal/periodic_sampler.h193
-rw-r--r--absl/base/internal/periodic_sampler_benchmark.cc70
-rw-r--r--absl/base/internal/periodic_sampler_test.cc175
-rw-r--r--absl/debugging/internal/stacktrace_win32-inl.inc2
-rw-r--r--absl/debugging/symbolize_win32.inc6
-rw-r--r--absl/synchronization/notification.cc9
-rw-r--r--absl/synchronization/notification.h9
-rw-r--r--absl/time/internal/cctz/src/zone_info_source.cc7
12 files changed, 581 insertions, 19 deletions
diff --git a/absl/algorithm/algorithm.h b/absl/algorithm/algorithm.h
index bb90215d80da..771228a0201e 100644
--- a/absl/algorithm/algorithm.h
+++ b/absl/algorithm/algorithm.h
@@ -84,6 +84,8 @@ It RotateImpl(It first, It middle, It last, std::false_type) {
 
 }  // namespace algorithm_internal
 
+// equal()
+//
 // Compares the equality of two ranges specified by pairs of iterators, using
 // the given predicate, returning true iff for each corresponding iterator i1
 // and i2 in the first and second range respectively, pred(*i1, *i2) == true
@@ -104,8 +106,8 @@ bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
       typename std::iterator_traits<InputIter2>::iterator_category{});
 }
 
-// Performs comparison of two ranges specified by pairs of iterators using
-// operator==.
+// Overload of equal() that performs comparison of two ranges specified by pairs
+// of iterators using operator==.
 template <typename InputIter1, typename InputIter2>
 bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
            InputIter2 last2) {
@@ -113,6 +115,8 @@ bool equal(InputIter1 first1, InputIter1 last1, InputIter2 first2,
                      algorithm_internal::EqualTo{});
 }
 
+// linear_search()
+//
 // Performs a linear search for `value` using the iterator `first` up to
 // but not including `last`, returning true if [`first`, `last`) contains an
 // element equal to `value`.
@@ -126,6 +130,8 @@ bool linear_search(InputIterator first, InputIterator last,
   return std::find(first, last, value) != last;
 }
 
+// rotate()
+//
 // Performs a left rotation on a range of elements (`first`, `last`) such that
 // `middle` is now the first element. `rotate()` returns an iterator pointing to
 // the first element before rotation. This function is exactly the same as
@@ -135,7 +141,6 @@ bool linear_search(InputIterator first, InputIterator last,
 // The complexity of this algorithm is the same as that of `std::rotate`, but if
 // `ForwardIterator` is not a random-access iterator, then `absl::rotate`
 // performs an additional pass over the range to construct the return value.
-
 template <typename ForwardIterator>
 ForwardIterator rotate(ForwardIterator first, ForwardIterator middle,
                        ForwardIterator last) {
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 7e234bc66779..f6b210f41e31 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -586,6 +586,47 @@ cc_test(
 )
 
 cc_library(
+    name = "periodic_sampler",
+    srcs = ["internal/periodic_sampler.cc"],
+    hdrs = ["internal/periodic_sampler.h"],
+    copts = ABSL_DEFAULT_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    deps = [
+        ":core_headers",
+        ":exponential_biased",
+    ],
+)
+
+cc_test(
+    name = "periodic_sampler_test",
+    size = "small",
+    srcs = ["internal/periodic_sampler_test.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    visibility = ["//visibility:private"],
+    deps = [
+        ":core_headers",
+        ":periodic_sampler",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
+cc_binary(
+    name = "periodic_sampler_benchmark",
+    testonly = 1,
+    srcs = ["internal/periodic_sampler_benchmark.cc"],
+    copts = ABSL_TEST_COPTS,
+    linkopts = ABSL_DEFAULT_LINKOPTS,
+    tags = ["benchmark"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":core_headers",
+        ":periodic_sampler",
+        "@com_github_google_benchmark//:benchmark_main",
+    ],
+)
+
+cc_library(
     name = "scoped_set_env",
     testonly = 1,
     srcs = ["internal/scoped_set_env.cc"],
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 7ab6955e2176..9b0174d80efe 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -536,6 +536,33 @@ absl_cc_test(
 
 absl_cc_library(
   NAME
+    periodic_sampler
+  SRCS
+    "internal/periodic_sampler.cc"
+  HDRS
+    "internal/periodic_sampler.h"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::core_headers
+    absl::exponential_biased
+)
+
+absl_cc_test(
+  NAME
+    periodic_sampler_test
+  SRCS
+    "internal/periodic_sampler_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::core_headers
+    absl::periodic_sampler
+    gmock_main
+)
+
+absl_cc_library(
+  NAME
     scoped_set_env
   SRCS
     "internal/scoped_set_env.cc"
diff --git a/absl/base/internal/periodic_sampler.cc b/absl/base/internal/periodic_sampler.cc
new file mode 100644
index 000000000000..439745d0c514
--- /dev/null
+++ b/absl/base/internal/periodic_sampler.cc
@@ -0,0 +1,50 @@
+// Copyright 2019 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
+//
+//      https://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/base/internal/periodic_sampler.h"
+
+#include <atomic>
+
+#include "absl/base/internal/exponential_biased.h"
+
+namespace absl {
+namespace base_internal {
+
+int64_t PeriodicSamplerBase::GetExponentialBiased(int period) noexcept {
+  return rng_.Get(period);
+}
+
+bool PeriodicSamplerBase::SubtleConfirmSample() noexcept {
+  int current_period = period();
+
+  // Deal with period case 0 (always off) and 1 (always on)
+  if (ABSL_PREDICT_FALSE(current_period < 2)) {
+    stride_ = 0;
+    return current_period == 1;
+  }
+
+  // Check if this is the first call to Sample()
+  if (ABSL_PREDICT_FALSE(stride_ == 1)) {
+    stride_ = -1 - GetExponentialBiased(current_period);
+    if (stride_ < -1) {
+      ++stride_;
+      return false;
+    }
+  }
+  stride_ = -1 - GetExponentialBiased(current_period);
+  return true;
+}
+
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/periodic_sampler.h b/absl/base/internal/periodic_sampler.h
new file mode 100644
index 000000000000..2c0600f05ea4
--- /dev/null
+++ b/absl/base/internal/periodic_sampler.h
@@ -0,0 +1,193 @@
+// Copyright 2019 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
+//
+//      https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
+#define ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
+
+#include <stdint.h>
+
+#include <atomic>
+
+#include "absl/base/internal/exponential_biased.h"
+#include "absl/base/optimization.h"
+
+namespace absl {
+namespace base_internal {
+
+// PeriodicSamplerBase provides the basic period sampler implementation.
+//
+// This is the base class for the templated PeriodicSampler class, which holds
+// a global std::atomic value identified by a user defined tag, such that
+// each specific PeriodSampler implementation holds its own global period.
+//
+// PeriodicSamplerBase is thread-compatible except where stated otherwise.
+class PeriodicSamplerBase {
+ public:
+  // PeriodicSamplerBase is trivial / copyable / movable / destructible.
+  PeriodicSamplerBase() = default;
+  PeriodicSamplerBase(PeriodicSamplerBase&&) = default;
+  PeriodicSamplerBase(const PeriodicSamplerBase&) = default;
+
+  // Returns true roughly once every `period` calls. This is established by a
+  // randomly picked `stride` that is counted down on each call to `Sample`.
+  // This stride is picked such that the probability of `Sample()` returning
+  // true is 1 in `period`.
+  inline bool Sample() noexcept;
+
+  // The below methods are intended for optimized use cases where the
+  // size of the inlined fast path code is highly important. Applications
+  // should use the `Sample()` method unless they have proof that their
+  // specific use case requires the optimizations offered by these methods.
+  //
+  // An example of such a use case is SwissTable sampling. All sampling checks
+  // are in inlined SwissTable methods, and the number of call sites is huge.
+  // In this case, the inlined code size added to each translation unit calling
+  // SwissTable methods is non-trivial.
+  //
+  // The `SubtleMaybeSample()` function spuriously returns true even if the
+  // function should not be sampled, applications MUST match each call to
+  // 'SubtleMaybeSample()' returning true with a `SubtleConfirmSample()` call,
+  // and use the result of the latter as the sampling decision.
+  // In other words: the code should logically be equivalent to:
+  //
+  //    if (SubtleMaybeSample() && SubtleConfirmSample()) {
+  //      // Sample this call
+  //    }
+  //
+  // In the 'inline-size' optimized case, the `SubtleConfirmSample()` call can
+  // be placed out of line, for example, the typical use case looks as follows:
+  //
+  //   // --- frobber.h -----------
+  //   void FrobberSampled();
+  //
+  //   inline void FrobberImpl() {
+  //     // ...
+  //   }
+  //
+  //   inline void Frobber() {
+  //     if (ABSL_PREDICT_FALSE(sampler.SubtleMaybeSample())) {
+  //       FrobberSampled();
+  //     } else {
+  //       FrobberImpl();
+  //     }
+  //   }
+  //
+  //   // --- frobber.cc -----------
+  //   void FrobberSampled() {
+  //     if (!sampler.SubtleConfirmSample())) {
+  //       // Spurious false positive
+  //       FrobberImpl();
+  //       return;
+  //     }
+  //
+  //     // Sampled execution
+  //     // ...
+  //   }
+  inline bool SubtleMaybeSample() noexcept;
+  bool SubtleConfirmSample() noexcept;
+
+ protected:
+  // We explicitly don't use a virtual destructor as this class is never
+  // virtually destroyed, and it keeps the class trivial, which avoids TLS
+  // prologue and epilogue code for our TLS instances.
+  ~PeriodicSamplerBase() = default;
+
+  // Returns the next stride for our sampler.
+  // This function is virtual for testing purposes only.
+  virtual int64_t GetExponentialBiased(int period) noexcept;
+
+ private:
+  // Returns the current period of this sampler. Thread-safe.
+  virtual int period() const noexcept = 0;
+
+  int64_t stride_ = 0;
+  ExponentialBiased rng_;
+};
+
+inline bool PeriodicSamplerBase::SubtleMaybeSample() noexcept {
+  // We explicitly count up and not down, as the compiler does not generate
+  // ideal code for counting down. See also https://gcc.godbolt.org/z/FTPDSM
+  //
+  // With `if (ABSL_PREDICT_FALSE(++stride_ < 0))`
+  //    add     QWORD PTR fs:sampler@tpoff+8, 1
+  //    jns     .L15
+  //    ret
+  //
+  // With `if (ABSL_PREDICT_FALSE(--stride_ > 0))`
+  //    mov     rax, QWORD PTR fs:sampler@tpoff+8
+  //    sub     rax, 1
+  //    mov     QWORD PTR fs:sampler@tpoff+8, rax
+  //    test    rax, rax
+  //    jle     .L15
+  //    ret
+  //    add     QWORD PTR fs:sampler@tpoff+8, 1
+  //    jns     .L15
+  //    ret
+  //
+  // --stride >= 0 does work, but makes our logic slightly harder as in that
+  // case we have less convenient zero-init and over-run values.
+  if (ABSL_PREDICT_FALSE(++stride_ < 0)) {
+    return false;
+  }
+  return true;
+}
+
+inline bool PeriodicSamplerBase::Sample() noexcept {
+  return ABSL_PREDICT_FALSE(SubtleMaybeSample()) ? SubtleConfirmSample()
+                                                 : false;
+}
+
+// PeriodicSampler is a concreted periodic sampler implementation.
+// The user provided Tag identifies the implementation, and is required to
+// isolate the global state of this instance from other instances.
+//
+// Typical use case:
+//
+//   struct HashTablezTag {};
+//   thread_local PeriodicSampler sampler;
+//
+//   void HashTableSamplingLogic(...) {
+//     if (sampler.Sample()) {
+//       HashTableSlowSamplePath(...);
+//     }
+//   }
+//
+template <typename Tag, int default_period = 0>
+class PeriodicSampler final : public PeriodicSamplerBase {
+ public:
+  ~PeriodicSampler() = default;
+
+  int period() const noexcept final {
+    return period_.load(std::memory_order_relaxed);
+  }
+
+  // Sets the global period for this sampler. Thread-safe.
+  // Setting a period of 0 disables the sampler, i.e., every call to Sample()
+  // will return false. Setting a period of 1 puts the sampler in 'always on'
+  // mode, i.e., every call to Sample() returns true.
+  static void SetGlobalPeriod(int period) {
+    period_.store(period, std::memory_order_relaxed);
+  }
+
+ private:
+  static std::atomic<int> period_;
+};
+
+template <typename Tag, int default_period>
+std::atomic<int> PeriodicSampler<Tag, default_period>::period_(default_period);
+
+}  // namespace base_internal
+}  // namespace absl
+
+#endif  // ABSL_BASE_INTERNAL_PERIODIC_SAMPLER_H_
diff --git a/absl/base/internal/periodic_sampler_benchmark.cc b/absl/base/internal/periodic_sampler_benchmark.cc
new file mode 100644
index 000000000000..f87cef73dc16
--- /dev/null
+++ b/absl/base/internal/periodic_sampler_benchmark.cc
@@ -0,0 +1,70 @@
+// Copyright 2019 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
+//
+//      https://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 "benchmark/benchmark.h"
+#include "absl/base/internal/periodic_sampler.h"
+
+namespace absl {
+namespace base_internal {
+namespace {
+
+template <typename Sampler>
+void BM_Sample(Sampler* sampler, benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(sampler);
+    benchmark::DoNotOptimize(sampler->Sample());
+  }
+}
+
+template <typename Sampler>
+void BM_SampleMinunumInlined(Sampler* sampler, benchmark::State& state) {
+  for (auto _ : state) {
+    benchmark::DoNotOptimize(sampler);
+    if (ABSL_PREDICT_FALSE(sampler->SubtleMaybeSample())) {
+      benchmark::DoNotOptimize(sampler->SubtleConfirmSample());
+    }
+  }
+}
+
+void BM_PeriodicSampler_ShortSample(benchmark::State& state) {
+  struct Tag {};
+  PeriodicSampler<Tag, 1024> sampler;
+  BM_Sample(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_ShortSample);
+
+void BM_PeriodicSampler_LongSample(benchmark::State& state) {
+  struct Tag {};
+  PeriodicSampler<Tag, 1024 * 1024> sampler;
+  BM_Sample(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_LongSample);
+
+void BM_PeriodicSampler_LongSampleMinunumInlined(benchmark::State& state) {
+  struct Tag {};
+  PeriodicSampler<Tag, 1024 * 1024> sampler;
+  BM_SampleMinunumInlined(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_LongSampleMinunumInlined);
+
+void BM_PeriodicSampler_Disabled(benchmark::State& state) {
+  struct Tag {};
+  PeriodicSampler<Tag, 0> sampler;
+  BM_Sample(&sampler, state);
+}
+BENCHMARK(BM_PeriodicSampler_Disabled);
+
+}  // namespace
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/base/internal/periodic_sampler_test.cc b/absl/base/internal/periodic_sampler_test.cc
new file mode 100644
index 000000000000..1ba61377a0f4
--- /dev/null
+++ b/absl/base/internal/periodic_sampler_test.cc
@@ -0,0 +1,175 @@
+// Copyright 2019 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
+//
+//      https://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/base/internal/periodic_sampler.h"
+
+#include <thread>  // NOLINT(build/c++11)
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "absl/base/attributes.h"
+#include "absl/base/macros.h"
+
+namespace absl {
+namespace base_internal {
+namespace {
+
+using testing::Eq;
+using testing::Return;
+using testing::StrictMock;
+
+class MockPeriodicSampler : public PeriodicSamplerBase {
+ public:
+  virtual ~MockPeriodicSampler() = default;
+
+  MOCK_METHOD(int, period, (), (const, noexcept));
+  MOCK_METHOD(int64_t, GetExponentialBiased, (int), (noexcept));
+};
+
+TEST(PeriodicSamplerBaseTest, Sample) {
+  StrictMock<MockPeriodicSampler> sampler;
+
+  EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(16));
+  EXPECT_CALL(sampler, GetExponentialBiased(16))
+      .WillOnce(Return(1))
+      .WillOnce(Return(2))
+      .WillOnce(Return(3));
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_TRUE(sampler.Sample());
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_TRUE(sampler.Sample());
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, ImmediatelySample) {
+  StrictMock<MockPeriodicSampler> sampler;
+
+  EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16));
+  EXPECT_CALL(sampler, GetExponentialBiased(16))
+      .WillOnce(Return(0))
+      .WillOnce(Return(1))
+      .WillOnce(Return(2));
+
+  EXPECT_TRUE(sampler.Sample());
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_TRUE(sampler.Sample());
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, Disabled) {
+  StrictMock<MockPeriodicSampler> sampler;
+
+  EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(0));
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, AlwaysOn) {
+  StrictMock<MockPeriodicSampler> sampler;
+
+  EXPECT_CALL(sampler, period()).Times(3).WillRepeatedly(Return(1));
+
+  EXPECT_TRUE(sampler.Sample());
+  EXPECT_TRUE(sampler.Sample());
+  EXPECT_TRUE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, Disable) {
+  StrictMock<MockPeriodicSampler> sampler;
+
+  EXPECT_CALL(sampler, period()).WillOnce(Return(16));
+  EXPECT_CALL(sampler, GetExponentialBiased(16)).WillOnce(Return(2));
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+
+  EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(0));
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerBaseTest, Enable) {
+  StrictMock<MockPeriodicSampler> sampler;
+
+  EXPECT_CALL(sampler, period()).WillOnce(Return(0));
+  EXPECT_FALSE(sampler.Sample());
+
+  EXPECT_CALL(sampler, period()).Times(2).WillRepeatedly(Return(16));
+  EXPECT_CALL(sampler, GetExponentialBiased(16))
+      .Times(2)
+      .WillRepeatedly(Return(2));
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_TRUE(sampler.Sample());
+
+  EXPECT_FALSE(sampler.Sample());
+  EXPECT_FALSE(sampler.Sample());
+}
+
+TEST(PeriodicSamplerTest, ConstructConstInit) {
+  struct Tag {};
+  ABSL_CONST_INIT static PeriodicSampler<Tag> sampler;
+  (void)sampler;
+}
+
+TEST(PeriodicSamplerTest, DefaultPeriod0) {
+  struct Tag {};
+  PeriodicSampler<Tag> sampler;
+  EXPECT_THAT(sampler.period(), Eq(0));
+}
+
+TEST(PeriodicSamplerTest, DefaultPeriod) {
+  struct Tag {};
+  PeriodicSampler<Tag, 100> sampler;
+  EXPECT_THAT(sampler.period(), Eq(100));
+}
+
+TEST(PeriodicSamplerTest, SetGlobalPeriod) {
+  struct Tag1 {};
+  struct Tag2 {};
+  PeriodicSampler<Tag1, 25> sampler1;
+  PeriodicSampler<Tag2, 50> sampler2;
+
+  EXPECT_THAT(sampler1.period(), Eq(25));
+  EXPECT_THAT(sampler2.period(), Eq(50));
+
+  std::thread thread([] {
+    PeriodicSampler<Tag1, 25> sampler1;
+    PeriodicSampler<Tag2, 50> sampler2;
+    EXPECT_THAT(sampler1.period(), Eq(25));
+    EXPECT_THAT(sampler2.period(), Eq(50));
+    sampler1.SetGlobalPeriod(10);
+    sampler2.SetGlobalPeriod(20);
+  });
+  thread.join();
+
+  EXPECT_THAT(sampler1.period(), Eq(10));
+  EXPECT_THAT(sampler2.period(), Eq(20));
+}
+
+}  // namespace
+}  // namespace base_internal
+}  // namespace absl
diff --git a/absl/debugging/internal/stacktrace_win32-inl.inc b/absl/debugging/internal/stacktrace_win32-inl.inc
index b46491f8143d..247e7428df8b 100644
--- a/absl/debugging/internal/stacktrace_win32-inl.inc
+++ b/absl/debugging/internal/stacktrace_win32-inl.inc
@@ -54,7 +54,7 @@ static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
 
 template <bool IS_STACK_FRAMES, bool IS_WITH_CONTEXT>
 static int UnwindImpl(void** result, int* sizes, int max_depth, int skip_count,
-                      const void *ucp, int *min_dropped_frames) {
+                      const void*, int* min_dropped_frames) {
   int n = 0;
   if (!RtlCaptureStackBackTrace_fn) {
     // can't find a stacktrace with no function to call
diff --git a/absl/debugging/symbolize_win32.inc b/absl/debugging/symbolize_win32.inc
index b0fb3b9a3e13..bd6fbd5ef463 100644
--- a/absl/debugging/symbolize_win32.inc
+++ b/absl/debugging/symbolize_win32.inc
@@ -34,7 +34,7 @@ namespace absl {
 
 static HANDLE process = NULL;
 
-void InitializeSymbolizer(const char *argv0) {
+void InitializeSymbolizer(const char*) {
   if (process != nullptr) {
     return;
   }
@@ -53,12 +53,12 @@ void InitializeSymbolizer(const char *argv0) {
   }
 }
 
-bool Symbolize(const void *pc, char *out, int out_size) {
+bool Symbolize(const void* pc, char* out, int out_size) {
   if (out_size <= 0) {
     return false;
   }
   alignas(SYMBOL_INFO) char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
-  SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(buf);
+  SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(buf);
   symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
   symbol->MaxNameLen = MAX_SYM_NAME;
   if (!SymFromAddr(process, reinterpret_cast<DWORD64>(pc), nullptr, symbol)) {
diff --git a/absl/synchronization/notification.cc b/absl/synchronization/notification.cc
index 53ace00870c9..1eb7f4161905 100644
--- a/absl/synchronization/notification.cc
+++ b/absl/synchronization/notification.cc
@@ -44,15 +44,6 @@ Notification::~Notification() {
   MutexLock l(&this->mutex_);
 }
 
-static inline bool HasBeenNotifiedInternal(
-    const std::atomic<bool> *notified_yet) {
-  return notified_yet->load(std::memory_order_acquire);
-}
-
-bool Notification::HasBeenNotified() const {
-  return HasBeenNotifiedInternal(&this->notified_yet_);
-}
-
 void Notification::WaitForNotification() const {
   if (!HasBeenNotifiedInternal(&this->notified_yet_)) {
     this->mutex_.LockWhen(Condition(&HasBeenNotifiedInternal,
diff --git a/absl/synchronization/notification.h b/absl/synchronization/notification.h
index 82d111a5492f..36c2ce3dcefd 100644
--- a/absl/synchronization/notification.h
+++ b/absl/synchronization/notification.h
@@ -73,7 +73,9 @@ class Notification {
   // Notification::HasBeenNotified()
   //
   // Returns the value of the notification's internal "notified" state.
-  bool HasBeenNotified() const;
+  bool HasBeenNotified() const {
+    return HasBeenNotifiedInternal(&this->notified_yet_);
+  }
 
   // Notification::WaitForNotification()
   //
@@ -105,6 +107,11 @@ class Notification {
   void Notify();
 
  private:
+  static inline bool HasBeenNotifiedInternal(
+      const std::atomic<bool>* notified_yet) {
+    return notified_yet->load(std::memory_order_acquire);
+  }
+
   mutable Mutex mutex_;
   std::atomic<bool> notified_yet_;  // written under mutex_
 };
diff --git a/absl/time/internal/cctz/src/zone_info_source.cc b/absl/time/internal/cctz/src/zone_info_source.cc
index 42f50c5e8fb4..d5758efa2952 100644
--- a/absl/time/internal/cctz/src/zone_info_source.cc
+++ b/absl/time/internal/cctz/src/zone_info_source.cc
@@ -49,10 +49,13 @@ std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
 #if !defined(__has_attribute)
 #define __has_attribute(x) 0
 #endif
-#if __has_attribute(weak) || defined(__GNUC__)
+// MinGW is GCC on Windows, so while it asserts __has_attribute(weak), the
+// Windows linker cannot handle that. Nor does the MinGW compiler know how to
+// pass "#pragma comment(linker, ...)" to the Windows linker.
+#if (__has_attribute(weak) || defined(__GNUC__)) && !defined(__MINGW32__)
 ZoneInfoSourceFactory zone_info_source_factory
     __attribute__((weak)) = DefaultFactory;
-#elif defined(_MSC_VER) && !defined(_LIBCPP_VERSION)
+#elif defined(_MSC_VER) && !defined(__MINGW32__) && !defined(_LIBCPP_VERSION)
 extern ZoneInfoSourceFactory zone_info_source_factory;
 extern ZoneInfoSourceFactory default_factory;
 ZoneInfoSourceFactory default_factory = DefaultFactory;