summaryrefslogtreecommitdiff
path: root/ACE/performance-tests/Misc
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/performance-tests/Misc')
-rw-r--r--ACE/performance-tests/Misc/Makefile.am157
-rw-r--r--ACE/performance-tests/Misc/Misc.mpc67
-rw-r--r--ACE/performance-tests/Misc/basic_func.cpp49
-rw-r--r--ACE/performance-tests/Misc/basic_func.h77
-rw-r--r--ACE/performance-tests/Misc/basic_perf.cpp646
-rw-r--r--ACE/performance-tests/Misc/childbirth_time.cpp403
-rw-r--r--ACE/performance-tests/Misc/context_switch_time.cpp1318
-rw-r--r--ACE/performance-tests/Misc/preempt.cpp467
-rw-r--r--ACE/performance-tests/Misc/test_guard.cpp119
-rw-r--r--ACE/performance-tests/Misc/test_mutex.cpp238
-rw-r--r--ACE/performance-tests/Misc/test_naming.cpp199
-rw-r--r--ACE/performance-tests/Misc/test_singleton.cpp179
-rw-r--r--ACE/performance-tests/Misc/test_singleton.h24
13 files changed, 3943 insertions, 0 deletions
diff --git a/ACE/performance-tests/Misc/Makefile.am b/ACE/performance-tests/Misc/Makefile.am
new file mode 100644
index 00000000000..e454644170b
--- /dev/null
+++ b/ACE/performance-tests/Misc/Makefile.am
@@ -0,0 +1,157 @@
+## Process this file with automake to create Makefile.in
+##
+## $Id$
+##
+## This file was generated by MPC. Any changes made directly to
+## this file will be lost the next time it is generated.
+##
+## MPC Command:
+## ./bin/mwc.pl -type automake -noreldefs ACE.mwc
+
+ACE_BUILDDIR = $(top_builddir)
+ACE_ROOT = $(top_srcdir)
+
+noinst_PROGRAMS =
+
+## Makefile.Misc_Basic_Perf.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += basic_perf
+
+basic_perf_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+basic_perf_SOURCES = \
+ basic_func.cpp \
+ basic_perf.cpp \
+ basic_func.h
+
+basic_perf_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Misc_Childbirth_Time.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += childbirth_time
+
+childbirth_time_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+childbirth_time_SOURCES = \
+ childbirth_time.cpp \
+ basic_func.h \
+ test_singleton.h
+
+childbirth_time_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Misc_Context_Switch_Time.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += context_switch_time
+
+context_switch_time_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+context_switch_time_SOURCES = \
+ context_switch_time.cpp \
+ basic_func.h \
+ test_singleton.h
+
+context_switch_time_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Misc_Preempt.am
+
+noinst_PROGRAMS += preempt
+
+preempt_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+preempt_SOURCES = \
+ preempt.cpp \
+ basic_func.h \
+ test_singleton.h
+
+preempt_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+## Makefile.Misc_Test_Mutex.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += test_mutex
+
+test_mutex_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_mutex_SOURCES = \
+ test_mutex.cpp \
+ basic_func.h \
+ test_singleton.h
+
+test_mutex_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Misc_Test_Naming.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += test_naming
+
+test_naming_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_naming_SOURCES = \
+ test_naming.cpp \
+ basic_func.h \
+ test_singleton.h
+
+test_naming_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Makefile.Misc_Test_Singleton.am
+
+if !BUILD_ACE_FOR_TAO
+
+noinst_PROGRAMS += test_singleton
+
+test_singleton_CPPFLAGS = \
+ -I$(ACE_ROOT) \
+ -I$(ACE_BUILDDIR)
+
+test_singleton_SOURCES = \
+ test_singleton.cpp \
+ test_singleton.h
+
+test_singleton_LDADD = \
+ $(ACE_BUILDDIR)/ace/libACE.la
+
+endif !BUILD_ACE_FOR_TAO
+
+## Clean up template repositories, etc.
+clean-local:
+ -rm -f *~ *.bak *.rpo *.sym lib*.*_pure_* core core.*
+ -rm -f gcctemp.c gcctemp so_locations *.ics
+ -rm -rf cxx_repository ptrepository ti_files
+ -rm -rf templateregistry ir.out
+ -rm -rf ptrepository SunWS_cache Templates.DB
diff --git a/ACE/performance-tests/Misc/Misc.mpc b/ACE/performance-tests/Misc/Misc.mpc
new file mode 100644
index 00000000000..3be2b7e3078
--- /dev/null
+++ b/ACE/performance-tests/Misc/Misc.mpc
@@ -0,0 +1,67 @@
+// -*- MPC -*-
+// $Id$
+
+project(*basic_perf) : aceexe {
+ avoids += ace_for_tao
+ exename = basic_perf
+ Source_Files {
+ basic_func.cpp
+ basic_perf.cpp
+ }
+}
+
+project(*childbirth_time) : aceexe {
+ avoids += ace_for_tao
+ exename = childbirth_time
+ Source_Files {
+ childbirth_time.cpp
+ }
+}
+
+project(*context_switch_time) : aceexe {
+ avoids += ace_for_tao
+ exename = context_switch_time
+ Source_Files {
+ context_switch_time.cpp
+ }
+}
+
+project(*test_mutex) : aceexe {
+ avoids += ace_for_tao
+ exename = test_mutex
+ Source_Files {
+ test_mutex.cpp
+ }
+}
+
+project(*test_naming) : aceexe {
+ avoids += ace_for_tao
+ requires += ace_other
+ exename = test_naming
+ Source_Files {
+ test_naming.cpp
+ }
+}
+
+project(*test_singleton) : aceexe {
+ avoids += ace_for_tao
+ exename = test_singleton
+ Source_Files {
+ test_singleton.cpp
+ }
+}
+
+project(*preempt) : aceexe {
+ exename = preempt
+ Source_Files {
+ preempt.cpp
+ }
+}
+
+// May need to add an ace_obsolete_guard_class feature
+//project(*test_guard) : aceexe {
+// exename = test_guard
+// Source_Files {
+// test_guard.cpp
+// }
+//}
diff --git a/ACE/performance-tests/Misc/basic_func.cpp b/ACE/performance-tests/Misc/basic_func.cpp
new file mode 100644
index 00000000000..a76565d74fb
--- /dev/null
+++ b/ACE/performance-tests/Misc/basic_func.cpp
@@ -0,0 +1,49 @@
+// $Id$
+
+#include "basic_func.h"
+
+ACE_RCSID(Misc, basic_func, "$Id$")
+
+int A, BB, C, D, E, F;
+
+void
+func ()
+{
+ DO_SOMETHING
+}
+
+
+void
+Foo::func ()
+{
+ DO_SOMETHING
+}
+
+
+Foo_v::~Foo_v ()
+{
+}
+
+
+void
+Foo_v::func ()
+{
+ DO_SOMETHING
+}
+
+
+void
+Foo_v::v_func ()
+{
+ DO_SOMETHING
+}
+
+
+void
+Foo_d_v::v_func ()
+{
+ DO_SOMETHING
+}
+
+
+// EOF
diff --git a/ACE/performance-tests/Misc/basic_func.h b/ACE/performance-tests/Misc/basic_func.h
new file mode 100644
index 00000000000..bbaf4d4cfb9
--- /dev/null
+++ b/ACE/performance-tests/Misc/basic_func.h
@@ -0,0 +1,77 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// performance-tests/Misc
+//
+// = FILENAME
+// basic_func.h
+//
+// = DESCRIPTION
+// For use with basic_perf.cpp.
+//
+// = AUTHOR
+// David Levine
+//
+// ============================================================================
+
+#ifndef BASIC_FUNC_H
+#define BASIC_FUNC_H
+
+#include "ace/ACE.h"
+
+#if !defined (ACE_LACKS_PRAGMA_ONCE)
+# pragma once
+#endif /* ACE_LACKS_PRAGMA_ONCE */
+
+extern int A,BB,C,D,E,F;
+
+// If your compiler optimizes away Empty_Iteration_Test::run (), then
+// #defining ACE_HAS_OPTIMIZED_NULL_FUNCTIONS may help produce more
+// reasonable numbers.
+#if defined (_MSC_VER)
+ // MSVC 5.0 needs it . . .
+# define ACE_HAS_OPTIMIZED_NULL_FUNCTIONS
+#endif /* _MSC_VER */
+
+#if defined (ACE_HAS_OPTIMIZED_NULL_FUNCTIONS)
+# define EXPR(R,A,BB,C,D) (R=(A*BB + C*D))
+# define DO_SOMETHING EXPR(A,BB,EXPR(F,A,E,C,BB),EXPR(BB,F,A,D,E),EXPR(E,BB,F,A,C));
+#else /* ACE_HAS_OPTIMIZED_NULL_FUNCTIONS */
+# define DO_SOMETHING
+#endif /* ACE_HAS_OPTIMIZED_NULL_FUNCTIONS */
+
+
+// An external (global) function.
+void func ();
+
+
+// A class with no virtual functions.
+class Foo
+{
+ public:
+ void inline_func () { DO_SOMETHING }
+ void func ();
+};
+
+
+// A class with a virtual function.
+class Foo_v
+{
+ public:
+ virtual ~Foo_v ();
+ void inline_func () { DO_SOMETHING }
+ void func ();
+ virtual void v_func ();
+};
+
+
+// A derived class.
+class Foo_d_v : public Foo_v
+{
+ public:
+ virtual void v_func ();
+};
+
+#endif /* BASIC_FUNC_H */
diff --git a/ACE/performance-tests/Misc/basic_perf.cpp b/ACE/performance-tests/Misc/basic_perf.cpp
new file mode 100644
index 00000000000..d084e84e1b2
--- /dev/null
+++ b/ACE/performance-tests/Misc/basic_perf.cpp
@@ -0,0 +1,646 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// performance-tests/Misc
+//
+// = FILENAME
+// basic_perf.cpp
+//
+// = DESCRIPTION
+// Times various simple operations.
+//
+// With Sun C++, use -O2: make CFLAGS="-mt -O2" BIN=basic_perf
+// -fast seems to produce slower times.
+//
+// = AUTHOR
+// David Levine
+//
+// ============================================================================
+
+#include "basic_func.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_main.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_stdlib.h"
+#include "ace/OS_NS_sys_utsname.h"
+
+ACE_RCSID(Misc, basic_perf, "$Id$")
+
+static const char usage [] = "[-? |\n"
+ " [-i <iterations> [1000000]]";
+
+// These are global. They appear to bust the CPU cache, on an Ultra 2
+// w/Sun C++ 4.2.
+static u_int iterations = 1000000;
+Foo foo;
+Foo_v foo_v;
+
+inline
+void
+inline_func ()
+{
+ DO_SOMETHING
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// function per_iteration
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// Given an elapsed time in nanoseconds, returns the time per iteration
+// in microseconds.
+static
+inline
+double
+per_iteration (const ACE_hrtime_t elapsed /* nanoseconds */)
+{
+ double ms_per_iteration = (double) ACE_CU64_TO_CU32 (elapsed) / 1000.0 /
+ (double) iterations;
+
+ // Don't print out "-0.000" or "-0.001" . . .
+ return -0.002 < ms_per_iteration && ms_per_iteration < 0.0
+ ? 0.0
+ : ms_per_iteration;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Basic_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Basic_Test
+{
+public:
+ Basic_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time);
+ virtual ~Basic_Test (void);
+
+ virtual void run (void) = 0;
+
+ double iteration_time (void);
+
+ void print_iteration_time (const char *message);
+
+protected:
+ ACE_hrtime_t elapsed_time_;
+
+ void start_timing (void)
+ {
+ timer_.reset ();
+ timer_.start ();
+ }
+
+ void stop_timing (void)
+ {
+ timer_.stop ();
+ timer_.elapsed_time (elapsed_time_);
+ }
+
+private:
+ ACE_High_Res_Timer &timer_;
+ ACE_hrtime_t empty_iteration_time_;
+
+ // Require the timer reference.
+ Basic_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Basic_Test (const Basic_Test &);
+ Basic_Test &operator= (const Basic_Test &);
+};
+
+Basic_Test::Basic_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : elapsed_time_ (0),
+ timer_ (timer),
+ empty_iteration_time_ (empty_iteration_time)
+{
+}
+
+Basic_Test::~Basic_Test (void)
+{
+}
+
+double
+Basic_Test::iteration_time (void)
+{
+ return per_iteration (elapsed_time_ > empty_iteration_time_ ?
+ elapsed_time_ - empty_iteration_time_ :
+ static_cast<ACE_hrtime_t> (0));
+}
+
+void
+Basic_Test::print_iteration_time (const char *message)
+{
+ ACE_DEBUG ((LM_INFO, " %-41s %8.3f\n",
+ message,
+ this->iteration_time ()));
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Empty_Iteration_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Empty_Iteration_Test : public Basic_Test
+{
+public:
+ Empty_Iteration_Test (ACE_High_Res_Timer &timer) : Basic_Test (timer, 0) {}
+ virtual ~Empty_Iteration_Test (void) {};
+
+ virtual void run (void);
+
+ ACE_hrtime_t empty_iteration_time (void) const
+ {
+ return elapsed_time_;
+ }
+
+private:
+ // Require the timer reference.
+ Empty_Iteration_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Empty_Iteration_Test (const Empty_Iteration_Test &);
+ Empty_Iteration_Test &operator= (const Empty_Iteration_Test &);
+};
+
+void
+Empty_Iteration_Test::run (void)
+{
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ {
+ DO_SOMETHING
+ }
+
+ this->stop_timing ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Inline_Call_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Inline_Call_Test : public Basic_Test
+{
+public:
+ Inline_Call_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : Basic_Test (timer, empty_iteration_time) {}
+ virtual ~Inline_Call_Test (void) {};
+
+ virtual void run (void);
+
+private:
+ // Require the timer reference.
+ Inline_Call_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Inline_Call_Test (const Inline_Call_Test &);
+ Inline_Call_Test &operator= (const Inline_Call_Test &);
+};
+
+void
+Inline_Call_Test::run (void)
+{
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ inline_func ();
+
+ this->stop_timing ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Noninline_Call_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Noninline_Call_Test : public Basic_Test
+{
+public:
+ Noninline_Call_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : Basic_Test (timer, empty_iteration_time) {}
+ virtual ~Noninline_Call_Test (void) {};
+
+ virtual void run (void);
+
+private:
+ // Require the timer reference.
+ Noninline_Call_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Noninline_Call_Test (const Noninline_Call_Test &);
+ Noninline_Call_Test &operator= (const Noninline_Call_Test &);
+};
+
+void
+Noninline_Call_Test::run (void)
+{
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ func ();
+
+ this->stop_timing ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Inline_Member_Call_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Inline_Member_Call_Test : public Basic_Test
+{
+public:
+ Inline_Member_Call_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : Basic_Test (timer, empty_iteration_time) {}
+ virtual ~Inline_Member_Call_Test (void) {};
+
+ virtual void run (void);
+
+private:
+ // Require the timer reference.
+ Inline_Member_Call_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Inline_Member_Call_Test (const Inline_Member_Call_Test &);
+ Inline_Member_Call_Test &operator= (const Inline_Member_Call_Test &);
+};
+
+void
+Inline_Member_Call_Test::run (void)
+{
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ foo.inline_func ();
+
+ this->stop_timing ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Noninline_Member_Call_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Noninline_Member_Call_Test : public Basic_Test
+{
+public:
+ Noninline_Member_Call_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : Basic_Test (timer, empty_iteration_time) {}
+ virtual ~Noninline_Member_Call_Test (void) {};
+
+ virtual void run (void);
+
+private:
+ // Require the timer reference.
+ Noninline_Member_Call_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Noninline_Member_Call_Test (const Noninline_Member_Call_Test &);
+ Noninline_Member_Call_Test &operator= (const Noninline_Member_Call_Test &);
+};
+
+void
+Noninline_Member_Call_Test::run (void)
+{
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ foo.func ();
+
+ this->stop_timing ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Inline_Member_With_Virtual_Call_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Inline_Member_With_Virtual_Call_Test : public Basic_Test
+{
+public:
+ Inline_Member_With_Virtual_Call_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : Basic_Test (timer, empty_iteration_time) {}
+ virtual ~Inline_Member_With_Virtual_Call_Test (void) {};
+
+ virtual void run (void);
+
+private:
+ // Require the timer reference.
+ Inline_Member_With_Virtual_Call_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Inline_Member_With_Virtual_Call_Test (
+ const Inline_Member_With_Virtual_Call_Test &);
+ Inline_Member_With_Virtual_Call_Test &operator= (
+ const Inline_Member_With_Virtual_Call_Test &);
+};
+
+void
+Inline_Member_With_Virtual_Call_Test::run (void)
+{
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ foo_v.inline_func ();
+
+ this->stop_timing ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Noninline_Member_With_Virtual_Call_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Noninline_Member_With_Virtual_Call_Test : public Basic_Test
+{
+public:
+ Noninline_Member_With_Virtual_Call_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : Basic_Test (timer, empty_iteration_time) {}
+ virtual ~Noninline_Member_With_Virtual_Call_Test (void) {};
+
+ virtual void run (void);
+
+private:
+ // Require the timer reference.
+ Noninline_Member_With_Virtual_Call_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Noninline_Member_With_Virtual_Call_Test
+ (const Noninline_Member_With_Virtual_Call_Test &);
+ Noninline_Member_With_Virtual_Call_Test &operator=
+ (const Noninline_Member_With_Virtual_Call_Test &);
+};
+
+void
+Noninline_Member_With_Virtual_Call_Test::run (void)
+{
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ foo_v.func ();
+
+ this->stop_timing ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Virtual_Member_Optimizable_Call_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Virtual_Member_Optimizable_Call_Test : public Basic_Test
+{
+public:
+ Virtual_Member_Optimizable_Call_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : Basic_Test (timer, empty_iteration_time) {}
+ virtual ~Virtual_Member_Optimizable_Call_Test (void) {};
+
+ virtual void run (void);
+
+private:
+ // Require the timer reference.
+ Virtual_Member_Optimizable_Call_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Virtual_Member_Optimizable_Call_Test (
+ const Virtual_Member_Optimizable_Call_Test &);
+ Virtual_Member_Optimizable_Call_Test &operator= (
+ const Virtual_Member_Optimizable_Call_Test &);
+};
+
+void
+Virtual_Member_Optimizable_Call_Test::run (void)
+{
+ Foo_v &fv_o = foo_v;
+
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ fv_o.v_func ();
+
+ this->stop_timing ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Virtual_Member_Call_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+class Virtual_Member_Call_Test : public Basic_Test
+{
+public:
+ Virtual_Member_Call_Test (ACE_High_Res_Timer &timer,
+ ACE_hrtime_t empty_iteration_time)
+ : Basic_Test (timer, empty_iteration_time) {}
+ virtual ~Virtual_Member_Call_Test (void) {};
+
+ virtual void run (void);
+
+private:
+ // Require the timer reference.
+ Virtual_Member_Call_Test (void);
+
+ // Force construction of independent instances by prohibiting copying.
+ Virtual_Member_Call_Test (const Virtual_Member_Call_Test &);
+ Virtual_Member_Call_Test &operator= (const Virtual_Member_Call_Test &);
+};
+
+void
+Virtual_Member_Call_Test::run (void)
+{
+ Foo_v *fv;
+
+ if (iterations < 2)
+ fv = new Foo_v;
+ else
+ fv = new Foo_d_v;
+
+ this->start_timing ();
+
+ for (u_int i = 0; i < iterations; ++i)
+ fv->v_func ();
+
+ this->stop_timing ();
+
+ delete fv;
+ fv = 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// function get_options
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+static
+unsigned int
+get_options (int argc, ACE_TCHAR *argv [])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("i:?"));
+ int opt;
+
+ while ((opt = get_opt ()) != EOF)
+ {
+ switch (opt)
+ {
+ case 'i':
+ {
+ int temp = ACE_OS::atoi (get_opt.opt_arg ());
+ if (temp > 0)
+ iterations = (u_int) temp;
+ else
+ {
+ ACE_DEBUG ((LM_ERROR, "%s: number of iterations must be > 0\n",
+ argv [0]));
+ return 1;
+ }
+ break;
+ }
+ case '?':
+ ACE_DEBUG ((LM_INFO, "usage: %s %s\n", argv [0], usage));
+ ACE_OS::exit (0);
+ break;
+ default:
+ ACE_DEBUG ((LM_ERROR, "%s: unknown arg, %c\n", argv [0],
+ (char) opt));
+ ACE_DEBUG ((LM_ERROR, "usage: %s %s\n", argv [0], usage));
+ return 1;
+ }
+ }
+
+ switch (argc - get_opt.opt_ind ())
+ {
+ case 0:
+ // OK
+ break;
+ default:
+ ACE_DEBUG ((LM_ERROR, "%s: too many arguments\n", argv [0]));
+ ACE_DEBUG ((LM_ERROR, "usage: %s %s\n", argv [0], usage));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// function main
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ if (get_options (argc, argv))
+ ACE_OS::exit (-1);
+
+ ACE_utsname name;
+
+ if (ACE_OS::uname (&name) != -1)
+ ACE_DEBUG ((LM_INFO, "%s (%s), %s %s at %T\n",
+ name.nodename, name.machine, name.sysname, name.release));
+
+ ACE_DEBUG ((LM_INFO, "%u iterations\n", iterations));
+
+
+ // Use one timer for all the tests. No particular reason why.
+ ACE_High_Res_Timer timer;
+
+ // Calculate the time for an "empty iteration", and subtract it
+ // from each test time.
+ ACE_hrtime_t iteration_time;
+
+ Empty_Iteration_Test empty_iteration_test (timer);
+ empty_iteration_test.run ();
+ ACE_DEBUG ((LM_INFO, "An empty iteration costs %8.3f microseconds.\n\n",
+ empty_iteration_test.iteration_time ()));
+ iteration_time = empty_iteration_test.empty_iteration_time ();
+
+
+ // Run the real tests . . .
+ Inline_Call_Test inline_call_test (timer, iteration_time);
+ inline_call_test.run ();
+
+ Noninline_Call_Test noninline_call_test (timer, iteration_time);
+ noninline_call_test.run ();
+
+ Inline_Member_Call_Test inline_member_call_test (timer, iteration_time);
+ inline_member_call_test.run ();
+
+ Noninline_Member_Call_Test noninline_member_call_test (
+ timer, iteration_time);
+ noninline_member_call_test.run ();
+
+ Inline_Member_With_Virtual_Call_Test
+ inline_member_with_virtual_call_test (timer, iteration_time);
+ inline_member_with_virtual_call_test.run ();
+
+ Noninline_Member_With_Virtual_Call_Test
+ noninline_member_with_virtual_call_test (timer, iteration_time);
+ noninline_member_with_virtual_call_test.run ();
+
+ Virtual_Member_Optimizable_Call_Test
+ virtual_member_optimizable_call_test (timer, iteration_time);
+ virtual_member_optimizable_call_test.run ();
+
+ Virtual_Member_Call_Test virtual_member_call_test (timer, iteration_time);
+ virtual_member_call_test.run ();
+
+
+ // Print results . . .
+ ACE_DEBUG ((LM_INFO, "operation "
+ "time, microseconds\n"));
+ ACE_DEBUG ((LM_INFO, "========= "
+ "=================="));
+
+ ACE_DEBUG ((LM_INFO, "\nglobal function calls:\n"));
+ inline_call_test.print_iteration_time ("inline function call");
+ noninline_call_test.print_iteration_time ("non-inline function call");
+
+ ACE_DEBUG ((LM_INFO, "\nmember function calls:\n"));
+ inline_member_call_test.print_iteration_time (
+ "inline member function call");
+ noninline_member_call_test.print_iteration_time (
+ "non-inline member function call");
+
+ ACE_DEBUG ((LM_INFO, "\nmember function calls, class has a virtual "
+ "function:\n"));
+ inline_member_with_virtual_call_test.print_iteration_time (
+ "inline member function with virtual call");
+ noninline_member_with_virtual_call_test.print_iteration_time (
+ "non-inline member function w/virtual call");
+
+ ACE_DEBUG ((LM_INFO, "\nvirtual member function calls:\n"));
+ virtual_member_optimizable_call_test.print_iteration_time (
+ "virtual member function call, optimizable");
+ virtual_member_call_test.print_iteration_time (
+ "virtual member function call");
+
+ return 0;
+}
+
+
+// EOF
diff --git a/ACE/performance-tests/Misc/childbirth_time.cpp b/ACE/performance-tests/Misc/childbirth_time.cpp
new file mode 100644
index 00000000000..913b4de0e25
--- /dev/null
+++ b/ACE/performance-tests/Misc/childbirth_time.cpp
@@ -0,0 +1,403 @@
+// $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:
+ 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;
+}
diff --git a/ACE/performance-tests/Misc/context_switch_time.cpp b/ACE/performance-tests/Misc/context_switch_time.cpp
new file mode 100644
index 00000000000..70e9a0610a0
--- /dev/null
+++ b/ACE/performance-tests/Misc/context_switch_time.cpp
@@ -0,0 +1,1318 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// (none)
+//
+// = FILENAME
+// context_switch_time.cpp
+//
+// = DESCRIPTION
+// Program that calculates context switch time between threads.
+// The Suspend-Resume test is based on the Task Context Switching
+// measurement approach described in:
+// Darren Cathey<br>
+// "RTOS Benchmarking -- All Things Considered . . ."<br>
+// <a href="http://www.realtime-info.be"><em>Real-Time Magazine</em></a>,
+// Second Quarter 1993,
+// <em>reprinted by <a href="http://www.wrs.com/artreqfm.html">Wind River
+// Systems</a></em><p>
+// which in turn is based on Superconducting Super Collider (SSC)
+// Laboratory Ping Suspend/Resume Task and Suspend/Resume Task benchmarks.
+// It measures two different times:
+// 1) The time to resume a blocked high priority task, which does
+// nothing other than block immediately. A lower priority task
+// resumes the high priority task, so the elapsed time includes
+// two context switches, one task suspend, and one task resume.
+// 2) The time to suspend and resume a low priority task that does
+// nothing. There is no context switching. This time is subtracted
+// from the one described in 1) above, and the result is divided by
+// two to yield the context switch time.
+//
+// Notes:
+// On Solaris 2.5.1, it appears that the lowest context switching times,
+// at least on a single-CPU machine, are obtained _without_ creating new
+// LWPs for new threads (THR_NEW_LWP). The -n option enables the use of
+// THR_NEW_LWP for testing.
+//
+// = CREATION DATE
+// 17 January 1997
+//
+// = AUTHOR
+// David L. Levine
+//
+// ============================================================================
+
+static const char usage [] = "[-? |\n"
+ " [-c <repeat counter, 0 means forever>]\n"
+ " [-n to spawn a new LWP with each thread\n"
+ "[<iterations>]]";
+
+#include "ace/OS_NS_stdio.h"
+#include "ace/OS_main.h"
+#include "ace/Task.h"
+#include "ace/Sched_Params.h"
+#include "ace/Stats.h"
+#include "ace/High_Res_Timer.h"
+#include "ace/Get_Opt.h"
+#include "ace/Thread_Semaphore.h"
+#include "ace/Barrier.h"
+#include "ace/OS_NS_unistd.h"
+#include "ace/OS_NS_errno.h"
+
+ACE_RCSID(Misc, context_switch_time, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+#if !defined (ACE_DEBUG_CST)
+# define ACE_DEBUG_CST 0
+#endif /* ACE_DEBUG_CST */
+
+static const u_int LOW_PRIORITY = ACE_THR_PRI_FIFO_DEF;
+static u_int HIGH_PRIORITY;
+
+// Global test configuration parameters.
+static ACE_UINT32 counter = 1;
+static ACE_UINT32 num_iterations = 1000;
+static ACE_UINT32 new_lwp = 0;
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Low_Priority_Null_Task
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class Low_Priority_Null_Task : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ Low_Priority_Null_Task ();
+ virtual ~Low_Priority_Null_Task ();
+
+ virtual int svc ();
+
+ // Called by other task: it returns when this task is ready to
+ // continue.
+ void ready () { initialized_.acquire (); }
+
+ void done ();
+
+ ACE_hthread_t thread_id () const { return thread_id_; }
+private:
+ ACE_hthread_t thread_id_;
+ ACE_Semaphore initialized_; // Blocks until thread_id_ is assigned.
+ ACE_Semaphore blocked_semaphore_;
+
+ // Force proper construction of independent instances.
+ Low_Priority_Null_Task (const Low_Priority_Null_Task &);
+ Low_Priority_Null_Task &operator= (const Low_Priority_Null_Task &);
+};
+
+inline
+Low_Priority_Null_Task::Low_Priority_Null_Task() :
+ ACE_Task<ACE_MT_SYNCH> (ACE_Thread_Manager::instance ()),
+ initialized_ (0), // initialize to locked, then unlock when ready
+ blocked_semaphore_ (0)
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task ctor\n"));
+#endif /* ACE_DEBUG_CST */
+
+ if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
+ 1, 0, LOW_PRIORITY))
+ ACE_OS::perror (ACE_TEXT("activate"));
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task ctor, activated\n"));
+#endif /* ACE_DEBUG_CST */
+}
+
+Low_Priority_Null_Task::~Low_Priority_Null_Task()
+{
+}
+
+int
+Low_Priority_Null_Task::svc ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task::svc (), entering"));
+#endif /* ACE_DEBUG_CST */
+
+ ACE_Thread_Manager::instance ()->thr_self (thread_id_);
+ initialized_.release ();
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_));
+#endif /* ACE_DEBUG_CST */
+
+ // This task must never actually execute, so just have it block
+ // on a semaphore forever . . .
+ blocked_semaphore_.acquire ();
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Low_Priority_Task::svc, finishing\n"));
+#endif /* ACE_DEBUG_CST */
+
+ return 0;
+}
+
+void
+Low_Priority_Null_Task::done ()
+{
+ blocked_semaphore_.release ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Suspend_Resume_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class Suspend_Resume_Test : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ Suspend_Resume_Test (const ACE_UINT32 iterations);
+ virtual ~Suspend_Resume_Test ();
+
+ virtual int svc ();
+
+ ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
+private:
+ const ACE_UINT32 iterations_;
+
+ Low_Priority_Null_Task low_;
+
+ ACE_High_Res_Timer timer_;
+
+ ACE_hrtime_t elapsed_time_;
+
+ // Force proper construction of independent instances.
+ Suspend_Resume_Test ();
+ Suspend_Resume_Test (const Suspend_Resume_Test &);
+ Suspend_Resume_Test &operator= (const Suspend_Resume_Test &);
+};
+
+Suspend_Resume_Test::Suspend_Resume_Test (const ACE_UINT32 iterations) :
+ ACE_Task<ACE_MT_SYNCH> (),
+ iterations_ (iterations),
+ low_ (),
+ timer_ ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test ctor\n"));
+#endif /* ACE_DEBUG_CST */
+
+ if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
+ 1, 0, HIGH_PRIORITY))
+ ACE_OS::perror (ACE_TEXT("activate"));
+}
+
+Suspend_Resume_Test::~Suspend_Resume_Test()
+{
+}
+
+int
+Suspend_Resume_Test::svc ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_hthread_t thread_id;
+ ACE_Thread_Manager::instance ()->thr_self (thread_id);
+
+ ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test::svc (), thread ID is %d\n",
+ thread_id));
+#endif /* ACE_DEBUG_CST */
+
+ low_.ready ();
+
+ // For information: the cost of the just the loop itself below,
+ // without the suspend and resume calls, on a 166 MHz Ultrasparc
+ // is about 12.3 nanoseconds per iteration.
+
+ timer_.start ();
+
+ for (ACE_UINT32 i = 0; i < iterations_; ++i)
+ {
+#if ACE_DEBUG_CST > 0
+ if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0)
+ ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test::svc (), iteration %u\n",
+ i));
+#endif /* ACE_DEBUG_CST */
+
+ if (ACE_OS::thr_suspend (low_.thread_id ()) != 0)
+ {
+ ACE_ERROR ((LM_ERROR, "%p\n", "thr_suspend"));
+ low_.done ();
+ return -1;
+ }
+
+ if (ACE_OS::thr_continue (low_.thread_id ()) != 0 &&
+ errno != EINVAL)
+ // EINVAL is OK: it just means that the thread needs to be joined.
+ {
+ ACE_ERROR ((LM_ERROR, "%p\n", "thr_continue"));
+ low_.done ();
+ return -1;
+ }
+ }
+
+ timer_.stop ();
+ timer_.elapsed_microseconds (elapsed_time_);
+
+ low_.done ();
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test::svc, finishing\n"));
+#endif /* ACE_DEBUG_CST */
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class High_Priority_Simple_Task
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class High_Priority_Simple_Task : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ High_Priority_Simple_Task ();
+ virtual ~High_Priority_Simple_Task ();
+
+ virtual int svc ();
+
+ // called by other task: it returns when this task is ready to
+ // continue
+ void ready () { initialized_.acquire (); }
+
+ void done ();
+
+ ACE_hthread_t thread_id () const { return thread_id_; }
+ ACE_UINT32 iterations () const { return iterations_; }
+private:
+ ACE_hthread_t thread_id_;
+ ACE_Semaphore initialized_; // Block until thread_id_ is assigned.
+ int terminate_;
+ ACE_UINT32 iterations_;
+
+ // Force proper construction of independent instances.
+ High_Priority_Simple_Task (const High_Priority_Simple_Task &);
+ High_Priority_Simple_Task &operator= (const High_Priority_Simple_Task &);
+};
+
+inline
+High_Priority_Simple_Task::High_Priority_Simple_Task() :
+ ACE_Task<ACE_MT_SYNCH> (ACE_Thread_Manager::instance ()),
+ initialized_ (0), // Initialize to locked, then unlock when ready.
+ terminate_ (0),
+ iterations_ (0)
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task ctor\n"));
+#endif /* ACE_DEBUG_CST */
+
+ if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
+ 1, 0, HIGH_PRIORITY))
+ ACE_OS::perror (ACE_TEXT("activate"));
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task ctor, activated\n"));
+#endif /* ACE_DEBUG_CST */
+}
+
+High_Priority_Simple_Task::~High_Priority_Simple_Task()
+{
+}
+
+int
+High_Priority_Simple_Task::svc ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc (), entering"));
+#endif /* ACE_DEBUG_CST */
+
+ ACE_Thread_Manager::instance ()->thr_self (thread_id_);
+ initialized_.release ();
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_));
+#endif /* ACE_DEBUG_CST */
+
+ for (ACE_UINT32 i = 0; ! terminate_; ++i)
+ {
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, suspend self ("
+ "%u)\n", thread_id_));
+#endif /* ACE_DEBUG_CST */
+
+ ++iterations_;
+
+ // immediately suspend self
+ if (ACE_OS::thr_suspend (thread_id_) != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "thr_suspend"), -1);
+ }
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, resumed (%u)\n",
+ thread_id_));
+#endif /* ACE_DEBUG_CST */
+ }
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, finishing\n"));
+#endif /* ACE_DEBUG_CST */
+
+ return 0;
+}
+
+inline
+void
+High_Priority_Simple_Task::done ()
+{
+ terminate_ = 1;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Ping_Suspend_Resume_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class Ping_Suspend_Resume_Test : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ Ping_Suspend_Resume_Test (const ACE_UINT32 iterations);
+ virtual ~Ping_Suspend_Resume_Test ();
+
+ virtual int svc ();
+
+ ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
+private:
+ const ACE_UINT32 iterations_;
+
+ High_Priority_Simple_Task high_;
+
+ ACE_High_Res_Timer timer_;
+
+ ACE_hrtime_t elapsed_time_;
+
+ // Force proper construction of independent instances.
+ Ping_Suspend_Resume_Test ();
+ Ping_Suspend_Resume_Test (const Ping_Suspend_Resume_Test &);
+ Ping_Suspend_Resume_Test &operator= (const Ping_Suspend_Resume_Test &);
+};
+
+Ping_Suspend_Resume_Test::Ping_Suspend_Resume_Test (
+ const ACE_UINT32 iterations)
+:
+ ACE_Task<ACE_MT_SYNCH> (),
+ iterations_ (iterations),
+ high_ (),
+ timer_ ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test ctor\n"));
+#endif /* ACE_DEBUG_CST */
+
+ if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
+ 1, 0, LOW_PRIORITY))
+ ACE_OS::perror (ACE_TEXT("activate"));
+}
+
+Ping_Suspend_Resume_Test::~Ping_Suspend_Resume_Test()
+{
+}
+
+int
+Ping_Suspend_Resume_Test::svc ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc (), entering"));
+
+ ACE_hthread_t thread_id;
+ ACE_Thread_Manager::instance ()->thr_self (thread_id);
+
+ ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id));
+#endif /* ACE_DEBUG_CST */
+
+ high_.ready ();
+
+#if ACE_DEBUG_CST > 0
+ int priority, high_priority;
+ ACE_OS::thr_getprio (thread_id, priority);
+ ACE_OS::thr_getprio (high_.thread_id (), high_priority);
+ ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc (), priority is %d, "
+ ", high thread priority is %d\n",
+ priority, high_priority));
+#endif /* ACE_DEBUG_CST */
+
+ // For information: the cost of the just the loop itself below,
+ // without the suspend and resume calls, on a 166 MHz Ultrasparc
+ // is about 12.3 nanoseconds per iteration.
+
+ timer_.start ();
+
+ ACE_UINT32 i;
+
+ for (i = 0; i < iterations_; ++i)
+ {
+#if ACE_DEBUG_CST > 0
+ if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc (), iteration "
+ "%d, continue high-priority thread %u\n",
+ i, high_.thread_id ()));
+ }
+#endif /* ACE_DEBUG_CST */
+ if (ACE_OS::thr_continue (high_.thread_id ()) != 0 &&
+ errno != EINVAL)
+ // EINVAL is OK: it just means that the thread needs to be joined.
+ {
+ ACE_ERROR ((LM_ERROR, "%p\n", "thr_continue"));
+ high_.done ();
+ return -1;
+ }
+ }
+
+ timer_.stop ();
+ timer_.elapsed_microseconds (elapsed_time_);
+
+ high_.done ();
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc: told high priority "
+ "task to terminate\n"));
+#endif /* ACE_DEBUG_CST */
+
+ // Resume the thread until thr_continue fails, indicating that it has
+ // finished.
+ for (i = 0; i < 10000 && ! ACE_OS::thr_continue (high_.thread_id ());
+ ++i) /* null */;
+
+ // Don't count the one iteration that was used to allow the high-priority
+ // thread to terminate.
+ if (high_.iterations () < iterations_)
+ ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test: high priority task "
+ "executed only %u iterations!\n",
+ high_.iterations ()));
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc, finishing\n"));
+#endif /* ACE_DEBUG_CST */
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Yield_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class Yield_Test : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ Yield_Test (const ACE_UINT32 iterations);
+ virtual ~Yield_Test ();
+
+ virtual int svc ();
+
+ ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
+private:
+ const ACE_UINT32 iterations_;
+#if defined (VXWORKS)
+ ACE_Thread_Mutex mutex_;
+ u_int started_;
+ u_int stopped_;
+#else /* ! VXWORKS */
+ ACE_Barrier timer_barrier_;
+#endif /* ! VXWORKS */
+ ACE_High_Res_Timer timer_;
+ ACE_hrtime_t elapsed_time_;
+
+ // Force proper construction of independent instances.
+ Yield_Test ();
+ Yield_Test (const Yield_Test &);
+ Yield_Test &operator= (const Yield_Test &);
+};
+
+Yield_Test::Yield_Test (const ACE_UINT32 iterations) :
+ ACE_Task<ACE_MT_SYNCH> (),
+ iterations_ (iterations),
+#if defined (VXWORKS)
+ mutex_ (),
+ started_ (0),
+ stopped_ (0),
+#else /* ! VXWORKS */
+ timer_barrier_ (3),
+#endif /* ! VXWORKS */
+ timer_ ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Yield_Test ctor\n"));
+#endif /* ACE_DEBUG_CST */
+
+#if !defined (VXWORKS)
+ timer_.start ();
+#endif /* ! VXWORKS */
+
+ if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
+ 2, 0, LOW_PRIORITY))
+ ACE_OS::perror (ACE_TEXT("activate"));
+
+#if !defined (VXWORKS)
+ timer_barrier_.wait ();
+ timer_.stop ();
+#endif /* ! VXWORKS */
+
+ timer_.elapsed_microseconds (elapsed_time_);
+}
+
+Yield_Test::~Yield_Test()
+{
+}
+
+int
+Yield_Test::svc ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Yield_Test::svc (), entering"));
+
+ ACE_hthread_t thread_id;
+ ACE_Thread_Manager::instance ()->thr_self (thread_id);
+
+ int priority;
+ ACE_OS::thr_getprio (thread_id, priority);
+
+ ACE_DEBUG ((LM_DEBUG, "; thread ID is %u, priority is %u\n", thread_id,
+ priority));
+#endif /* ACE_DEBUG_CST */
+
+#if defined (VXWORKS)
+ // Start the timer, if it hasn't already been started.
+ if (! started_)
+ {
+ // Double-check.
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, mutex_, -1);
+
+ if (! started_)
+ {
+ started_ = 1;
+ timer_.start ();
+ }
+ }
+#endif /* VXWORKS */
+
+ for (ACE_UINT32 i = 0; i < iterations_; ++i)
+ {
+#if ACE_DEBUG_CST > 0
+ if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG, "Yield_Test::svc () [%u], iteration %u\n",
+ thread_id, i));
+ }
+#endif /* ACE_DEBUG_CST */
+
+ ACE_OS::thr_yield ();
+ }
+
+#if defined (VXWORKS)
+ // Stop the timer, if it hasn't already been started.
+ if (! stopped_)
+ {
+ // Maybe it would be better to read the clock before grabbing
+ // the mutex. Then, only apply the clock reading below, instead
+ // of reading the clock after grabbing the mutex.
+
+ // Double-check.
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, mutex_, -1);
+
+ if (! stopped_)
+ {
+ stopped_ = 1;
+ timer_.stop ();
+ timer_.elapsed_time (elapsed_time_); /* nanoseconds */
+ }
+ }
+#else /* ! VXWORKS */
+ timer_barrier_.wait ();
+#endif /* ! VXWORKS */
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Yield_Test::svc, finishing\n"));
+#endif /* ACE_DEBUG_CST */
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Mutex_Acquire_Release_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class Mutex_Acquire_Release_Test
+{
+public:
+ Mutex_Acquire_Release_Test (const ACE_UINT32 iterations);
+ virtual ~Mutex_Acquire_Release_Test ();
+
+ virtual int svc ();
+
+ ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
+private:
+ ACE_Thread_Mutex mutex_;
+ // Mutex used for acquire/release time measurement.
+
+ ACE_Thread_Semaphore sem_;
+ // Semaphore used for acquire/release time measurement.
+
+ const ACE_UINT32 iterations_;
+
+ ACE_High_Res_Timer timer_;
+
+ ACE_hrtime_t elapsed_time_;
+
+ // Force proper construction of independent instances.
+ Mutex_Acquire_Release_Test ();
+ Mutex_Acquire_Release_Test (const Mutex_Acquire_Release_Test &);
+ Mutex_Acquire_Release_Test &operator= (const Mutex_Acquire_Release_Test &);
+};
+
+Mutex_Acquire_Release_Test::Mutex_Acquire_Release_Test (
+ const ACE_UINT32 iterations) :
+ mutex_ (),
+ sem_ (),
+ iterations_ (iterations),
+ timer_ ()
+{
+}
+
+Mutex_Acquire_Release_Test::~Mutex_Acquire_Release_Test()
+{
+}
+
+int
+Mutex_Acquire_Release_Test::svc ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_hthread_t thread_id;
+ ACE_Thread_Manager::instance ()->thr_self (thread_id);
+
+ ACE_DEBUG ((LM_DEBUG,
+ "Mutex_Acquire_Release_Test::svc (), thread ID is %d\n",
+ thread_id));
+#endif /* ACE_DEBUG_CST */
+
+ timer_.start ();
+
+ for (ACE_UINT32 i = 0; i < iterations_; ++i)
+ {
+ // Block on the mutex.
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, mutex_, -1);
+
+ // Release the mutex so that the low priority thread can
+ // proceed. The ACE_GUARD_RETURN macro implicity releases the
+ // mutex.
+ }
+
+ timer_.stop ();
+ timer_.elapsed_time (elapsed_time_); /* nanoseconds */
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Mutex_Acquire_Release_Test::svc, finishing\n"));
+#endif /* ACE_DEBUG_CST */
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class High_Priority_Synchronized_Task
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class High_Priority_Synchronized_Task : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ High_Priority_Synchronized_Task (ACE_Thread_Semaphore &sem,
+ ACE_Thread_Mutex &mutex,
+ ACE_High_Res_Timer &timer);
+ virtual ~High_Priority_Synchronized_Task ();
+
+ virtual int svc ();
+
+ void ready () { initialized_.acquire (); }
+ // Called by other task: it returns when this task is ready to
+ // continue
+
+ void done ();
+
+ ACE_UINT32 average_context_switch_time () const;
+
+ ACE_hthread_t thread_id () const { return thread_id_; }
+ ACE_UINT32 iterations () const { return iterations_; }
+private:
+ ACE_hthread_t thread_id_;
+ ACE_Semaphore initialized_; // Block until thread_id_ is assigned.
+ int terminate_;
+ ACE_UINT32 iterations_;
+
+ ACE_Thread_Semaphore &sem_;
+ // Semaphore used to resume the task.
+
+ ACE_Thread_Mutex &mutex_;
+ // Mutex used to block the task.
+
+ ACE_High_Res_Timer &timer_;
+ // Clock shared between low and high priority tasks.
+
+ ACE_hrtime_t total_time_;
+ // Running total context switch time, nsec.
+
+ // Force proper construction of independent instances.
+ High_Priority_Synchronized_Task ();
+ High_Priority_Synchronized_Task (const High_Priority_Synchronized_Task &);
+ High_Priority_Synchronized_Task &
+ operator= (const High_Priority_Synchronized_Task &);
+};
+
+High_Priority_Synchronized_Task::High_Priority_Synchronized_Task (
+ ACE_Thread_Semaphore &sem,
+ ACE_Thread_Mutex &mutex,
+ ACE_High_Res_Timer &timer) :
+ ACE_Task<ACE_MT_SYNCH> (ACE_Thread_Manager::instance ()),
+ initialized_ (0), // Initialize to locked, then unlock when ready.
+ terminate_ (0),
+ iterations_ (0),
+ sem_ (sem),
+ mutex_ (mutex),
+ timer_ (timer),
+ total_time_ (0)
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task ctor\n"));
+#endif /* ACE_DEBUG_CST */
+
+ if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
+ 1, 0, HIGH_PRIORITY))
+ ACE_OS::perror (ACE_TEXT("activate"));
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task ctor, activated\n"));
+#endif /* ACE_DEBUG_CST */
+}
+
+High_Priority_Synchronized_Task::~High_Priority_Synchronized_Task()
+{
+}
+
+int
+High_Priority_Synchronized_Task::svc ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task::svc (), entering"));
+#endif /* ACE_DEBUG_CST */
+
+ ACE_Thread_Manager::instance ()->thr_self (thread_id_);
+
+ ACE_UINT32 mutex_acquire_release_time = 0;
+ {
+ Mutex_Acquire_Release_Test mutex_acquire_release_test (num_iterations);
+ mutex_acquire_release_test.svc ();
+ mutex_acquire_release_time =
+ static_cast<ACE_UINT32> (mutex_acquire_release_test.elapsed_time () /
+ num_iterations);
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "mutex_acquire_release: %u nsec\n",
+ mutex_acquire_release_time));
+#endif /* ACE_DEBUG_CST */
+ }
+
+ initialized_.release ();
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_));
+#endif /* ACE_DEBUG_CST */
+
+ for (ACE_UINT32 i = 0; ! terminate_; ++i)
+ {
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG,
+ "High_Priority_Synchronized_Task::svc, wait on sem ("
+ "%u)\n", thread_id_));
+#endif /* ACE_DEBUG_CST */
+
+ if (sem_.acquire () != 0)
+ {
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "sem_.acquire"), -1);
+ }
+
+ {
+ // Block on the mutex.
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, guard, mutex_, -1);
+
+ timer_.stop ();
+
+ ++iterations_;
+
+ ACE_hrtime_t nsec;
+ timer_.elapsed_time (nsec);
+ const ACE_UINT32 context_switch_time =
+ ACE_U64_TO_U32 (nsec) >= mutex_acquire_release_time ?
+ ACE_U64_TO_U32 (nsec) - mutex_acquire_release_time : 0;
+
+ total_time_ += context_switch_time;
+
+ // Release the mutex so that the low priority thread can
+ // proceed. The ACE_GUARD_RETURN macro implicity releases the
+ // mutex.
+ }
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG,
+ "High_Priority_Synchronized_Task::svc, resumed (%u)\n",
+ thread_id_));
+#endif /* ACE_DEBUG_CST */
+ }
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task::svc, finishing\n"));
+#endif /* ACE_DEBUG_CST */
+
+ return 0;
+}
+
+inline
+void
+High_Priority_Synchronized_Task::done ()
+{
+ terminate_ = 1;
+}
+
+ACE_UINT32
+High_Priority_Synchronized_Task:: average_context_switch_time () const
+{
+ return iterations_ > 0 ? static_cast<ACE_UINT32> (total_time_ / iterations_)
+ : 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Synchronized_Suspend_Resume_Test
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class Synchronized_Suspend_Resume_Test : public ACE_Task<ACE_MT_SYNCH>
+{
+public:
+ Synchronized_Suspend_Resume_Test (const ACE_UINT32 iterations);
+ virtual ~Synchronized_Suspend_Resume_Test ();
+
+ virtual int svc ();
+
+ ACE_UINT32 average_context_switch_time ();
+
+ ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
+private:
+ const ACE_UINT32 iterations_;
+
+ ACE_Thread_Semaphore sem_;
+ // Used by the low priority thread to resume the high priority thread.
+
+ ACE_Thread_Mutex mutex_;
+ // Used by the low priority thread to block the high priority thread.
+
+ ACE_High_Res_Timer timer_;
+ // Clock shared between low and high priority tasks.
+
+ High_Priority_Synchronized_Task high_;
+ // The high priority task.
+
+ ACE_hrtime_t elapsed_time_;
+
+ ACE_UINT32 mutex_acquire_release_time_;
+
+ // Force proper construction of independent instances.
+ Synchronized_Suspend_Resume_Test ();
+ Synchronized_Suspend_Resume_Test (const Synchronized_Suspend_Resume_Test &);
+ Synchronized_Suspend_Resume_Test &
+ operator= (const Synchronized_Suspend_Resume_Test &);
+};
+
+Synchronized_Suspend_Resume_Test::Synchronized_Suspend_Resume_Test (
+ const ACE_UINT32 iterations)
+:
+ ACE_Task<ACE_MT_SYNCH> (),
+ iterations_ (iterations),
+ sem_ (0),
+ mutex_ (),
+ timer_ (),
+ high_ (sem_, mutex_, timer_),
+ mutex_acquire_release_time_ (0)
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Synchronized_Suspend_Resume_Test ctor\n"));
+#endif /* ACE_DEBUG_CST */
+
+ if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
+ 1, 0, LOW_PRIORITY))
+ ACE_OS::perror (ACE_TEXT("activate"));
+}
+
+Synchronized_Suspend_Resume_Test::~Synchronized_Suspend_Resume_Test()
+{
+}
+
+int
+Synchronized_Suspend_Resume_Test::svc ()
+{
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Synchronized_Suspend_Resume_Test::svc (), entering"));
+
+ ACE_hthread_t thread_id;
+ ACE_Thread_Manager::instance ()->thr_self (thread_id);
+
+ ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id));
+#endif /* ACE_DEBUG_CST */
+
+ {
+ Mutex_Acquire_Release_Test mutex_acquire_release_test (num_iterations);
+ mutex_acquire_release_test.svc ();
+ mutex_acquire_release_time_ =
+ static_cast<ACE_UINT32> (mutex_acquire_release_test.elapsed_time () /
+ num_iterations);
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "mutex_acquire_release: %u nsec\n",
+ mutex_acquire_release_time_));
+#endif /* ACE_DEBUG_CST */
+ }
+
+ high_.ready ();
+
+#if ACE_DEBUG_CST > 0
+ int priority, high_priority;
+ ACE_OS::thr_getprio (thread_id, priority);
+ ACE_OS::thr_getprio (high_.thread_id (), high_priority);
+ ACE_DEBUG ((LM_DEBUG,
+ "Synchronized_Suspend_Resume_Test::svc (), priority is %d, "
+ ", high thread priority is %d\n",
+ priority, high_priority));
+#endif /* ACE_DEBUG_CST */
+
+ // For information: the cost of the just the loop itself below,
+ // without the suspend and resume calls, on a 166 MHz Ultrasparc
+ // is about 12.3 nanoseconds per iteration.
+
+ ACE_UINT32 i;
+
+ for (i = 0; i < iterations_; ++i)
+ {
+#if ACE_DEBUG_CST > 0
+ if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "Synchronized_Suspend_Resume_Test::svc (), iteration "
+ "%d, continue high-priority thread %u\n",
+ i, high_.thread_id ()));
+ }
+#endif /* ACE_DEBUG_CST */
+
+ {
+ // Acquire the mutex so that the high priority thread will
+ // block after we signal it via the condition variable.
+ ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, mutex_, -1);
+
+ // Release the semaphore so that the high priority thread can
+ // proceed.
+ if (sem_.release () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "sem_.release"), -1);
+
+ timer_.start ();
+
+ // Release the mutex so that the high priority thread can
+ // proceed. The ACE_GUARD_RETURN macro implicity releases
+ // the mutex.
+ }
+ }
+
+ high_.done ();
+
+ // The high priority thread will be block on the semaphore, so
+ // release it.
+ if (sem_.release () != 0)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "sem_.release"), -1);
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG,
+ "Synchronized_Suspend_Resume_Test::svc: told high priority "
+ "task to terminate\n"));
+#endif /* ACE_DEBUG_CST */
+
+ // Resume the thread until thr_continue fails, indicating that it has
+ // finished.
+ for (i = 0; i < 10000 && ! ACE_OS::thr_continue (high_.thread_id ());
+ ++i) /* null */;
+
+#if ACE_DEBUG_CST > 0
+ ACE_DEBUG ((LM_DEBUG, "Synchronized_Suspend_Resume_Test::svc, finishing\n"));
+#endif /* ACE_DEBUG_CST */
+
+ return 0;
+}
+
+ACE_UINT32
+Synchronized_Suspend_Resume_Test::average_context_switch_time ()
+{
+ return high_.average_context_switch_time ();
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// function get_options
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static
+u_int
+get_options (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("c:n?"));
+ int opt;
+ while ((opt = get_opt ()) != EOF) {
+ switch (opt) {
+ case 'c':
+ if (ACE_OS::atoi (get_opt.opt_arg ()) >= 0)
+ {
+ counter = ACE_OS::atoi (get_opt.opt_arg ());
+ }
+ else
+ {
+ ACE_DEBUG ((LM_ERROR, "%n: count must be >= 0\n"));
+ return 1;
+ }
+ break;
+ case 'n':
+ new_lwp = THR_NEW_LWP;
+ break;
+ case '?':
+ ACE_DEBUG ((LM_ERROR, "usage: %n %s\n", usage));
+ ACE_OS::exit (1);
+ /* NOTREACHED */
+ break;
+ default:
+ ACE_DEBUG ((LM_ERROR, "%n: unknown arg, %c\n", opt));
+ ACE_DEBUG ((LM_ERROR, "usage: %n %s\n", usage));
+ return 1;
+ }
+ }
+
+ switch (argc - get_opt.opt_ind ()) {
+ case 0:
+ // use default number of iterations
+ break;
+ case 1:
+ if (ACE_OS::atoi (argv [get_opt.opt_ind ()]) > 0)
+ num_iterations = ACE_OS::atoi (argv [get_opt.opt_ind ()]);
+ else
+ {
+ ACE_DEBUG ((LM_ERROR, "%n: iterations must be > 0\n"));
+ return 1;
+ }
+ break;
+ default:
+ ACE_DEBUG ((LM_ERROR, "%n: too many arguments\n"));
+ ACE_DEBUG ((LM_ERROR, "usage: %n %s\n", usage));
+ return 1;
+ }
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// function main
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv [])
+{
+ ACE_LOG_MSG->open (argv[0] > 0 ? argv[0] : ACE_TEXT("context_switch_time"));
+
+ if (get_options (argc, argv))
+ ACE_OS::exit (-1);
+
+ // Disable LM_DEBUG.
+ ACE_Log_Msg::instance ()->priority_mask (ACE_LOG_MSG->priority_mask () ^
+ LM_DEBUG);
+
+#if defined (ACE_HAS_PENTIUM) && \
+ !defined (ACE_HAS_HI_RES_TIMER) && !defined (ACE_WIN32)
+ // Just to verify that ACE_High_Res_Timer::global_scale_factor ()
+ // correctly determines the clock speed.
+ ACE_DEBUG ((LM_INFO, "clock speed: %u MHz\n",
+ ACE_High_Res_Timer::global_scale_factor ()));
+#endif /* ACE_HAS_PENTIUM && ! ACE_HAS_HI_RES_TIMER && ! ACE_WIN32 */
+
+ if (ACE_OS::sched_params (
+ ACE_Sched_Params (
+ ACE_SCHED_FIFO,
+ ACE_Sched_Params::priority_min (ACE_SCHED_FIFO),
+ ACE_SCOPE_PROCESS)) != 0)
+ {
+ if (ACE_OS::last_error () == EPERM)
+ {
+ ACE_DEBUG ((LM_MAX, "context_switch_time: user is not superuser, "
+ "so remain in time-sharing class\n"));
+ }
+ else
+ {
+ ACE_OS::perror (ACE_TEXT("context_switch_time"));
+ ACE_OS::exit (-1);
+ }
+ }
+
+ HIGH_PRIORITY = ACE_Sched_Params::next_priority (ACE_SCHED_FIFO,
+ LOW_PRIORITY);
+ ACE_DEBUG ((LM_INFO, "low priority: %d, high priority: %d\n",
+ LOW_PRIORITY, HIGH_PRIORITY));
+
+ // Set the priority of this thread so that it's higher than any of
+ // the test threads. That might help avoid problems when waiting on
+ // those threads, below. It also seems to help the times
+ // significantly on LynxOS.
+ ACE_hthread_t self;
+ ACE_OS::thr_self (self);
+ ACE_OS::thr_setprio (ACE_Sched_Params::next_priority (ACE_SCHED_FIFO,
+ HIGH_PRIORITY));
+
+ bool forever = counter == 0;
+
+ ACE_Stats context_switch_test_stats;
+ ACE_Stats yield_test_stats;
+ ACE_Stats synchronized_suspend_resume_test_stats;
+
+ int suspend_resume_supported = 0;
+ // Check to see if thr_continue (), and therefore thr_suspend (),
+ // probably, are supported.
+ if (ACE_OS::thr_continue (self) == 0 || errno != ENOTSUP)
+ suspend_resume_supported = 1;
+
+ while (forever || counter-- > 0)
+ {
+ if (suspend_resume_supported)
+ {
+ // Run suspend/resume test first . . .
+ Suspend_Resume_Test suspend_resume_test (num_iterations);
+ // Wait for all tasks to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+
+ // Then Ping Suspend/Resume test.
+ Ping_Suspend_Resume_Test ping_suspend_resume_test (num_iterations);
+ // Wait for all tasks to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+
+ if (ping_suspend_resume_test.elapsed_time () >
+ suspend_resume_test.elapsed_time ())
+ {
+ context_switch_test_stats.
+ sample (ACE_U64_TO_U32 (
+ ping_suspend_resume_test.elapsed_time () -
+ suspend_resume_test.elapsed_time ()));
+
+ ACE_DEBUG ((LM_INFO, "context switch time is (%.3f - %.3f)/2 = "
+ "%.3f microseconds\n",
+ (double) ACE_UINT64_DBLCAST_ADAPTER (
+ ping_suspend_resume_test.elapsed_time ()) /
+ num_iterations,
+ (double) ACE_UINT64_DBLCAST_ADAPTER (
+ suspend_resume_test.elapsed_time ()) /
+ num_iterations,
+ (double) ACE_UINT64_DBLCAST_ADAPTER (
+ ping_suspend_resume_test.elapsed_time () -
+ suspend_resume_test.elapsed_time ()) /
+ num_iterations / 2u));
+ }
+ else
+ {
+ ACE_DEBUG ((LM_INFO, "ping suspend/resume time of %u usec was "
+ "less than suspend/resume time of %u\n",
+ ping_suspend_resume_test.elapsed_time () /
+ num_iterations,
+ suspend_resume_test.elapsed_time () /
+ num_iterations));
+ }
+ }
+
+ // Then Yield test.
+ Yield_Test yield_test (num_iterations);
+ // Wait for all tasks to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+
+ yield_test_stats.sample (ACE_U64_TO_U32 (yield_test.elapsed_time ()));
+
+ // Try _really_ hard not to use floating point.
+ ACE_DEBUG ((LM_INFO, "context switch time from yield test is %u.%03u "
+ "microseconds\n",
+ (ACE_UINT32)
+ (yield_test.elapsed_time () / num_iterations / 2u),
+ (ACE_UINT32)
+ (yield_test.elapsed_time () % (num_iterations * 2u)) *
+ 1000u / num_iterations / 2u));
+
+ Synchronized_Suspend_Resume_Test
+ synchronized_suspend_resume_test (num_iterations);
+ // Wait for all tasks to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+
+ synchronized_suspend_resume_test_stats.sample (
+ synchronized_suspend_resume_test.average_context_switch_time ());
+
+ ACE_DEBUG ((LM_INFO, "context switch time from synch susp/resume test "
+ "is %u.%03u microseconds\n",
+ synchronized_suspend_resume_test.
+ average_context_switch_time () / 1000u,
+ synchronized_suspend_resume_test.
+ average_context_switch_time () % 1000u));
+
+ // Give, e.g., Draft 4 Posix platforms a chance to cleanup threads.
+ const ACE_Time_Value half_sec (0L, 500000L);
+ ACE_OS::sleep (half_sec);
+ }
+
+ if (suspend_resume_supported)
+ {
+ ACE_OS::printf ("suspend-resume test: ");
+ context_switch_test_stats.print_summary (3, num_iterations * 2u);
+ }
+
+ ACE_OS::printf ("\nyield_test: ");
+ yield_test_stats.print_summary (3, num_iterations * 2u);
+
+ ACE_OS::printf ("\nsynchronized suspend-resume test: ");
+ synchronized_suspend_resume_test_stats.print_summary (3,
+ 1000u /* nsec/usec */);
+
+ return 0;
+}
+#else
+int
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n"));
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
+
+
+// EOF
diff --git a/ACE/performance-tests/Misc/preempt.cpp b/ACE/performance-tests/Misc/preempt.cpp
new file mode 100644
index 00000000000..0e6edcfbc30
--- /dev/null
+++ b/ACE/performance-tests/Misc/preempt.cpp
@@ -0,0 +1,467 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// performance-tests/Misc
+//
+// = FILENAME
+// preempt.cpp
+//
+// = DESCRIPTION
+// This is a simple test to illustrate OS thread preemption. One
+// ore more high priority threads periodically (every half
+// second, by default) reads the clock. They use select () to
+// block for that duration. Meanwhile, a low priority thread
+// continually chews up the CPU. Without preemption, the high
+// priority thread won't have a chance to read the clock in a
+// timely manner.
+//
+// At the end of the test, the actual clock read intervals by the
+// high priority task(s) are printed out. With proper
+// preemption, the intervals should correspond to the requested
+// clock read interval.
+//
+// There is a -y option for the low priority thread to periodically
+// yield. It shouldn't be necessary to use that option, if preemption
+// is supported. It's a handy option for testing.
+//
+// = AUTHOR
+// David L. Levine
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+#include "ace/ACE.h"
+#include "ace/Task.h"
+#include "ace/Sched_Params.h"
+#include "ace/Get_Opt.h"
+#include "ace/OS_NS_sys_select.h"
+#include "ace/OS_NS_time.h"
+#include "ace/OS_NS_errno.h"
+#include "ace/OS_NS_unistd.h"
+
+ACE_RCSID(Misc, preempt, "$Id$")
+
+#if defined (ACE_HAS_THREADS) || ! defined (ACE_LACKS_FORK)
+
+#if defined (ACE_HAS_STHREADS)
+# include <sys/lwp.h> /* for _lwp_self () */
+#endif /* ACE_HAS_STHREADS */
+
+static const char usage [] = "[-? |\n"
+#if defined (ACE_HAS_THREADS)
+ " [-f use fork instead of spawn]\n"
+#endif /* ACE_HAS_THREADS */
+ " [-h <high pri iterations, default 10>]\n"
+ " [-l <low pri iterations, default 25000>]\n"
+ " [-n <high priority threads, default 1>]\n"
+ " [-p <read period, default 500000 usec>]\n"
+ " [-y to yield the low priority thread]]\n";
+
+// Configuration options.
+#if defined (ACE_HAS_THREADS)
+u_int use_fork = 0;
+#else /* ! ACE_HAS_THREADS */
+u_int use_fork = 1;
+#endif /* ! ACE_HAS_THREADS */
+u_int high_iterations = 10;
+u_int high_priority_tasks = 1;
+u_int low_iterations = 25000; /* Big enough to keep the low priority task
+ cranking for a while */
+u_long read_period = 500000; /* usec */
+u_int low_yield = 0;
+
+// To permit calculation of relative times.
+ACE_hrtime_t starttime;
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class High_Priority_Task
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class High_Priority_Task : public ACE_Task<ACE_SYNCH>
+{
+public:
+ High_Priority_Task (void);
+ ~High_Priority_Task (void);
+
+ //FUZZ: disable check_for_lack_ACE_OS
+ int open (void *);
+ //FUZZ: enable check_for_lack_ACE_OS
+
+ int svc (void);
+ int done () const { return done_; }
+ void print_times () const;
+
+private:
+ int priority_;
+ int done_;
+ u_long *time_;
+};
+
+High_Priority_Task::High_Priority_Task (void)
+ : ACE_Task<ACE_SYNCH> (ACE_Thread_Manager::instance ()),
+ priority_ (ACE_Sched_Params::next_priority (
+ ACE_SCHED_FIFO,
+ ACE_Sched_Params::priority_min (ACE_SCHED_FIFO,
+ ACE_SCOPE_THREAD),
+ ACE_SCOPE_THREAD)),
+ done_ (0)
+{
+ ACE_NEW (time_, u_long[high_iterations]);
+}
+
+High_Priority_Task::~High_Priority_Task (void)
+{
+ delete [] time_;
+ time_ = 0;
+}
+
+int
+High_Priority_Task::open (void *)
+{
+ if (use_fork == 1)
+ {
+ ACE_hthread_t thr_handle;
+ ACE_Thread::self (thr_handle);
+
+ if (ACE_Thread::setprio (thr_handle, priority_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "setprio failed"), -1);
+
+ return svc ();
+ }
+ else
+ {
+ long flags = THR_BOUND | THR_NEW_LWP | THR_SCHED_FIFO;
+
+ // Become an active object.
+ if (this->activate (flags, 1, 0, this->priority_) == -1)
+ {
+ ACE_DEBUG ((LM_ERROR, "(%P|%t) task activation failed, exiting!\n"));
+ ACE_OS::exit (1);
+ }
+
+ return 0;
+ }
+}
+
+int
+High_Priority_Task::svc (void)
+{
+ ACE_hthread_t thr_handle;
+ ACE_Thread::self (thr_handle);
+ int prio;
+
+ if (ACE_Thread::getprio (thr_handle, prio) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getprio failed"), -1);
+
+#if defined (ACE_HAS_STHREADS)
+ ACE_DEBUG ((LM_DEBUG, "(%P|%u|%t) High: prio = %d, priority_ = %d\n",
+ _lwp_self (), prio, this->priority_));
+#else /* ! ACE_HAS_STHREADS */
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) High: prio = %d, priority_ = %d\n",
+ prio, this->priority_));
+#endif /* ! ACE_HAS_STHREADS */
+ ACE_ASSERT (this->priority_ == prio);
+
+ ACE_Time_Value pause (0, read_period);
+
+ for (u_int i = 0; i < high_iterations; ++i)
+ {
+ time_ [i] = (u_long) ((ACE_OS::gethrtime () - starttime)/
+ (ACE_UINT32) 1000000u);
+ ACE_OS::select (0, 0, 0, 0, &pause);
+ }
+
+ done_ = 1;
+
+ return 0;
+}
+
+void
+High_Priority_Task::print_times () const
+{
+ for (u_int i = 0; i < high_iterations; ++i)
+ {
+ ACE_DEBUG ((LM_INFO, " iteration %u, time %u msec\n",
+ i, time_ [i]));
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// class Low_Priority_Task
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+class Low_Priority_Task : public ACE_Task<ACE_SYNCH>
+{
+public:
+ Low_Priority_Task (const High_Priority_Task &);
+
+ //FUZZ: disable check_for_lack_ACE_OS
+ int open (void *);
+ //FUZZ: enable check_for_lack_ACE_OS
+
+ int svc (void);
+
+private:
+ int priority_;
+ const High_Priority_Task &high_priority_task_;
+};
+
+Low_Priority_Task::Low_Priority_Task (
+ const High_Priority_Task &high_priority_task)
+ : ACE_Task<ACE_SYNCH> (ACE_Thread_Manager::instance ()),
+ priority_ (ACE_Sched_Params::priority_min (ACE_SCHED_FIFO,
+ ACE_SCOPE_THREAD)),
+ high_priority_task_ (high_priority_task)
+{
+}
+
+int
+Low_Priority_Task::open (void *)
+{
+ if (use_fork == 1)
+ {
+ ACE_hthread_t thr_handle;
+ ACE_Thread::self (thr_handle);
+
+ if (ACE_Thread::setprio (thr_handle, priority_) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "setprio failed"), -1);
+
+ return svc ();
+ }
+ else
+ {
+ long flags = THR_BOUND | THR_NEW_LWP | THR_SCHED_FIFO;
+
+ // Become an active object.
+ if (this->activate (flags, 1, 0, this->priority_) == -1)
+ ACE_ERROR ((LM_ERROR,
+ "(%P|%t) task activation failed, exiting!\n%a",
+ -1));
+ return 0;
+ }
+}
+
+int
+Low_Priority_Task::svc (void)
+{
+ ACE_hthread_t thr_handle;
+ ACE_Thread::self (thr_handle);
+ int prio;
+
+ if (ACE_Thread::getprio (thr_handle, prio) == -1)
+ ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "getprio failed"), -1);
+
+#if defined (ACE_HAS_STHREADS)
+ ACE_DEBUG ((LM_DEBUG, "(%P|%u|%t) Low: prio = %d, priority_ = %d\n",
+ _lwp_self (), prio, this->priority_));
+#else /* ! ACE_HAS_STHREADS */
+ ACE_DEBUG ((LM_DEBUG, "(%P|%t) Low: prio = %d, priority_ = %d\n",
+ prio, this->priority_));
+#endif /* ! ACE_HAS_STHREADS */
+ ACE_ASSERT (this->priority_ == prio);
+
+ u_long iterations = 0;
+
+ // Chew up CPU for the entire interval.
+ for (;
+ ! high_priority_task_.done () && iterations < low_iterations;
+ ++iterations)
+ {
+ u_long n = 1279ul; /* Takes about 40.2 usecs on a 168 MHz Ultra2. */
+ ACE::is_prime (n,
+ 2ul /* min_factor */,
+ n/2 /* max_factor */);
+
+ if (low_yield)
+ ACE_OS::thr_yield ();
+ }
+
+ ACE_DEBUG ((LM_INFO, "Low completed %u iterations\n", iterations));
+
+ return 0;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// function get_options
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int
+get_options (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("fh:l:n:p:y?"));
+ int opt;
+ while ((opt = get_opt ()) != EOF) {
+ switch (opt) {
+ case 'f':
+ use_fork = 1;
+ break;
+ case 'h':
+ if (ACE_OS::atoi (get_opt.opt_arg ()) >= 2)
+ high_iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "%n: high iterations must be >= 2\n"),
+ -1);
+ break;
+ case 'l':
+ if (ACE_OS::atoi (get_opt.opt_arg ()) >= 2)
+ low_iterations = ACE_OS::atoi (get_opt.opt_arg ());
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "%n: low iterations must be >= 2\n"), -1);
+ break;
+ case 'n':
+ if (ACE_OS::atoi (get_opt.opt_arg ()) >= 1)
+ high_priority_tasks = ACE_OS::atoi (get_opt.opt_arg ());
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "%n: number of high priority threads "
+ "must be >= 1\n"), -1);
+ break;
+ case 'p':
+ if (ACE_OS::atoi (get_opt.opt_arg ()) > 0)
+ read_period = ACE_OS::atoi (get_opt.opt_arg ());
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "%n: read period > 0\n"), -1);
+ break;
+ case 'y':
+ low_yield = 1;
+ break;
+ case '?':
+ ACE_DEBUG ((LM_ERROR, "usage: %n %s\n%a", usage, 0));
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%n: unknown arg, %c\nusage: %n %s\n", opt, usage),
+ -1);
+ }
+ }
+
+ switch (argc - get_opt.opt_ind ()) {
+ case 0:
+ // OK, no non-flag arguments.
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "%n: too many arguments\nusage: %n %s\n", usage),
+ -1);
+ }
+
+ return 0;
+}
+
+#endif /* ACE_HAS_THREADS || ! ACE_LACKS_FORK */
+
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// function main
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_LOG_MSG->open (argv[0] ? argv[0] : ACE_TEXT("preempt"));
+
+#if defined (ACE_HAS_THREADS) || !defined (ACE_LACKS_FORK)
+
+ u_int i;
+
+ if (get_options (argc, argv))
+ ACE_OS::exit (-1);
+
+ // Enable FIFO scheduling, e.g., RT scheduling class on Solaris.
+ if (ACE_OS::sched_params (
+ ACE_Sched_Params (
+ ACE_SCHED_FIFO,
+ ACE_Sched_Params::priority_min (ACE_SCHED_FIFO),
+ ACE_SCOPE_PROCESS)) != 0)
+ {
+ if (ACE_OS::last_error () == EPERM)
+ ACE_DEBUG ((LM_MAX, "preempt: user is not superuser, "
+ "so remain in time-sharing class\n"));
+ else
+ ACE_ERROR_RETURN ((LM_ERROR, "%n: ACE_OS::sched_params failed\n%a"),
+ -1);
+ }
+
+ High_Priority_Task *high_priority_task;
+ ACE_NEW_RETURN (high_priority_task, High_Priority_Task [high_priority_tasks],
+ 1);
+
+ Low_Priority_Task low_priority_task (high_priority_task[0]);
+
+ if (! use_fork)
+ {
+ ACE_DEBUG ((LM_DEBUG,
+ "(%P|%t) main (), wait for threads to exit . . .\n"));
+ }
+
+ // Save the start time, so that deltas can be displayed later.
+ starttime = ACE_OS::gethrtime ();
+
+ // Spawn the threads/processes . . .
+ pid_t child = 0;
+ if (use_fork == 1)
+ {
+ switch ((child = ACE_OS::fork (ACE_TEXT("preempt-low_priority_process"))))
+ {
+ case -1:
+ ACE_ERROR ((LM_ERROR, "%p\n%a", "fork failed"));
+ return -1;
+ case 0: // In child
+ {
+ low_priority_task.open (0);
+ break;
+ }
+ default: // In parent
+ for (i = 0; i < high_priority_tasks; ++i)
+ {
+ high_priority_task[i].open (0);
+ }
+ break;
+ }
+ }
+ else
+ {
+ for (i = 0; i < high_priority_tasks; ++i)
+ {
+ high_priority_task[i].open (0);
+ }
+ low_priority_task.open (0);
+
+#if defined (ACE_HAS_THREADS)
+ // Wait for all threads to exit.
+ ACE_Thread_Manager::instance ()->wait ();
+#endif /* ACE_HAS_THREADS */
+ }
+
+ // Display the time deltas. They should be about a half second apart.
+ if (child || ! use_fork)
+ {
+ for (i = 0; i < high_priority_tasks; ++i)
+ {
+ ACE_DEBUG ((LM_DEBUG, "High priority task %u:\n", i + 1));
+ high_priority_task[i].print_times ();
+ }
+ }
+
+ delete [] high_priority_task;
+
+#else /* ! ACE_HAS_THREADS && ACE_LACKS_FORK */
+ ACE_UNUSED_ARG (argc);
+ ACE_UNUSED_ARG (argv);
+ ACE_ERROR ((LM_ERROR, "threads and fork not supported on this platform\n"));
+#endif /* ! ACE_HAS_THREADS && ACE_LACKS_FORK */
+
+ return 0;
+}
diff --git a/ACE/performance-tests/Misc/test_guard.cpp b/ACE/performance-tests/Misc/test_guard.cpp
new file mode 100644
index 00000000000..11c28741405
--- /dev/null
+++ b/ACE/performance-tests/Misc/test_guard.cpp
@@ -0,0 +1,119 @@
+// $Id$
+
+// This test program illustrates the performance of ACE_Guard and
+// ACE_Thread_Mutex_Guard.
+
+#include "ace/Log_Msg.h"
+#include "ace/Get_Opt.h"
+#include "ace/Profile_Timer.h"
+
+#if !defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+#error You must compile ACE and this program with ACE_USES_OBSOLETE_GUARD_CLASSES defined!
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+
+ACE_RCSID(Misc, test_guard, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+# define ACE_THREAD_GUARD(OBJ,LOCK) \
+ ACE_Thread_Mutex_Guard OBJ (LOCK); \
+ if (OBJ.locked () == 0) return;
+
+static const int DEFAULT_ITERATIONS = 100000000;
+
+enum
+{
+ TEST_GUARD,
+ TEST_THR_GUARD,
+ TEST_END
+};
+
+ACE_Thread_Mutex lock_;
+typedef void (*guard_func)(void);
+int test_type = TEST_GUARD;
+int dummy = 0;
+
+void guard (void)
+{
+ ACE_GUARD (ACE_Thread_Mutex, _ace_mon, lock_);
+ dummy++;
+}
+
+void thr_guard (void)
+{
+ ACE_THREAD_GUARD (_ace_mon, lock_);
+ dummy++;
+}
+
+char *test_name[TEST_END] = { "ACE_Guard", "ACE_Thread_Mutex_Guard" };
+
+guard_func test_function=guard;
+
+int
+ACE_TMAIN(int argc, ACE_TCHAR *argv[])
+{
+ ACE_Profile_Timer timer;
+
+ //FUZZ: disable check_for_lack_ACE_OS
+ ACE_Get_Opt getopt (argc, argv, "gtn:");
+ //FUZZ: enable check_for_lack_ACE_OS
+
+ int iterations = DEFAULT_ITERATIONS;
+ int c, i;
+
+ //FUZZ: disable check_for_lack_ACE_OS
+ while ((c = getopt()) != -1)
+ //FUZZ: enable check_for_lack_ACE_OS
+ switch (c)
+ {
+#if defined (ACE_USES_OBSOLETE_GUARD_CLASSES)
+ case 't':
+ test_type = TEST_THR_GUARD;
+ test_function = thr_guard;
+ break;
+#endif /* ACE_USES_OBSOLETE_GUARD_CLASSES */
+ case 'g':
+ test_type = TEST_GUARD;
+ test_function = guard;
+ break;
+ case 'n':
+ iterations = ACE_OS::atoi (getopt.opt_arg ());
+ break;
+ default:
+ ACE_ERROR_RETURN ((LM_ERROR,
+ "Invalid option\n"), -1);
+ }
+
+ ACE_DEBUG ((LM_DEBUG, "%s for iterations = %d\n", test_name[test_type], iterations));
+
+ timer.start ();
+
+ // Test the thread mutex (which doesn't use inheritance or dynamic
+ // binding).
+
+ for (i = 0; i < iterations; i++)
+ test_function ();
+
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG, "Thread_Mutex\n"));
+ ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n",
+ et.real_time, et.user_time, et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n",
+ (et.real_time / double (iterations)) * 1000000));
+
+ return 0;
+}
+#else
+int
+ACE_TMAIN(int, ACE_TCHAR *[])
+{
+ ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n"));
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/performance-tests/Misc/test_mutex.cpp b/ACE/performance-tests/Misc/test_mutex.cpp
new file mode 100644
index 00000000000..cff5dd76249
--- /dev/null
+++ b/ACE/performance-tests/Misc/test_mutex.cpp
@@ -0,0 +1,238 @@
+// $Id$
+
+// This test program illustrates the performance difference between
+// three versions of wrappers for thread mutexes. These three
+// versions exercise various combinations of the following classes:
+//
+// Thread_Mutex --
+// This version is just like ACE_Thread_Mutex, which doesn't use
+// inheritance and dynamic binding.
+//
+// Mutex_Base --
+// This is an abstract base class that defines the
+// acquire()/release() interface.
+//
+// Thread_Mutex_Derived --
+// This derived from Mutex_Base and uses inheritance and
+// dynamic binding.
+//
+// The following are the results I got when running this on our
+// SPARCstation 20 model 712:
+//
+// ./test_mutex 1000000
+// iterations = 1000000
+// Thread_Mutex
+// real time = 1.727843 secs, user time = 1.729262 secs, system time = 0.000325 secs
+// time per call = 1.747843 usecs
+// Thread_Mutex_Derived
+// real time = 1.730225 secs, user time = 1.724744 secs, system time = 0.000096 secs
+// time per call = 1.730225 usecs
+// Mutex_Base
+// real time = 2.112831 secs, user time = 2.104245 secs, system time = 0.000095 secs
+// time per call = 2.112831 usecs
+//
+// My conclusions are as follows:
+//
+// 1. If your C++ compiler optimizes calls to virtual functions that
+// are made through instances of derived classes, then the
+// performance of the Thread_Mutex and Thread_Mutex_Derived are
+// essentially identical.
+//
+// 2. The overhead from using virtual functions is approximately
+// 20%. Naturally, as the amount of contention goes up, the
+// relative overhead of the virtual function calls will decrease.
+//
+// Keep in mind, however, that using virtual functions to implement
+// the Thread_Mutex will make it infeasible to put instances of
+// Thread_Mutex into shared memory since the vptrs won't point to the
+// correct vtables...
+
+#include "ace/Log_Msg.h"
+#include "ace/Profile_Timer.h"
+#include "ace/OS_main.h"
+#include "ace/OS_NS_Thread.h"
+
+ACE_RCSID(Misc, test_mutex, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+static const int DEFAULT_ITERATIONS = 100000000;
+
+// A thread mutex that doesn't use virtual functions.
+class Thread_Mutex
+{
+public:
+ Thread_Mutex (void);
+ ~Thread_Mutex (void);
+ int acquire (void);
+ int release (void);
+
+private:
+ ACE_mutex_t mutex_;
+};
+
+Thread_Mutex::Thread_Mutex (void)
+{
+ ACE_OS::mutex_init (&this->mutex_);
+}
+
+Thread_Mutex::~Thread_Mutex (void)
+{
+ ACE_OS::mutex_destroy (&this->mutex_);
+}
+
+inline int
+Thread_Mutex::acquire (void)
+{
+ return ACE_OS::mutex_lock (&this->mutex_);
+}
+
+inline int
+Thread_Mutex::release (void)
+{
+ return ACE_OS::mutex_unlock (&this->mutex_);
+}
+
+// Base class for mutex, declares pure virtual functions.
+class Mutex_Base
+{
+public:
+ virtual ~Mutex_Base (void);
+ virtual int acquire (void) = 0;
+ virtual int release (void) = 0;
+};
+
+Mutex_Base::~Mutex_Base (void)
+{
+}
+
+// Subclass for threaded mutex, defines virtual functions.
+class Thread_Mutex_Derived : public Mutex_Base
+{
+public:
+ Thread_Mutex_Derived (void);
+ virtual ~Thread_Mutex_Derived (void);
+ virtual int acquire (void);
+ virtual int release (void);
+
+private:
+ ACE_mutex_t mutex_;
+};
+
+Thread_Mutex_Derived::Thread_Mutex_Derived (void)
+{
+ ACE_OS::mutex_init (&this->mutex_);
+}
+
+Thread_Mutex_Derived::~Thread_Mutex_Derived (void)
+{
+ ACE_OS::mutex_destroy (&this->mutex_);
+}
+
+inline int
+Thread_Mutex_Derived::acquire (void)
+{
+ return ACE_OS::mutex_lock (&this->mutex_);
+}
+
+inline int
+Thread_Mutex_Derived::release (void)
+{
+ return ACE_OS::mutex_unlock (&this->mutex_);
+}
+
+static Thread_Mutex thread_mutex;
+static Thread_Mutex_Derived thread_mutex_derived;
+static Mutex_Base *mutex_base = &thread_mutex_derived;
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Profile_Timer timer;
+ int iterations = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_ITERATIONS;
+ int i;
+
+ ACE_DEBUG ((LM_DEBUG, "iterations = %d\n", iterations));
+
+ timer.start ();
+
+ // Test the thread mutex (which doesn't use inheritance or dynamic
+ // binding).
+
+ for (i = 0; i < iterations; i++)
+ {
+ thread_mutex.acquire ();
+ thread_mutex.release ();
+ }
+
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG, "Thread_Mutex\n"));
+ ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n",
+ et.real_time, et.user_time, et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n",
+ (et.real_time / double (iterations)) * 1000000));
+
+ // Test the thread mutex derived (which does use inheritance or
+ // dynamic binding). Note that we call this via an instance of the
+ // derived class, so good C++ compilers should optimize the virtual
+ // function calls in this case.
+
+ timer.start ();
+
+ for (i = 0; i < iterations; i++)
+ {
+ thread_mutex_derived.acquire ();
+ thread_mutex_derived.release ();
+ }
+
+ timer.stop ();
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG, "Thread_Mutex_Derived\n"));
+ ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n",
+ et.real_time, et.user_time, et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n",
+ (et.real_time / double (iterations)) * 1000000));
+
+ // Test the thread mutex derived (which does use inheritance or
+ // dynamic binding). Note that we call this via a pointer to the
+ // base class, which points to an instance of the derived class.
+ // Thus, C++ compilers won't be able to optimize the virtual
+ // function calls in this case.
+
+ timer.start ();
+
+ for (i = 0; i < iterations; i++)
+ {
+ mutex_base->acquire ();
+ mutex_base->release ();
+ }
+
+ timer.stop ();
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG, "Mutex_Base\n"));
+ ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n",
+ et.real_time, et.user_time, et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n",
+ (et.real_time / double (iterations)) * 1000000));
+ return 0;
+}
+#else
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n"));
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/performance-tests/Misc/test_naming.cpp b/ACE/performance-tests/Misc/test_naming.cpp
new file mode 100644
index 00000000000..01938e7e563
--- /dev/null
+++ b/ACE/performance-tests/Misc/test_naming.cpp
@@ -0,0 +1,199 @@
+// $Id$
+
+// ============================================================================
+//
+// = LIBRARY
+// performance_tests
+//
+// = FILENAME
+// test_naming.cpp
+//
+// = DESCRIPTION
+// This is an example to do performance testing of the Naming Service
+// using both the normal Memory Pool as well as the light Memory Pool.
+//
+// = AUTHOR
+// Prashant Jain
+//
+// ============================================================================
+
+#include "ace/OS_main.h"
+#include "ace/ACE.h"
+#include "ace/SString.h"
+#include "ace/Naming_Context.h"
+#include "ace/Profile_Timer.h"
+#include "ace/Log_Msg.h"
+#include "ace/OS_NS_stdio.h"
+
+ACE_RCSID(Misc, test_naming, "$Id$")
+
+
+#define ACE_NS_MAX_ENTRIES 4000
+
+static char name[BUFSIZ];
+static char value[BUFSIZ];
+static char type[BUFSIZ];
+
+//FUZZ: disable check_for_lack_ACE_OS
+void
+bind (ACE_Naming_Context *ns_context, int result)
+{
+//FUZZ: enable check_for_lack_ACE_OS
+
+ // do the binds
+ for (int i = 1; i <= ACE_NS_MAX_ENTRIES; i++)
+ {
+ if (i % 50 == 0)
+ ACE_DEBUG ((LM_DEBUG, "."));
+ ACE_OS::sprintf (name, "%s%d", "name", i);
+ ACE_NS_WString w_name (name);
+
+ ACE_OS::sprintf (value, "%s%d", "value", i);
+ ACE_NS_WString w_value (value);
+
+ ACE_OS::sprintf (type, "%s%d", "type", i);
+ if (ns_context->bind (w_name, w_value, type) != result) {
+ ACE_ERROR ((LM_ERROR, "bind failed!"));
+ }
+ }
+ ACE_DEBUG ((LM_DEBUG, "\n"));
+}
+
+void
+rebind (ACE_Naming_Context *ns_context, int result)
+{
+ // do the rebinds
+ for (int i = 1; i <= ACE_NS_MAX_ENTRIES; i++)
+ {
+ ACE_OS::sprintf (name, "%s%d", "name", i);
+ ACE_NS_WString w_name (name);
+ ACE_OS::sprintf (value, "%s%d", "value", -i);
+ ACE_NS_WString w_value (value);
+ ACE_OS::sprintf (type, "%s%d", "type", -i);
+ if (ns_context->rebind (w_name, w_value, type) != result) {
+ ACE_ERROR ((LM_ERROR, "rebind failed!"));
+ }
+ }
+}
+
+void
+unbind (ACE_Naming_Context *ns_context, int result)
+{
+ // do the unbinds
+ for (int i = 1; i <= ACE_NS_MAX_ENTRIES; i++)
+ {
+ ACE_OS::sprintf (name, "%s%d", "name", i);
+ ACE_NS_WString w_name (name);
+ if (ns_context->unbind (w_name) != result) {
+ ACE_ERROR ((LM_ERROR, "unbind failed!"));
+ }
+ }
+}
+
+void
+find (ACE_Naming_Context *ns_context, int sign, int result)
+{
+ char temp_val[BUFSIZ];
+ char temp_type[BUFSIZ];
+
+ // do the finds
+ for (int i = 1; i <= ACE_NS_MAX_ENTRIES; i++)
+ {
+ ACE_OS::sprintf (name, "%s%d", "name", i);
+ ACE_NS_WString w_name (name);
+
+ ACE_NS_WString w_value;
+ char *type_out;
+
+ if (sign == 1)
+ {
+ ACE_OS::sprintf (temp_val, "%s%d", "value", i);
+ ACE_OS::sprintf (temp_type, "%s%d", "type", i);
+ }
+ else
+ {
+ ACE_OS::sprintf (temp_val, "%s%d", "value", -i);
+ ACE_OS::sprintf (temp_type, "%s%d", "type", -i);
+ }
+
+ ACE_NS_WString val (temp_val);
+
+ int resolve_result = ns_context->resolve (w_name, w_value, type_out);
+ if (resolve_result != result) {
+ ACE_ERROR ((LM_ERROR, "resolved failed!"));
+ }
+ ACE_ASSERT (resolve_result == result);
+ ACE_UNUSED_ARG (resolve_result); // To avoid compile warning
+ // with ACE_NDEBUG.
+
+ if (w_value.char_rep ())
+ {
+ ACE_DEBUG ((LM_DEBUG, "Name: %s\tValue: %s\tType: %s\n",
+ name, w_value.char_rep (), type_out));
+ ACE_ASSERT (w_value == val);
+ if (type_out)
+ {
+ ACE_ASSERT (ACE_OS::strcmp (type_out, temp_type) == 0);
+ delete[] type_out;
+ }
+ }
+ }
+}
+
+void do_testing (int argc, ACE_TCHAR *argv[], int light)
+{
+ ACE_Profile_Timer timer;
+
+ ACE_Naming_Context ns_context;
+ ACE_Name_Options *name_options = ns_context.name_options ();
+ name_options->parse_args (argc, argv);
+
+ if (light == 0) // Use SYNC
+ {
+ name_options->database (ACE::basename (name_options->process_name (),
+ ACE_DIRECTORY_SEPARATOR_CHAR));
+ ns_context.open (ACE_Naming_Context::PROC_LOCAL);
+ }
+ else // Use NO-SYNC
+ {
+ const ACE_TCHAR *p = ACE::basename (name_options->process_name (),
+ ACE_DIRECTORY_SEPARATOR_CHAR);
+ ACE_TCHAR s[5 /* strlen ("light") */ + MAXNAMELEN + 1];
+ ACE_OS::sprintf (s, ACE_TEXT("light%s"), p);
+ name_options->database (s);
+ ns_context.open (ACE_Naming_Context::PROC_LOCAL, 1);
+ }
+
+ // Add bindings to the database
+ ACE_DEBUG ((LM_DEBUG, "Binding\n"));
+
+ timer.start ();
+
+ //FUZZ: disable check_for_lack_ACE_OS
+ bind (&ns_context, 0);
+ //FUZZ: enable check_for_lack_ACE_OS
+
+ ACE_DEBUG ((LM_DEBUG, "Unbinding\n"));
+ unbind (&ns_context, 0);
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+
+ timer.elapsed_time (et);
+ ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n",
+ et.real_time, et.user_time, et.system_time));
+}
+
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ // Do testing with SYNC on
+ ACE_DEBUG ((LM_DEBUG, "SYNC is ON\n"));
+ do_testing (argc, argv, 0);
+
+ // Do testing with SYNC off
+ ACE_DEBUG ((LM_DEBUG, "SYNC is OFF\n"));
+ do_testing (argc, argv, 1);
+ return 0;
+}
diff --git a/ACE/performance-tests/Misc/test_singleton.cpp b/ACE/performance-tests/Misc/test_singleton.cpp
new file mode 100644
index 00000000000..53790a0fca4
--- /dev/null
+++ b/ACE/performance-tests/Misc/test_singleton.cpp
@@ -0,0 +1,179 @@
+// $Id$
+
+// This example illustrates the performance impact of using the
+// Double-Checked Locking pattern compared with using the "standard"
+// practice of acquiring and releasing a lock on every instance()
+// call. In addition, we compare the performance of using the
+// ACE_Singleton (which encapsulates the Double-Check Locking pattern)
+// vs. hand-coding the pattern.
+//
+// Here's the output from running this test on our SPARCstation 20, model 712s.
+//
+// ./test_singleton 1000000
+// iterations = 1000000
+// ACE_Singleton
+// real time = 0.193731 secs, user time = 0.190416 secs, system time = 0.000549 secs
+// time per call = 0.193731 usecs
+// DC_Singleton
+// real time = 0.176208 secs, user time = 0.176045 secs, system time = 0.000092 secs
+// time per call = 0.176208 usecs
+// Mutex_Singleton
+// real time = 3.160998 secs, user time = 3.121434 secs, system time = 0.000109 secs
+// time per call = 3.160998 usecs
+//
+// As you can see, both Double-Checked Locking implementations are about
+// 15 times faster than the standard mutex version. Moreover,
+// this test is run with only a single thread, so there's no contention
+// for the lock. If there were multiple threads contending for the lock,
+// the Mutex_Singleton performance would get increasing worse...
+
+#include "ace/OS_main.h"
+#include "ace/Guard_T.h"
+#include "ace/Profile_Timer.h"
+#include "ace/Singleton.h"
+#include "ace/Synch_Traits.h"
+#include "ace/Log_Msg.h"
+
+#include "test_singleton.h"
+
+ACE_RCSID(Misc, test_singleton, "$Id$")
+
+#if defined (ACE_HAS_THREADS)
+
+static const int DEFAULT_ITERATIONS = 100000000;
+
+class Mutex_Singleton
+{
+public:
+ Mutex_Singleton (void) {}
+ void svc (void) {}
+ static Mutex_Singleton *instance (void);
+
+private:
+ static ACE_SYNCH_MUTEX lock_;
+ static Mutex_Singleton *instance_;
+};
+
+ACE_SYNCH_MUTEX Mutex_Singleton::lock_;
+
+Mutex_Singleton *Mutex_Singleton::instance_;
+
+Mutex_Singleton *
+Mutex_Singleton::instance (void)
+{
+ // Acquire the lock every time in.
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, Mutex_Singleton::lock_, 0);
+
+ if (Mutex_Singleton::instance_ == 0)
+ ACE_NEW_RETURN (Mutex_Singleton::instance_, Mutex_Singleton, 0);
+
+ return Mutex_Singleton::instance_;
+}
+
+ACE_SYNCH_MUTEX DC_Singleton::lock_;
+
+DC_Singleton *DC_Singleton::instance_;
+
+DC_Singleton *
+DC_Singleton::instance (void)
+{
+ if (DC_Singleton::instance_ == 0)
+ {
+ // Only lock if instance_ isn't 0.
+ ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, DC_Singleton::lock_, 0);
+
+ // Perform the Double-Check.
+ if (DC_Singleton::instance_ == 0)
+ ACE_NEW_RETURN (DC_Singleton::instance_, DC_Singleton, 0);
+ }
+
+ return DC_Singleton::instance_;
+}
+
+typedef ACE_Singleton <DC_Singleton, ACE_SYNCH_MUTEX> My_Singleton;
+
+int
+ACE_TMAIN (int argc, ACE_TCHAR *argv[])
+{
+ ACE_Profile_Timer timer;
+ int iterations = argc > 1 ? ACE_OS::atoi (argv[1]) : DEFAULT_ITERATIONS;
+ int i;
+
+ ACE_DEBUG ((LM_DEBUG, "iterations = %d\n", iterations));
+
+ // Test the ACE_Singleton performance (which uses Double-Checked
+ // Locking).
+
+ timer.start ();
+
+ for (i = 0; i < iterations; i++)
+ My_Singleton::instance ()->svc ();
+
+ timer.stop ();
+
+ ACE_Profile_Timer::ACE_Elapsed_Time et;
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG, "ACE_Singleton\n"));
+ ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n",
+ et.real_time, et.user_time, et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n",
+ (et.real_time / double (iterations)) * 1000000));
+
+ // Test the hand-coded Singleton performance (which uses
+ // Double-Checked Locking).
+
+ timer.start ();
+
+ for (i = 0; i < iterations; i++)
+ DC_Singleton::instance ()->svc ();
+
+ timer.stop ();
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG, "DC_Singleton\n"));
+ ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n",
+ et.real_time, et.user_time, et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n",
+ (et.real_time / double (iterations)) * 1000000));
+
+ // Test the Mutex_Singleton implementation (which does not use
+ // Double-Checked Locking).
+
+ timer.start ();
+
+ for (i = 0; i < iterations; i++)
+ Mutex_Singleton::instance ()->svc ();
+
+ timer.stop ();
+
+ timer.elapsed_time (et);
+
+ ACE_DEBUG ((LM_DEBUG, "Mutex_Singleton\n"));
+ ACE_DEBUG ((LM_DEBUG, "real time = %f secs, user time = %f secs, system time = %f secs\n",
+ et.real_time, et.user_time, et.system_time));
+
+ ACE_DEBUG ((LM_DEBUG, "time per call = %f usecs\n",
+ (et.real_time / double (iterations)) * 1000000));
+
+ return 0;
+}
+
+#if defined (ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION)
+template ACE_Singleton<DC_Singleton, ACE_SYNCH_MUTEX> *
+ ACE_Singleton<DC_Singleton, ACE_SYNCH_MUTEX>::singleton_;
+#endif /* ACE_HAS_EXPLICIT_STATIC_TEMPLATE_MEMBER_INSTANTIATION */
+
+
+#else
+int
+ACE_TMAIN (int, ACE_TCHAR *[])
+{
+ ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n"));
+ return 0;
+}
+#endif /* ACE_HAS_THREADS */
diff --git a/ACE/performance-tests/Misc/test_singleton.h b/ACE/performance-tests/Misc/test_singleton.h
new file mode 100644
index 00000000000..70aef65d89b
--- /dev/null
+++ b/ACE/performance-tests/Misc/test_singleton.h
@@ -0,0 +1,24 @@
+// $Id$
+
+// Define the DC_Singleton here - it needs to be in a separate file to
+// get picked up correctly on AIX with auto template instantiation using
+// IBM C++ compiler (xlC).
+
+#ifndef __TEST_SINGLETON_H
+#define __TEST_SINGLETON_H
+
+#include "ace/Synch_Traits.h"
+
+class DC_Singleton
+{
+public:
+ DC_Singleton (void) {}
+ void svc (void) {}
+ static DC_Singleton *instance (void);
+
+private:
+ static ACE_SYNCH_MUTEX lock_;
+ static DC_Singleton *instance_;
+};
+
+#endif /* __TEST_SINGLETON_H */