blob: 998518c9c55b25b931e5910dd8cb23ea15eaaaab [file] [log] [blame]
// 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