| |
| // 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 <cstdio> |
| #include <cstdlib> |
| #include <iostream> |
| #include <stdexcept> |
| |
| #include <boost/assert.hpp> |
| #include <boost/bind.hpp> |
| #include <boost/function.hpp> |
| #include <boost/config.hpp> |
| #include <boost/context/all.hpp> |
| #include <boost/preprocessor/repetition/repeat_from_to.hpp> |
| #include <boost/program_options.hpp> |
| |
| #include "../example/simple_stack_allocator.hpp" |
| |
| #ifdef BOOST_USE_UCONTEXT |
| #include <ucontext.h> |
| #endif |
| |
| #include "bind_processor.hpp" |
| #include "cycle.hpp" |
| |
| #if _POSIX_C_SOURCE >= 199309L |
| #include "zeit.hpp" |
| #endif |
| |
| namespace ctx = boost::context; |
| |
| typedef ctx::simple_stack_allocator< |
| 8 * 1024 * 1024, // 8MB |
| 64 * 1024, // 64kB |
| 8 * 1024 // 8kB |
| > stack_allocator; |
| |
| bool pres_fpu = false; |
| |
| #define CALL_FCONTEXT(z,n,unused) ctx::jump_fcontext( & fcm, fc, 7, pres_fpu); |
| |
| #ifdef BOOST_USE_UCONTEXT |
| # define CALL_UCONTEXT(z,n,unused) ::swapcontext( & ucm, & uc); |
| #endif |
| |
| #define CALL_FUNCTION(z,n,unused) fn(); |
| |
| |
| ctx::fcontext_t fcm, * fc; |
| |
| #ifdef BOOST_USE_UCONTEXT |
| ucontext_t uc, ucm; |
| #endif |
| |
| |
| static void f1( intptr_t) |
| { while ( true) ctx::jump_fcontext( fc, & fcm, 7, pres_fpu); } |
| |
| #ifdef BOOST_USE_UCONTEXT |
| static void f2() |
| { while ( true) ::swapcontext( & uc, & ucm); } |
| #endif |
| |
| static void f3() |
| {} |
| |
| |
| #ifdef BOOST_CONTEXT_CYCLE |
| cycle_t test_fcontext_cycle( cycle_t ov) |
| { |
| stack_allocator alloc; |
| fc = ctx::make_fcontext( |
| alloc.allocate(stack_allocator::default_stacksize()), |
| stack_allocator::default_stacksize(), |
| f1); |
| |
| ctx::jump_fcontext( & fcm, fc, 7, pres_fpu); |
| |
| // cache warum-up |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FCONTEXT, ~) |
| |
| cycle_t start( cycles() ); |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FCONTEXT, ~) |
| cycle_t total( cycles() - 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; |
| } |
| |
| # ifdef BOOST_USE_UCONTEXT |
| cycle_t test_ucontext_cycle( cycle_t ov) |
| { |
| stack_allocator alloc; |
| |
| ::getcontext( & uc); |
| uc.uc_stack.ss_sp = alloc.allocate(stack_allocator::default_stacksize()); |
| uc.uc_stack.ss_size = stack_allocator::default_stacksize(); |
| ::makecontext( & uc, f2, 7); |
| |
| // cache warum-up |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_UCONTEXT, ~) |
| |
| cycle_t start( cycles() ); |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_UCONTEXT, ~) |
| cycle_t total( cycles() - 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 |
| |
| cycle_t test_function_cycle( cycle_t ov) |
| { |
| boost::function< void() > fn( boost::bind( f3) ); |
| // cache warum-up |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FUNCTION, ~) |
| |
| cycle_t start( cycles() ); |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FUNCTION, ~) |
| cycle_t total( cycles() - 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 |
| |
| |
| #if _POSIX_C_SOURCE >= 199309L |
| zeit_t test_fcontext_zeit( zeit_t ov) |
| { |
| stack_allocator alloc; |
| fc = ctx::make_fcontext( |
| alloc.allocate(stack_allocator::default_stacksize()), |
| stack_allocator::default_stacksize(), |
| f1); |
| |
| ctx::jump_fcontext( & fcm, fc, 7, pres_fpu); |
| |
| // cache warum-up |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FCONTEXT, ~) |
| |
| zeit_t start( zeit() ); |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FCONTEXT, ~) |
| 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; |
| } |
| |
| # ifdef BOOST_USE_UCONTEXT |
| zeit_t test_ucontext_zeit( zeit_t ov) |
| { |
| stack_allocator alloc; |
| |
| ::getcontext( & uc); |
| uc.uc_stack.ss_sp = alloc.allocate(stack_allocator::default_stacksize()); |
| uc.uc_stack.ss_size = stack_allocator::default_stacksize(); |
| ::makecontext( & uc, f2, 7); |
| |
| // cache warum-up |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_UCONTEXT, ~) |
| |
| zeit_t start( zeit() ); |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_UCONTEXT, ~) |
| 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 |
| |
| zeit_t test_function_zeit( zeit_t ov) |
| { |
| boost::function< void() > fn( boost::bind( f3) ); |
| // cache warum-up |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FUNCTION, ~) |
| |
| zeit_t start( zeit() ); |
| BOOST_PP_REPEAT_FROM_TO( 0, BOOST_PP_LIMIT_MAG, CALL_FUNCTION, ~) |
| 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 |
| { |
| 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_fcontext_cycle( ov); |
| std::cout << "fcontext: average of " << res << " cycles per switch" << std::endl; |
| # ifdef BOOST_USE_UCONTEXT |
| res = test_ucontext_cycle( ov); |
| std::cout << "ucontext: average of " << res << " cycles per switch" << std::endl; |
| # endif |
| res = test_function_cycle( ov); |
| std::cout << "boost::function: 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_fcontext_zeit( ov); |
| std::cout << "fcontext: average of " << res << " ns per switch" << std::endl; |
| # ifdef BOOST_USE_UCONTEXT |
| res = test_ucontext_zeit( ov); |
| std::cout << "ucontext: average of " << res << " ns per switch" << std::endl; |
| # endif |
| res = test_function_zeit( ov); |
| std::cout << "boost::function: 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; |
| } |
| |
| #undef CALL_FCONTEXT |
| #undef CALL_UCONTEXT |