diff options
Diffstat (limited to 'performance-tests/Misc/context_switch_time.cpp')
-rw-r--r-- | performance-tests/Misc/context_switch_time.cpp | 1305 |
1 files changed, 0 insertions, 1305 deletions
diff --git a/performance-tests/Misc/context_switch_time.cpp b/performance-tests/Misc/context_switch_time.cpp deleted file mode 100644 index 48b184c9eb6..00000000000 --- a/performance-tests/Misc/context_switch_time.cpp +++ /dev/null @@ -1,1305 +0,0 @@ -// $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 count, 0 means forever>]\n" - " [-n to spawn a new LWP with each thread\n" - "[<iterations>]]"; - -#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/Synch.h" - -ACE_RCSID(Misc, context_switch_time, "$Id$") - -#if defined (ACE_HAS_THREADS) - -#if !defined (DEBUG) -# define DEBUG 0 -#endif /* DEBUG */ - -static const u_int LOW_PRIORITY = ACE_THR_PRI_FIFO_DEF; -static u_int HIGH_PRIORITY; - -// Global test configuration parameters. -static ACE_UINT32 count = 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task ctor\n")); -#endif /* DEBUG */ - - this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp, - 1, 0, LOW_PRIORITY); - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task ctor, activated\n")); -#endif /* DEBUG */ -} - -Low_Priority_Null_Task::~Low_Priority_Null_Task() -{ -} - -int -Low_Priority_Null_Task::svc () -{ -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task::svc (), entering")); -#endif /* DEBUG */ - - ACE_Thread_Manager::instance ()->thr_self (thread_id_); - initialized_.release (); - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_)); -#endif /* DEBUG */ - - // This task must never actually execute, so just have it block - // on a semaphore forever . . . - blocked_semaphore_.acquire (); - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Low_Priority_Task::svc, finishing\n")); -#endif /* DEBUG */ - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test ctor\n")); -#endif /* DEBUG */ - - this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp, - 1, 0, HIGH_PRIORITY); -} - -Suspend_Resume_Test::~Suspend_Resume_Test() -{ -} - -int -Suspend_Resume_Test::svc () -{ -#if DEBUG > 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 /* DEBUG */ - - 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 DEBUG > 0 - if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0) - ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test::svc (), iteration %u\n", - i)); -#endif /* DEBUG */ - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test::svc, finishing\n")); -#endif /* DEBUG */ - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task ctor\n")); -#endif /* DEBUG */ - - this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp, - 1, 0, HIGH_PRIORITY); - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task ctor, activated\n")); -#endif /* DEBUG */ -} - -High_Priority_Simple_Task::~High_Priority_Simple_Task() -{ -} - -int -High_Priority_Simple_Task::svc () -{ -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc (), entering")); -#endif /* DEBUG */ - - ACE_Thread_Manager::instance ()->thr_self (thread_id_); - initialized_.release (); - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_)); -#endif /* DEBUG */ - - for (ACE_UINT32 i = 0; ! terminate_; ++i) - { -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, suspend self (" - "%u)\n", thread_id_)); -#endif /* DEBUG */ - - ++iterations_; - - // immediately suspend self - if (ACE_OS::thr_suspend (thread_id_) != 0) - { - ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "thr_suspend"), -1); - } - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, resumed (%u)\n", - thread_id_)); -#endif /* DEBUG */ - } - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, finishing\n")); -#endif /* DEBUG */ - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test ctor\n")); -#endif /* DEBUG */ - - this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp, - 1, 0, LOW_PRIORITY); -} - -Ping_Suspend_Resume_Test::~Ping_Suspend_Resume_Test() -{ -} - -int -Ping_Suspend_Resume_Test::svc () -{ -#if DEBUG > 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 /* DEBUG */ - - high_.ready (); - -#if DEBUG > 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 /* DEBUG */ - - // 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 DEBUG > 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 /* DEBUG */ - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc: told high priority " - "task to terminate\n")); -#endif /* DEBUG */ - - // 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc, finishing\n")); -#endif /* DEBUG */ - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Yield_Test ctor\n")); -#endif /* DEBUG */ - -#if !defined (VXWORKS) - timer_.start (); -#endif /* ! VXWORKS */ - - this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp, - 2, 0, LOW_PRIORITY); - -#if !defined (VXWORKS) - timer_barrier_.wait (); - timer_.stop (); -#endif /* ! VXWORKS */ - - timer_.elapsed_microseconds (elapsed_time_); -} - -Yield_Test::~Yield_Test() -{ -} - -int -Yield_Test::svc () -{ -#if DEBUG > 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 /* DEBUG */ - -#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 DEBUG > 0 - if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0) - { - ACE_DEBUG ((LM_DEBUG, "Yield_Test::svc () [%u], iteration %u\n", - thread_id, i)); - } -#endif /* DEBUG */ - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Yield_Test::svc, finishing\n")); -#endif /* DEBUG */ - - 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 DEBUG > 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 /* DEBUG */ - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Mutex_Acquire_Release_Test::svc, finishing\n")); -#endif /* DEBUG */ - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task ctor\n")); -#endif /* DEBUG */ - - this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp, - 1, 0, HIGH_PRIORITY); - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task ctor, activated\n")); -#endif /* DEBUG */ -} - -High_Priority_Synchronized_Task::~High_Priority_Synchronized_Task() -{ -} - -int -High_Priority_Synchronized_Task::svc () -{ -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task::svc (), entering")); -#endif /* DEBUG */ - - 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 = - ACE_static_cast (ACE_UINT32, - mutex_acquire_release_test.elapsed_time () / - num_iterations); -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "mutex_acquire_release: %u nsec\n", - mutex_acquire_release_time)); -#endif /* DEBUG */ - } - - initialized_.release (); - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_)); -#endif /* DEBUG */ - - for (ACE_UINT32 i = 0; ! terminate_; ++i) - { -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, - "High_Priority_Synchronized_Task::svc, wait on sem (" - "%u)\n", thread_id_)); -#endif /* DEBUG */ - - - 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); - // Convert the elapsed time from 64 to 32 bits. - const ACE_UINT32 delta_t = - ACE_static_cast (ACE_UINT32, - nsec / ACE_static_cast (ACE_UINT32, 1u)); - - const ACE_UINT32 context_switch_time = - delta_t - mutex_acquire_release_time; - - 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, - "High_Priority_Synchronized_Task::svc, resumed (%u)\n", - thread_id_)); -#endif /* DEBUG */ - } - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task::svc, finishing\n")); -#endif /* DEBUG */ - - 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 ? ACE_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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Synchronized_Suspend_Resume_Test ctor\n")); -#endif /* DEBUG */ - - this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp, - 1, 0, LOW_PRIORITY); -} - -Synchronized_Suspend_Resume_Test::~Synchronized_Suspend_Resume_Test() -{ -} - -int -Synchronized_Suspend_Resume_Test::svc () -{ -#if DEBUG > 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 /* DEBUG */ - - { - Mutex_Acquire_Release_Test mutex_acquire_release_test (num_iterations); - mutex_acquire_release_test.svc (); - mutex_acquire_release_time_ = - ACE_static_cast (ACE_UINT32, - mutex_acquire_release_test.elapsed_time () / - num_iterations); -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "mutex_acquire_release: %u nsec\n", - mutex_acquire_release_time_)); -#endif /* DEBUG */ - } - - high_.ready (); - -#if DEBUG > 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 /* DEBUG */ - - // 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 DEBUG > 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 /* DEBUG */ - - { - // 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_.acquire"), -1); - -#if DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, - "Synchronized_Suspend_Resume_Test::svc: told high priority " - "task to terminate\n")); -#endif /* DEBUG */ - - // 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 DEBUG > 0 - ACE_DEBUG ((LM_DEBUG, "Synchronized_Suspend_Resume_Test::svc, finishing\n")); -#endif /* DEBUG */ - - 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, char *argv[]) -{ - ACE_Get_Opt get_opt (argc, argv, "c:n?"); - int opt; - while ((opt = get_opt ()) != EOF) { - switch (opt) { - case 'c': - if (ACE_OS::atoi (get_opt.optarg) >= 0) - { - count = ACE_OS::atoi (get_opt.optarg); - } - 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%a", usage, 0)); - 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.optind) { - case 0: - // use default number of iterations - break; - case 1: - if (ACE_OS::atoi (argv [get_opt.optind]) > 0) - { - num_iterations = ACE_OS::atoi (argv [get_opt.optind]); - } - 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 -main (int argc, char *argv []) -{ - ACE_LOG_MSG->open (argv[0] > 0 ? argv[0] : "context_switch_time"); - -#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_DEBUG, "clock speed: %u MHz\n", - ACE_High_Res_Timer::global_scale_factor ())); -#endif /* ACE_HAS_PENTIUM && ! ACE_HAS_HI_RES_TIMER && ! ACE_WIN32 */ - - // Disable LM_DEBUG. - ACE_Log_Msg::instance ()->priority_mask (ACE_LOG_MSG->priority_mask () ^ - LM_DEBUG); - - if (get_options (argc, argv)) ACE_OS::exit (-1); - - 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 ("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)); - - int forever = count == 0; - - ACE_Stats context_switch_test_stats; - ACE_Stats yield_test_stats; - ACE_Stats synchronized_suspend_resume_test_stats; - - while (forever || count-- > 0) - { - // Check to see if thr_continue (), and therefore thr_suspend (), - // probably, are supported. - if (ACE_OS::thr_continue (self) == 0 || - errno != ENOTSUP) - { - // 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 ((ping_suspend_resume_test.elapsed_time () - - suspend_resume_test.elapsed_time ()) / - ACE_static_cast (ACE_UINT32, 1u)); - - ACE_DEBUG ((LM_INFO, "context switch time is (%.3f - %.3f)/2 = " - "%.3f microseconds\n", - (double) (ping_suspend_resume_test.elapsed_time () / - num_iterations), - (double) (suspend_resume_test.elapsed_time () / - num_iterations), - (double) ((ping_suspend_resume_test.elapsed_time () - - suspend_resume_test.elapsed_time ()) / - num_iterations / 2u))); - } - else - { - ACE_DEBUG ((LM_INFO, "ping suspend/resume time of %.3f usec was " - "less than suspend/resume time of %.3f\n", - (double) (ping_suspend_resume_test.elapsed_time () / - num_iterations), - (double) (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 (yield_test.elapsed_time () / - ACE_static_cast (ACE_UINT32, 1u)); - - // 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); - } - - ACE_OS::printf ("context_switch_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 -main (int, char *[]) -{ - ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n")); - return 0; -} -#endif /* ACE_HAS_THREADS */ - - -// EOF |