Merge pull request #2309 from mitza-oci/warnings
[ACE_TAO.git] / ACE / performance-tests / Misc / context_switch_time.cpp
bloba4315a1a15537f146e5f1a3b10897dccdbd6a61c
2 //=============================================================================
3 /**
4 * @file context_switch_time.cpp
6 * Program that calculates context switch time between threads.
7 * The Suspend-Resume test is based on the Task Context Switching
8 * measurement approach described in:
9 * Darren Cathey<br>
10 * "RTOS Benchmarking -- All Things Considered . . ."<br>
11 * <a href="http://www.realtime-info.be"><em>Real-Time Magazine</em></a>,
12 * Second Quarter 1993,
13 * <em>reprinted by <a href="http://www.wrs.com/artreqfm.html">Wind River
14 * Systems</a></em><p>
15 * which in turn is based on Superconducting Super Collider (SSC)
16 * Laboratory Ping Suspend/Resume Task and Suspend/Resume Task benchmarks.
17 * It measures two different times:
18 * 1) The time to resume a blocked high priority task, which does
19 * nothing other than block immediately. A lower priority task
20 * resumes the high priority task, so the elapsed time includes
21 * two context switches, one task suspend, and one task resume.
22 * 2) The time to suspend and resume a low priority task that does
23 * nothing. There is no context switching. This time is subtracted
24 * from the one described in 1) above, and the result is divided by
25 * two to yield the context switch time.
27 * = CREATION DATE
28 * 17 January 1997
30 * @author David L. Levine
32 //=============================================================================
35 static const char usage [] = "[-? |\n"
36 " [-c <repeat counter, 0 means forever>]\n"
37 " [-n to spawn a new LWP with each thread\n"
38 "[<iterations>]]";
40 #include "ace/OS_NS_stdio.h"
41 #include "ace/OS_main.h"
42 #include "ace/Task.h"
43 #include "ace/Sched_Params.h"
44 #include "ace/Stats.h"
45 #include "ace/High_Res_Timer.h"
46 #include "ace/Get_Opt.h"
47 #include "ace/Thread_Semaphore.h"
48 #include "ace/Barrier.h"
49 #include "ace/OS_NS_unistd.h"
50 #include "ace/OS_NS_errno.h"
52 #if defined (ACE_HAS_THREADS)
54 #if !defined (ACE_DEBUG_CST)
55 # define ACE_DEBUG_CST 0
56 #endif /* ACE_DEBUG_CST */
58 static const u_int LOW_PRIORITY = ACE_THR_PRI_FIFO_DEF;
59 static u_int HIGH_PRIORITY;
61 // Global test configuration parameters.
62 static ACE_UINT32 counter = 1;
63 static ACE_UINT32 num_iterations = 1000;
64 static ACE_UINT32 new_lwp = 0;
67 ///////////////////////////////////////////////////////////////////////////////
68 ///////////////////////////////////////////////////////////////////////////////
69 // class Low_Priority_Null_Task
70 ///////////////////////////////////////////////////////////////////////////////
71 ///////////////////////////////////////////////////////////////////////////////
73 class Low_Priority_Null_Task : public ACE_Task<ACE_MT_SYNCH>
75 public:
76 Low_Priority_Null_Task ();
77 virtual ~Low_Priority_Null_Task ();
79 virtual int svc ();
81 // Called by other task: it returns when this task is ready to
82 // continue.
83 void ready () { initialized_.acquire (); }
85 void done ();
87 ACE_hthread_t thread_id () const { return thread_id_; }
88 private:
89 ACE_hthread_t thread_id_;
90 ACE_Semaphore initialized_; // Blocks until thread_id_ is assigned.
91 ACE_Semaphore blocked_semaphore_;
93 // Force proper construction of independent instances.
94 Low_Priority_Null_Task (const Low_Priority_Null_Task &);
95 Low_Priority_Null_Task &operator= (const Low_Priority_Null_Task &);
98 inline
99 Low_Priority_Null_Task::Low_Priority_Null_Task() :
100 ACE_Task<ACE_MT_SYNCH> (ACE_Thread_Manager::instance ()),
101 initialized_ (0), // initialize to locked, then unlock when ready
102 blocked_semaphore_ (0)
104 #if ACE_DEBUG_CST > 0
105 ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task ctor\n"));
106 #endif /* ACE_DEBUG_CST */
108 if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
109 1, 0, LOW_PRIORITY))
110 ACE_OS::perror (ACE_TEXT("activate"));
112 #if ACE_DEBUG_CST > 0
113 ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task ctor, activated\n"));
114 #endif /* ACE_DEBUG_CST */
117 Low_Priority_Null_Task::~Low_Priority_Null_Task()
122 Low_Priority_Null_Task::svc ()
124 #if ACE_DEBUG_CST > 0
125 ACE_DEBUG ((LM_DEBUG, "Low_Priority_Null_Task::svc (), entering"));
126 #endif /* ACE_DEBUG_CST */
128 ACE_Thread_Manager::instance ()->thr_self (thread_id_);
129 initialized_.release ();
131 #if ACE_DEBUG_CST > 0
132 ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_));
133 #endif /* ACE_DEBUG_CST */
135 // This task must never actually execute, so just have it block
136 // on a semaphore forever . . .
137 blocked_semaphore_.acquire ();
139 #if ACE_DEBUG_CST > 0
140 ACE_DEBUG ((LM_DEBUG, "Low_Priority_Task::svc, finishing\n"));
141 #endif /* ACE_DEBUG_CST */
143 return 0;
146 void
147 Low_Priority_Null_Task::done ()
149 blocked_semaphore_.release ();
153 ///////////////////////////////////////////////////////////////////////////////
154 ///////////////////////////////////////////////////////////////////////////////
155 // class Suspend_Resume_Test
156 ///////////////////////////////////////////////////////////////////////////////
157 ///////////////////////////////////////////////////////////////////////////////
159 class Suspend_Resume_Test : public ACE_Task<ACE_MT_SYNCH>
161 public:
162 Suspend_Resume_Test (const ACE_UINT32 iterations);
163 virtual ~Suspend_Resume_Test ();
165 virtual int svc ();
167 ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
168 private:
169 const ACE_UINT32 iterations_;
171 Low_Priority_Null_Task low_;
173 ACE_High_Res_Timer timer_;
175 ACE_hrtime_t elapsed_time_;
177 // Force proper construction of independent instances.
178 Suspend_Resume_Test ();
179 Suspend_Resume_Test (const Suspend_Resume_Test &);
180 Suspend_Resume_Test &operator= (const Suspend_Resume_Test &);
183 Suspend_Resume_Test::Suspend_Resume_Test (const ACE_UINT32 iterations) :
184 ACE_Task<ACE_MT_SYNCH> (),
185 iterations_ (iterations),
186 low_ (),
187 timer_ ()
189 #if ACE_DEBUG_CST > 0
190 ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test ctor\n"));
191 #endif /* ACE_DEBUG_CST */
193 if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
194 1, 0, HIGH_PRIORITY))
195 ACE_OS::perror (ACE_TEXT("activate"));
198 Suspend_Resume_Test::~Suspend_Resume_Test()
203 Suspend_Resume_Test::svc ()
205 #if ACE_DEBUG_CST > 0
206 ACE_hthread_t thread_id;
207 ACE_Thread_Manager::instance ()->thr_self (thread_id);
209 ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test::svc (), thread ID is %d\n",
210 thread_id));
211 #endif /* ACE_DEBUG_CST */
213 low_.ready ();
215 timer_.start ();
217 for (ACE_UINT32 i = 0; i < iterations_; ++i)
219 #if ACE_DEBUG_CST > 0
220 if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0)
221 ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test::svc (), iteration %u\n",
222 i));
223 #endif /* ACE_DEBUG_CST */
225 if (ACE_OS::thr_suspend (low_.thread_id ()) != 0)
227 ACE_ERROR ((LM_ERROR, "%p\n", "thr_suspend"));
228 low_.done ();
229 return -1;
232 if (ACE_OS::thr_continue (low_.thread_id ()) != 0 &&
233 errno != EINVAL)
234 // EINVAL is OK: it just means that the thread needs to be joined.
236 ACE_ERROR ((LM_ERROR, "%p\n", "thr_continue"));
237 low_.done ();
238 return -1;
242 timer_.stop ();
243 timer_.elapsed_microseconds (elapsed_time_);
245 low_.done ();
247 #if ACE_DEBUG_CST > 0
248 ACE_DEBUG ((LM_DEBUG, "Suspend_Resume_Test::svc, finishing\n"));
249 #endif /* ACE_DEBUG_CST */
251 return 0;
255 ///////////////////////////////////////////////////////////////////////////////
256 ///////////////////////////////////////////////////////////////////////////////
257 // class High_Priority_Simple_Task
258 ///////////////////////////////////////////////////////////////////////////////
259 ///////////////////////////////////////////////////////////////////////////////
261 class High_Priority_Simple_Task : public ACE_Task<ACE_MT_SYNCH>
263 public:
264 High_Priority_Simple_Task ();
265 virtual ~High_Priority_Simple_Task ();
267 virtual int svc ();
269 // called by other task: it returns when this task is ready to
270 // continue
271 void ready () { initialized_.acquire (); }
273 void done ();
275 ACE_hthread_t thread_id () const { return thread_id_; }
276 ACE_UINT32 iterations () const { return iterations_; }
277 private:
278 ACE_hthread_t thread_id_;
279 ACE_Semaphore initialized_; // Block until thread_id_ is assigned.
280 int terminate_;
281 ACE_UINT32 iterations_;
283 // Force proper construction of independent instances.
284 High_Priority_Simple_Task (const High_Priority_Simple_Task &);
285 High_Priority_Simple_Task &operator= (const High_Priority_Simple_Task &);
288 inline
289 High_Priority_Simple_Task::High_Priority_Simple_Task() :
290 ACE_Task<ACE_MT_SYNCH> (ACE_Thread_Manager::instance ()),
291 initialized_ (0), // Initialize to locked, then unlock when ready.
292 terminate_ (0),
293 iterations_ (0)
295 #if ACE_DEBUG_CST > 0
296 ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task ctor\n"));
297 #endif /* ACE_DEBUG_CST */
299 if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
300 1, 0, HIGH_PRIORITY))
301 ACE_OS::perror (ACE_TEXT("activate"));
303 #if ACE_DEBUG_CST > 0
304 ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task ctor, activated\n"));
305 #endif /* ACE_DEBUG_CST */
308 High_Priority_Simple_Task::~High_Priority_Simple_Task()
313 High_Priority_Simple_Task::svc ()
315 #if ACE_DEBUG_CST > 0
316 ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc (), entering"));
317 #endif /* ACE_DEBUG_CST */
319 ACE_Thread_Manager::instance ()->thr_self (thread_id_);
320 initialized_.release ();
322 #if ACE_DEBUG_CST > 0
323 ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_));
324 #endif /* ACE_DEBUG_CST */
326 for (ACE_UINT32 i = 0; ! terminate_; ++i)
328 #if ACE_DEBUG_CST > 0
329 ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, suspend self ("
330 "%u)\n", thread_id_));
331 #endif /* ACE_DEBUG_CST */
333 ++iterations_;
335 // immediately suspend self
336 if (ACE_OS::thr_suspend (thread_id_) != 0)
338 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "thr_suspend"), -1);
341 #if ACE_DEBUG_CST > 0
342 ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, resumed (%u)\n",
343 thread_id_));
344 #endif /* ACE_DEBUG_CST */
347 #if ACE_DEBUG_CST > 0
348 ACE_DEBUG ((LM_DEBUG, "High_Priority_Simple_Task::svc, finishing\n"));
349 #endif /* ACE_DEBUG_CST */
351 return 0;
354 inline
355 void
356 High_Priority_Simple_Task::done ()
358 terminate_ = 1;
362 ///////////////////////////////////////////////////////////////////////////////
363 ///////////////////////////////////////////////////////////////////////////////
364 // class Ping_Suspend_Resume_Test
365 ///////////////////////////////////////////////////////////////////////////////
366 ///////////////////////////////////////////////////////////////////////////////
368 class Ping_Suspend_Resume_Test : public ACE_Task<ACE_MT_SYNCH>
370 public:
371 Ping_Suspend_Resume_Test (const ACE_UINT32 iterations);
372 virtual ~Ping_Suspend_Resume_Test ();
374 virtual int svc ();
376 ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
377 private:
378 const ACE_UINT32 iterations_;
380 High_Priority_Simple_Task high_;
382 ACE_High_Res_Timer timer_;
384 ACE_hrtime_t elapsed_time_;
386 // Force proper construction of independent instances.
387 Ping_Suspend_Resume_Test ();
388 Ping_Suspend_Resume_Test (const Ping_Suspend_Resume_Test &);
389 Ping_Suspend_Resume_Test &operator= (const Ping_Suspend_Resume_Test &);
392 Ping_Suspend_Resume_Test::Ping_Suspend_Resume_Test (
393 const ACE_UINT32 iterations)
395 ACE_Task<ACE_MT_SYNCH> (),
396 iterations_ (iterations),
397 high_ (),
398 timer_ ()
400 #if ACE_DEBUG_CST > 0
401 ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test ctor\n"));
402 #endif /* ACE_DEBUG_CST */
404 if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
405 1, 0, LOW_PRIORITY))
406 ACE_OS::perror (ACE_TEXT("activate"));
409 Ping_Suspend_Resume_Test::~Ping_Suspend_Resume_Test()
414 Ping_Suspend_Resume_Test::svc ()
416 #if ACE_DEBUG_CST > 0
417 ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc (), entering"));
419 ACE_hthread_t thread_id;
420 ACE_Thread_Manager::instance ()->thr_self (thread_id);
422 ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id));
423 #endif /* ACE_DEBUG_CST */
425 high_.ready ();
427 #if ACE_DEBUG_CST > 0
428 int priority, high_priority;
429 ACE_OS::thr_getprio (thread_id, priority);
430 ACE_OS::thr_getprio (high_.thread_id (), high_priority);
431 ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc (), priority is %d, "
432 ", high thread priority is %d\n",
433 priority, high_priority));
434 #endif /* ACE_DEBUG_CST */
436 timer_.start ();
438 ACE_UINT32 i;
440 for (i = 0; i < iterations_; ++i)
442 #if ACE_DEBUG_CST > 0
443 if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0)
445 ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc (), iteration "
446 "%d, continue high-priority thread %u\n",
447 i, high_.thread_id ()));
449 #endif /* ACE_DEBUG_CST */
450 if (ACE_OS::thr_continue (high_.thread_id ()) != 0 &&
451 errno != EINVAL)
452 // EINVAL is OK: it just means that the thread needs to be joined.
454 ACE_ERROR ((LM_ERROR, "%p\n", "thr_continue"));
455 high_.done ();
456 return -1;
460 timer_.stop ();
461 timer_.elapsed_microseconds (elapsed_time_);
463 high_.done ();
464 #if ACE_DEBUG_CST > 0
465 ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc: told high priority "
466 "task to terminate\n"));
467 #endif /* ACE_DEBUG_CST */
469 // Resume the thread until thr_continue fails, indicating that it has
470 // finished.
471 for (i = 0; i < 10000 && ! ACE_OS::thr_continue (high_.thread_id ());
472 ++i) /* null */;
474 // Don't count the one iteration that was used to allow the high-priority
475 // thread to terminate.
476 if (high_.iterations () < iterations_)
477 ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test: high priority task "
478 "executed only %u iterations!\n",
479 high_.iterations ()));
481 #if ACE_DEBUG_CST > 0
482 ACE_DEBUG ((LM_DEBUG, "Ping_Suspend_Resume_Test::svc, finishing\n"));
483 #endif /* ACE_DEBUG_CST */
485 return 0;
489 ///////////////////////////////////////////////////////////////////////////////
490 ///////////////////////////////////////////////////////////////////////////////
491 // class Yield_Test
492 ///////////////////////////////////////////////////////////////////////////////
493 ///////////////////////////////////////////////////////////////////////////////
495 class Yield_Test : public ACE_Task<ACE_MT_SYNCH>
497 public:
498 Yield_Test (const ACE_UINT32 iterations);
499 virtual ~Yield_Test ();
501 virtual int svc ();
503 ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
504 private:
505 const ACE_UINT32 iterations_;
506 #if defined (VXWORKS)
507 ACE_Thread_Mutex mutex_;
508 u_int started_;
509 u_int stopped_;
510 #else /* ! VXWORKS */
511 ACE_Barrier timer_barrier_;
512 #endif /* ! VXWORKS */
513 ACE_High_Res_Timer timer_;
514 ACE_hrtime_t elapsed_time_;
516 // Force proper construction of independent instances.
517 Yield_Test ();
518 Yield_Test (const Yield_Test &);
519 Yield_Test &operator= (const Yield_Test &);
522 Yield_Test::Yield_Test (const ACE_UINT32 iterations) :
523 ACE_Task<ACE_MT_SYNCH> (),
524 iterations_ (iterations),
525 #if defined (VXWORKS)
526 mutex_ (),
527 started_ (0),
528 stopped_ (0),
529 #else /* ! VXWORKS */
530 timer_barrier_ (3),
531 #endif /* ! VXWORKS */
532 timer_ ()
534 #if ACE_DEBUG_CST > 0
535 ACE_DEBUG ((LM_DEBUG, "Yield_Test ctor\n"));
536 #endif /* ACE_DEBUG_CST */
538 #if !defined (VXWORKS)
539 timer_.start ();
540 #endif /* ! VXWORKS */
542 if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
543 2, 0, LOW_PRIORITY))
544 ACE_OS::perror (ACE_TEXT("activate"));
546 #if !defined (VXWORKS)
547 timer_barrier_.wait ();
548 timer_.stop ();
549 #endif /* ! VXWORKS */
551 timer_.elapsed_microseconds (elapsed_time_);
554 Yield_Test::~Yield_Test()
559 Yield_Test::svc ()
561 #if ACE_DEBUG_CST > 0
562 ACE_DEBUG ((LM_DEBUG, "Yield_Test::svc (), entering"));
564 ACE_hthread_t thread_id;
565 ACE_Thread_Manager::instance ()->thr_self (thread_id);
567 int priority;
568 ACE_OS::thr_getprio (thread_id, priority);
570 ACE_DEBUG ((LM_DEBUG, "; thread ID is %u, priority is %u\n", thread_id,
571 priority));
572 #endif /* ACE_DEBUG_CST */
574 #if defined (VXWORKS)
575 // Start the timer, if it hasn't already been started.
576 if (! started_)
578 // Double-check.
579 ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, mutex_, -1);
581 if (! started_)
583 started_ = 1;
584 timer_.start ();
587 #endif /* VXWORKS */
589 for (ACE_UINT32 i = 0; i < iterations_; ++i)
591 #if ACE_DEBUG_CST > 0
592 if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0)
594 ACE_DEBUG ((LM_DEBUG, "Yield_Test::svc () [%u], iteration %u\n",
595 thread_id, i));
597 #endif /* ACE_DEBUG_CST */
599 ACE_OS::thr_yield ();
602 #if defined (VXWORKS)
603 // Stop the timer, if it hasn't already been started.
604 if (! stopped_)
606 // Maybe it would be better to read the clock before grabbing
607 // the mutex. Then, only apply the clock reading below, instead
608 // of reading the clock after grabbing the mutex.
610 // Double-check.
611 ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, mutex_, -1);
613 if (! stopped_)
615 stopped_ = 1;
616 timer_.stop ();
617 timer_.elapsed_time (elapsed_time_); /* nanoseconds */
620 #else /* ! VXWORKS */
621 timer_barrier_.wait ();
622 #endif /* ! VXWORKS */
624 #if ACE_DEBUG_CST > 0
625 ACE_DEBUG ((LM_DEBUG, "Yield_Test::svc, finishing\n"));
626 #endif /* ACE_DEBUG_CST */
628 return 0;
632 ///////////////////////////////////////////////////////////////////////////////
633 ///////////////////////////////////////////////////////////////////////////////
634 // class Mutex_Acquire_Release_Test
635 ///////////////////////////////////////////////////////////////////////////////
636 ///////////////////////////////////////////////////////////////////////////////
638 class Mutex_Acquire_Release_Test
640 public:
641 Mutex_Acquire_Release_Test (const ACE_UINT32 iterations);
642 virtual ~Mutex_Acquire_Release_Test ();
644 virtual int svc ();
646 ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
647 private:
648 /// Mutex used for acquire/release time measurement.
649 ACE_Thread_Mutex mutex_;
651 /// Semaphore used for acquire/release time measurement.
652 ACE_Thread_Semaphore sem_;
654 const ACE_UINT32 iterations_;
656 ACE_High_Res_Timer timer_;
658 ACE_hrtime_t elapsed_time_;
660 // Force proper construction of independent instances.
661 Mutex_Acquire_Release_Test ();
662 Mutex_Acquire_Release_Test (const Mutex_Acquire_Release_Test &);
663 Mutex_Acquire_Release_Test &operator= (const Mutex_Acquire_Release_Test &);
666 Mutex_Acquire_Release_Test::Mutex_Acquire_Release_Test (
667 const ACE_UINT32 iterations) :
668 mutex_ (),
669 sem_ (),
670 iterations_ (iterations),
671 timer_ ()
675 Mutex_Acquire_Release_Test::~Mutex_Acquire_Release_Test()
680 Mutex_Acquire_Release_Test::svc ()
682 #if ACE_DEBUG_CST > 0
683 ACE_hthread_t thread_id;
684 ACE_Thread_Manager::instance ()->thr_self (thread_id);
686 ACE_DEBUG ((LM_DEBUG,
687 "Mutex_Acquire_Release_Test::svc (), thread ID is %d\n",
688 thread_id));
689 #endif /* ACE_DEBUG_CST */
691 timer_.start ();
693 for (ACE_UINT32 i = 0; i < iterations_; ++i)
695 // Block on the mutex.
696 ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, mutex_, -1);
698 // Release the mutex so that the low priority thread can
699 // proceed. The ACE_GUARD_RETURN macro implicity releases the
700 // mutex.
703 timer_.stop ();
704 timer_.elapsed_time (elapsed_time_); /* nanoseconds */
706 #if ACE_DEBUG_CST > 0
707 ACE_DEBUG ((LM_DEBUG, "Mutex_Acquire_Release_Test::svc, finishing\n"));
708 #endif /* ACE_DEBUG_CST */
710 return 0;
714 ///////////////////////////////////////////////////////////////////////////////
715 ///////////////////////////////////////////////////////////////////////////////
716 // class High_Priority_Synchronized_Task
717 ///////////////////////////////////////////////////////////////////////////////
718 ///////////////////////////////////////////////////////////////////////////////
720 class High_Priority_Synchronized_Task : public ACE_Task<ACE_MT_SYNCH>
722 public:
723 High_Priority_Synchronized_Task (ACE_Thread_Semaphore &sem,
724 ACE_Thread_Mutex &mutex,
725 ACE_High_Res_Timer &timer);
726 virtual ~High_Priority_Synchronized_Task ();
728 virtual int svc ();
730 /// Called by other task: it returns when this task is ready to
731 /// continue
732 void ready () { initialized_.acquire (); }
734 void done ();
736 ACE_UINT32 average_context_switch_time () const;
738 ACE_hthread_t thread_id () const { return thread_id_; }
739 ACE_UINT32 iterations () const { return iterations_; }
740 private:
741 ACE_hthread_t thread_id_;
742 ACE_Semaphore initialized_; // Block until thread_id_ is assigned.
743 int terminate_;
744 ACE_UINT32 iterations_;
746 /// Semaphore used to resume the task.
747 ACE_Thread_Semaphore &sem_;
749 /// Mutex used to block the task.
750 ACE_Thread_Mutex &mutex_;
752 /// Clock shared between low and high priority tasks.
753 ACE_High_Res_Timer &timer_;
755 /// Running total context switch time, nsec.
756 ACE_hrtime_t total_time_;
758 // Force proper construction of independent instances.
759 High_Priority_Synchronized_Task ();
760 High_Priority_Synchronized_Task (const High_Priority_Synchronized_Task &);
761 High_Priority_Synchronized_Task &
762 operator= (const High_Priority_Synchronized_Task &);
765 High_Priority_Synchronized_Task::High_Priority_Synchronized_Task (
766 ACE_Thread_Semaphore &sem,
767 ACE_Thread_Mutex &mutex,
768 ACE_High_Res_Timer &timer) :
769 ACE_Task<ACE_MT_SYNCH> (ACE_Thread_Manager::instance ()),
770 initialized_ (0), // Initialize to locked, then unlock when ready.
771 terminate_ (0),
772 iterations_ (0),
773 sem_ (sem),
774 mutex_ (mutex),
775 timer_ (timer),
776 total_time_ (0)
778 #if ACE_DEBUG_CST > 0
779 ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task ctor\n"));
780 #endif /* ACE_DEBUG_CST */
782 if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
783 1, 0, HIGH_PRIORITY))
784 ACE_OS::perror (ACE_TEXT("activate"));
786 #if ACE_DEBUG_CST > 0
787 ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task ctor, activated\n"));
788 #endif /* ACE_DEBUG_CST */
791 High_Priority_Synchronized_Task::~High_Priority_Synchronized_Task()
796 High_Priority_Synchronized_Task::svc ()
798 #if ACE_DEBUG_CST > 0
799 ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task::svc (), entering"));
800 #endif /* ACE_DEBUG_CST */
802 ACE_Thread_Manager::instance ()->thr_self (thread_id_);
804 ACE_UINT32 mutex_acquire_release_time = 0;
806 Mutex_Acquire_Release_Test mutex_acquire_release_test (num_iterations);
807 mutex_acquire_release_test.svc ();
808 mutex_acquire_release_time =
809 static_cast<ACE_UINT32> (mutex_acquire_release_test.elapsed_time () /
810 num_iterations);
811 #if ACE_DEBUG_CST > 0
812 ACE_DEBUG ((LM_DEBUG, "mutex_acquire_release: %u nsec\n",
813 mutex_acquire_release_time));
814 #endif /* ACE_DEBUG_CST */
817 initialized_.release ();
819 #if ACE_DEBUG_CST > 0
820 ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id_));
821 #endif /* ACE_DEBUG_CST */
823 for (ACE_UINT32 i = 0; ! terminate_; ++i)
825 #if ACE_DEBUG_CST > 0
826 ACE_DEBUG ((LM_DEBUG,
827 "High_Priority_Synchronized_Task::svc, wait on sem ("
828 "%u)\n", thread_id_));
829 #endif /* ACE_DEBUG_CST */
831 if (sem_.acquire () != 0)
833 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "sem_.acquire"), -1);
837 // Block on the mutex.
838 ACE_GUARD_RETURN (ACE_Thread_Mutex, guard, mutex_, -1);
840 timer_.stop ();
842 ++iterations_;
844 ACE_hrtime_t nsec;
845 timer_.elapsed_time (nsec);
846 const ACE_UINT32 context_switch_time =
847 ACE_U64_TO_U32 (nsec) >= mutex_acquire_release_time ?
848 ACE_U64_TO_U32 (nsec) - mutex_acquire_release_time : 0;
850 total_time_ += context_switch_time;
852 // Release the mutex so that the low priority thread can
853 // proceed. The ACE_GUARD_RETURN macro implicity releases the
854 // mutex.
857 #if ACE_DEBUG_CST > 0
858 ACE_DEBUG ((LM_DEBUG,
859 "High_Priority_Synchronized_Task::svc, resumed (%u)\n",
860 thread_id_));
861 #endif /* ACE_DEBUG_CST */
864 #if ACE_DEBUG_CST > 0
865 ACE_DEBUG ((LM_DEBUG, "High_Priority_Synchronized_Task::svc, finishing\n"));
866 #endif /* ACE_DEBUG_CST */
868 return 0;
871 inline
872 void
873 High_Priority_Synchronized_Task::done ()
875 terminate_ = 1;
878 ACE_UINT32
879 High_Priority_Synchronized_Task:: average_context_switch_time () const
881 return iterations_ > 0 ? static_cast<ACE_UINT32> (total_time_ / iterations_)
882 : 0;
885 ///////////////////////////////////////////////////////////////////////////////
886 ///////////////////////////////////////////////////////////////////////////////
887 // class Synchronized_Suspend_Resume_Test
888 ///////////////////////////////////////////////////////////////////////////////
889 ///////////////////////////////////////////////////////////////////////////////
891 class Synchronized_Suspend_Resume_Test : public ACE_Task<ACE_MT_SYNCH>
893 public:
894 Synchronized_Suspend_Resume_Test (const ACE_UINT32 iterations);
895 virtual ~Synchronized_Suspend_Resume_Test ();
897 virtual int svc ();
899 ACE_UINT32 average_context_switch_time ();
901 ACE_hrtime_t elapsed_time () const { return elapsed_time_; }
902 private:
903 const ACE_UINT32 iterations_;
905 /// Used by the low priority thread to resume the high priority thread.
906 ACE_Thread_Semaphore sem_;
908 /// Used by the low priority thread to block the high priority thread.
909 ACE_Thread_Mutex mutex_;
911 /// Clock shared between low and high priority tasks.
912 ACE_High_Res_Timer timer_;
914 /// The high priority task.
915 High_Priority_Synchronized_Task high_;
917 ACE_hrtime_t elapsed_time_;
919 ACE_UINT32 mutex_acquire_release_time_;
921 // Force proper construction of independent instances.
922 Synchronized_Suspend_Resume_Test ();
923 Synchronized_Suspend_Resume_Test (const Synchronized_Suspend_Resume_Test &);
924 Synchronized_Suspend_Resume_Test &
925 operator= (const Synchronized_Suspend_Resume_Test &);
928 Synchronized_Suspend_Resume_Test::Synchronized_Suspend_Resume_Test (
929 const ACE_UINT32 iterations)
931 ACE_Task<ACE_MT_SYNCH> (),
932 iterations_ (iterations),
933 sem_ (0),
934 mutex_ (),
935 timer_ (),
936 high_ (sem_, mutex_, timer_),
937 mutex_acquire_release_time_ (0)
939 #if ACE_DEBUG_CST > 0
940 ACE_DEBUG ((LM_DEBUG, "Synchronized_Suspend_Resume_Test ctor\n"));
941 #endif /* ACE_DEBUG_CST */
943 if (this->activate (THR_BOUND | THR_DETACHED | THR_SCHED_FIFO | new_lwp,
944 1, 0, LOW_PRIORITY))
945 ACE_OS::perror (ACE_TEXT("activate"));
948 Synchronized_Suspend_Resume_Test::~Synchronized_Suspend_Resume_Test()
953 Synchronized_Suspend_Resume_Test::svc ()
955 #if ACE_DEBUG_CST > 0
956 ACE_DEBUG ((LM_DEBUG, "Synchronized_Suspend_Resume_Test::svc (), entering"));
958 ACE_hthread_t thread_id;
959 ACE_Thread_Manager::instance ()->thr_self (thread_id);
961 ACE_DEBUG ((LM_DEBUG, "; thread ID is %u\n", thread_id));
962 #endif /* ACE_DEBUG_CST */
965 Mutex_Acquire_Release_Test mutex_acquire_release_test (num_iterations);
966 mutex_acquire_release_test.svc ();
967 mutex_acquire_release_time_ =
968 static_cast<ACE_UINT32> (mutex_acquire_release_test.elapsed_time () /
969 num_iterations);
970 #if ACE_DEBUG_CST > 0
971 ACE_DEBUG ((LM_DEBUG, "mutex_acquire_release: %u nsec\n",
972 mutex_acquire_release_time_));
973 #endif /* ACE_DEBUG_CST */
976 high_.ready ();
978 #if ACE_DEBUG_CST > 0
979 int priority, high_priority;
980 ACE_OS::thr_getprio (thread_id, priority);
981 ACE_OS::thr_getprio (high_.thread_id (), high_priority);
982 ACE_DEBUG ((LM_DEBUG,
983 "Synchronized_Suspend_Resume_Test::svc (), priority is %d, "
984 ", high thread priority is %d\n",
985 priority, high_priority));
986 #endif /* ACE_DEBUG_CST */
988 ACE_UINT32 i;
990 for (i = 0; i < iterations_; ++i)
992 #if ACE_DEBUG_CST > 0
993 if (i % (iterations_ >= 10 ? iterations_ / 10 : 1) == 0)
995 ACE_DEBUG ((LM_DEBUG,
996 "Synchronized_Suspend_Resume_Test::svc (), iteration "
997 "%d, continue high-priority thread %u\n",
998 i, high_.thread_id ()));
1000 #endif /* ACE_DEBUG_CST */
1003 // Acquire the mutex so that the high priority thread will
1004 // block after we signal it via the condition variable.
1005 ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, mutex_, -1);
1007 // Release the semaphore so that the high priority thread can
1008 // proceed.
1009 if (sem_.release () != 0)
1010 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "sem_.release"), -1);
1012 timer_.start ();
1014 // Release the mutex so that the high priority thread can
1015 // proceed. The ACE_GUARD_RETURN macro implicity releases
1016 // the mutex.
1020 high_.done ();
1022 // The high priority thread will be block on the semaphore, so
1023 // release it.
1024 if (sem_.release () != 0)
1025 ACE_ERROR_RETURN ((LM_ERROR, "%p\n", "sem_.release"), -1);
1027 #if ACE_DEBUG_CST > 0
1028 ACE_DEBUG ((LM_DEBUG,
1029 "Synchronized_Suspend_Resume_Test::svc: told high priority "
1030 "task to terminate\n"));
1031 #endif /* ACE_DEBUG_CST */
1033 // Resume the thread until thr_continue fails, indicating that it has
1034 // finished.
1035 for (i = 0; i < 10000 && ! ACE_OS::thr_continue (high_.thread_id ());
1036 ++i) /* null */;
1038 #if ACE_DEBUG_CST > 0
1039 ACE_DEBUG ((LM_DEBUG, "Synchronized_Suspend_Resume_Test::svc, finishing\n"));
1040 #endif /* ACE_DEBUG_CST */
1042 return 0;
1045 ACE_UINT32
1046 Synchronized_Suspend_Resume_Test::average_context_switch_time ()
1048 return high_.average_context_switch_time ();
1052 ///////////////////////////////////////////////////////////////////////////////
1053 ///////////////////////////////////////////////////////////////////////////////
1054 // function get_options
1055 ///////////////////////////////////////////////////////////////////////////////
1056 ///////////////////////////////////////////////////////////////////////////////
1058 static
1059 u_int
1060 get_options (int argc, ACE_TCHAR *argv[])
1062 ACE_Get_Opt get_opt (argc, argv, ACE_TEXT("c:n?"));
1063 int opt;
1064 while ((opt = get_opt ()) != EOF) {
1065 switch (opt) {
1066 case 'c':
1067 if (ACE_OS::atoi (get_opt.opt_arg ()) >= 0)
1069 counter = ACE_OS::atoi (get_opt.opt_arg ());
1071 else
1073 ACE_DEBUG ((LM_ERROR, "%n: count must be >= 0\n"));
1074 return 1;
1076 break;
1077 case 'n':
1078 new_lwp = THR_NEW_LWP;
1079 break;
1080 case '?':
1081 ACE_DEBUG ((LM_ERROR, "usage: %n %s\n", usage));
1082 ACE_OS::exit (1);
1083 /* NOTREACHED */
1084 break;
1085 default:
1086 ACE_DEBUG ((LM_ERROR, "%n: unknown arg, %c\n", opt));
1087 ACE_DEBUG ((LM_ERROR, "usage: %n %s\n", usage));
1088 return 1;
1092 switch (argc - get_opt.opt_ind ()) {
1093 case 0:
1094 // use default number of iterations
1095 break;
1096 case 1:
1097 if (ACE_OS::atoi (argv [get_opt.opt_ind ()]) > 0)
1098 num_iterations = ACE_OS::atoi (argv [get_opt.opt_ind ()]);
1099 else
1101 ACE_DEBUG ((LM_ERROR, "%n: iterations must be > 0\n"));
1102 return 1;
1104 break;
1105 default:
1106 ACE_DEBUG ((LM_ERROR, "%n: too many arguments\n"));
1107 ACE_DEBUG ((LM_ERROR, "usage: %n %s\n", usage));
1108 return 1;
1111 return 0;
1115 ///////////////////////////////////////////////////////////////////////////////
1116 ///////////////////////////////////////////////////////////////////////////////
1117 // function main
1118 ///////////////////////////////////////////////////////////////////////////////
1119 ///////////////////////////////////////////////////////////////////////////////
1122 ACE_TMAIN (int argc, ACE_TCHAR *argv [])
1124 ACE_LOG_MSG->open (argv[0] != 0 ? argv[0] : ACE_TEXT("context_switch_time"));
1126 if (get_options (argc, argv))
1127 ACE_OS::exit (-1);
1129 // Disable LM_DEBUG.
1130 ACE_Log_Msg::instance ()->priority_mask (ACE_LOG_MSG->priority_mask () ^
1131 LM_DEBUG);
1133 #if defined (ACE_HAS_PENTIUM) && \
1134 !defined (ACE_HAS_HI_RES_TIMER) && !defined (ACE_WIN32)
1135 // Just to verify that ACE_High_Res_Timer::global_scale_factor ()
1136 // correctly determines the clock speed.
1137 ACE_DEBUG ((LM_INFO, "clock speed: %u MHz\n",
1138 ACE_High_Res_Timer::global_scale_factor ()));
1139 #endif /* ACE_HAS_PENTIUM && ! ACE_HAS_HI_RES_TIMER && ! ACE_WIN32 */
1141 if (ACE_OS::sched_params (
1142 ACE_Sched_Params (
1143 ACE_SCHED_FIFO,
1144 ACE_Sched_Params::priority_min (ACE_SCHED_FIFO),
1145 ACE_SCOPE_PROCESS)) != 0)
1147 if (ACE_OS::last_error () == EPERM)
1149 ACE_DEBUG ((LM_MAX, "context_switch_time: user is not superuser, "
1150 "so remain in time-sharing class\n"));
1152 else
1154 ACE_OS::perror (ACE_TEXT("context_switch_time"));
1155 ACE_OS::exit (-1);
1159 HIGH_PRIORITY = ACE_Sched_Params::next_priority (ACE_SCHED_FIFO,
1160 LOW_PRIORITY);
1161 ACE_DEBUG ((LM_INFO, "low priority: %d, high priority: %d\n",
1162 LOW_PRIORITY, HIGH_PRIORITY));
1164 // Set the priority of this thread so that it's higher than any of
1165 // the test threads. That might help avoid problems when waiting on
1166 // those threads, below. It also seems to help the times
1167 // significantly on LynxOS.
1168 ACE_hthread_t self;
1169 ACE_OS::thr_self (self);
1170 ACE_OS::thr_setprio (ACE_Sched_Params::next_priority (ACE_SCHED_FIFO,
1171 HIGH_PRIORITY));
1173 bool forever = counter == 0;
1175 ACE_Stats context_switch_test_stats;
1176 ACE_Stats yield_test_stats;
1177 ACE_Stats synchronized_suspend_resume_test_stats;
1179 int suspend_resume_supported = 0;
1180 // Check to see if thr_continue (), and therefore thr_suspend (),
1181 // probably, are supported.
1182 if (ACE_OS::thr_continue (self) == 0 || errno != ENOTSUP)
1183 suspend_resume_supported = 1;
1185 while (forever || counter-- > 0)
1187 if (suspend_resume_supported)
1189 // Run suspend/resume test first . . .
1190 Suspend_Resume_Test suspend_resume_test (num_iterations);
1191 // Wait for all tasks to exit.
1192 ACE_Thread_Manager::instance ()->wait ();
1194 // Then Ping Suspend/Resume test.
1195 Ping_Suspend_Resume_Test ping_suspend_resume_test (num_iterations);
1196 // Wait for all tasks to exit.
1197 ACE_Thread_Manager::instance ()->wait ();
1199 if (ping_suspend_resume_test.elapsed_time () >
1200 suspend_resume_test.elapsed_time ())
1202 context_switch_test_stats.
1203 sample (ACE_U64_TO_U32 (
1204 ping_suspend_resume_test.elapsed_time () -
1205 suspend_resume_test.elapsed_time ()));
1207 ACE_DEBUG ((LM_INFO, "context switch time is (%.3f - %.3f)/2 = "
1208 "%.3f microseconds\n",
1209 (double) ACE_UINT64_DBLCAST_ADAPTER (
1210 ping_suspend_resume_test.elapsed_time ()) /
1211 num_iterations,
1212 (double) ACE_UINT64_DBLCAST_ADAPTER (
1213 suspend_resume_test.elapsed_time ()) /
1214 num_iterations,
1215 (double) ACE_UINT64_DBLCAST_ADAPTER (
1216 ping_suspend_resume_test.elapsed_time () -
1217 suspend_resume_test.elapsed_time ()) /
1218 num_iterations / 2u));
1220 else
1222 ACE_DEBUG ((LM_INFO, "ping suspend/resume time of %u usec was "
1223 "less than suspend/resume time of %u\n",
1224 ping_suspend_resume_test.elapsed_time () /
1225 num_iterations,
1226 suspend_resume_test.elapsed_time () /
1227 num_iterations));
1231 // Then Yield test.
1232 Yield_Test yield_test (num_iterations);
1233 // Wait for all tasks to exit.
1234 ACE_Thread_Manager::instance ()->wait ();
1236 yield_test_stats.sample (ACE_U64_TO_U32 (yield_test.elapsed_time ()));
1238 // Try _really_ hard not to use floating point.
1239 ACE_DEBUG ((LM_INFO, "context switch time from yield test is %u.%03u "
1240 "microseconds\n",
1241 (ACE_UINT32)
1242 (yield_test.elapsed_time () / num_iterations / 2u),
1243 (ACE_UINT32)
1244 (yield_test.elapsed_time () % (num_iterations * 2u)) *
1245 1000u / num_iterations / 2u));
1247 Synchronized_Suspend_Resume_Test
1248 synchronized_suspend_resume_test (num_iterations);
1249 // Wait for all tasks to exit.
1250 ACE_Thread_Manager::instance ()->wait ();
1252 synchronized_suspend_resume_test_stats.sample (
1253 synchronized_suspend_resume_test.average_context_switch_time ());
1255 ACE_DEBUG ((LM_INFO, "context switch time from synch susp/resume test "
1256 "is %u.%03u microseconds\n",
1257 synchronized_suspend_resume_test.
1258 average_context_switch_time () / 1000u,
1259 synchronized_suspend_resume_test.
1260 average_context_switch_time () % 1000u));
1262 // Give, e.g., Draft 4 Posix platforms a chance to cleanup threads.
1263 const ACE_Time_Value half_sec (0L, 500000L);
1264 ACE_OS::sleep (half_sec);
1267 if (suspend_resume_supported)
1269 ACE_OS::printf ("suspend-resume test: ");
1270 context_switch_test_stats.print_summary (3, num_iterations * 2u);
1273 ACE_OS::printf ("\nyield_test: ");
1274 yield_test_stats.print_summary (3, num_iterations * 2u);
1276 ACE_OS::printf ("\nsynchronized suspend-resume test: ");
1277 synchronized_suspend_resume_test_stats.print_summary (3,
1278 1000u /* nsec/usec */);
1280 return 0;
1282 #else
1284 ACE_TMAIN(int, ACE_TCHAR *[])
1286 ACE_ERROR ((LM_ERROR, "threads not supported on this platform\n"));
1287 return 0;
1289 #endif /* ACE_HAS_THREADS */
1292 // EOF