/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <folly/AtomicHashMap.h>
-#include <glog/logging.h>
-#include <gtest/gtest.h>
-#include <thread>
#include <atomic>
#include <memory>
+#include <thread>
+
+#include <glog/logging.h>
-#include <folly/Assume.h>
#include <folly/Benchmark.h>
#include <folly/Conv.h>
-#include <folly/portability/Atomic.h>
+#include <folly/portability/GTest.h>
#include <folly/portability/SysTime.h>
using std::vector;
static int64_t nowInUsec() {
timeval tv;
- gettimeofday(&tv, 0);
+ gettimeofday(&tv, nullptr);
return int64_t(tv.tv_sec) * 1000 * 1000 + tv.tv_usec;
}
struct HashTraits {
size_t operator()(const char* a) {
size_t result = 0;
- while (a[0] != 0) result += static_cast<size_t>(*(a++));
+ while (a[0] != 0) {
+ result += static_cast<size_t>(*(a++));
+ }
return result;
}
size_t operator()(const char& a) {
}
size_t operator()(const StringPiece a) {
size_t result = 0;
- for (const auto& ch : a) result += static_cast<size_t>(ch);
+ for (const auto& ch : a) {
+ result += static_cast<size_t>(ch);
+ }
return result;
}
};
}
class Counters {
-private:
+ private:
// Note: Unfortunately can't currently put a std::atomic<int64_t> in
// the value in ahm since it doesn't support types that are both non-copy
// and non-move constructible yet.
AtomicHashMap<int64_t,int64_t> ahm;
-public:
+ public:
explicit Counters(size_t numCounters) : ahm(numCounters) {}
void increment(int64_t obj_id) {
inline KeyT randomizeKey(int key) {
// We deterministically randomize the key to more accurately simulate
// real-world usage, and to avoid pathalogical performance patterns (e.g.
- // those related to __gnu_cxx::hash<int64_t>()(1) == 1).
+ // those related to std::hash<int64_t>()(1) == 1).
//
// Use a hash function we don't normally use for ints to avoid interactions.
return folly::hash::jenkins_rev_mix32(key);
}
std::atomic<bool> runThreadsCreatedAllThreads;
-void runThreads(void *(*thread)(void*), int numThreads, void **statuses) {
+void runThreads(void *(*mainFunc)(void*), int numThreads, void **statuses) {
folly::BenchmarkSuspender susp;
runThreadsCreatedAllThreads.store(false);
- vector<pthread_t> threadIds;
+ vector<std::thread> threads;
for (int64_t j = 0; j < numThreads; j++) {
- pthread_t tid;
- if (pthread_create(&tid, nullptr, thread, (void*) j) != 0) {
- LOG(ERROR) << "Could not start thread";
- } else {
- threadIds.push_back(tid);
- }
+ threads.emplace_back([statuses, mainFunc, j]() {
+ auto ret = mainFunc((void*)j);
+ if (statuses != nullptr) {
+ statuses[j] = ret;
+ }
+ });
}
susp.dismiss();
runThreadsCreatedAllThreads.store(true);
- for (size_t i = 0; i < threadIds.size(); ++i) {
- pthread_join(threadIds[i], statuses == nullptr ? nullptr : &statuses[i]);
+ for (size_t i = 0; i < threads.size(); ++i) {
+ threads[i].join();
}
}
-void runThreads(void *(*thread)(void*)) {
- runThreads(thread, FLAGS_numThreads, nullptr);
+void runThreads(void *(*mainFunc)(void*)) {
+ runThreads(mainFunc, FLAGS_numThreads, nullptr);
}
}
int currentLevel;
do {
currentLevel = insertedLevel.load(std::memory_order_acquire);
- if (currentLevel == kTestEraseInsertions) currentLevel += lag + 1;
+ if (currentLevel == kTestEraseInsertions) {
+ currentLevel += lag + 1;
+ }
} while (currentLevel - lag < i);
KeyT key = randomizeKey(i);
void* atomicHashArrayInsertRaceThread(void* /* j */) {
AHA* arr = atomicHashArrayInsertRaceArray.get();
uintptr_t numInserted = 0;
- while (!runThreadsCreatedAllThreads.load());
+ while (!runThreadsCreatedAllThreads.load()) {
+ ;
+ }
for (int i = 0; i < 2; i++) {
if (arr->insert(RecordT(randomizeKey(i), 0)).first != arr->end()) {
numInserted++;
}
}
- pthread_exit((void *) numInserted);
- folly::assume(false);
+ return (void*)numInserted;
}
TEST(Ahm, atomic_hash_array_insert_race) {
AHA* arr = atomicHashArrayInsertRaceArray.get();
numOpsPerThread = iters / FLAGS_numThreads;
runThreads([](void* jj) -> void* {
int64_t j = (int64_t) jj;
- while (!runThreadsCreatedAllThreads.load());
+ while (!runThreadsCreatedAllThreads.load()) {
+ ;
+ }
for (int i = 0; i < numOpsPerThread; ++i) {
KeyT key = i + j * numOpsPerThread * 100;
folly::doNotOptimizeAway(globalAHM->find(key) == globalAHM->end());
numOpsPerThread = iters / FLAGS_numThreads;
runThreads([](void* jj) -> void* {
int64_t j = (int64_t) jj;
- while (!runThreadsCreatedAllThreads.load());
+ while (!runThreadsCreatedAllThreads.load()) {
+ ;
+ }
for (int i = 0; i < numOpsPerThread; ++i) {
KeyT key = i + j * numOpsPerThread * 100;
folly::doNotOptimizeAway(globalQPAHM->find(key) == globalQPAHM->end());
numOpsPerThread = iters / FLAGS_numThreads;
runThreads([](void* jj) -> void* {
int64_t j = (int64_t) jj;
- while (!runThreadsCreatedAllThreads.load());
+ while (!runThreadsCreatedAllThreads.load()) {
+ ;
+ }
for (int i = 0; i < numOpsPerThread; ++i) {
if (i % 128) { // ~1% insert mix
KeyT key = randomizeKey(i + j * numOpsPerThread);
numOpsPerThread = iters / FLAGS_numThreads;
runThreads([](void* jj) -> void* {
int64_t j = (int64_t) jj;
- while (!runThreadsCreatedAllThreads.load());
+ while (!runThreadsCreatedAllThreads.load()) {
+ ;
+ }
for (int i = 0; i < numOpsPerThread; ++i) {
if (i % 128) { // ~1% insert mix
KeyT key = randomizeKey(i + j * numOpsPerThread);
numOpsPerThread = iters / FLAGS_numThreads;
runThreads([](void* jj) -> void* {
int64_t j = (int64_t) jj;
- while (!runThreadsCreatedAllThreads.load());
+ while (!runThreadsCreatedAllThreads.load()) {
+ ;
+ }
for (int i = 0; i < numOpsPerThread; ++i) {
KeyT key = randomizeKey(i + j * numOpsPerThread);
folly::doNotOptimizeAway(globalAHA->find(key)->second);
numOpsPerThread = iters / FLAGS_numThreads;
runThreads([](void* jj) -> void* {
int64_t j = (int64_t) jj;
- while (!runThreadsCreatedAllThreads.load());
+ while (!runThreadsCreatedAllThreads.load()) {
+ ;
+ }
for (int i = 0; i < numOpsPerThread; ++i) {
KeyT key = randomizeKey(i + j * numOpsPerThread);
folly::doNotOptimizeAway(globalAHM->find(key)->second);
numOpsPerThread = iters / FLAGS_numThreads;
runThreads([](void* jj) -> void* {
int64_t j = (int64_t) jj;
- while (!runThreadsCreatedAllThreads.load());
+ while (!runThreadsCreatedAllThreads.load()) {
+ ;
+ }
for (int i = 0; i < numOpsPerThread; ++i) {
KeyT key = randomizeKey(i + j * numOpsPerThread);
folly::doNotOptimizeAway(globalQPAHM->find(key)->second);