2 //=============================================================================
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:
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
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.
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"
40 #include "ace/OS_NS_stdio.h"
41 #include "ace/OS_main.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
>
76 Low_Priority_Null_Task ();
77 virtual ~Low_Priority_Null_Task ();
81 // Called by other task: it returns when this task is ready to
83 void ready () { initialized_
.acquire (); }
87 ACE_hthread_t
thread_id () const { return thread_id_
; }
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
&);
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
,
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 */
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
>
162 Suspend_Resume_Test (const ACE_UINT32 iterations
);
163 virtual ~Suspend_Resume_Test ();
167 ACE_hrtime_t
elapsed_time () const { return elapsed_time_
; }
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
),
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",
211 #endif /* ACE_DEBUG_CST */
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",
223 #endif /* ACE_DEBUG_CST */
225 if (ACE_OS::thr_suspend (low_
.thread_id ()) != 0)
227 ACE_ERROR ((LM_ERROR
, "%p\n", "thr_suspend"));
232 if (ACE_OS::thr_continue (low_
.thread_id ()) != 0 &&
234 // EINVAL is OK: it just means that the thread needs to be joined.
236 ACE_ERROR ((LM_ERROR
, "%p\n", "thr_continue"));
243 timer_
.elapsed_microseconds (elapsed_time_
);
247 #if ACE_DEBUG_CST > 0
248 ACE_DEBUG ((LM_DEBUG
, "Suspend_Resume_Test::svc, finishing\n"));
249 #endif /* ACE_DEBUG_CST */
255 ///////////////////////////////////////////////////////////////////////////////
256 ///////////////////////////////////////////////////////////////////////////////
257 // class High_Priority_Simple_Task
258 ///////////////////////////////////////////////////////////////////////////////
259 ///////////////////////////////////////////////////////////////////////////////
261 class High_Priority_Simple_Task
: public ACE_Task
<ACE_MT_SYNCH
>
264 High_Priority_Simple_Task ();
265 virtual ~High_Priority_Simple_Task ();
269 // called by other task: it returns when this task is ready to
271 void ready () { initialized_
.acquire (); }
275 ACE_hthread_t
thread_id () const { return thread_id_
; }
276 ACE_UINT32
iterations () const { return iterations_
; }
278 ACE_hthread_t thread_id_
;
279 ACE_Semaphore initialized_
; // Block until thread_id_ is assigned.
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
&);
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.
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 */
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",
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 */
356 High_Priority_Simple_Task::done ()
362 ///////////////////////////////////////////////////////////////////////////////
363 ///////////////////////////////////////////////////////////////////////////////
364 // class Ping_Suspend_Resume_Test
365 ///////////////////////////////////////////////////////////////////////////////
366 ///////////////////////////////////////////////////////////////////////////////
368 class Ping_Suspend_Resume_Test
: public ACE_Task
<ACE_MT_SYNCH
>
371 Ping_Suspend_Resume_Test (const ACE_UINT32 iterations
);
372 virtual ~Ping_Suspend_Resume_Test ();
376 ACE_hrtime_t
elapsed_time () const { return elapsed_time_
; }
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
),
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
,
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 */
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 */
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 &&
452 // EINVAL is OK: it just means that the thread needs to be joined.
454 ACE_ERROR ((LM_ERROR
, "%p\n", "thr_continue"));
461 timer_
.elapsed_microseconds (elapsed_time_
);
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
471 for (i
= 0; i
< 10000 && ! ACE_OS::thr_continue (high_
.thread_id ());
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 */
489 ///////////////////////////////////////////////////////////////////////////////
490 ///////////////////////////////////////////////////////////////////////////////
492 ///////////////////////////////////////////////////////////////////////////////
493 ///////////////////////////////////////////////////////////////////////////////
495 class Yield_Test
: public ACE_Task
<ACE_MT_SYNCH
>
498 Yield_Test (const ACE_UINT32 iterations
);
499 virtual ~Yield_Test ();
503 ACE_hrtime_t
elapsed_time () const { return elapsed_time_
; }
505 const ACE_UINT32 iterations_
;
506 #if defined (VXWORKS)
507 ACE_Thread_Mutex mutex_
;
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.
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)
529 #else /* ! VXWORKS */
531 #endif /* ! VXWORKS */
534 #if ACE_DEBUG_CST > 0
535 ACE_DEBUG ((LM_DEBUG
, "Yield_Test ctor\n"));
536 #endif /* ACE_DEBUG_CST */
538 #if !defined (VXWORKS)
540 #endif /* ! VXWORKS */
542 if (this->activate (THR_BOUND
| THR_DETACHED
| THR_SCHED_FIFO
| new_lwp
,
544 ACE_OS::perror (ACE_TEXT("activate"));
546 #if !defined (VXWORKS)
547 timer_barrier_
.wait ();
549 #endif /* ! VXWORKS */
551 timer_
.elapsed_microseconds (elapsed_time_
);
554 Yield_Test::~Yield_Test()
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
);
568 ACE_OS::thr_getprio (thread_id
, priority
);
570 ACE_DEBUG ((LM_DEBUG
, "; thread ID is %u, priority is %u\n", thread_id
,
572 #endif /* ACE_DEBUG_CST */
574 #if defined (VXWORKS)
575 // Start the timer, if it hasn't already been started.
579 ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, mutex_
, -1);
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",
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.
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.
611 ACE_GUARD_RETURN (ACE_Thread_Mutex
, ace_mon
, mutex_
, -1);
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 */
632 ///////////////////////////////////////////////////////////////////////////////
633 ///////////////////////////////////////////////////////////////////////////////
634 // class Mutex_Acquire_Release_Test
635 ///////////////////////////////////////////////////////////////////////////////
636 ///////////////////////////////////////////////////////////////////////////////
638 class Mutex_Acquire_Release_Test
641 Mutex_Acquire_Release_Test (const ACE_UINT32 iterations
);
642 virtual ~Mutex_Acquire_Release_Test ();
646 ACE_hrtime_t
elapsed_time () const { return elapsed_time_
; }
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
) :
670 iterations_ (iterations
),
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",
689 #endif /* ACE_DEBUG_CST */
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
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 */
714 ///////////////////////////////////////////////////////////////////////////////
715 ///////////////////////////////////////////////////////////////////////////////
716 // class High_Priority_Synchronized_Task
717 ///////////////////////////////////////////////////////////////////////////////
718 ///////////////////////////////////////////////////////////////////////////////
720 class High_Priority_Synchronized_Task
: public ACE_Task
<ACE_MT_SYNCH
>
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 ();
730 /// Called by other task: it returns when this task is ready to
732 void ready () { initialized_
.acquire (); }
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_
; }
741 ACE_hthread_t thread_id_
;
742 ACE_Semaphore initialized_
; // Block until thread_id_ is assigned.
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.
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 () /
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);
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
857 #if ACE_DEBUG_CST > 0
858 ACE_DEBUG ((LM_DEBUG
,
859 "High_Priority_Synchronized_Task::svc, resumed (%u)\n",
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 */
873 High_Priority_Synchronized_Task::done ()
879 High_Priority_Synchronized_Task:: average_context_switch_time () const
881 return iterations_
> 0 ? static_cast<ACE_UINT32
> (total_time_
/ iterations_
)
885 ///////////////////////////////////////////////////////////////////////////////
886 ///////////////////////////////////////////////////////////////////////////////
887 // class Synchronized_Suspend_Resume_Test
888 ///////////////////////////////////////////////////////////////////////////////
889 ///////////////////////////////////////////////////////////////////////////////
891 class Synchronized_Suspend_Resume_Test
: public ACE_Task
<ACE_MT_SYNCH
>
894 Synchronized_Suspend_Resume_Test (const ACE_UINT32 iterations
);
895 virtual ~Synchronized_Suspend_Resume_Test ();
899 ACE_UINT32
average_context_switch_time ();
901 ACE_hrtime_t
elapsed_time () const { return elapsed_time_
; }
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
),
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
,
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 () /
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 */
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 */
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
1009 if (sem_
.release () != 0)
1010 ACE_ERROR_RETURN ((LM_ERROR
, "%p\n", "sem_.release"), -1);
1014 // Release the mutex so that the high priority thread can
1015 // proceed. The ACE_GUARD_RETURN macro implicity releases
1022 // The high priority thread will be block on the semaphore, so
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
1035 for (i
= 0; i
< 10000 && ! ACE_OS::thr_continue (high_
.thread_id ());
1038 #if ACE_DEBUG_CST > 0
1039 ACE_DEBUG ((LM_DEBUG
, "Synchronized_Suspend_Resume_Test::svc, finishing\n"));
1040 #endif /* ACE_DEBUG_CST */
1046 Synchronized_Suspend_Resume_Test::average_context_switch_time ()
1048 return high_
.average_context_switch_time ();
1052 ///////////////////////////////////////////////////////////////////////////////
1053 ///////////////////////////////////////////////////////////////////////////////
1054 // function get_options
1055 ///////////////////////////////////////////////////////////////////////////////
1056 ///////////////////////////////////////////////////////////////////////////////
1060 get_options (int argc
, ACE_TCHAR
*argv
[])
1062 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT("c:n?"));
1064 while ((opt
= get_opt ()) != EOF
) {
1067 if (ACE_OS::atoi (get_opt
.opt_arg ()) >= 0)
1069 counter
= ACE_OS::atoi (get_opt
.opt_arg ());
1073 ACE_DEBUG ((LM_ERROR
, "%n: count must be >= 0\n"));
1078 new_lwp
= THR_NEW_LWP
;
1081 ACE_DEBUG ((LM_ERROR
, "usage: %n %s\n", usage
));
1086 ACE_DEBUG ((LM_ERROR
, "%n: unknown arg, %c\n", opt
));
1087 ACE_DEBUG ((LM_ERROR
, "usage: %n %s\n", usage
));
1092 switch (argc
- get_opt
.opt_ind ()) {
1094 // use default number of iterations
1097 if (ACE_OS::atoi (argv
[get_opt
.opt_ind ()]) > 0)
1098 num_iterations
= ACE_OS::atoi (argv
[get_opt
.opt_ind ()]);
1101 ACE_DEBUG ((LM_ERROR
, "%n: iterations must be > 0\n"));
1106 ACE_DEBUG ((LM_ERROR
, "%n: too many arguments\n"));
1107 ACE_DEBUG ((LM_ERROR
, "usage: %n %s\n", usage
));
1115 ///////////////////////////////////////////////////////////////////////////////
1116 ///////////////////////////////////////////////////////////////////////////////
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
))
1129 // Disable LM_DEBUG.
1130 ACE_Log_Msg::instance ()->priority_mask (ACE_LOG_MSG
->priority_mask () ^
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 (
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"));
1154 ACE_OS::perror (ACE_TEXT("context_switch_time"));
1159 HIGH_PRIORITY
= ACE_Sched_Params::next_priority (ACE_SCHED_FIFO
,
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.
1169 ACE_OS::thr_self (self
);
1170 ACE_OS::thr_setprio (ACE_Sched_Params::next_priority (ACE_SCHED_FIFO
,
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 ()) /
1212 (double) ACE_UINT64_DBLCAST_ADAPTER (
1213 suspend_resume_test
.elapsed_time ()) /
1215 (double) ACE_UINT64_DBLCAST_ADAPTER (
1216 ping_suspend_resume_test
.elapsed_time () -
1217 suspend_resume_test
.elapsed_time ()) /
1218 num_iterations
/ 2u));
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 () /
1226 suspend_resume_test
.elapsed_time () /
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 "
1242 (yield_test
.elapsed_time () / num_iterations
/ 2u),
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 */);
1284 ACE_TMAIN(int, ACE_TCHAR
*[])
1286 ACE_ERROR ((LM_ERROR
, "threads not supported on this platform\n"));
1289 #endif /* ACE_HAS_THREADS */