From d946ad0948f73acff59a80d1504831c2cd86fcc7 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sat, 23 Oct 2021 17:27:08 +0800 Subject: [PATCH] modify interface of sync.condition --- include/libipc/condition.h | 4 +- src/libipc/platform/linux/condition.h | 4 +- src/libipc/platform/win/condition.h | 4 +- src/libipc/sync/condition.cpp | 8 +-- src/libipc/waiter.h | 4 +- test/profiler/README.md | 11 ---- test/profiler/profiler.cpp | 77 --------------------------- test/profiler/profiler.h | 35 ------------ test/profiler/rdtsc.h | 52 ------------------ test/test_sync.cpp | 29 +++++++--- 10 files changed, 33 insertions(+), 195 deletions(-) delete mode 100644 test/profiler/README.md delete mode 100644 test/profiler/profiler.cpp delete mode 100644 test/profiler/profiler.h delete mode 100644 test/profiler/rdtsc.h diff --git a/include/libipc/condition.h b/include/libipc/condition.h index d3b3a59..a4e2ac3 100644 --- a/include/libipc/condition.h +++ b/include/libipc/condition.h @@ -27,8 +27,8 @@ public: void close() noexcept; bool wait(ipc::sync::mutex &mtx, std::uint64_t tm = ipc::invalid_value) noexcept; - bool notify() noexcept; - bool broadcast() noexcept; + bool notify(ipc::sync::mutex &mtx) noexcept; + bool broadcast(ipc::sync::mutex &mtx) noexcept; private: class condition_; diff --git a/src/libipc/platform/linux/condition.h b/src/libipc/platform/linux/condition.h index 7e5878a..2422985 100644 --- a/src/libipc/platform/linux/condition.h +++ b/src/libipc/platform/linux/condition.h @@ -115,7 +115,7 @@ public: return true; } - bool notify() noexcept { + bool notify(ipc::sync::mutex &) noexcept { if (!valid()) return false; int eno; if ((eno = ::pthread_cond_signal(cond_)) != 0) { @@ -125,7 +125,7 @@ public: return true; } - bool broadcast() noexcept { + bool broadcast(ipc::sync::mutex &) noexcept { if (!valid()) return false; int eno; if ((eno = ::pthread_cond_broadcast(cond_)) != 0) { diff --git a/src/libipc/platform/win/condition.h b/src/libipc/platform/win/condition.h index 5d82d47..e477bff 100644 --- a/src/libipc/platform/win/condition.h +++ b/src/libipc/platform/win/condition.h @@ -89,7 +89,7 @@ public: return rs && rl; } - bool notify() noexcept { + bool notify(ipc::sync::mutex &) noexcept { if (!valid()) return false; auto &cnt = counter(); if (!lock_.lock()) return false; @@ -101,7 +101,7 @@ public: return lock_.unlock() && ret; } - bool broadcast() noexcept { + bool broadcast(ipc::sync::mutex &) noexcept { if (!valid()) return false; auto &cnt = counter(); if (!lock_.lock()) return false; diff --git a/src/libipc/sync/condition.cpp b/src/libipc/sync/condition.cpp index 6da8772..ff17cd1 100644 --- a/src/libipc/sync/condition.cpp +++ b/src/libipc/sync/condition.cpp @@ -58,12 +58,12 @@ bool condition::wait(ipc::sync::mutex &mtx, std::uint64_t tm) noexcept { return impl(p_)->cond_.wait(mtx, tm); } -bool condition::notify() noexcept { - return impl(p_)->cond_.notify(); +bool condition::notify(ipc::sync::mutex &mtx) noexcept { + return impl(p_)->cond_.notify(mtx); } -bool condition::broadcast() noexcept { - return impl(p_)->cond_.broadcast(); +bool condition::broadcast(ipc::sync::mutex &mtx) noexcept { + return impl(p_)->cond_.broadcast(mtx); } } // namespace sync diff --git a/src/libipc/waiter.h b/src/libipc/waiter.h index 7983702..2e13dc3 100644 --- a/src/libipc/waiter.h +++ b/src/libipc/waiter.h @@ -63,12 +63,12 @@ public: bool notify() noexcept { std::lock_guard{lock_}; // barrier - return cond_.notify(); + return cond_.notify(lock_); } bool broadcast() noexcept { std::lock_guard{lock_}; // barrier - return cond_.broadcast(); + return cond_.broadcast(lock_); } bool quit_waiting() { diff --git a/test/profiler/README.md b/test/profiler/README.md deleted file mode 100644 index d4a6bea..0000000 --- a/test/profiler/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# A Quick Introduction to C++ Performance Tuning -(From: https://github.com/adah1972/cpp_summit_2020.git) - -This repository contains the presentation file and example code for my -presentation at the C++ Summit 2020 held in Shenzhen, China on 4–5 December -2020. - -The presentation content is shared under a [Creative Commons Attribution-Share -Alike 2.5 Licence](http://creativecommons.org/licenses/by-sa/2.5/). The code -is put in the public domain (i.e. do whatever you like with it), though an -acknowledgement will be appreciated (but not required). diff --git a/test/profiler/profiler.cpp b/test/profiler/profiler.cpp deleted file mode 100644 index d8fd7bc..0000000 --- a/test/profiler/profiler.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "profiler.h" -#include -#include -#include - -namespace { - -struct profiling_data { - int number; - int call_count{}; - uint64_t call_duration{}; -}; - -class profiler { -public: - profiler(); - ~profiler(); - - void add_data(int number, uint64_t duration); - -private: - std::vector data_; -}; - -profiler::profiler() -{ - size_t len = 0; - for (;;) { - if (name_map[len].name == NULL) { - break; - } - ++len; - } - data_.resize(len); - int i = 0; - for (auto& item : data_) { - assert(i == name_map[i].number); - item.number = i; - ++i; - } -} - -profiler::~profiler() -{ -#ifndef NDEBUG - for (auto& item : data_) { - if (item.call_count == 0) { - continue; - } - std::cout << item.number << " " << name_map[item.number].name - << ":\n"; - std::cout << " Call count: " << item.call_count << '\n'; - std::cout << " Call duration: " << item.call_duration << '\n'; - std::cout << " Average duration: " - << item.call_duration * 1.0 / - (item.call_count != 0 ? item.call_count : 1) - << '\n'; - } -#endif -} - -void profiler::add_data(int number, uint64_t duration) -{ - assert(number >= 0 && number < static_cast(data_.size())); - data_[number].call_count++; - data_[number].call_duration += duration; -} - -profiler profiler_instance; - -} // unnamed namespace - -profiling_checker::~profiling_checker() -{ - auto end_time = rdtsc(); - profiler_instance.add_data(number_, end_time - start_time_); -} diff --git a/test/profiler/profiler.h b/test/profiler/profiler.h deleted file mode 100644 index d04264a..0000000 --- a/test/profiler/profiler.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef PROFILER_H -#define PROFILER_H - -#include "rdtsc.h" - -struct name_mapper { - int number; - const char* name; -}; - -extern name_mapper name_map[]; - -class profiling_checker { -public: - profiling_checker(int number); - ~profiling_checker(); - -private: - int number_; - uint64_t start_time_; -}; - -inline profiling_checker::profiling_checker(int number) - : number_(number) -{ - start_time_ = rdtsc(); -} - -#ifdef NDEBUG -#define PROFILE_CHECK(func_number) (void)0 -#else -#define PROFILE_CHECK(func_number) profiling_checker _checker(func_number) -#endif - -#endif // PROFILER_H diff --git a/test/profiler/rdtsc.h b/test/profiler/rdtsc.h deleted file mode 100644 index 80e35c7..0000000 --- a/test/profiler/rdtsc.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef RDTSC_H -#define RDTSC_H - -#include // uint64_t - -#if defined(_M_X64) || defined(_M_IX86) || defined(__x86_64) || defined(__i386) -# ifdef _WIN32 -# include // __rdtsc -# else -# include // __rdtsc -# endif -# define HAS_HW_RDTSC 1 -#else -# include // std::chrono::high_resolution_clock -# define HAS_HW_RDTSC 0 -#endif - -inline uint64_t rdtsc() -{ -#if HAS_HW_RDTSC - // _mm_lfence() might be used to serialize the instruction stream, - // and it would guarantee that RDTSC will not be reordered with - // other instructions. However, measurements show that the overhead - // may be too big (easily 15 to 30 CPU cycles) for profiling - // purposes: if reordering matters, the overhead matters too! - - // Forbid the compiler from reordering instructions -# ifdef _MSC_VER - _ReadWriteBarrier(); -# else - __asm__ __volatile__("" : : : "memory"); -# endif - - uint64_t result = __rdtsc(); - - // Forbid the compiler from reordering instructions -# ifdef _MSC_VER - _ReadWriteBarrier(); -# else - __asm__ __volatile__("" : : : "memory"); -# endif - - return result; -#else - auto now = std::chrono::high_resolution_clock::now(); - return std::chrono::duration_cast( - now.time_since_epoch()) - .count(); -#endif -} - -#endif // RDTSC_H diff --git a/test/test_sync.cpp b/test/test_sync.cpp index 84ace7b..750d304 100644 --- a/test/test_sync.cpp +++ b/test/test_sync.cpp @@ -113,7 +113,7 @@ TEST(Sync, Condition) { auto job = [&que](int num) { ipc::sync::condition cond {"test-cond"}; ipc::sync::mutex lock {"test-mutex"}; - for (;;) { + for (int i = 0; i < 10; ++i) { int val = 0; { std::lock_guard guard {lock}; @@ -123,6 +123,19 @@ TEST(Sync, Condition) { val = que.front(); que.pop_front(); } + EXPECT_NE(val, 0); + std::printf("test-cond-%d: %d\n", num, val); + } + for (;;) { + int val = 0; + { + std::lock_guard guard {lock}; + while (que.empty()) { + EXPECT_TRUE(cond.wait(lock, 1000)); + } + val = que.front(); + que.pop_front(); + } if (val == 0) { std::printf("test-cond-%d: exit.\n", num); return; @@ -139,16 +152,16 @@ TEST(Sync, Condition) { { std::lock_guard guard {lock}; que.push_back(i); + ASSERT_TRUE(cond.notify(lock)); } - cond.notify(); std::this_thread::sleep_for(std::chrono::milliseconds(20)); } for (int i = 1; i < 100; ++i) { { std::lock_guard guard {lock}; que.push_back(i); + ASSERT_TRUE(cond.broadcast(lock)); } - cond.broadcast(); std::this_thread::sleep_for(std::chrono::milliseconds(20)); } { @@ -156,8 +169,8 @@ TEST(Sync, Condition) { for (int i = 0; i < (int)test_conds.size(); ++i) { que.push_back(0); } + ASSERT_TRUE(cond.broadcast(lock)); } - cond.broadcast(); for (auto &t : test_conds) t.join(); } @@ -171,7 +184,7 @@ TEST(Sync, ConditionRobust) { printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 2\n"); ipc::sync::mutex lock {"test-mutex"}; printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 3\n"); - lock.lock(); + ASSERT_TRUE(lock.lock()); std::thread unlock {[] { printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 1\n"); ipc::sync::condition cond {"test-cond"}; @@ -183,13 +196,13 @@ TEST(Sync, ConditionRobust) { } std::this_thread::sleep_for(std::chrono::seconds(1)); printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 4\n"); - cond.broadcast(); + ASSERT_TRUE(cond.broadcast(lock)); printf("WWWWWWWWWWWWWWWWWWWWWWWWWWWWWW 5\n"); }}; printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 4\n"); - cond.wait(lock); + ASSERT_TRUE(cond.wait(lock)); printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 5\n"); - lock.unlock(); + ASSERT_TRUE(lock.unlock()); printf("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 6\n"); unlock.join(); } \ No newline at end of file