Consistency in namespace-closing comments
[folly.git] / folly / experimental / flat_combining / test / FlatCombiningTestHelpers.h
1 /*
2  * Copyright 2017 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <folly/experimental/flat_combining/test/FlatCombiningExamples.h>
20
21 #include <folly/Benchmark.h>
22 #include <glog/logging.h>
23
24 #include <atomic>
25 #include <chrono>
26 #include <thread>
27
28 namespace folly {
29 namespace test {
30
31 void doWork(int work) {
32   uint64_t a = 0;
33   for (int i = work; i > 0; --i) {
34     a += i;
35   }
36   folly::doNotOptimizeAway(a);
37 }
38
39 template <
40     typename Example,
41     typename Req = bool,
42     typename Mutex = std::mutex,
43     template <typename> class Atom = std::atomic>
44 uint64_t fc_test(
45     int nthreads,
46     int lines,
47     int numRecs,
48     int work,
49     int ops,
50     bool combining,
51     bool dedicated,
52     bool tc,
53     bool syncops,
54     bool excl = false,
55     bool allocAll = false) {
56   using FC = FlatCombining<Example, Mutex, Atom, Req>;
57   using Rec = typename FC::Rec;
58
59   folly::BenchmarkSuspender susp;
60
61   std::atomic<bool> start{false};
62   std::atomic<int> started{0};
63   Example ex(lines, dedicated, numRecs);
64   std::atomic<uint64_t> total{0};
65   bool mutex = false;
66
67   if (allocAll) {
68     std::vector<Rec*> v(numRecs);
69     for (int i = 0; i < numRecs; ++i) {
70       v[i] = ex.allocRec();
71     }
72     for (int i = numRecs; i > 0; --i) {
73       ex.freeRec(v[i - 1]);
74     }
75   }
76
77   std::vector<std::thread> threads(nthreads);
78   for (int tid = 0; tid < nthreads; ++tid) {
79     threads[tid] = std::thread([&, tid] {
80       started.fetch_add(1);
81       Rec* myrec = (combining && tc) ? ex.allocRec() : nullptr;
82       uint64_t sum = 0;
83       while (!start.load())
84         ;
85
86       if (!combining) {
87         // no combining
88         for (int i = tid; i < ops; i += nthreads) {
89           sum += ex.fetchAddNoFC(1);
90           doWork(work); // unrelated work
91         }
92       } else if (syncops) {
93         // sync combining
94         for (int i = tid; i < ops; i += nthreads) {
95           sum += ex.fetchAdd(1, myrec);
96           doWork(work); // unrelated work
97         }
98       } else {
99         // async combining
100         for (int i = tid; i < ops; i += nthreads) {
101           ex.add(1, myrec);
102           doWork(work); // unrelated work
103         }
104       }
105
106       if (excl) {
107         // test of exclusive access through a lock holder
108         {
109           std::unique_lock<Mutex> l;
110           ex.holdLock(l);
111           CHECK(!mutex);
112           mutex = true;
113           VLOG(2) << tid << " " << ex.getVal() << " ...........";
114           using namespace std::chrono_literals;
115           /* sleep override */ // for coverage
116           std::this_thread::sleep_for(10ms);
117           VLOG(2) << tid << " " << ex.getVal() << " ===========";
118           CHECK(mutex);
119           mutex = false;
120         }
121         // test of explicit acquisition and release of exclusive access
122         ex.acquireExclusive();
123         {
124           CHECK(!mutex);
125           mutex = true;
126           VLOG(2) << tid << " " << ex.getVal() << " ...........";
127           using namespace std::chrono_literals;
128           /* sleep override */ // for coverage
129           std::this_thread::sleep_for(10ms);
130           VLOG(2) << tid << " " << ex.getVal() << " ===========";
131           CHECK(mutex);
132           mutex = false;
133         }
134         ex.releaseExclusive();
135       }
136
137       total.fetch_add(sum);
138       if (combining && tc) {
139         ex.freeRec(myrec);
140       }
141     });
142   }
143
144   while (started.load() < nthreads)
145     ;
146   auto tbegin = std::chrono::steady_clock::now();
147
148   // begin time measurement
149   susp.dismiss();
150   start.store(true);
151
152   for (auto& t : threads) {
153     t.join();
154   }
155
156   if (!syncops) {
157     // complete any pending asynch ops
158     ex.drainAll();
159   }
160
161   // end time measurement
162   uint64_t duration = 0;
163   BENCHMARK_SUSPEND {
164     auto tend = std::chrono::steady_clock::now();
165     CHECK_EQ(ops, ex.getVal());
166     if (syncops) {
167       uint64_t n = (uint64_t)ops;
168       uint64_t expected = n * (n - 1) / 2;
169       CHECK_EQ(expected, total);
170     }
171     duration =
172         std::chrono::duration_cast<std::chrono::nanoseconds>(tend - tbegin)
173             .count();
174   }
175   return duration;
176 }
177
178 uint64_t run_test(
179     int nthreads,
180     int lines,
181     int numRecs,
182     int work,
183     int ops,
184     bool combining,
185     bool simple,
186     bool dedicated,
187     bool tc,
188     bool syncops,
189     bool excl = false,
190     bool allocAll = false) {
191   using M = std::mutex;
192   if (simple) {
193     using Example = FcSimpleExample<M>;
194     return fc_test<Example, bool, M>(
195         nthreads,
196         lines,
197         numRecs,
198         work,
199         ops,
200         combining,
201         dedicated,
202         tc,
203         syncops,
204         excl,
205         allocAll);
206   } else {
207     using Example = FcCustomExample<Req, M>;
208     return fc_test<Example, Req, M>(
209         nthreads,
210         lines,
211         numRecs,
212         work,
213         ops,
214         combining,
215         dedicated,
216         tc,
217         syncops,
218         excl,
219         allocAll);
220   }
221 }
222
223 } // namespace test
224 } // namespace folly