From 9af486515c82c048db260f5c1faffc6c0fccdbaa Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Sat, 26 Oct 2013 10:13:48 +0200 Subject: [PATCH] performance --- performance/Jamfile.v2 | 4 + performance/lockfree_queue.cpp | 2 +- performance/performance.cpp | 105 ------------------------- performance/simple_stack_allocator.hpp | 69 ---------------- performance/spinlock_queue.cpp | 73 ++++++++++++++++- 5 files changed, 74 insertions(+), 179 deletions(-) delete mode 100644 performance/performance.cpp delete mode 100644 performance/simple_stack_allocator.hpp diff --git a/performance/Jamfile.v2 b/performance/Jamfile.v2 index 5e98f1fc..54b0421e 100644 --- a/performance/Jamfile.v2 +++ b/performance/Jamfile.v2 @@ -28,3 +28,7 @@ project boost/context/performance exe lockfree_queue : lockfree_queue.cpp ; + +exe spinlock_queue + : spinlock_queue.cpp + ; diff --git a/performance/lockfree_queue.cpp b/performance/lockfree_queue.cpp index c652a874..43c40e59 100644 --- a/performance/lockfree_queue.cpp +++ b/performance/lockfree_queue.cpp @@ -26,7 +26,7 @@ boost::atomic_int consumer_count(0); boost::lockfree::queue< int > queue( 128); -const int iterations = 100000; +const int iterations = 500000; const int producer_thread_count = 4; const int consumer_thread_count = 4; diff --git a/performance/performance.cpp b/performance/performance.cpp deleted file mode 100644 index 7244a923..00000000 --- a/performance/performance.cpp +++ /dev/null @@ -1,105 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#define BOOST_PP_LIMIT_MAG 10 - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "zeit.hpp" - -boost::atomic_int producer_count(0); -boost::atomic_int consumer_count(0); - -boost::lockfree::queue< int > queue( 128); - -const int iterations = 100000; -const int producer_thread_count = 4; -const int consumer_thread_count = 4; - -void producer(void) -{ - for (int i = 0; i != iterations; ++i) { - int value = ++producer_count; - while (!queue.push(value)); - } -} - -boost::atomic done (false); -void consumer(void) -{ - int value; - while (!done) { - while (queue.pop(value)) - ++consumer_count; - } - - while (queue.pop(value)) - ++consumer_count; -} - -zeit_t test_zeit( zeit_t ov) -{ - std::cout << "boost::lockfree::queue is "; - if (!queue.is_lock_free()) - std::cout << "not "; - std::cout << "lockfree" << std::endl; - - boost::thread_group producer_threads, consumer_threads; - - // start measurement - zeit_t start( zeit() ); - - for (int i = 0; i != producer_thread_count; ++i) - producer_threads.create_thread(producer); - - for (int i = 0; i != consumer_thread_count; ++i) - consumer_threads.create_thread(consumer); - - producer_threads.join_all(); - done = true; - consumer_threads.join_all(); - - // stop measurement - zeit_t total( zeit() - start); - - std::cout << "produced " << producer_count << " objects." << std::endl; - std::cout << "consumed " << consumer_count << " objects." << std::endl; - - // we have two jumps and two measuremt-overheads - total -= ov; // overhead of measurement - - return total; -} - -int main( int argc, char * argv[]) -{ - try - { - zeit_t ov( overhead_zeit() ); - std::cout << "\noverhead for clock_gettime() == " << ov << " ns" << std::endl; - - unsigned int res = test_zeit( ov); - std::cout << "lockfree::queue< int >: " << (res/1000000) << " ms" << std::endl; - - return EXIT_SUCCESS; - } - catch ( std::exception const& e) - { std::cerr << "exception: " << e.what() << std::endl; } - catch (...) - { std::cerr << "unhandled exception" << std::endl; } - return EXIT_FAILURE; -} diff --git a/performance/simple_stack_allocator.hpp b/performance/simple_stack_allocator.hpp deleted file mode 100644 index d6724d70..00000000 --- a/performance/simple_stack_allocator.hpp +++ /dev/null @@ -1,69 +0,0 @@ - -// Copyright Oliver Kowalke 2009. -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) - -#ifndef BOOST_CONTEXT_SIMPLE_STACK_ALLOCATOR_H -#define BOOST_CONTEXT_SIMPLE_STACK_ALLOCATOR_H - -#include -#include -#include - -#include -#include - -#include -#include - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_PREFIX -#endif - -namespace boost { -namespace coroutines { - -template< std::size_t Max, std::size_t Default, std::size_t Min > -class simple_stack_allocator -{ -public: - static std::size_t maximum_stacksize() - { return Max; } - - static std::size_t default_stacksize() - { return Default; } - - static std::size_t minimum_stacksize() - { return Min; } - - void allocate( stack_context & ctx, std::size_t size) - { - BOOST_ASSERT( minimum_stacksize() <= size); - BOOST_ASSERT( maximum_stacksize() >= size); - - void * limit = std::calloc( size, sizeof( char) ); - if ( ! limit) throw std::bad_alloc(); - - ctx.size = size; - ctx.sp = static_cast< char * >( limit) + ctx.size; - } - - void deallocate( stack_context & ctx) - { - BOOST_ASSERT( ctx.sp); - BOOST_ASSERT( minimum_stacksize() <= ctx.size); - BOOST_ASSERT( maximum_stacksize() >= ctx.size); - - void * limit = static_cast< char * >( ctx.sp) - ctx.size; - std::free( limit); - } -}; - -}} - -#ifdef BOOST_HAS_ABI_HEADERS -# include BOOST_ABI_SUFFIX -#endif - -#endif // BOOST_CONTEXT_SIMPLE_STACK_ALLOCATOR_H diff --git a/performance/spinlock_queue.cpp b/performance/spinlock_queue.cpp index d86967f7..be0c7276 100644 --- a/performance/spinlock_queue.cpp +++ b/performance/spinlock_queue.cpp @@ -7,6 +7,7 @@ #define BOOST_PP_LIMIT_MAG 10 #include +#include #include #include #include @@ -14,19 +15,83 @@ #include #include #include -#include +#include #include #include -#include +#include +#include #include "zeit.hpp" +class spinlock : private boost::noncopyable +{ +private: + enum state_t { + LOCKED = 0, + UNLOCKED + }; + + boost::atomic< state_t > state_; + +public: + spinlock() : + state_( UNLOCKED) + {} + + void lock() + { + while ( LOCKED == state_.exchange( LOCKED) ) + { + // busy-wait + boost::this_thread::yield(); + } + } + + void unlock() + { + BOOST_ASSERT( LOCKED == state_); + + state_ = UNLOCKED; + } +}; + +template< typename T > +class spinlock_queue +{ +private: + typedef std::deque< T > queue_t; + + spinlock splk_; + queue_t queue_; + +public: + spinlock_queue() : + splk_(), + queue_() + {} + + void push( T const& t) + { + boost::unique_lock< spinlock > lk( splk_); + queue_.push_back( t); + } + + bool pop( T & t) + { + boost::unique_lock< spinlock > lk( splk_); + if ( queue_.empty() ) return false; + std::swap( t, queue_.front() ); + queue_.pop_front(); + return true; + } +}; + boost::atomic_int producer_count(0); boost::atomic_int consumer_count(0); -boost::lockfree::queue< int > queue( 128); +spinlock_queue< int > queue; -const int iterations = 100000; +const int iterations = 500000; const int producer_thread_count = 4; const int consumer_thread_count = 4;