2 * Copyright 2017-present 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;
83 while (!start.load()) {
89 for (int i = tid; i < ops; i += nthreads) {
90 sum += ex.fetchAddNoFC(1);
91 doWork(work); // unrelated work
95 for (int i = tid; i < ops; i += nthreads) {
96 sum += ex.fetchAdd(1, myrec);
97 doWork(work); // unrelated work
101 for (int i = tid; i < ops; i += nthreads) {
103 doWork(work); // unrelated work
108 // test of exclusive access through a lock holder
110 std::unique_lock<Mutex> l;
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() << " ===========";
122 // test of explicit acquisition and release of exclusive access
123 ex.acquireExclusive();
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() << " ===========";
135 ex.releaseExclusive();
138 total.fetch_add(sum);
139 if (combining && tc) {
145 while (started.load() < nthreads) {
148 auto tbegin = std::chrono::steady_clock::now();
150 // begin time measurement
154 for (auto& t : threads) {
159 // complete any pending asynch ops
163 // end time measurement
164 uint64_t duration = 0;
166 auto tend = std::chrono::steady_clock::now();
167 CHECK_EQ(ops, ex.getVal());
169 uint64_t n = (uint64_t)ops;
170 uint64_t expected = n * (n - 1) / 2;
171 CHECK_EQ(expected, total);
174 std::chrono::duration_cast<std::chrono::nanoseconds>(tend - tbegin)
192 bool allocAll = false) {
193 using M = std::mutex;
195 using Example = FcSimpleExample<M>;
196 return fc_test<Example, bool, M>(
209 using Example = FcCustomExample<Req, M>;
210 return fc_test<Example, Req, M>(