29 #include <glog/logging.h> 31 DEFINE_int32(num_threads, 12,
"num concurrent threads to test");
44 using namespace folly;
46 typedef int ValueType;
48 typedef SkipListType::Accessor SkipListAccessor;
49 typedef std::set<ValueType> SetType;
51 static std::vector<ValueType> gData;
52 static void initData() {
57 std::shuffle(gData.begin(), gData.end(), std::mt19937{});
61 void BM_IterateOverSet(
int iters,
int size) {
66 for (
int i = 0;
i <
size; ++
i) {
72 auto iter = a_set.begin();
73 for (
int i = 0;
i < iters; ++
i) {
75 if (iter == a_set.end()) {
84 void BM_IterateSkipList(
int iters,
int size) {
88 for (
int i = 0;
i <
size; ++
i) {
94 auto iter = skipList.begin();
95 for (
int i = 0;
i < iters; ++
i) {
97 if (iter == skipList.end()) {
98 iter = skipList.begin();
107 void BM_SetMerge(
int iters,
int size) {
111 for (
int i = 0;
i < iters; ++
i) {
114 for (
int i = 0;
i <
size; ++
i) {
121 if (b_set.find(*it) != b_set.end()) {
130 void BM_CSLMergeLookup(
int iters,
int size) {
135 for (
int i = 0;
i < iters; ++
i) {
138 for (
int i = 0;
i <
size; ++
i) {
144 SkipListType::Skipper skipper(skipList2);
146 if (skipper.to(*it)) {
157 void BM_CSLMergeIntersection(
int iters,
int size) {
161 for (
int i = 0;
i < iters; ++
i) {
164 for (
int i = 0;
i <
size; ++
i) {
169 SkipListType::Skipper s1(skipList);
170 SkipListType::Skipper s2(skipList2);
174 while (s1.good() && s2.good()) {
179 }
else if (v1 > v2) {
193 void BM_SetContainsNotFound(
int iters,
int size) {
197 for (
int i = 0;
i <
size; ++
i) {
203 for (
int i = 0;
i < iters; ++
i) {
204 sum += (aset.end() == aset.find(2 *
i + 1));
212 void BM_SetContainsFound(
int iters,
int size) {
217 for (
int i = 0;
i <
size; ++
i) {
222 for (
int i = 0;
i < iters; ++
i) {
223 values.push_back(rand() % size);
228 for (
int i = 0;
i < iters; ++
i) {
229 sum += (aset.end() == aset.find(values[
i]));
237 void BM_CSLContainsFound(
int iters,
int size) {
242 for (
int i = 0;
i <
size; ++
i) {
246 for (
int i = 0;
i < iters; ++
i) {
247 values.push_back(rand() % size);
252 for (
int i = 0;
i < iters; ++
i) {
253 sum += skipList.contains(values[
i]);
261 void BM_CSLContainsNotFound(
int iters,
int size) {
266 for (
int i = 0;
i <
size; ++
i) {
272 for (
int i = 0;
i < iters; ++
i) {
273 sum += skipList.contains(2 *
i + 1);
281 void BM_AddSet(
int iters,
int size) {
284 for (
int i = 0;
i <
size; ++
i) {
285 aset.insert(gData[
i]);
289 for (
int i = size;
i < size + iters; ++
i) {
290 aset.insert(gData[
i]);
294 void BM_AddSkipList(
int iters,
int size) {
297 for (
int i = 0;
i <
size; ++
i) {
298 skipList.add(gData[
i]);
302 for (
int i = size;
i < size + iters; ++
i) {
303 skipList.add(gData[
i]);
310 auto sl = skiplist.get();
313 for (
size_t i = 0;
i < iters; ++
i) {
314 SkipListAccessor accessor(sl);
320 BENCHMARK(accessorBasicRefcounting, iters) {
322 auto*
value =
new std::atomic<int32_t>();
323 auto* dirty =
new std::atomic<int32_t>();
329 for (
size_t i = 0;
i < iters; ++
i) {
330 value->fetch_add(1, std::memory_order_relaxed);
331 if (dirty->load(std::memory_order_acquire) != 0) {
334 value->fetch_sub(1, std::memory_order_relaxed);
344 class ConcurrentAccessData {
346 explicit ConcurrentAccessData(
int size)
347 : skipList_(SkipListType::create(10)),
348 sets_(FLAGS_num_sets),
349 locks_(FLAGS_num_sets) {
350 for (
int i = 0;
i <
size; ++
i) {
355 for (
int i = 0;
i < FLAGS_num_sets; ++
i) {
364 #ifdef _GLIBCXX_SYMVER 366 int64_t setMemorySize = sets_[0].size() *
sizeof(*sets_[0].begin()._M_node);
368 for (
auto it = skipList_.begin(); it != skipList_.end(); ++it) {
369 cslMemorySize += it.nodeSize();
372 LOG(
INFO) <<
"size=" << sets_[0].size()
373 <<
"; std::set memory size=" << setMemorySize
374 <<
"; csl memory size=" << cslMemorySize;
377 readValues_.reserve(size);
378 deleteValues_.reserve(size);
379 writeValues_.reserve(size);
380 for (
int i = size;
i < 2 *
size; ++
i) {
381 readValues_.push_back(2 *
i);
382 deleteValues_.push_back(2 *
i);
385 writeValues_.push_back((rand() % 2) + 2 *
i);
387 std::shuffle(readValues_.begin(), readValues_.end(), std::mt19937{});
388 std::shuffle(deleteValues_.begin(), deleteValues_.end(), std::mt19937{});
389 std::shuffle(writeValues_.begin(), writeValues_.end(), std::mt19937{});
392 ~ConcurrentAccessData() {
397 inline bool skipListFind(
int , ValueType
val) {
398 return skipList_.contains(val);
400 inline void skipListInsert(
int , ValueType val) {
403 inline void skipListErase(
int , ValueType val) {
404 skipList_.remove(val);
407 inline bool setFind(
int idx, ValueType val) {
409 return sets_[idx].find(val) == sets_[idx].end();
411 inline void setInsert(
int idx, ValueType val) {
413 sets_[idx].insert(val);
415 inline void setErase(
int idx, ValueType val) {
417 sets_[idx].erase(val);
420 void runSkipList(
int id,
size_t iters) {
422 for (
size_t i = 0;
i < iters; ++
i) {
423 sum += accessSkipList(
id,
i);
428 void runSet(
size_t id,
size_t iters) {
430 for (
size_t i = 0;
i < iters; ++
i) {
431 sum += accessSet(
id,
i);
436 bool accessSkipList(
int64_t id,
size_t t) {
437 if (t > readValues_.size()) {
438 t = t % readValues_.size();
443 if ((h & 0x31) == 0) {
444 skipListErase(0, deleteValues_[t]);
446 skipListInsert(0, writeValues_[t]);
450 return skipListFind(0, readValues_[t]);
454 bool accessSet(
int64_t id,
size_t t) {
455 if (t > readValues_.size()) {
456 t = t % readValues_.size();
459 int idx = (h % FLAGS_num_sets);
462 if ((h & 0x31) == 0) {
463 setErase(idx, deleteValues_[t]);
465 setInsert(idx, writeValues_[t]);
469 return setFind(idx, readValues_[t]);
474 SkipListType::Accessor skipList_;
475 std::vector<SetType> sets_;
476 std::vector<RWSpinLock*> locks_;
478 std::vector<ValueType> readValues_;
479 std::vector<ValueType> writeValues_;
480 std::vector<ValueType> deleteValues_;
483 static std::map<int, std::shared_ptr<ConcurrentAccessData>> g_data;
485 static ConcurrentAccessData* mayInitTestData(
int size) {
486 auto it = g_data.find(size);
487 if (it == g_data.end()) {
488 auto ptr = std::make_shared<ConcurrentAccessData>(
size);
492 return it->second.get();
495 void BM_ContentionCSL(
int iters,
int size) {
497 auto data = mayInitTestData(size);
498 std::vector<std::thread>
threads;
501 for (
int i = 0;
i < FLAGS_num_threads; ++
i) {
503 std::thread(&ConcurrentAccessData::runSkipList,
data,
i, iters));
508 void BM_ContentionStdSet(
int iters,
int size) {
510 auto data = mayInitTestData(size);
511 std::vector<std::thread>
threads;
514 for (
int i = 0;
i < FLAGS_num_threads; ++
i) {
516 std::thread(&ConcurrentAccessData::runSet,
data,
i, iters));
602 google::InitGoogleLogging(argv[0]);
603 gflags::ParseCommandLineFlags(&argc, &argv,
true);
std::atomic< int64_t > sum(0)
#define BENCHMARK_SUSPEND
std::lock_guard< MicroSpinLock > MSLGuard
—— Concurrent Priority Queue Implementation ——
uint32_t twang_32from64(uint64_t key) noexcept
std::vector< std::thread::id > threads
constexpr auto size(C const &c) -> decltype(c.size())
auto lock(SynchronizedLocker...lockersIn) -> std::tuple< typename SynchronizedLocker::LockedPtr... >
#define BENCHMARK(name,...)
DEFINE_int32(num_threads, 12,"num concurrent threads to test")
static const char *const value
#define BENCHMARK_PARAM(name, param)
static const int kMaxValue
static constexpr uint64_t data[1]
#define BENCHMARK_DRAW_LINE()
static const int kInitHeadHeight
int main(int argc, char **argv)
std::vector< int > values(1'000)