abseil-cpp/absl/flags/internal/sequence_lock_test.cc
Go to the documentation of this file.
1 // Copyright 2020 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "absl/flags/internal/sequence_lock.h"
15 
16 #include <algorithm>
17 #include <atomic>
18 #include <thread> // NOLINT(build/c++11)
19 #include <tuple>
20 #include <vector>
21 
22 #include "gtest/gtest.h"
23 #include "absl/base/internal/sysinfo.h"
24 #include "absl/container/fixed_array.h"
25 #include "absl/time/clock.h"
26 
27 namespace {
28 
29 namespace flags = absl::flags_internal;
30 
31 class ConcurrentSequenceLockTest
32  : public testing::TestWithParam<std::tuple<int, int>> {
33  public:
34  ConcurrentSequenceLockTest()
35  : buf_bytes_(std::get<0>(GetParam())),
36  num_threads_(std::get<1>(GetParam())) {}
37 
38  protected:
39  const int buf_bytes_;
40  const int num_threads_;
41 };
42 
43 TEST_P(ConcurrentSequenceLockTest, ReadAndWrite) {
44  const int buf_words =
45  flags::AlignUp(buf_bytes_, sizeof(uint64_t)) / sizeof(uint64_t);
46 
47  // The buffer that will be protected by the SequenceLock.
48  absl::FixedArray<std::atomic<uint64_t>> protected_buf(buf_words);
49  for (auto& v : protected_buf) v = -1;
50 
51  flags::SequenceLock seq_lock;
52  std::atomic<bool> stop{false};
53  std::atomic<int64_t> bad_reads{0};
54  std::atomic<int64_t> good_reads{0};
55  std::atomic<int64_t> unsuccessful_reads{0};
56 
57  // Start a bunch of threads which read 'protected_buf' under the sequence
58  // lock. The main thread will concurrently update 'protected_buf'. The updates
59  // always consist of an array of identical integers. The reader ensures that
60  // any data it reads matches that pattern (i.e. the reads are not "torn").
61  std::vector<std::thread> threads;
62  for (int i = 0; i < num_threads_; i++) {
63  threads.emplace_back([&]() {
64  absl::FixedArray<char> local_buf(buf_bytes_);
65  while (!stop.load(std::memory_order_relaxed)) {
66  if (seq_lock.TryRead(local_buf.data(), protected_buf.data(),
67  buf_bytes_)) {
68  bool good = true;
69  for (const auto& v : local_buf) {
70  if (v != local_buf[0]) good = false;
71  }
72  if (good) {
73  good_reads.fetch_add(1, std::memory_order_relaxed);
74  } else {
75  bad_reads.fetch_add(1, std::memory_order_relaxed);
76  }
77  } else {
78  unsuccessful_reads.fetch_add(1, std::memory_order_relaxed);
79  }
80  }
81  });
82  }
83  while (unsuccessful_reads.load(std::memory_order_relaxed) < num_threads_) {
85  }
86  seq_lock.MarkInitialized();
87 
88  // Run a maximum of 5 seconds. On Windows, the scheduler behavior seems
89  // somewhat unfair and without an explicit timeout for this loop, the tests
90  // can run a long time.
91  absl::Time deadline = absl::Now() + absl::Seconds(5);
92  for (int i = 0; i < 100 && absl::Now() < deadline; i++) {
93  absl::FixedArray<char> writer_buf(buf_bytes_);
94  for (auto& v : writer_buf) v = i;
95  seq_lock.Write(protected_buf.data(), writer_buf.data(), buf_bytes_);
97  }
98  stop.store(true, std::memory_order_relaxed);
99  for (auto& t : threads) t.join();
100  ASSERT_GE(good_reads, 0);
101  ASSERT_EQ(bad_reads, 0);
102 }
103 
104 // Simple helper for generating a range of thread counts.
105 // Generates [low, low*scale, low*scale^2, ...high)
106 // (even if high is between low*scale^k and low*scale^(k+1)).
107 std::vector<int> MultiplicativeRange(int low, int high, int scale) {
108  std::vector<int> result;
109  for (int current = low; current < high; current *= scale) {
110  result.push_back(current);
111  }
112  result.push_back(high);
113  return result;
114 }
115 
116 #ifndef ABSL_HAVE_THREAD_SANITIZER
117 const int kMaxThreads = absl::base_internal::NumCPUs();
118 #else
119 // With TSAN, a lot of threads contending for atomic access on the sequence
120 // lock make this test run too slowly.
121 const int kMaxThreads = std::min(absl::base_internal::NumCPUs(), 4);
122 #endif
123 
124 // Return all of the interesting buffer sizes worth testing:
125 // powers of two and adjacent values.
126 std::vector<int> InterestingBufferSizes() {
127  std::vector<int> ret;
128  for (int v : MultiplicativeRange(1, 128, 2)) {
129  ret.push_back(v);
130  if (v > 1) {
131  ret.push_back(v - 1);
132  }
133  ret.push_back(v + 1);
134  }
135  return ret;
136 }
137 
139  TestManyByteSizes, ConcurrentSequenceLockTest,
141  // Buffer size (bytes).
142  testing::ValuesIn(InterestingBufferSizes()),
143  // Number of reader threads.
144  testing::ValuesIn(MultiplicativeRange(1, kMaxThreads, 2))));
145 
146 // Simple single-threaded test, parameterized by the size of the buffer to be
147 // protected.
148 class SequenceLockTest : public testing::TestWithParam<int> {};
149 
150 TEST_P(SequenceLockTest, SingleThreaded) {
151  const int size = GetParam();
153  flags::AlignUp(size, sizeof(uint64_t)) / sizeof(uint64_t));
154 
155  flags::SequenceLock seq_lock;
156  seq_lock.MarkInitialized();
157 
158  std::vector<char> src_buf(size, 'x');
159  seq_lock.Write(protected_buf.data(), src_buf.data(), size);
160 
161  std::vector<char> dst_buf(size, '0');
162  ASSERT_TRUE(seq_lock.TryRead(dst_buf.data(), protected_buf.data(), size));
163  ASSERT_EQ(src_buf, dst_buf);
164 }
165 INSTANTIATE_TEST_SUITE_P(TestManyByteSizes, SequenceLockTest,
166  // Buffer size (bytes).
167  testing::Range(1, 128));
168 
169 } // namespace
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
get
absl::string_view get(const Cont &c)
Definition: abseil-cpp/absl/strings/str_replace_test.cc:185
absl::Time
Definition: third_party/abseil-cpp/absl/time/time.h:642
ASSERT_GE
#define ASSERT_GE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2072
absl::base_internal::NumCPUs
int NumCPUs()
Definition: abseil-cpp/absl/base/internal/sysinfo.cc:347
absl::flags_internal::AlignUp
constexpr size_t AlignUp(size_t x, size_t align)
Definition: abseil-cpp/absl/flags/internal/sequence_lock.h:33
testing::Range
internal::ParamGenerator< T > Range(T start, T end, IncrementT step)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:229
absl::SleepFor
void SleepFor(absl::Duration duration)
Definition: abseil-cpp/absl/time/clock.h:70
threads
static uv_thread_t * threads
Definition: threadpool.c:38
absl::flags_internal::SequenceLock::Write
void Write(std::atomic< uint64_t > *dst, const void *src, size_t size)
Definition: abseil-cpp/absl/flags/internal/sequence_lock.h:99
testing::TestWithParam
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1883
absl::Milliseconds
constexpr Duration Milliseconds(T n)
Definition: third_party/abseil-cpp/absl/time/time.h:415
absl::Microseconds
constexpr Duration Microseconds(T n)
Definition: third_party/abseil-cpp/absl/time/time.h:411
TEST_P
#define TEST_P(test_suite_name, test_name)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:414
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
absl::flags_internal::SequenceLock::TryRead
bool TryRead(void *dst, const std::atomic< uint64_t > *src, size_t size) const
Definition: abseil-cpp/absl/flags/internal/sequence_lock.h:80
bm_speedup.scale
def scale(a, mul)
Definition: bm_speedup.py:24
min
#define min(a, b)
Definition: qsort.h:83
absl::Seconds
constexpr Duration Seconds(T n)
Definition: third_party/abseil-cpp/absl/time/time.h:419
absl::Now
ABSL_NAMESPACE_BEGIN Time Now()
Definition: abseil-cpp/absl/time/clock.cc:39
absl::flags_internal
Definition: abseil-cpp/absl/flags/commandlineflag.h:40
absl::str_format_internal::LengthMod::t
@ t
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
testing::Combine
internal::CartesianProductHolder< Generator... > Combine(const Generator &... g)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:410
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
stop
static const char stop[]
Definition: benchmark-async-pummel.c:35
testing::ValuesIn
internal::ParamGenerator< typename std::iterator_traits< ForwardIterator >::value_type > ValuesIn(ForwardIterator begin, ForwardIterator end)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:297
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
absl::flags_internal::SequenceLock::MarkInitialized
void MarkInitialized()
Definition: abseil-cpp/absl/flags/internal/sequence_lock.h:63
absl::FixedArray
Definition: abseil-cpp/absl/container/fixed_array.h:78
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
ASSERT_EQ
#define ASSERT_EQ(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2056
absl::flags_internal::SequenceLock
Definition: abseil-cpp/absl/flags/internal/sequence_lock.h:58
INSTANTIATE_TEST_SUITE_P
#define INSTANTIATE_TEST_SUITE_P(prefix, test_suite_name,...)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest-param-test.h:460


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:10