From 930c75ffee7931cb06e8c5fa99779c2d67bd2cb1 Mon Sep 17 00:00:00 2001 From: Peizhao Ou Date: Fri, 9 Feb 2018 10:27:29 -0800 Subject: [PATCH] Uses cmake to build folly test drivers --- folly/stress-test/CMakeLists.txt | 45 ++++ folly/stress-test/clean.sh | 11 - .../stress-test/stress-parallel-folly-map.cpp | 168 +++++++++++++++ .../stress-parallel-folly-queue.cpp | 196 ++++++++++++++++++ .../stress-parallel-folly-sync.cpp | 157 ++++++++++++++ 5 files changed, 566 insertions(+), 11 deletions(-) create mode 100644 folly/stress-test/CMakeLists.txt delete mode 100755 folly/stress-test/clean.sh create mode 100644 folly/stress-test/stress-parallel-folly-map.cpp create mode 100644 folly/stress-test/stress-parallel-folly-queue.cpp create mode 100644 folly/stress-test/stress-parallel-folly-sync.cpp diff --git a/folly/stress-test/CMakeLists.txt b/folly/stress-test/CMakeLists.txt new file mode 100644 index 00000000..289efdb4 --- /dev/null +++ b/folly/stress-test/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 2.8.5) + +set(CMAKE_C_COMPILER clang-native) +set(CMAKE_CXX_COMPILER clang++-native) + +set(CMAKE_BUILD_TYPE Release) + +include_directories( + /scratch/googletest/googletest/include + /scratch/gflags/gflags/build/include + /scratch/glog/glog/src + ../.. +) + +link_directories( + /scratch/folly/orig-folly/folly/folly-lib + /scratch/glog/glog/glog-lib + /scratch/gflags/gflags/build/gflags-lib + /scratch/googletest/googletest +) + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y") + +set(FOLLY_LIB folly pthread gflags glog gtest) +set(RCU_OBJ ../synchronization/.libs/Rcu.o) + +# Sequential driver +add_executable(stress-sequential-folly-map stress-sequential-folly-map.cpp ${RCU_OBJ}) +target_link_libraries(stress-sequential-folly-map ${FOLLY_LIB}) + +add_executable(stress-sequential-folly-queue stress-sequential-folly-queue.cpp ${RCU_OBJ}) +target_link_libraries(stress-sequential-folly-queue ${FOLLY_LIB}) + +add_executable(stress-sequential-folly-sync stress-sequential-folly-sync.cpp ${RCU_OBJ}) +target_link_libraries(stress-sequential-folly-sync ${FOLLY_LIB}) + +# Parallel driver +add_executable(stress-parallel-folly-map stress-parallel-folly-map.cpp ${RCU_OBJ}) +target_link_libraries(stress-parallel-folly-map ${FOLLY_LIB}) + +add_executable(stress-parallel-folly-queue stress-parallel-folly-queue.cpp ${RCU_OBJ}) +target_link_libraries(stress-parallel-folly-queue ${FOLLY_LIB}) + +add_executable(stress-parallel-folly-sync stress-parallel-folly-sync.cpp ${RCU_OBJ}) +target_link_libraries(stress-parallel-folly-sync ${FOLLY_LIB}) diff --git a/folly/stress-test/clean.sh b/folly/stress-test/clean.sh deleted file mode 100755 index 19a24e70..00000000 --- a/folly/stress-test/clean.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -e - -Benchmarks=( - stress-sequential-folly-queue - stress-sequential-folly-map - stress-sequential-folly-sync -) - -for bench in ${Benchmarks[*]}; do - rm -rf $bench ${bench}.bc ${bench}.o -done diff --git a/folly/stress-test/stress-parallel-folly-map.cpp b/folly/stress-test/stress-parallel-folly-map.cpp new file mode 100644 index 00000000..53b95290 --- /dev/null +++ b/folly/stress-test/stress-parallel-folly-map.cpp @@ -0,0 +1,168 @@ +#include +#include +#include + +#include + +#include + +namespace { + +const unsigned s_nInsertPercentage = 10; + +const size_t kConcurrentHashMapSize = 10000; +const size_t kConcurrentHashMapPassCount = 36000; + +const size_t kAtomicHashMapSize = 10000; +const size_t kAtomicHashMapPassCount = 250000; + +const size_t kAtomicUnorderedInsertMapSize = 10000; +const size_t kAtomicUnorderedInsertMapPassCount = 500000; + +typedef folly::ConcurrentHashMap ConcurrentHashMap; +typedef folly::AtomicHashMap AtomicHashMap; +typedef folly::AtomicUnorderedInsertMap64 + AtomicUnorderedInsertMap; +} + +template +bool map_contains(const AtomicUnorderedInsertMap* map, Key key) { + return map->find(key) != map->cend(); +} + +template +bool map_contains(const ConcurrentHashMap* map, Key key) { + return map->find(key) != map->cend(); +} + +template +bool map_contains(const Map* map, Key key) { + return map->find(key) != map->end(); +} + +template +void run_atomic_unordered_insert_map(size_t map_size, size_t pass_count) { + size_t nInsertedNum = 0; + size_t nFindSuccess = 0; + std::unique_ptr 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; + } + } + } + } + EXPECT_EQ(nFindSuccess, nInsertedNum); +} + +template +void run_atomic_hashmap(size_t map_size, size_t pass_count) { + size_t nInsertedNum = 0; + size_t nFindSuccess = 0; + std::unique_ptr 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; + } + } + } + } + EXPECT_EQ(nFindSuccess, nInsertedNum); +} + +template +void run_concurrent_hashmap(size_t map_size, size_t pass_count) { + size_t nInsertedNum = 0; + size_t nFindSuccess = 0; + std::unique_ptr 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++; + } + // Find + { + if (map_contains(map.get(), i)) { + ++nFindSuccess; + } + } + // Delete + if (i % s_nInsertPercentage == 1) { + if (map_contains(map.get(), i)) { + map->erase(i); + } + } + } + } + EXPECT_EQ(nFindSuccess, nInsertedNum); +} + +class FollyMapInsDelFindTest: public ::testing::Test { +}; + +TEST_F(FollyMapInsDelFindTest, FollyConcurrentHashMap) { + run_concurrent_hashmap( + kConcurrentHashMapSize, + kConcurrentHashMapPassCount); +} + +TEST_F(FollyMapInsDelFindTest, FollyAtomicHashMap) { + run_atomic_hashmap( + kAtomicHashMapSize, + kAtomicHashMapPassCount); +} + +TEST_F(FollyMapInsDelFindTest, FollyAtomicUnorderedInsertMap) { + run_atomic_unordered_insert_map( + kAtomicUnorderedInsertMapSize, + kAtomicUnorderedInsertMapPassCount); +} + +int main(int argc, char** argv) { + // Init Google test + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + return result; +} diff --git a/folly/stress-test/stress-parallel-folly-queue.cpp b/folly/stress-test/stress-parallel-folly-queue.cpp new file mode 100644 index 00000000..70bcb15d --- /dev/null +++ b/folly/stress-test/stress-parallel-folly-queue.cpp @@ -0,0 +1,196 @@ +#include +#include +#include +#include + +#include + +#include + +namespace { + +// Unbounded queue +size_t kUnboundedQueueEnqueueStride = 10000; +size_t kUSPSCQueueEnqueueCount = 1200000000; +size_t kUMPSCQueueEnqueueCount = 320000000; +size_t kUSPMCQueueEnqueueCount = 320000000; +size_t kUMPMCQueueEnqueueCount = 320000000; + +typedef folly::USPSCQueue USPSCQueue; +typedef folly::UMPSCQueue UMPSCQueue; +typedef folly::USPMCQueue USPMCQueue; +typedef folly::UMPMCQueue UMPMCQueue; + +// Dynamic bounded queue +size_t kDynamicBoundedQueueEnqueueStride = 50000; +size_t kDynamicBoundedQueueCapacity = 200000; +size_t kDSPSCQueueEnqueueCount = 1200000000; +size_t kDMPSCQueueEnqueueCount = 320000000; +size_t kDSPMCQueueEnqueueCount = 320000000; +size_t kDMPMCQueueEnqueueCount = 320000000; + +typedef folly::DSPSCQueue DSPSCQueue; +typedef folly::DMPSCQueue DMPSCQueue; +typedef folly::DSPMCQueue DSPMCQueue; +typedef folly::DMPMCQueue DMPMCQueue; + +// AtomicLinkedList +size_t kAtomicLinkedListSize = 50000; +size_t kAtomicLinkedListPassCount = 10000; +typedef folly::AtomicLinkedList AtomicLinkedList; + +// MPMC Queue (linearizable) +size_t kMPMCQueueEnqueueStride = 10000; +size_t kMPMCQueueCapacity = 50000; +size_t kMPMCQueueEnqueueCount = 500000000; +typedef folly::MPMCQueue MPMCQueue; + +} + +void run_atomic_linkedlist() { + for (size_t pass = 0; pass < kAtomicLinkedListPassCount; pass++) { + std::unique_ptr list(new AtomicLinkedList()); + bool in_order = true; + for (size_t i = 0; i < kAtomicLinkedListSize; i++) { + list->insertHead(i); + } + size_t nSum = 0; + auto func = [&nSum] (size_t elem) { nSum += elem; }; + if (in_order) { + list->sweep(func); + } else { + list->reverseSweep(func); + } + in_order = !in_order; + + size_t supposed_sum = kAtomicLinkedListSize * (kAtomicLinkedListSize - 1) / 2; + EXPECT_EQ(nSum, supposed_sum); + } +} + +template +void run_queue(Queue* q, size_t enqueue_count, size_t enqueue_stride) { + size_t nNo = 0; + size_t pop_sum = 0; + while (nNo < enqueue_count) { + size_t curr_push_count = + std::min(enqueue_count - nNo, enqueue_stride); + for (size_t i = 0; i < curr_push_count; i++) { + q->enqueue(nNo++); + } + size_t res; + for (size_t i = 0; i < curr_push_count; i++) { + q->dequeue(res); + pop_sum += res; + } + } + size_t supposed_sum = enqueue_count * (enqueue_count - 1) / 2; + EXPECT_EQ (pop_sum, supposed_sum); +} + +// MPMC Specialization. +template <> +void run_queue(MPMCQueue* q, size_t enqueue_count, size_t enqueue_stride) { + size_t nNo = 0; + size_t push_sum = 0; + size_t pop_sum = 0; + while (nNo < enqueue_count) { + size_t curr_push_count = + std::min(enqueue_count - nNo, enqueue_stride); + for (size_t i = 0; i < curr_push_count; i++) { + if (q->write(nNo)) { + push_sum += nNo; + nNo++; + } + } + size_t res; + while (q->read(res)) { + pop_sum += res; + } + } + + size_t supposed_sum = enqueue_count * (enqueue_count - 1) / 2; + EXPECT_EQ(pop_sum, supposed_sum); +} + +template +void run_without_initial_capacity(size_t enqueue_count, size_t enqueue_stride) { + std::unique_ptr q(new Queue()); + run_queue(q.get(), enqueue_count, enqueue_stride); +} + +template +void run_with_initial_capacity(size_t queue_capacity, size_t enqueue_count, + size_t enqueue_stride) { + std::unique_ptr q(new Queue(queue_capacity)); + run_queue(q.get(), enqueue_count, enqueue_stride); +} + +class FollyQueueEnqueueDequeueTest : public ::testing::Test { + +}; + +TEST_F(FollyQueueEnqueueDequeueTest, FollyMPMCQueue) { + run_with_initial_capacity( + kMPMCQueueCapacity, kMPMCQueueEnqueueCount, kMPMCQueueEnqueueStride); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyAtomicLinkedList) { + run_atomic_linkedlist(); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyUnboundedQueue_SPSC) { + run_without_initial_capacity( + kUSPSCQueueEnqueueCount, kUnboundedQueueEnqueueStride); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyUnboundedQueue_MPSC) { + run_without_initial_capacity( + kUMPSCQueueEnqueueCount, kUnboundedQueueEnqueueStride); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyUnboundedQueue_SPMC) { + run_without_initial_capacity( + kUSPMCQueueEnqueueCount, kUnboundedQueueEnqueueStride); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyUnboundedQueue_MPMC) { + run_without_initial_capacity( + kUMPMCQueueEnqueueCount, + kUnboundedQueueEnqueueStride); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyDynamicBoundedQueue_SPSC) { + // DynamicBoundedQueue + run_with_initial_capacity( + kDynamicBoundedQueueCapacity, + kDSPSCQueueEnqueueCount, kDynamicBoundedQueueEnqueueStride); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyDynamicBoundedQueue_MPSC) { + run_with_initial_capacity( + kDynamicBoundedQueueCapacity, + kDMPSCQueueEnqueueCount, + kDynamicBoundedQueueEnqueueStride); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyDynamicBoundedQueue_SPMC) { + run_with_initial_capacity( + kDynamicBoundedQueueCapacity, + kDSPMCQueueEnqueueCount, + kDynamicBoundedQueueEnqueueStride); +} + +TEST_F(FollyQueueEnqueueDequeueTest, FollyDynamicBoundedQueue_MPMC) { + run_with_initial_capacity( + kDynamicBoundedQueueCapacity, + kDMPMCQueueEnqueueCount, + kDynamicBoundedQueueEnqueueStride); +} + +int main(int argc, char** argv) { + // Init Google test + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + return result; +} diff --git a/folly/stress-test/stress-parallel-folly-sync.cpp b/folly/stress-test/stress-parallel-folly-sync.cpp new file mode 100644 index 00000000..775252c1 --- /dev/null +++ b/folly/stress-test/stress-parallel-folly-sync.cpp @@ -0,0 +1,157 @@ +#include +#include +#include +#include + +#include + +#include + +namespace { + +// MicroLock +const size_t kMicroLockPassCount = 2000000000; +typedef folly::MicroLock MicroLock; + +// MicroSpinLock +const size_t kMicroSpinLockPassCount = 1500000000; +typedef folly::MicroSpinLock MicroSpinLock; + +// PicoSpinLock +const size_t kPicoSpinLockPassCount = 2700000000; +typedef folly::PicoSpinLock PicoSpinLock; + +// SharedMutex +const size_t kSharedMutexPassCount = 5000000; +typedef folly::SharedMutexReadPriority SharedMutexReadPriority; +typedef folly::SharedMutexWritePriority SharedMutexWritePriority; + +// RWSpinLock +const size_t kRWSpinLockPassCount = 5000000; +typedef folly::RWSpinLock RWSpinLock; + +// RWTicketSpinLock +const size_t kRWTicketSpinLockPassCount = 5000000; +typedef folly::RWTicketSpinLock32 RWTicketSpinLock32; +typedef folly::RWTicketSpinLock64 RWTicketSpinLock64; + +// RCU +const size_t kRcuSyncPassCount = 180000; +const size_t kRcuNoSyncPassCount = 3500000; +// Represent the RCU-protected data. +struct RcuFoo { + size_t f1; + size_t f2; +}; + +} + +void run_rcu_sync(size_t pass_count) { + for (int write_percentage = 1; write_percentage <= 5; write_percentage += 1) { + for (size_t count = 0; count < pass_count; count++) { + for (int i = 0; i < 100; ++i) { + if (i < write_percentage) { + RcuFoo* f = new RcuFoo(); + folly::rcu_retire(f); + folly::synchronize_rcu(); + } else { + folly::rcu_reader g; + } + } + } + } +} + +void run_rcu_no_sync(size_t pass_count) { + for (int write_percentage = 1; write_percentage <= 5; write_percentage += 1) { + for (size_t count = 0; count < pass_count; count++) { + for (int i = 0; i < 100; ++i) { + if (i < write_percentage) { + RcuFoo* f = new RcuFoo(); + folly::rcu_retire(f); + } else { + folly::rcu_reader g; + } + } + } + } +} + +template +void run_rw_lock(size_t pass_count) { + std::unique_ptr l(new Lock()); + for (int write_percentage = 5; write_percentage < 20; write_percentage += 5) { + for (size_t count = 0; count < pass_count; count++) { + for (int i = 0; i < 100; ++i) { + if (i < write_percentage) { + l->lock(); + l->unlock(); + } else { + l->lock_shared(); + l->unlock_shared(); + } + } + } + } +} + +template +void run_small_lock(size_t pass_count) { + std::unique_ptr l(new Lock()); + l->init(); + for (size_t count = 0; count < pass_count; count++) { + l->lock(); + l->unlock(); + } +} + +class FollySyncTest: public ::testing::Test { + +}; + +TEST_F(FollySyncTest, FollyRCU_Sync) { + run_rcu_sync(kRcuSyncPassCount); +} + +TEST_F(FollySyncTest, FollyRCU_NoSync) { + run_rcu_no_sync(kRcuNoSyncPassCount); +} + +TEST_F(FollySyncTest, FollyRWTicketSpinLock_32) { + run_rw_lock(kRWTicketSpinLockPassCount); +} + +TEST_F(FollySyncTest, FollyRWTicketSpinLock_64) { + run_rw_lock(kRWTicketSpinLockPassCount); +} + +TEST_F(FollySyncTest, FollyRWSpinLock) { + run_rw_lock(kRWSpinLockPassCount); +} + +TEST_F(FollySyncTest, FollySharedMutex_ReadPriority) { + run_rw_lock(kSharedMutexPassCount); +} + +TEST_F(FollySyncTest, FollySharedMutex_WritePriority) { + run_rw_lock(kSharedMutexPassCount); +} + +TEST_F(FollySyncTest, FollyMicroSpinLock) { + run_small_lock(kMicroSpinLockPassCount); +} + +TEST_F(FollySyncTest, FollyPicoSpinLock) { + run_small_lock(kPicoSpinLockPassCount); +} + +TEST_F(FollySyncTest, FollyMicroLock) { + run_small_lock(kMicroLockPassCount); +} + +int main(int argc, char** argv) { + // Init Google test + ::testing::InitGoogleTest(&argc, argv); + int result = RUN_ALL_TESTS(); + return result; +} -- 2.34.1