2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <folly/experimental/flat_combining/test/FlatCombiningExamples.h>
21 #include <folly/Benchmark.h>
22 #include <glog/logging.h>
31 void doWork(int work) {
33 for (int i = work; i > 0; --i) {
36 folly::doNotOptimizeAway(a);
42 typename Mutex = std::mutex,
43 template <typename> class Atom = std::atomic>
55 bool allocAll = false) {
56 using FC = FlatCombining<Example, Mutex, Atom, Req>;
57 using Rec = typename FC::Rec;
59 folly::BenchmarkSuspender susp;
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};
68 std::vector<Rec*> v(numRecs);
69 for (int i = 0; i < numRecs; ++i) {
72 for (int i = numRecs; i > 0; --i) {
77 std::vector<std::thread> threads(nthreads);
78 for (int tid = 0; tid < nthreads; ++tid) {
79 threads[tid] = std::thread([&, tid] {
81 Rec* myrec = (combining && tc) ? ex.allocRec() : nullptr;
88 for (int i = tid; i < ops; i += nthreads) {
89 sum += ex.fetchAddNoFC(1);
90 doWork(work); // unrelated work
94 for (int i = tid; i < ops; i += nthreads) {
95 sum += ex.fetchAdd(1, myrec);
96 doWork(work); // unrelated work
100 for (int i = tid; i < ops; i += nthreads) {
102 doWork(work); // unrelated work
107 // test of exclusive access through a lock holder
109 std::unique_lock<Mutex> l;
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() << " ===========";
121 // test of explicit acquisition and release of exclusive access
122 ex.acquireExclusive();
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() << " ===========";
134 ex.releaseExclusive();
137 total.fetch_add(sum);
138 if (combining && tc) {
144 while (started.load() < nthreads)
146 auto tbegin = std::chrono::steady_clock::now();
148 // begin time measurement
152 for (auto& t : threads) {
157 // complete any pending asynch ops
161 // end time measurement
162 uint64_t duration = 0;
164 auto tend = std::chrono::steady_clock::now();
165 CHECK_EQ(ops, ex.getVal());
167 uint64_t n = (uint64_t)ops;
168 uint64_t expected = n * (n - 1) / 2;
169 CHECK_EQ(expected, total);
172 std::chrono::duration_cast<std::chrono::nanoseconds>(tend - tbegin)
190 bool allocAll = false) {
191 using M = std::mutex;
193 using Example = FcSimpleExample<M>;
194 return fc_test<Example, bool, M>(
207 using Example = FcCustomExample<Req, M>;
208 return fc_test<Example, Req, M>(