--- /dev/null
+#include <folly/concurrency/ConcurrentHashMap.h>
+#include <folly/AtomicHashMap.h>
+#include <folly/AtomicUnorderedMap.h>
+
+
+#include <chrono>
+#include <cassert>
+#include <iostream>
+#include <memory>
+
+namespace {
+
+const unsigned s_nInsertPercentage = 10;
+const char* kTestName = "InsDelFind";
+
+const size_t kConcurrentHashMapSize = 10000;
+const size_t kConcurrentHashMapPassCount = 6000;
+const char* kConcurrentHashMapBenchmarkName = "FollyConcurrentHashMap";
+
+const size_t kAtomicHashMapSize = 10000;
+const size_t kAtomicHashMapPassCount = 16000;
+const char* kAtomicHashMapBenchmarkName = "FollyAtomicHashMap";
+
+const size_t kAtomicUnorderedInsertMapSize = 10000;
+const size_t kAtomicUnorderedInsertMapPassCount = 32000;
+const char* kAtomicUnorderedInsertMapBenchmarkName =
+ "FollyAtomicUnorderedInsertMap";
+
+typedef folly::ConcurrentHashMap<size_t, size_t> ConcurrentHashMap;
+typedef folly::AtomicHashMap<size_t, size_t> AtomicHashMap;
+typedef folly::AtomicUnorderedInsertMap64<size_t, size_t>
+ AtomicUnorderedInsertMap;
+}
+
+template <typename Key>
+bool map_contains(const AtomicUnorderedInsertMap* map, Key key) {
+ return map->find(key) != map->cend();
+}
+
+template <typename Key>
+bool map_contains(const ConcurrentHashMap* map, Key key) {
+ return map->find(key) != map->cend();
+}
+
+template <typename Map, typename Key>
+bool map_contains(const Map* map, Key key) {
+ return map->find(key) != map->end();
+}
+
+template <typename Map>
+void run_atomic_unordered_insert_map(size_t map_size, size_t pass_count,
+ const char* bench_name) {
+ std::cout << "[ RUN ] " << kTestName << "." << bench_name << std::endl;
+ auto start_time = std::chrono::system_clock::now();
+
+ size_t nInsertedNum = 0;
+ size_t nFindSuccess = 0;
+ std::unique_ptr<Map> map(new Map(map_size));
+ for (size_t count = 0; count < pass_count; count++) {
+ for (size_t i = 0; i < map_size; ++i) {
+ // The number to operate on the map.
+ size_t n = map_size + i;
+ // Insert
+ if (i % s_nInsertPercentage == 1) {
+ auto iter = map->find(i);
+ if (iter != map->cend()) {
+ if (iter->second == n) {
+ map->emplace(i, n / 2);
+ } else {
+ map->emplace(i, n);
+ }
+ } else {
+ map->emplace(i, n);
+ }
+ nInsertedNum++;
+ }
+ // Find
+ {
+ if (map_contains(map.get(), i)) {
+ ++nFindSuccess;
+// std::cout << "Found" << i << "\n";
+ }
+ }
+ }
+ }
+ auto finish_time = std::chrono::system_clock::now();
+ auto dur = finish_time - start_time;
+ auto milisecs = std::chrono::duration_cast<std::chrono::milliseconds>(dur);
+
+ if (nFindSuccess != nInsertedNum) {
+ std::cout << "nFindSuccess=" << nFindSuccess << ", nInsertedNum="
+ << nInsertedNum << std::endl;
+ std::cout << "[ FAILED ] " << kTestName << "." << bench_name
+ << " (" << milisecs.count() << " ms)" << std::endl;
+ assert(false && "ConcurrentMap ERROR");
+ } else {
+ std::cout << "[ OK ] " << kTestName << "." << bench_name
+ << " (" << milisecs.count() << " ms)" << std::endl;
+ }
+}
+
+template <typename Map>
+void run_atomic_hashmap(size_t map_size, size_t pass_count, const char* bench_name) {
+ std::cout << "[ RUN ] " << kTestName << "." << bench_name << std::endl;
+ auto start_time = std::chrono::system_clock::now();
+
+ size_t nInsertedNum = 0;
+ size_t nFindSuccess = 0;
+ std::unique_ptr<Map> map(new Map(map_size));
+ for (size_t count = 0; count < pass_count; count++) {
+ for (size_t i = 0; i < map_size; ++i) {
+ // The number to operate on the map.
+ size_t n = map_size + i;
+ // Insert
+ if (i % s_nInsertPercentage == 1) {
+ auto iter = map->find(i);
+ if (iter != map->end()) {
+ if (iter->second == n) {
+ iter->second = n / 2;
+ } else {
+ iter->second = n;
+ }
+ } else {
+ map->insert({i, n});
+ }
+ nInsertedNum++;
+ }
+ // Find
+ {
+ if (map_contains(map.get(), i)) {
+ ++nFindSuccess;
+// std::cout << "Found" << i << "\n";
+ }
+ }
+ }
+ }
+ auto finish_time = std::chrono::system_clock::now();
+ auto dur = finish_time - start_time;
+ auto milisecs = std::chrono::duration_cast<std::chrono::milliseconds>(dur);
+
+ if (nFindSuccess != nInsertedNum) {
+ std::cout << "nFindSuccess=" << nFindSuccess << ", nInsertedNum="
+ << nInsertedNum << std::endl;
+ std::cout << "[ FAILED ] " << kTestName << "." << bench_name
+ << " (" << milisecs.count() << " ms)" << std::endl;
+ assert(false && "ConcurrentMap ERROR");
+ } else {
+ std::cout << "[ OK ] " << kTestName << "." << bench_name
+ << " (" << milisecs.count() << " ms)" << std::endl;
+ }
+}
+
+template <typename Map>
+void run_concurrent_hashmap(size_t map_size, size_t pass_count,
+ const char* bench_name) {
+ std::cout << "[ RUN ] " << kTestName << "." << bench_name << std::endl;
+ auto start_time = std::chrono::system_clock::now();
+
+ size_t nInsertedNum = 0;
+ size_t nFindSuccess = 0;
+ std::unique_ptr<Map> map(new Map(map_size));
+ for (size_t count = 0; count < pass_count; count++) {
+ for (size_t i = 0; i < map_size; ++i) {
+ // The number to operate on the map.
+ size_t n = map_size + i;
+ // Insert
+ if (i % s_nInsertPercentage == 1) {
+ auto iter = map->insert({i, n});
+ nInsertedNum++;
+// std::cout << "Inserted" << i << "\n";
+ }
+ // Find
+ {
+ if (map_contains(map.get(), i)) {
+ ++nFindSuccess;
+// std::cout << "Found" << i << "\n";
+ }
+ }
+ // Delete
+ if (i % s_nInsertPercentage == 1) {
+ if (map_contains(map.get(), i)) {
+ map->erase(i);
+// std::cout << "Erased" << i << "\n";
+ }
+ }
+ }
+ }
+ auto finish_time = std::chrono::system_clock::now();
+ auto dur = finish_time - start_time;
+ auto milisecs = std::chrono::duration_cast<std::chrono::milliseconds>(dur);
+
+ if (nFindSuccess != nInsertedNum) {
+ std::cout << "nFindSuccess=" << nFindSuccess << ", nInsertedNum="
+ << nInsertedNum << std::endl;
+ std::cout << "[ FAILED ] " << kTestName << "." << bench_name
+ << " (" << milisecs.count() << " ms)" << std::endl;
+ assert(false && "ConcurrentMap ERROR");
+ } else {
+ std::cout << "[ OK ] " << kTestName << "." << bench_name
+ << " (" << milisecs.count() << " ms)" << std::endl;
+ }
+}
+
+int main() {
+ run_concurrent_hashmap<ConcurrentHashMap>(
+ kConcurrentHashMapSize,
+ kConcurrentHashMapPassCount,
+ kConcurrentHashMapBenchmarkName);
+ run_atomic_hashmap<AtomicHashMap>(
+ kAtomicHashMapSize,
+ kAtomicHashMapPassCount,
+ kAtomicHashMapBenchmarkName);
+ run_atomic_unordered_insert_map<AtomicUnorderedInsertMap>(
+ kAtomicUnorderedInsertMapSize,
+ kAtomicUnorderedInsertMapPassCount,
+ kAtomicUnorderedInsertMapBenchmarkName);
+
+ return 0;
+}