Fix copyright lines
[folly.git] / folly / experimental / flat_combining / test / FlatCombiningTestHelpers.h
1 /*
2  * Copyright 2017-present 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
87       if (!combining) {
88         // no combining
89         for (int i = tid; i < ops; i += nthreads) {
90           sum += ex.fetchAddNoFC(1);
91           doWork(work); // unrelated work
92         }
93       } else if (syncops) {
94         // sync combining
95         for (int i = tid; i < ops; i += nthreads) {
96           sum += ex.fetchAdd(1, myrec);
97           doWork(work); // unrelated work
98         }
99       } else {
100         // async combining
101         for (int i = tid; i < ops; i += nthreads) {
102           ex.add(1, myrec);
103           doWork(work); // unrelated work
104         }
105       }
106
107       if (excl) {
108         // test of exclusive access through a lock holder
109         {
110           std::unique_lock<Mutex> l;
111           ex.holdLock(l);
112           CHECK(!mutex);
113           mutex = true;
114           VLOG(2) << tid << " " << ex.getVal() << " ...........";
115           using namespace std::chrono_literals;
116           /* sleep override */ // for coverage
117           std::this_thread::sleep_for(10ms);
118           VLOG(2) << tid << " " << ex.getVal() << " ===========";
119           CHECK(mutex);
120           mutex = false;
121         }
122         // test of explicit acquisition and release of exclusive access
123         ex.acquireExclusive();
124         {
125           CHECK(!mutex);
126           mutex = true;
127           VLOG(2) << tid << " " << ex.getVal() << " ...........";
128           using namespace std::chrono_literals;
129           /* sleep override */ // for coverage
130           std::this_thread::sleep_for(10ms);
131           VLOG(2) << tid << " " << ex.getVal() << " ===========";
132           CHECK(mutex);
133           mutex = false;
134         }
135         ex.releaseExclusive();
136       }
137
138       total.fetch_add(sum);
139       if (combining && tc) {
140         ex.freeRec(myrec);
141       }
142     });
143   }
144
145   while (started.load() < nthreads) {
146     ;
147   }
148   auto tbegin = std::chrono::steady_clock::now();
149
150   // begin time measurement
151   susp.dismiss();
152   start.store(true);
153
154   for (auto& t : threads) {
155     t.join();
156   }
157
158   if (!syncops) {
159     // complete any pending asynch ops
160     ex.drainAll();
161   }
162
163   // end time measurement
164   uint64_t duration = 0;
165   BENCHMARK_SUSPEND {
166     auto tend = std::chrono::steady_clock::now();
167     CHECK_EQ(ops, ex.getVal());
168     if (syncops) {
169       uint64_t n = (uint64_t)ops;
170       uint64_t expected = n * (n - 1) / 2;
171       CHECK_EQ(expected, total);
172     }
173     duration =
174         std::chrono::duration_cast<std::chrono::nanoseconds>(tend - tbegin)
175             .count();
176   }
177   return duration;
178 }
179
180 uint64_t run_test(
181     int nthreads,
182     int lines,
183     int numRecs,
184     int work,
185     int ops,
186     bool combining,
187     bool simple,
188     bool dedicated,
189     bool tc,
190     bool syncops,
191     bool excl = false,
192     bool allocAll = false) {
193   using M = std::mutex;
194   if (simple) {
195     using Example = FcSimpleExample<M>;
196     return fc_test<Example, bool, M>(
197         nthreads,
198         lines,
199         numRecs,
200         work,
201         ops,
202         combining,
203         dedicated,
204         tc,
205         syncops,
206         excl,
207         allocAll);
208   } else {
209     using Example = FcCustomExample<Req, M>;
210     return fc_test<Example, Req, M>(
211         nthreads,
212         lines,
213         numRecs,
214         work,
215         ops,
216         combining,
217         dedicated,
218         tc,
219         syncops,
220         excl,
221         allocAll);
222   }
223 }
224
225 } // namespace test
226 } // namespace folly