summaryrefslogtreecommitdiff
path: root/ACE/performance-tests/Misc/childbirth_time.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/performance-tests/Misc/childbirth_time.cpp')
-rw-r--r--ACE/performance-tests/Misc/childbirth_time.cpp398
1 files changed, 398 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..ad30cbf6e28
--- /dev/null
+++ b/ACE/performance-tests/Misc/childbirth_time.cpp
@@ -0,0 +1,398 @@
+
+//=============================================================================
+/**
+ * @file childbirth_time.cpp
+ *
+ * $Id$
+ *
+ * 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"
+
+#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:
+ ACE_OS::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)
+ //FUZZ: disable check_for_lack_ACE_OS
+ if (::thr_create (0,
+ 0,
+ &ace_empty,
+ 0,
+ THR_SUSPENDED,
+ 0) != 0)
+#endif
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "CreateThread"), -1);
+ //FUZZ: enable check_for_lack_ACE_OS
+ }
+ 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;
+}