diff options
Diffstat (limited to 'ACE/performance-tests/Misc/childbirth_time.cpp')
-rw-r--r-- | ACE/performance-tests/Misc/childbirth_time.cpp | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/ACE/performance-tests/Misc/childbirth_time.cpp b/ACE/performance-tests/Misc/childbirth_time.cpp new file mode 100644 index 00000000000..739d676a5fb --- /dev/null +++ b/ACE/performance-tests/Misc/childbirth_time.cpp @@ -0,0 +1,401 @@ +// $Id$ + +// ============================================================================ +// +// = LIBRARY +// (none) +// +// = FILENAME +// childbirth_time.cpp +// +// = DESCRIPTION +// This program is used to measure various child-creation mechanisms +// on various platforms. By default, the program measure the time +// to 'fork' a new process using ACE_Process.spawn (). Other tests +// are possible as described below. James Hu provides the idea to +// batch measuring threads creation. +// +// Usage: childbirth_time [-n ###] [-l ###] [-p|-f|-t|-a|-m|-x] [-h] [-e] +// +// -n ###: Specify number of iteration in tens. If this +// option is not specified, the default is +// MULTIPLY_FACTOR * (100 iterations,) which is +// equivalent to -n 10. +// +// -l ###: Specify MULTIPLY_FACTOR. Default is 10. +// +// *-p: Measure the performance of forking a child process +// and exec an "empty" program. This test uses +// ACE_Process.spawn (). (Default) +// +// -f: Measure the performance of native "fork" function +// call. Notice that there is no equivalent NT +// function calls and this option is only available +// on UN*X platform. +// +// -t: Measure the performance of native thread creation +// mechanisms. On Solaris, this is thr_create (). +// On NT, this is CreateThread (). Currently, only +// these two platforms are implemented. +// +// -m: Measure the performance of Thread_Manager::spawn_n +// method. +// +// -x: Test the baseline performance of ACE_Thread_Mutex. +// This really doesn't belong here +// +// -a: Measure the performance of thread creation using +// ACE_OS::thr_create (). +// +// -h: Use High Resolution Timer if supported by platform. +// +// -e: Exec a program after fork (). This option has no +// effect on NT. +// +// = CREATION DATE +// June 29, 1997 +// +// = AUTHOR +// Nanbor Wang +// +// ============================================================================ + +// Process Creation profiling + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_main.h" +#include "ace/Get_Opt.h" +#include "ace/Process.h" +#include "ace/Profile_Timer.h" +#include "ace/Thread_Manager.h" + +ACE_RCSID(Misc, childbirth_time, "$Id$") + +#define ACE_STOP_SIGN ACE_OS::sleep (0) + +#define MAX_NO_ITERATION 10000 +#if defined (ACE_WIN32) +#define SUBPROGRAM ACE_TEXT ("date.exe") +#else +#define SUBPROGRAM ACE_TEXT ("date") +#endif + +size_t MULTIPLY_FACTOR = 10; +typedef double (*Profiler)(size_t); +static int do_exec_after_fork = 0; + +/// do nothing thread function +extern "C" void *ace_empty (void*) +{ + return 0; +} + +static double +prof_ace_process (size_t iteration) +{ + if (iteration != 0) + { + ACE_Process_Options popt; + ACE_Process aProcess; + + popt.command_line (SUBPROGRAM); + + iteration *= MULTIPLY_FACTOR; + + if (do_exec_after_fork == 0) + popt.creation_flags (ACE_Process_Options::NO_EXEC); + + ACE_Profile_Timer ptimer; + ACE_Profile_Timer::ACE_Elapsed_Time et; + double time = 0; + pid_t result; + + for (size_t c = 0; c < iteration; c++) + { + ACE_STOP_SIGN; + ptimer.start (); + result = aProcess.spawn (popt); + ptimer.stop (); + + if (result == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "process.spawn"), -1); + else if (do_exec_after_fork == 0 && result == 0) + ACE_OS::exit (0) ; + else + { + ptimer.elapsed_time (et); + time += et.real_time; + } + } + + return time / iteration; + } + else + return -1.0; +} + +static double +prof_fork (size_t iteration) +{ +#if !defined (ACE_LACKS_EXEC) + if (iteration != 0) + { + ACE_Profile_Timer ptimer; + ACE_Profile_Timer::ACE_Elapsed_Time et; + double time = 0; + + iteration *= MULTIPLY_FACTOR; + + for (size_t i = 0; i < iteration; i++) + { + ACE_STOP_SIGN; + ptimer.start (); + switch (ACE_OS::fork ()) + { + case -1: + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "process.spawn"), -1); + /* NOTREACHED */ + case 0: + exit (0); + /* NOTREACHED */ + break; + default: + ptimer.stop (); + ptimer.elapsed_time (et); + time += et.real_time; + } + } + return time / iteration; + } + else + return -1.0; +#else + ACE_UNUSED_ARG (iteration); + ACE_ERROR_RETURN ((LM_ERROR, "fork () is not supported on this platform."), -1); +#endif +} + +static double +prof_native_thread (size_t iteration) +{ +#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_WTHREADS) || defined (ACE_HAS_STHREADS)) + if (iteration != 0) + { + ACE_Profile_Timer ptimer; + ACE_Profile_Timer::ACE_Elapsed_Time et; + double time = 0; + + for (size_t i = 0; i < iteration; i++) + { + ACE_STOP_SIGN; + ptimer.start (); + for (size_t j = 0; j < MULTIPLY_FACTOR; j++) + { +#if defined (ACE_HAS_WTHREADS) + if (::CreateThread (0, + 0, + LPTHREAD_START_ROUTINE (ace_empty), + 0, + CREATE_SUSPENDED, + 0) == 0) +#elif defined (ACE_HAS_STHREADS) + if (::thr_create (0, + 0, + &ace_empty, + 0, + THR_SUSPENDED, + 0) != 0) +#endif + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "CreateThread"), -1); + } + ptimer.stop (); + ptimer.elapsed_time (et); + time += et.real_time; + } + iteration *= MULTIPLY_FACTOR; + return time / iteration; + } + else + return -1.0; +#else + ACE_UNUSED_ARG (iteration); + ACE_ERROR_RETURN ((LM_ERROR, "Testing of native threads is not supported on this platform.\n"), -1); +#endif +} + +static double +prof_ace_os_thread (size_t iteration) +{ +#if defined (ACE_HAS_THREADS) + if (iteration != 0) + { + ACE_Profile_Timer ptimer; + ACE_Profile_Timer::ACE_Elapsed_Time et; + double time = 0; + + for (size_t i = 0; i < iteration; i++) + { + ACE_STOP_SIGN; + ptimer.start (); + + for (size_t j = 0; j < MULTIPLY_FACTOR; j++) + if (ACE_OS::thr_create ((ACE_THR_FUNC) ace_empty, + 0, + THR_SUSPENDED, + 0) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "CreateThread"), -1); + + ptimer.stop (); + ptimer.elapsed_time (et); + time += et.real_time; + } + iteration *= MULTIPLY_FACTOR; + return time / iteration; + } + else + return -1.0; +#else + ACE_UNUSED_ARG (iteration); + ACE_ERROR_RETURN ((LM_ERROR, "Threads are not supported on this platform.\n"), -1); +#endif +} + +static double +prof_tm_thread (size_t iteration) +{ +#if defined (ACE_HAS_THREADS) + if (iteration != 0) + { + ACE_Profile_Timer ptimer; + ACE_Profile_Timer::ACE_Elapsed_Time et; + double time = 0; + + for (size_t i = 0; i < iteration; i++) + { + ACE_STOP_SIGN; + ptimer.start (); + + if (ACE_Thread_Manager::instance ()->spawn_n (MULTIPLY_FACTOR, + (ACE_THR_FUNC) ace_empty, + 0, + THR_SUSPENDED) == -1) + ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "CreateThread"), -1); + + ptimer.stop (); + ptimer.elapsed_time (et); + time += et.real_time; + } + iteration *= MULTIPLY_FACTOR; + return time / iteration; + } + else + return -1.0; +#else + ACE_UNUSED_ARG (iteration); + ACE_ERROR_RETURN ((LM_ERROR, "Threads are not supported on this platform."), -1); +#endif +} + +static double +prof_mutex_base (size_t iteration) +{ +#if defined (ACE_HAS_THREADS) + ACE_Thread_Mutex plain; + if (iteration != 0) + { + ACE_Profile_Timer ptimer; + ACE_Profile_Timer::ACE_Elapsed_Time et; + double time = 0; + + for (size_t i = 0; i < iteration; i++) + { + ACE_STOP_SIGN; + ptimer.start (); + + for (size_t j=0; j < MULTIPLY_FACTOR; j++) + { + plain.acquire (); + plain.release (); + } + + ptimer.stop (); + ptimer.elapsed_time (et); + time += et.real_time; + } + iteration *= MULTIPLY_FACTOR; + return time / iteration; + } + else + return -1.0; +#else + ACE_UNUSED_ARG (iteration); + ACE_ERROR_RETURN ((LM_ERROR, "Threads are not supported on this platform."), -1); +#endif +} + +int +ACE_TMAIN (int argc, ACE_TCHAR* argv[]) +{ + ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("n:l:pftahmxe")); + int c; + size_t iteration = 10; + Profiler profiler = 0; + const char *profile_name = 0 ; + + while ((c=get_opt ()) != -1) + { + switch (c) + { + case 'n': + iteration = ACE_OS::atoi (get_opt.opt_arg ()); + break; + case 'l': + MULTIPLY_FACTOR = static_cast<size_t> (ACE_OS::atoi (get_opt.opt_arg ())); + break; + case 'p': // test ACE_Process.spawn () + profiler = prof_ace_process; + profile_name = "ACE_Process.spawn ()"; + break; + case 'f': // test fork () + profiler = prof_fork; + profile_name = "fork ()"; + break; + case 't': // test native thread creation + profiler = prof_native_thread; + profile_name = "native threads"; + break; + case 'a': // test ACE_OS::thr_create + profiler = prof_ace_os_thread; + profile_name = "ACE_OS::thr_create ()"; + break; + case 'm': + profiler = prof_tm_thread; + profile_name = "ACE_Thread_Manager::spawn_n ()"; + break; + case 'x': + profiler = prof_mutex_base; + profile_name = "ACE_Thread_Mutex Baseline"; + break; + case 'h': // use high resolution timer + ACE_High_Res_Timer::get_env_global_scale_factor (); + break; + case 'e': + do_exec_after_fork = 1; + break; + default: + break; + } + } + + if (profiler == 0) + ACE_ERROR_RETURN ((LM_ERROR, "Usage: childbirth_time {-p|-f|-t|-a|-m|-x} [-n ###] [-L ###] [-h] [-e]\n"), 1); + else + { + double time = profiler (iteration); + if (time > 0) + ACE_DEBUG ((LM_DEBUG, + "Average performance of %d iterations of %s: %.0f usec\n", + iteration * MULTIPLY_FACTOR, profile_name, time * 1e6)); + } + return 0; +} |