From 82f4ae7f001ff8af1bf41e136daf87a6812e62af Mon Sep 17 00:00:00 2001 From: Liu Yiqun Date: Mon, 27 Mar 2017 13:20:45 +0800 Subject: [PATCH] Add alternative implementation of SpinLock and ThreadBarrier, using the same implemetation as mac os. --- cmake/flags.cmake | 12 +++ paddle/utils/arch/linux/Locks.cpp | 131 +++++++++++++++++++----------- 2 files changed, 95 insertions(+), 48 deletions(-) diff --git a/cmake/flags.cmake b/cmake/flags.cmake index b76852fc6c5..0a13a02df3c 100644 --- a/cmake/flags.cmake +++ b/cmake/flags.cmake @@ -2,6 +2,7 @@ include(CheckCXXCompilerFlag) include(CheckCCompilerFlag) include(CheckCXXSymbolExists) +include(CheckTypeSize) function(CheckCompilerCXX11Flag) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") @@ -83,6 +84,17 @@ if(NOT UINT64_MAX_EXISTS) endif() endif() +SET(CMAKE_EXTRA_INCLUDE_FILES "pthread.h") +CHECK_TYPE_SIZE(pthread_spinlock_t SPINLOCK_FOUND) +CHECK_TYPE_SIZE(pthread_barrier_t BARRIER_FOUND) +if(SPINLOCK_FOUND) + add_definitions(-DPADDLE_USE_PTHREAD_SPINLOCK) +endif(SPINLOCK_FOUND) +if(BARRIER_FOUND) + add_definitions(-DPADDLE_USE_PTHREAD_BARRIER) +endif(BARRIER_FOUND) +SET(CMAKE_EXTRA_INCLUDE_FILES "") + # Common flags. the compiler flag used for C/C++ sources whenever release or debug # Do not care if this flag is support for gcc. set(COMMON_FLAGS diff --git a/paddle/utils/arch/linux/Locks.cpp b/paddle/utils/arch/linux/Locks.cpp index c189229cfcc..310c9a65425 100644 --- a/paddle/utils/arch/linux/Locks.cpp +++ b/paddle/utils/arch/linux/Locks.cpp @@ -15,6 +15,7 @@ limitations under the License. */ #include "paddle/utils/Locks.h" #include #include +#include "paddle/utils/Logging.h" namespace paddle { class SemaphorePrivate { @@ -26,7 +27,10 @@ Semaphore::Semaphore(int initValue) : m(new SemaphorePrivate()) { sem_init(&m->sem, 0, initValue); } -Semaphore::~Semaphore() { sem_destroy(&m->sem); } +Semaphore::~Semaphore() { + sem_destroy(&m->sem); + delete m; +} bool Semaphore::timeWait(struct timespec* ts) { return (0 == sem_timedwait(&m->sem, ts)); @@ -36,70 +40,101 @@ void Semaphore::wait() { sem_wait(&m->sem); } void Semaphore::post() { sem_post(&m->sem); } +#ifdef PADDLE_USE_PTHREAD_SPINLOCK + class SpinLockPrivate { public: - inline SpinLockPrivate() { -#ifndef __ANDROID__ - pthread_spin_init(&lock_, 0); -#else - lock_ = 0; -#endif - } - inline ~SpinLockPrivate() { -#ifndef __ANDROID__ - pthread_spin_destroy(&lock_); -#endif - } -#ifndef __ANDROID__ + inline SpinLockPrivate() { pthread_spin_init(&lock_, 0); } + inline ~SpinLockPrivate() { pthread_spin_destroy(&lock_); } + + inline void lock() { pthread_spin_lock(&lock_); } + inline void unlock() { pthread_spin_unlock(&lock_); } + pthread_spinlock_t lock_; -#else - unsigned long lock_; -#endif - char padding_[64 - sizeof(lock_)]; + char padding_[64 - sizeof(pthread_spinlock_t)]; }; -SpinLock::SpinLock() : m(new SpinLockPrivate()) {} +#else -SpinLock::~SpinLock() { delete m; } +#include +class SpinLockPrivate { +public: + inline void lock() { + while (lock_.test_and_set(std::memory_order_acquire)) { + } + } + inline void unlock() { lock_.clear(std::memory_order_release); } -void SpinLock::lock() { -#ifndef __ANDROID__ - pthread_spin_lock(&m->lock_); -#endif -} + std::atomic_flag lock_ = ATOMIC_FLAG_INIT; + char padding_[64 - sizeof(lock_)]; // Padding to cache line size +}; -void SpinLock::unlock() { -#ifndef __ANDROID__ - pthread_spin_unlock(&m->lock_); #endif -} + +SpinLock::SpinLock() : m(new SpinLockPrivate()) {} +SpinLock::~SpinLock() { delete m; } +void SpinLock::lock() { m->lock(); } +void SpinLock::unlock() { m->unlock(); } + +#ifdef PADDLE_USE_PTHREAD_BARRIER class ThreadBarrierPrivate { public: -#ifndef __ANDROID__ pthread_barrier_t barrier_; -#else - unsigned long barrier_; -#endif + + inline explicit ThreadBarrierPrivate(int count) { + pthread_barrier_init(&barrier_, nullptr, count); + } + + inline ~ThreadBarrierPrivate() { pthread_barrier_destroy(&barrier_); } + + inline void wait() { pthread_barrier_wait(&barrier_); } }; -ThreadBarrier::ThreadBarrier(int count) : m(new ThreadBarrierPrivate()) { -#ifndef __ANDROID__ - pthread_barrier_init(&m->barrier_, nullptr, count); -#endif -} +#else -ThreadBarrier::~ThreadBarrier() { -#ifndef __ANDROID__ - pthread_barrier_destroy(&m->barrier_); -#endif - delete m; -} +class ThreadBarrierPrivate { +public: + pthread_mutex_t mutex_; + pthread_cond_t cond_; + int count_; + int tripCount_; + + inline explicit ThreadBarrierPrivate(int cnt) : count_(0), tripCount_(cnt) { + CHECK_NE(cnt, 0); + CHECK_GE(pthread_mutex_init(&mutex_, 0), 0); + CHECK_GE(pthread_cond_init(&cond_, 0), 0); + } + + inline ~ThreadBarrierPrivate() { + pthread_cond_destroy(&cond_); + pthread_mutex_destroy(&mutex_); + } + + /** + * @brief wait + * @return true if the last wait + */ + inline bool wait() { + pthread_mutex_lock(&mutex_); + ++count_; + if (count_ >= tripCount_) { + count_ = 0; + pthread_cond_broadcast(&cond_); + pthread_mutex_unlock(&mutex_); + return true; + } else { + pthread_cond_wait(&cond_, &mutex_); + pthread_mutex_unlock(&mutex_); + return false; + } + } +}; -void ThreadBarrier::wait() { -#ifndef __ANDROID__ - pthread_barrier_wait(&m->barrier_); #endif -} + +ThreadBarrier::ThreadBarrier(int count) : m(new ThreadBarrierPrivate(count)) {} +ThreadBarrier::~ThreadBarrier() { delete m; } +void ThreadBarrier::wait() { m->wait(); } } // namespace paddle -- GitLab