5 class FollySyncTest_Parallel: public cds_test::stress_fixture {
7 static size_t s_nThreadCount;
8 // Simulate as the data protected by the lock.
9 static size_t locked_data;
10 static std::atomic<RcuData*> rcu_data;
11 // For RCU, we want to benchmark two things:
12 // (1) Readers --- we have a writer thread that runs nonstop until all other
13 // reader threads are done with a certain number of reads.
14 // (2) Writers --- we have several reader threads that run nonstop until a
15 // writer thread finishes a certain number of writes.
16 static std::atomic_uint rcu_readers_num;
17 static std::atomic_uint rcu_writers_num;
19 static size_t s_nMicroLockPassCount;
21 static size_t s_nMicroSpinLockPassCount;
23 static size_t s_nPicoSpinLockPassCount;
25 static size_t s_nSharedMutexPassCount;
27 static size_t s_nRWSpinLockPassCount;
29 static size_t s_nRWTicketSpinLockPassCount;
31 static size_t s_nRcuReaderPassCount;
32 static size_t s_nRcuWriterPassCount;
33 static size_t s_nRcuWriterFrequency;
35 static unsigned s_nSharedMutexWritePercentage;
36 static unsigned s_nRWSpinLockWritePercentage;
37 static unsigned s_nRWTicketSpinLockWritePercentage;
39 static void SetUpTestCase() {
40 const cds_test::config& cfg = get_config("ParallelFollySync");
41 GetConfigNonZeroExpected(ThreadCount, 4);
42 GetConfigNonZeroExpected(MicroLockPassCount, 2000000000);
43 GetConfigNonZeroExpected(MicroSpinLockPassCount, 1500000000);
44 GetConfigNonZeroExpected(PicoSpinLockPassCount, 2700000000);
45 GetConfigNonZeroExpected(SharedMutexPassCount, 5000000);
46 GetConfigNonZeroExpected(RWSpinLockPassCount, 5000000);
47 GetConfigNonZeroExpected(RWTicketSpinLockPassCount, 5000000);
48 GetConfigNonZeroExpected(RcuReaderPassCount, 10000);
49 // Every 100 ms by default there will be a writer.
50 GetConfigNonZeroExpected(RcuWriterFrequency, 100);
51 GetConfigNonZeroExpected(RcuWriterPassCount, 500);
53 GetConfigNonZeroExpected(SharedMutexWritePercentage, 5);
54 GetConfigNonZeroExpected(RWSpinLockWritePercentage, 5);
55 GetConfigNonZeroExpected(RWTicketSpinLockWritePercentage, 5);
57 rcu_data.store(new RcuData(), std::memory_order_relaxed);
60 static void rcu_write_sync() {
61 auto *old_data = rcu_data.load(std::memory_order_consume);
62 auto *new_data = new RcuData(*old_data);
65 rcu_data.store(new_data, std::memory_order_release);
66 folly::synchronize_rcu();
70 static void rcu_write_retire() {
71 auto *old_data = rcu_data.load(std::memory_order_consume);
72 auto *new_data = new RcuData(*old_data);
75 rcu_data.store(new_data, std::memory_order_release);
76 folly::rcu_retire(old_data);
79 static void run_rcu_writer_sync_nonstop(size_t pass_count) {
80 while (rcu_readers_num.load(std::memory_order_acquire) > 0) {
82 std::this_thread::sleep_for(
83 std::chrono::milliseconds(s_nRcuWriterFrequency));
87 static void run_rcu_writer_retire_nonstop(size_t pass_count) {
88 while (rcu_readers_num.load(std::memory_order_acquire) > 0) {
90 std::this_thread::sleep_for(
91 std::chrono::milliseconds(s_nRcuWriterFrequency));
95 static void run_rcu_reader_pass_count(size_t pass_count) {
97 for (size_t count = 0; count < pass_count; count++) {
99 auto *data = rcu_data.load(std::memory_order_consume);
100 sum += (data->d1 + data->d2);
102 rcu_readers_num.fetch_sub(1, std::memory_order_release);
103 // Just want to simulate the reading.
107 static void run_rcu_writer_sync_pass_count(size_t pass_count) {
108 for (size_t count = 0; count < pass_count; count++) {
111 rcu_writers_num.fetch_sub(1, std::memory_order_release);
114 static void run_rcu_writer_retire_pass_count(size_t pass_count) {
115 for (size_t count = 0; count < pass_count; count++) {
118 rcu_writers_num.fetch_sub(1, std::memory_order_release);
121 static void run_rcu_reader_nonstop(size_t pass_count) {
123 while (rcu_writers_num.load(std::memory_order_acquire) > 0) {
125 auto *data = rcu_data.load(std::memory_order_consume);
126 sum += (data->d1 + data->d2);
131 template <typename Lock>
132 static void run_rw_lock(Lock *l, size_t pass_count,
133 unsigned write_percentage) {
135 for (size_t count = 0; count < pass_count; count++) {
136 if (rand(100) < write_percentage) {
146 EXPECT_GE(sum, pass_count * write_percentage / 100);
149 template <typename Lock>
150 static void run_small_lock(Lock* l, size_t pass_count) {
151 for (size_t count = 0; count < pass_count; count++) {
158 template <typename... Args>
159 static void FollySyncThreading(Args... args) {
160 std::unique_ptr<std::thread[]> threads(new std::thread[s_nThreadCount]);
161 for (size_t i = 0; i < s_nThreadCount; i++) {
162 threads[i] = std::thread(args...);
164 for (size_t i = 0; i < s_nThreadCount; i++) {
169 template <typename WriterFunc, typename ReaderFunc>
170 static void FollyRcuThreading(WriterFunc writer_func,
171 ReaderFunc reader_func) {
172 rcu_readers_num.store(s_nThreadCount - 1, std::memory_order_release);
173 rcu_writers_num.store(1, std::memory_order_release);
175 std::unique_ptr<std::thread[]> threads(new std::thread[s_nThreadCount]);
176 // One of the threads is a writer.
177 threads[0] = std::thread(writer_func, s_nRcuWriterPassCount);
178 for (size_t i = 1; i < s_nThreadCount; i++) {
179 threads[i] = std::thread(reader_func, s_nRcuReaderPassCount);
181 for (size_t i = 0; i < s_nThreadCount; i++) {
186 template <typename SmallLockType>
187 static void FollySmallLockThreading(size_t pass_count) {
188 std::unique_ptr<SmallLockType> l(new SmallLockType());
191 FollySyncThreading(run_small_lock<SmallLockType>, l.get(), pass_count);
192 EXPECT_EQ(locked_data, pass_count * s_nThreadCount);
195 template <typename RWLockType>
196 static void FollyRWLockThreading(size_t pass_count, unsigned write_percentage) {
197 std::unique_ptr<RWLockType> l(new RWLockType());
199 FollySyncThreading(run_rw_lock<RWLockType>, l.get(), pass_count,
204 size_t FollySyncTest_Parallel::locked_data;
205 std::atomic<RcuData*> FollySyncTest_Parallel::rcu_data;
206 std::atomic_uint FollySyncTest_Parallel::rcu_readers_num;
207 std::atomic_uint FollySyncTest_Parallel::rcu_writers_num;
208 size_t FollySyncTest_Parallel::s_nThreadCount;
209 size_t FollySyncTest_Parallel::s_nMicroLockPassCount;
210 size_t FollySyncTest_Parallel::s_nMicroSpinLockPassCount;
211 size_t FollySyncTest_Parallel::s_nPicoSpinLockPassCount;
212 size_t FollySyncTest_Parallel::s_nSharedMutexPassCount;
213 size_t FollySyncTest_Parallel::s_nRWSpinLockPassCount;
214 size_t FollySyncTest_Parallel::s_nRWTicketSpinLockPassCount;
216 size_t FollySyncTest_Parallel::s_nRcuReaderPassCount;
217 size_t FollySyncTest_Parallel::s_nRcuWriterPassCount;
218 size_t FollySyncTest_Parallel::s_nRcuWriterFrequency;
220 unsigned FollySyncTest_Parallel::s_nSharedMutexWritePercentage;
221 unsigned FollySyncTest_Parallel::s_nRWSpinLockWritePercentage;
222 unsigned FollySyncTest_Parallel::s_nRWTicketSpinLockWritePercentage;
224 TEST_F(FollySyncTest_Parallel, FollyRCU_NonstopWriterSync) {
225 FollyRcuThreading(run_rcu_writer_sync_nonstop, run_rcu_reader_pass_count);
228 TEST_F(FollySyncTest_Parallel, FollyRCU_NonstopWriterNoSync) {
229 FollyRcuThreading(run_rcu_writer_retire_nonstop, run_rcu_reader_pass_count);
232 //TEST_F(FollySyncTest_Parallel, FollyRCU_NonstopReaderSync) {
233 // FollyRcuThreading(run_rcu_writer_sync_pass_count, run_rcu_reader_nonstop);
236 TEST_F(FollySyncTest_Parallel, FollyRCU_NonstopReaderNoSync) {
237 FollyRcuThreading(run_rcu_writer_retire_pass_count, run_rcu_reader_nonstop);
240 TEST_F(FollySyncTest_Parallel, FollyRWTicketSpinLock_32) {
241 FollyRWLockThreading<RWTicketSpinLock32>(s_nRWTicketSpinLockPassCount,
242 s_nRWTicketSpinLockWritePercentage);
245 TEST_F(FollySyncTest_Parallel, FollyRWTicketSpinLock_64) {
246 FollyRWLockThreading<RWTicketSpinLock64>(s_nRWTicketSpinLockPassCount,
247 s_nRWTicketSpinLockWritePercentage);
250 TEST_F(FollySyncTest_Parallel, FollyRWSpinLock) {
251 FollyRWLockThreading<RWSpinLock>(s_nRWSpinLockPassCount,
252 s_nRWSpinLockWritePercentage);
255 TEST_F(FollySyncTest_Parallel, FollySharedMutex_ReadPriority) {
256 FollyRWLockThreading<SharedMutexReadPriority>(s_nSharedMutexPassCount,
257 s_nSharedMutexWritePercentage);
260 TEST_F(FollySyncTest_Parallel, FollySharedMutex_WritePriority) {
261 FollyRWLockThreading<SharedMutexWritePriority>(s_nSharedMutexPassCount,
262 s_nSharedMutexWritePercentage);
265 TEST_F(FollySyncTest_Parallel, FollyMicroSpinLock) {
266 FollySmallLockThreading<MicroSpinLock>(s_nMicroSpinLockPassCount);
269 TEST_F(FollySyncTest_Parallel, FollyPicoSpinLock) {
270 FollySmallLockThreading<PicoSpinLock>(s_nPicoSpinLockPassCount);
273 TEST_F(FollySyncTest_Parallel, FollyMicroLock) {
274 FollySmallLockThreading<MicroLock>(s_nMicroLockPassCount);
277 } // namespace folly_test