From f86d9c38c6929047753e90860ac8ea18ee40cc8b Mon Sep 17 00:00:00 2001 From: Oliver Kowalke Date: Thu, 16 Jan 2014 20:40:16 +0100 Subject: [PATCH] refactored perforamnce tests --- performance/Jamfile.v2 | 41 +++--- performance/clock.hpp | 44 +++++++ performance/cycle_i386.hpp | 22 ++-- performance/cycle_x86-64.hpp | 22 ++-- performance/performance.cpp | 124 ------------------ performance/performance_create_prealloc.cpp | 118 +++++++++++++++++ performance/performance_create_protected.cpp | 109 +++++++++++++++ performance/performance_create_simple.cpp | 109 +++++++++++++++ performance/performance_switch.cpp | 109 +++++++++++++++ performance/preallocated_stack_allocator.hpp | 106 +++++++++++++++ performance/segmented/Jamfile.v2 | 66 ++++++++++ .../performance_create_segmented.cpp | 103 +++++++++++++++ performance/simple_stack_allocator.hpp | 69 ---------- performance/zeit.hpp | 53 -------- 14 files changed, 811 insertions(+), 284 deletions(-) create mode 100644 performance/clock.hpp delete mode 100644 performance/performance.cpp create mode 100644 performance/performance_create_prealloc.cpp create mode 100644 performance/performance_create_protected.cpp create mode 100644 performance/performance_create_simple.cpp create mode 100644 performance/performance_switch.cpp create mode 100644 performance/preallocated_stack_allocator.hpp create mode 100644 performance/segmented/Jamfile.v2 create mode 100644 performance/segmented/performance_create_segmented.cpp delete mode 100644 performance/simple_stack_allocator.hpp delete mode 100644 performance/zeit.hpp diff --git a/performance/Jamfile.v2 b/performance/Jamfile.v2 index 01e4536..ca43d2c 100644 --- a/performance/Jamfile.v2 +++ b/performance/Jamfile.v2 @@ -15,53 +15,62 @@ import toolset ; project boost/coroutine/performance : requirements - /boost/context//boost_context + /boost/chrono//boost_chrono /boost/coroutine//boost_coroutine - gcc-4.7,on:-fsplit-stack - gcc-4.8,on:-fsplit-stack + /boost/program_options//boost_program_options "-lrt" static multi ; alias sources - : performance.cpp - bind_processor_aix.cpp + : bind_processor_aix.cpp : aix ; alias sources - : performance.cpp - bind_processor_freebsd.cpp + : bind_processor_freebsd.cpp : freebsd ; alias sources - : performance.cpp - bind_processor_hpux.cpp + : bind_processor_hpux.cpp : hpux ; alias sources - : performance.cpp - bind_processor_linux.cpp + : bind_processor_linux.cpp : linux ; alias sources - : performance.cpp - bind_processor_solaris.cpp + : bind_processor_solaris.cpp : solaris ; alias sources - : performance.cpp - bind_processor_windows.cpp + : bind_processor_windows.cpp : windows ; explicit sources ; -exe performance +exe performance_create_protected : sources + performance_create_protected.cpp + ; + +exe performance_create_simple + : sources + performance_create_simple.cpp + ; + +exe performance_create_prealloc + : sources + performance_create_prealloc.cpp + ; + +exe performance_switch + : sources + performance_switch.cpp ; diff --git a/performance/clock.hpp b/performance/clock.hpp new file mode 100644 index 0000000..6103951 --- /dev/null +++ b/performance/clock.hpp @@ -0,0 +1,44 @@ + +// 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 CLOCK_H +#define CLOCK_H + +#include +#include +#include +#include + +#include +#include +#include + +typedef boost::chrono::high_resolution_clock clock_type; +typedef clock_type::duration duration_type; +typedef clock_type::time_point time_point_type; + +struct clock_overhead +{ + boost::uint64_t operator()() + { + time_point_type start( clock_type::now() ); + return ( clock_type::now() - start).count(); + } +}; + +duration_type overhead_clock() +{ + std::size_t iterations( 10); + std::vector< boost::uint64_t > overhead( iterations, 0); + for ( std::size_t i = 0; i < iterations; ++i) + std::generate( + overhead.begin(), overhead.end(), + clock_overhead() ); + BOOST_ASSERT( overhead.begin() != overhead.end() ); + return duration_type( std::accumulate( overhead.begin(), overhead.end(), 0) / iterations); +} + +#endif // CLOCK_H diff --git a/performance/cycle_i386.hpp b/performance/cycle_i386.hpp index 3e67007..a3eb703 100644 --- a/performance/cycle_i386.hpp +++ b/performance/cycle_i386.hpp @@ -18,13 +18,13 @@ #define BOOST_CONTEXT_CYCLE -typedef boost::uint64_t cycle_t; +typedef boost::uint64_t cycle_type; #if _MSC_VER inline -cycle_t cycles() +cycle_type cycles() { - cycle_t c; + cycle_type c; __asm { cpuid rdtsc @@ -36,7 +36,7 @@ cycle_t cycles() #elif defined(__GNUC__) || \ defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL) inline -cycle_t cycles() +cycle_type cycles() { boost::uint32_t lo, hi; @@ -52,30 +52,30 @@ cycle_t cycles() ::: "%eax", "%ebx", "%ecx", "%edx" ); - return ( cycle_t)hi << 32 | lo; + return ( cycle_type)hi << 32 | lo; } #else # error "this compiler is not supported" #endif -struct measure_cycles +struct cycle_overhead { - cycle_t operator()() + cycle_type operator()() { - cycle_t start( cycles() ); + cycle_type start( cycles() ); return cycles() - start; } }; inline -cycle_t overhead_cycles() +cycle_type overhead_cycle() { std::size_t iterations( 10); - std::vector< cycle_t > overhead( iterations, 0); + std::vector< cycle_type > overhead( iterations, 0); for ( std::size_t i( 0); i < iterations; ++i) std::generate( overhead.begin(), overhead.end(), - measure_cycles() ); + cycle_overhead() ); BOOST_ASSERT( overhead.begin() != overhead.end() ); return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations; } diff --git a/performance/cycle_x86-64.hpp b/performance/cycle_x86-64.hpp index a2212b8..fae0226 100644 --- a/performance/cycle_x86-64.hpp +++ b/performance/cycle_x86-64.hpp @@ -18,21 +18,21 @@ #define BOOST_CONTEXT_CYCLE -typedef boost::uint64_t cycle_t; +typedef boost::uint64_t cycle_type; #if _MSC_VER >= 1400 # include # pragma intrinsic(__rdtsc) inline -cycle_t cycles() +cycle_type cycles() { return __rdtsc(); } #elif defined(__INTEL_COMPILER) || defined(__ICC) || defined(_ECC) || defined(__ICL) inline -cycle_t cycles() +cycle_type cycles() { return __rdtsc(); } #elif defined(__GNUC__) || defined(__SUNPRO_C) inline -cycle_t cycles() +cycle_type cycles() { boost::uint32_t lo, hi; @@ -48,30 +48,30 @@ cycle_t cycles() ::: "%rax", "%rbx", "%rcx", "%rdx" ); - return ( cycle_t)hi << 32 | lo; + return ( cycle_type)hi << 32 | lo; } #else # error "this compiler is not supported" #endif -struct measure_cycles +struct cycle_overhead { - cycle_t operator()() + cycle_type operator()() { - cycle_t start( cycles() ); + cycle_type start( cycles() ); return cycles() - start; } }; inline -cycle_t overhead_cycles() +cycle_type overhead_cycle() { std::size_t iterations( 10); - std::vector< cycle_t > overhead( iterations, 0); + std::vector< cycle_type > overhead( iterations, 0); for ( std::size_t i( 0); i < iterations; ++i) std::generate( overhead.begin(), overhead.end(), - measure_cycles() ); + cycle_overhead() ); BOOST_ASSERT( overhead.begin() != overhead.end() ); return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations; } diff --git a/performance/performance.cpp b/performance/performance.cpp deleted file mode 100644 index 40c5bbe..0000000 --- a/performance/performance.cpp +++ /dev/null @@ -1,124 +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 "bind_processor.hpp" -#include "cycle.hpp" -#include "simple_stack_allocator.hpp" - -#if _POSIX_C_SOURCE >= 199309L -#include "zeit.hpp" -#endif - -namespace coro = boost::coroutines; - -# define COUNTER BOOST_PP_LIMIT_MAG - -# define CALL_COROUTINE(z,n,unused) \ - c(); - -void fn( boost::coroutines::coroutine< void >::push_type & c) -{ while ( true) c(); } - -# ifdef BOOST_CONTEXT_CYCLE -cycle_t test_cycles( cycle_t ov, coro::flag_fpu_t preserve_fpu) -{ -# if defined(BOOST_USE_SEGMENTED_STACKS) - boost::coroutines::coroutine< void >::pull_type c( fn, coro::attributes( preserve_fpu) ); -# else - coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; - boost::coroutines::coroutine< void >::pull_type c( fn, coro::attributes( preserve_fpu), alloc); -# endif - - // cache warum-up -BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) - - cycle_t start( cycles() ); -BOOST_PP_REPEAT_FROM_TO( 0, COUNTER, CALL_COROUTINE, ~) - cycle_t total( cycles() - start); - - // we have two jumps and two measuremt-overheads - total -= ov; // overhead of measurement - total /= COUNTER; // per call - total /= 2; // 2x jump_to c1->c2 && c2->c1 - - return total; -} -# endif - -# if _POSIX_C_SOURCE >= 199309L -zeit_t test_zeit( zeit_t ov, coro::flag_fpu_t preserve_fpu) -{ -# if defined(BOOST_USE_SEGMENTED_STACKS) - boost::coroutines::coroutine< void >::pull_type c( fn, coro::attributes( preserve_fpu) ); -# else - coro::simple_stack_allocator< 8 * 1024 * 1024, 64 * 1024, 8 * 1024 > alloc; - boost::coroutines::coroutine< void >::pull_type c( fn, coro::attributes( preserve_fpu), alloc); -# endif - - // cache warum-up -BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~) - - zeit_t start( zeit() ); -BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_COROUTINE, ~) - zeit_t total( zeit() - start); - - // we have two jumps and two measuremt-overheads - total -= ov; // overhead of measurement - total /= BOOST_PP_LIMIT_MAG; // per call - total /= 2; // 2x jump_to c1->c2 && c2->c1 - - return total; -} -# endif - -int main( int argc, char * argv[]) -{ - try - { - coro::flag_fpu_t preserve_fpu = coro::fpu_not_preserved; - bind_to_processor( 0); - -#ifdef BOOST_CONTEXT_CYCLE - { - cycle_t ov( overhead_cycles() ); - std::cout << "overhead for rdtsc == " << ov << " cycles" << std::endl; - - unsigned int res = test_cycles( ov, preserve_fpu); - std::cout << "coroutine: average of " << res << " cycles per switch" << std::endl; - } -#endif - -#if _POSIX_C_SOURCE >= 199309L - { - zeit_t ov( overhead_zeit() ); - std::cout << "\noverhead for clock_gettime() == " << ov << " ns" << std::endl; - - unsigned int res = test_zeit( ov, preserve_fpu); - std::cout << "coroutine: average of " << res << " ns per switch" << std::endl; - } -#endif - - 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/performance_create_prealloc.cpp b/performance/performance_create_prealloc.cpp new file mode 100644 index 0000000..094b39f --- /dev/null +++ b/performance/performance_create_prealloc.cpp @@ -0,0 +1,118 @@ + +// 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) + +#include +#include +#include + +#include +#include +#include +#include + +#include "bind_processor.hpp" +#include "clock.hpp" +#include "cycle.hpp" +#include "preallocated_stack_allocator.hpp" + +typedef preallocated_stack_allocator< 8 * 1024 > stack_allocator; + +boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; +boost::uint64_t jobs = 1000; + +void fn( boost::coroutines::coroutine< void >::push_type & c) +{ while ( true) c(); } + +duration_type measure_time() +{ + stack_allocator stack_alloc( jobs + 1); + + // cache warum-up + boost::coroutines::coroutine< void >::pull_type c( fn, + boost::coroutines::attributes( stack_allocator::default_stacksize(), preserve_fpu), + stack_alloc); + + time_point_type start( clock_type::now() ); + for ( std::size_t i = 0; i < jobs; ++i) { + boost::coroutines::coroutine< void >::pull_type c( fn, + boost::coroutines::attributes( stack_allocator::default_stacksize(), preserve_fpu), + stack_alloc); + } + duration_type total = clock_type::now() - start; + total -= overhead_clock(); // overhead of measurement + total /= jobs; // loops + + return total; +} + +# ifdef BOOST_CONTEXT_CYCLE +cycle_type measure_cycles() +{ + stack_allocator stack_alloc( jobs + 1); + + // cache warum-up + boost::coroutines::coroutine< void >::pull_type c( fn, + boost::coroutines::attributes( stack_allocator::default_stacksize(), preserve_fpu), + stack_alloc); + + cycle_type start( cycles() ); + for ( std::size_t i = 0; i < jobs; ++i) { + boost::coroutines::coroutine< void >::pull_type c( fn, + boost::coroutines::attributes( stack_allocator::default_stacksize(), preserve_fpu), + stack_alloc); + } + cycle_type total = cycles() - start; + total -= overhead_cycle(); // overhead of measurement + total /= jobs; // loops + + return total; +} +# endif + +int main( int argc, char * argv[]) +{ + try + { + bind_to_processor( 0); + + bool preserve = false; + boost::program_options::options_description desc("allowed options"); + desc.add_options() + ("help", "help message") + ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") + ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line( + argc, + argv, + desc), + vm); + boost::program_options::notify( vm); + + if ( vm.count("help") ) { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; + + boost::uint64_t res = measure_time().count(); + std::cout << "average of " << res << " nano seconds" << std::endl; +#ifdef BOOST_CONTEXT_CYCLE + res = measure_cycles(); + std::cout << "average of " << res << " cpu cycles" << std::endl; +#endif + + 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/performance_create_protected.cpp b/performance/performance_create_protected.cpp new file mode 100644 index 0000000..0d2f862 --- /dev/null +++ b/performance/performance_create_protected.cpp @@ -0,0 +1,109 @@ + +// 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) + +#include +#include +#include + +#include +#include +#include +#include + +#include "bind_processor.hpp" +#include "clock.hpp" +#include "cycle.hpp" + +typedef boost::coroutines::protected_stack_allocator stack_allocator; + +boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; +boost::uint64_t jobs = 1000; + +void fn( boost::coroutines::coroutine< void >::push_type & c) +{ while ( true) c(); } + +duration_type measure_time() +{ + stack_allocator stack_alloc; + + // cache warum-up + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu), stack_alloc); + + time_point_type start( clock_type::now() ); + for ( std::size_t i = 0; i < jobs; ++i) { + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu), stack_alloc); + } + duration_type total = clock_type::now() - start; + total -= overhead_clock(); // overhead of measurement + total /= jobs; // loops + + return total; +} + +# ifdef BOOST_CONTEXT_CYCLE +cycle_type measure_cycles() +{ + stack_allocator stack_alloc; + + // cache warum-up + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu), stack_alloc); + + cycle_type start( cycles() ); + for ( std::size_t i = 0; i < jobs; ++i) { + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu), stack_alloc); + } + cycle_type total = cycles() - start; + total -= overhead_cycle(); // overhead of measurement + total /= jobs; // loops + + return total; +} +# endif + +int main( int argc, char * argv[]) +{ + try + { + bind_to_processor( 0); + + bool preserve = false; + boost::program_options::options_description desc("allowed options"); + desc.add_options() + ("help", "help message") + ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") + ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line( + argc, + argv, + desc), + vm); + boost::program_options::notify( vm); + + if ( vm.count("help") ) { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; + + boost::uint64_t res = measure_time().count(); + std::cout << "average of " << res << " nano seconds" << std::endl; +#ifdef BOOST_CONTEXT_CYCLE + res = measure_cycles(); + std::cout << "average of " << res << " cpu cycles" << std::endl; +#endif + + 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/performance_create_simple.cpp b/performance/performance_create_simple.cpp new file mode 100644 index 0000000..971a002 --- /dev/null +++ b/performance/performance_create_simple.cpp @@ -0,0 +1,109 @@ + +// 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) + +#include +#include +#include + +#include +#include +#include +#include + +#include "bind_processor.hpp" +#include "clock.hpp" +#include "cycle.hpp" + +typedef boost::coroutines::simple_stack_allocator stack_allocator; + +boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; +boost::uint64_t jobs = 1000; + +void fn( boost::coroutines::coroutine< void >::push_type & c) +{ while ( true) c(); } + +duration_type measure_time() +{ + stack_allocator stack_alloc; + + // cache warum-up + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu), stack_alloc); + + time_point_type start( clock_type::now() ); + for ( std::size_t i = 0; i < jobs; ++i) { + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu), stack_alloc); + } + duration_type total = clock_type::now() - start; + total -= overhead_clock(); // overhead of measurement + total /= jobs; // loops + + return total; +} + +# ifdef BOOST_CONTEXT_CYCLE +cycle_type measure_cycles() +{ + stack_allocator stack_alloc; + + // cache warum-up + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu), stack_alloc); + + cycle_type start( cycles() ); + for ( std::size_t i = 0; i < jobs; ++i) { + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu), stack_alloc); + } + cycle_type total = cycles() - start; + total -= overhead_cycle(); // overhead of measurement + total /= jobs; // loops + + return total; +} +# endif + +int main( int argc, char * argv[]) +{ + try + { + bind_to_processor( 0); + + bool preserve = false; + boost::program_options::options_description desc("allowed options"); + desc.add_options() + ("help", "help message") + ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") + ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line( + argc, + argv, + desc), + vm); + boost::program_options::notify( vm); + + if ( vm.count("help") ) { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; + + boost::uint64_t res = measure_time().count(); + std::cout << "average of " << res << " nano seconds" << std::endl; +#ifdef BOOST_CONTEXT_CYCLE + res = measure_cycles(); + std::cout << "average of " << res << " cpu cycles" << std::endl; +#endif + + 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/performance_switch.cpp b/performance/performance_switch.cpp new file mode 100644 index 0000000..bc7b606 --- /dev/null +++ b/performance/performance_switch.cpp @@ -0,0 +1,109 @@ + +// 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) + +#include +#include +#include + +#include +#include +#include +#include + +#include "bind_processor.hpp" +#include "clock.hpp" +#include "cycle.hpp" + +boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; +boost::uint64_t jobs = 1000; + +void fn( boost::coroutines::coroutine< void >::push_type & c) +{ while ( true) c(); } + +duration_type measure_time() +{ + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu) ); + + // cache warum-up + c(); + + time_point_type start( clock_type::now() ); + for ( std::size_t i = 0; i < jobs; ++i) { + c(); + } + duration_type total = clock_type::now() - start; + total -= overhead_clock(); // overhead of measurement + total /= jobs; // loops + total /= 2; // 2x jump_fcontext + + return total; +} + +# ifdef BOOST_CONTEXT_CYCLE +cycle_type measure_cycles() +{ + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu) ); + + // cache warum-up + c(); + + cycle_type start( cycles() ); + for ( std::size_t i = 0; i < jobs; ++i) { + c(); + } + cycle_type total = cycles() - start; + total -= overhead_cycle(); // overhead of measurement + total /= jobs; // loops + total /= 2; // 2x jump_fcontext + + return total; +} +# endif + +int main( int argc, char * argv[]) +{ + try + { + bind_to_processor( 0); + + bool preserve = false; + boost::program_options::options_description desc("allowed options"); + desc.add_options() + ("help", "help message") + ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") + ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line( + argc, + argv, + desc), + vm); + boost::program_options::notify( vm); + + if ( vm.count("help") ) { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; + + boost::uint64_t res = measure_time().count(); + std::cout << "average of " << res << " nano seconds" << std::endl; +#ifdef BOOST_CONTEXT_CYCLE + res = measure_cycles(); + std::cout << "average of " << res << " cpu cycles" << std::endl; +#endif + + 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/preallocated_stack_allocator.hpp b/performance/preallocated_stack_allocator.hpp new file mode 100644 index 0000000..57defd1 --- /dev/null +++ b/performance/preallocated_stack_allocator.hpp @@ -0,0 +1,106 @@ + +// 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_FIBER_PREALLOCATED_STACK_ALLOCATOR_H +#define BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +template< std::size_t Default > +class preallocated_stack_allocator +{ +private: + class impl : private boost::noncopyable + { + private: + std::size_t pos_; + std::vector< void * > stacks_; + + public: + impl( std::size_t count) : + pos_( 0), + stacks_() + { + for ( int i = 0; i < count; ++i) + { + void * limit = std::calloc( preallocated_stack_allocator::default_stacksize(), sizeof( char) ); + if ( ! limit) throw std::bad_alloc(); + limit = static_cast< char * >( limit) + preallocated_stack_allocator::default_stacksize(); + stacks_.push_back( limit); + } + } + + ~impl() + { + for ( int i = 0; i < stacks_.size(); ++i) + { + void * limit = static_cast< char * >( stacks_[i]); + limit = static_cast< char * >( limit) - preallocated_stack_allocator::default_stacksize(); + std::free( limit); + } + } + + void allocate( boost::coroutines::stack_context & ctx, std::size_t size) + { + BOOST_ASSERT( stacks_.size() > pos_); + BOOST_ASSERT( preallocated_stack_allocator::minimum_stacksize() <= size); + BOOST_ASSERT( preallocated_stack_allocator::maximum_stacksize() >= size); + + ctx.size = preallocated_stack_allocator::default_stacksize(); + ctx.sp = stacks_[pos_++]; + } + + void deallocate( boost::coroutines::stack_context & ctx) + { + BOOST_ASSERT( ctx.sp); + BOOST_ASSERT( preallocated_stack_allocator::minimum_stacksize() <= ctx.size); + BOOST_ASSERT( preallocated_stack_allocator::maximum_stacksize() >= ctx.size); + } + }; + + boost::shared_ptr< impl > p_; + +public: + static std::size_t maximum_stacksize() + { return Default; } + + static std::size_t default_stacksize() + { return Default; } + + static std::size_t minimum_stacksize() + { return Default; } + + preallocated_stack_allocator( std::size_t count) : + p_( new impl( count) ) + {} + + void allocate( boost::coroutines::stack_context & ctx, std::size_t size) + { p_->allocate( ctx, size); } + + void deallocate( boost::coroutines::stack_context & ctx) + { p_->deallocate( ctx); } +}; + +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#endif // BOOST_FIBER_PREALLOCATED_STACK_ALLOCATOR_H diff --git a/performance/segmented/Jamfile.v2 b/performance/segmented/Jamfile.v2 new file mode 100644 index 0000000..f7eb81f --- /dev/null +++ b/performance/segmented/Jamfile.v2 @@ -0,0 +1,66 @@ + +# 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) + +# For more information, see http://www.boost.org/ + +import common ; +import feature ; +import indirect ; +import modules ; +import os ; +import toolset ; + +project boost/coroutine/performance/segmented + : requirements + /boost/chrono//boost_chrono + /boost/coroutine//boost_coroutine + /boost/program_options//boost_program_options + gcc-4.7:-fsplit-stack + gcc-4.7:-DBOOST_USE_SEGMENTED_STACKS + gcc-4.8:-fsplit-stack + gcc-4.8:-DBOOST_USE_SEGMENTED_STACKS + on + "-lrt" + static + multi + ; + +alias sources + : ../bind_processor_aix.cpp + : aix + ; + +alias sources + : ../bind_processor_freebsd.cpp + : freebsd + ; + +alias sources + : ../bind_processor_hpux.cpp + : hpux + ; + +alias sources + : ../bind_processor_linux.cpp + : linux + ; + +alias sources + : ../bind_processor_solaris.cpp + : solaris + ; + +alias sources + : ../bind_processor_windows.cpp + : windows + ; + +explicit sources ; + +exe performance_create_segmented + : sources + performance_create_segmented.cpp + ; diff --git a/performance/segmented/performance_create_segmented.cpp b/performance/segmented/performance_create_segmented.cpp new file mode 100644 index 0000000..b7db646 --- /dev/null +++ b/performance/segmented/performance_create_segmented.cpp @@ -0,0 +1,103 @@ + +// 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) + +#include +#include +#include + +#include +#include +#include +#include + +#include "../bind_processor.hpp" +#include "../clock.hpp" +#include "../cycle.hpp" + +boost::coroutines::flag_fpu_t preserve_fpu = boost::coroutines::fpu_not_preserved; +boost::uint64_t jobs = 1000; + +void fn( boost::coroutines::coroutine< void >::push_type & c) +{ while ( true) c(); } + +duration_type measure_time() +{ + // cache warum-up + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu) ); + + time_point_type start( clock_type::now() ); + for ( std::size_t i = 0; i < jobs; ++i) { + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu) ); + } + duration_type total = clock_type::now() - start; + total -= overhead_clock(); // overhead of measurement + total /= jobs; // loops + + return total; +} + +# ifdef BOOST_CONTEXT_CYCLE +cycle_type measure_cycles() +{ + // cache warum-up + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu) ); + + cycle_type start( cycles() ); + for ( std::size_t i = 0; i < jobs; ++i) { + boost::coroutines::coroutine< void >::pull_type c( fn, boost::coroutines::attributes( preserve_fpu) ); + } + cycle_type total = cycles() - start; + total -= overhead_cycle(); // overhead of measurement + total /= jobs; // loops + + return total; +} +# endif + +int main( int argc, char * argv[]) +{ + try + { + bind_to_processor( 0); + + bool preserve = false; + boost::program_options::options_description desc("allowed options"); + desc.add_options() + ("help", "help message") + ("fpu,f", boost::program_options::value< bool >( & preserve), "preserve FPU registers") + ("jobs,j", boost::program_options::value< boost::uint64_t >( & jobs), "jobs to run"); + + boost::program_options::variables_map vm; + boost::program_options::store( + boost::program_options::parse_command_line( + argc, + argv, + desc), + vm); + boost::program_options::notify( vm); + + if ( vm.count("help") ) { + std::cout << desc << std::endl; + return EXIT_SUCCESS; + } + + if ( preserve) preserve_fpu = boost::coroutines::fpu_preserved; + + boost::uint64_t res = measure_time().count(); + std::cout << "average of " << res << " nano seconds" << std::endl; +#ifdef BOOST_CONTEXT_CYCLE + res = measure_cycles(); + std::cout << "average of " << res << " cpu cycles" << std::endl; +#endif + + 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 d6724d7..0000000 --- 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/zeit.hpp b/performance/zeit.hpp deleted file mode 100644 index 2c082bf..0000000 --- a/performance/zeit.hpp +++ /dev/null @@ -1,53 +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 ZEIT_H -#define ZEIT_H - -#include - -#include -#include -#include -#include - -#include -#include -#include - -typedef boost::uint64_t zeit_t; - -inline -zeit_t zeit() -{ - timespec t; - ::clock_gettime( CLOCK_PROCESS_CPUTIME_ID, & t); - return t.tv_sec * 1000000000 + t.tv_nsec; -} - -struct measure_zeit -{ - zeit_t operator()() - { - zeit_t start( zeit() ); - return zeit() - start; - } -}; - -inline -zeit_t overhead_zeit() -{ - std::size_t iterations( 10); - std::vector< zeit_t > overhead( iterations, 0); - for ( std::size_t i( 0); i < iterations; ++i) - std::generate( - overhead.begin(), overhead.end(), - measure_zeit() ); - BOOST_ASSERT( overhead.begin() != overhead.end() ); - return std::accumulate( overhead.begin(), overhead.end(), 0) / iterations; -} - -#endif // ZEIT_H