1
2 /**
3 * Copyright (C) 2018-present MongoDB, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the Server Side Public License, version 1,
7 * as published by MongoDB, Inc.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * Server Side Public License for more details.
13 *
14 * You should have received a copy of the Server Side Public License
15 * along with this program. If not, see
16 * <http://www.mongodb.com/licensing/server-side-public-license>.
17 *
18 * As a special exception, the copyright holders give permission to link the
19 * code of portions of this program with the OpenSSL library under certain
20 * conditions as described in each individual source file and distribute
21 * linked combinations including the program with the OpenSSL library. You
22 * must comply with the Server Side Public License in all respects for
23 * all of the code used other than as permitted herein. If you modify file(s)
24 * with this exception, you may extend this exception to your version of the
25 * file(s), but you are not obligated to do so. If you do not wish to do so,
26 * delete this exception statement from your version. If you delete this
27 * exception statement from all source files in the program, then also delete
28 * it in the license file.
29 */
30 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kDefault
31
32 #include "mongo/platform/basic.h"
33 #include <benchmark/benchmark.h>
34
35 #include "mongo/db/concurrency/d_concurrency.h"
36 #include "mongo/db/concurrency/lock_manager_test_help.h"
37 #include "mongo/db/storage/recovery_unit_noop.h"
38 #include "mongo/stdx/mutex.h"
39 #include "mongo/unittest/unittest.h"
40
41 namespace mongo {
42 namespace {
43
44 const int kMaxPerfThreads = 16; // max number of threads to use for lock perf
45
46
47 class DConcurrencyTest : public benchmark::Fixture {
48 public:
49 /**
50 * Returns a vector of Clients of length 'k', each of which has an OperationContext with its
51 * lockState set to a DefaultLockerImpl.
52 */
53 template <typename LockerType>
makeKClientsWithLockers(int k)54 void makeKClientsWithLockers(int k) {
55 clients.reserve(k);
56 for (int i = 0; i < k; ++i) {
57 auto client = getGlobalServiceContext()->makeClient(
58 str::stream() << "test client for thread " << i);
59 auto opCtx = client->makeOperationContext();
60 opCtx->releaseLockState();
61 opCtx->setLockState(stdx::make_unique<LockerType>());
62 clients.emplace_back(std::move(client), std::move(opCtx));
63 }
64 }
65
66 protected:
67 std::vector<std::pair<ServiceContext::UniqueClient, ServiceContext::UniqueOperationContext>>
68 clients;
69 std::array<DefaultLockerImpl, kMaxPerfThreads> locker;
70 };
71
BENCHMARK_DEFINE_F(DConcurrencyTest,BM_StdMutex)72 BENCHMARK_DEFINE_F(DConcurrencyTest, BM_StdMutex)(benchmark::State& state) {
73 static stdx::mutex mtx;
74
75 for (auto keepRunning : state) {
76 stdx::unique_lock<stdx::mutex> lk(mtx);
77 }
78 }
79
BENCHMARK_DEFINE_F(DConcurrencyTest,BM_ResourceMutexShared)80 BENCHMARK_DEFINE_F(DConcurrencyTest, BM_ResourceMutexShared)(benchmark::State& state) {
81 static Lock::ResourceMutex mtx("testMutex");
82
83 for (auto keepRunning : state) {
84 Lock::SharedLock lk(&locker[state.thread_index], mtx);
85 }
86 }
87
BENCHMARK_DEFINE_F(DConcurrencyTest,BM_ResourceMutexExclusive)88 BENCHMARK_DEFINE_F(DConcurrencyTest, BM_ResourceMutexExclusive)(benchmark::State& state) {
89 static Lock::ResourceMutex mtx("testMutex");
90
91 for (auto keepRunning : state) {
92 Lock::ExclusiveLock lk(&locker[state.thread_index], mtx);
93 }
94 }
95
BENCHMARK_DEFINE_F(DConcurrencyTest,BM_CollectionIntentSharedLock)96 BENCHMARK_DEFINE_F(DConcurrencyTest, BM_CollectionIntentSharedLock)(benchmark::State& state) {
97 std::unique_ptr<ForceSupportsDocLocking> supportDocLocking;
98
99 if (state.thread_index == 0) {
100 makeKClientsWithLockers<DefaultLockerImpl>(state.threads);
101 supportDocLocking = std::make_unique<ForceSupportsDocLocking>(true);
102 }
103
104 for (auto keepRunning : state) {
105 Lock::DBLock dlk(clients[state.thread_index].second.get(), "test", MODE_IS);
106 Lock::CollectionLock clk(
107 clients[state.thread_index].second->lockState(), "test.coll", MODE_IS);
108 }
109
110 if (state.thread_index == 0) {
111 clients.clear();
112 }
113 }
114
BENCHMARK_DEFINE_F(DConcurrencyTest,BM_CollectionIntentExclusiveLock)115 BENCHMARK_DEFINE_F(DConcurrencyTest, BM_CollectionIntentExclusiveLock)(benchmark::State& state) {
116 std::unique_ptr<ForceSupportsDocLocking> supportDocLocking;
117
118 if (state.thread_index == 0) {
119 makeKClientsWithLockers<DefaultLockerImpl>(state.threads);
120 supportDocLocking = std::make_unique<ForceSupportsDocLocking>(true);
121 }
122
123 for (auto keepRunning : state) {
124 Lock::DBLock dlk(clients[state.thread_index].second.get(), "test", MODE_IX);
125 Lock::CollectionLock clk(
126 clients[state.thread_index].second->lockState(), "test.coll", MODE_IX);
127 }
128
129 if (state.thread_index == 0) {
130 clients.clear();
131 }
132 }
133
BENCHMARK_DEFINE_F(DConcurrencyTest,BM_MMAPv1CollectionSharedLock)134 BENCHMARK_DEFINE_F(DConcurrencyTest, BM_MMAPv1CollectionSharedLock)(benchmark::State& state) {
135 std::unique_ptr<ForceSupportsDocLocking> supportDocLocking;
136
137 if (state.thread_index == 0) {
138 makeKClientsWithLockers<DefaultLockerImpl>(state.threads);
139 supportDocLocking = std::make_unique<ForceSupportsDocLocking>(false);
140 }
141
142 for (auto keepRunning : state) {
143 Lock::DBLock dlk(clients[state.thread_index].second.get(), "test", MODE_IS);
144 Lock::CollectionLock clk(
145 clients[state.thread_index].second->lockState(), "test.coll", MODE_S);
146 }
147
148 if (state.thread_index == 0) {
149 clients.clear();
150 }
151 }
152
BENCHMARK_DEFINE_F(DConcurrencyTest,BM_MMAPv1CollectionExclusiveLock)153 BENCHMARK_DEFINE_F(DConcurrencyTest, BM_MMAPv1CollectionExclusiveLock)(benchmark::State& state) {
154 std::unique_ptr<ForceSupportsDocLocking> supportDocLocking;
155
156 if (state.thread_index == 0) {
157 makeKClientsWithLockers<DefaultLockerImpl>(state.threads);
158 supportDocLocking = std::make_unique<ForceSupportsDocLocking>(false);
159 }
160
161 for (auto keepRunning : state) {
162 Lock::DBLock dlk(clients[state.thread_index].second.get(), "test", MODE_IX);
163 Lock::CollectionLock clk(
164 clients[state.thread_index].second->lockState(), "test.coll", MODE_X);
165 }
166
167 if (state.thread_index == 0) {
168 clients.clear();
169 }
170 }
171
172 BENCHMARK_REGISTER_F(DConcurrencyTest, BM_StdMutex)->ThreadRange(1, kMaxPerfThreads);
173
174 BENCHMARK_REGISTER_F(DConcurrencyTest, BM_ResourceMutexShared)->ThreadRange(1, kMaxPerfThreads);
175 BENCHMARK_REGISTER_F(DConcurrencyTest, BM_ResourceMutexExclusive)->ThreadRange(1, kMaxPerfThreads);
176
177 BENCHMARK_REGISTER_F(DConcurrencyTest, BM_CollectionIntentSharedLock)
178 ->ThreadRange(1, kMaxPerfThreads);
179 BENCHMARK_REGISTER_F(DConcurrencyTest, BM_CollectionIntentExclusiveLock)
180 ->ThreadRange(1, kMaxPerfThreads);
181
182 BENCHMARK_REGISTER_F(DConcurrencyTest, BM_MMAPv1CollectionSharedLock)
183 ->ThreadRange(1, kMaxPerfThreads);
184 BENCHMARK_REGISTER_F(DConcurrencyTest, BM_MMAPv1CollectionExclusiveLock)
185 ->ThreadRange(1, kMaxPerfThreads);
186
187 } // namespace
188 } // namespace mongo
189