2 //=============================================================================
4 * @file Timer_Queue_Test.cpp
6 * This is a simple test of <ACE_Timer_Queue> and four of its
7 * subclasses (<ACE_Timer_List>, <ACE_Timer_Heap>,
8 * <ACE_Timer_Wheel>, and <ACE_Timer_Hash>). The test sets up a
9 * bunch of timers and then adds them to a timer queue. The
10 * functionality of the timer queue is then tested. No command
11 * line arguments are needed to run the test.
13 * @author Douglas C. Schmidt <d.schmidt@vanderbilt.edu>
14 * @author Prashant Jain <pjain@cs.wustl.edu>
15 * @author and Darrell Brunsch <brunsch@cs.wustl.edu>
17 //=============================================================================
19 #include "test_config.h"
20 #include "randomize.h"
21 #include "ace/Profile_Timer.h"
22 #include "ace/Timer_Queue.h"
23 #include "ace/Timer_List.h"
24 #include "ace/Timer_Heap.h"
25 #include "ace/Timer_Wheel.h"
26 #include "ace/Timer_Hash.h"
27 #include "ace/Timer_Queue.h"
28 #include "ace/Time_Policy.h"
29 #include "ace/Recursive_Thread_Mutex.h"
30 #include "ace/Null_Mutex.h"
31 #include "ace/OS_NS_unistd.h"
32 #include "ace/Containers_T.h"
33 #include "ace/Event_Handler.h"
35 // Number of iterations for the performance tests. Some platforms
36 // have a very high ACE_DEFAULT_TIMERS (HP-UX is 400), so limit this
37 // to a reasonable run time.
38 #if (ACE_DEFAULT_TIMERS > 20)
39 static int max_iterations
= 2000;
41 static int max_iterations
= ACE_DEFAULT_TIMERS
* 100;
44 // Amount of time between each timer.
45 // (0 schedules all the timers to expire at exactly the same time.)
47 static int TIMER_DISTANCE
= 50;
49 // Array of timer ids assigned to us that we need to keep track of.
50 static long *timer_ids
= 0;
52 class Example_Handler
: public ACE_Event_Handler
55 Example_Handler (): close_count_ (0) {}
57 int handle_close (ACE_HANDLE
, ACE_Reactor_Mask mask
) override
59 ACE_TEST_ASSERT (mask
== ACE_Event_Handler::TIMER_MASK
);
64 int handle_timeout (const ACE_Time_Value
&,
65 const void *arg
) override
67 int *act
= (int *) arg
;
68 ACE_TEST_ASSERT (*act
== 42 || *act
== 007);
72 result
= -1; // This is the special value to trigger a handle_close
78 /// Keeps track of the number of times that <handle_close> is called.
83 struct Interval_Handler
: public ACE_Event_Handler
85 Interval_Handler () : trip_count_ (0) { }
87 int handle_timeout (const ACE_Time_Value
& , const void *) override
93 unsigned trip_count_
; // number of times handle_timeout has been tripped.
97 test_interval_timer (ACE_Timer_Queue
*tq
)
102 Set up a timer to fire on a 50ms interval.
105 ACE_Time_Value
interval (0, 50 * 1000 /* number of usec in millisecond */);
106 const unsigned NUM_INTERVAL_FIRINGS
= 50;
107 ACE_Time_Value loop_stop_time
=
108 tq
->gettimeofday () + (NUM_INTERVAL_FIRINGS
* interval
);
109 const unsigned EXPECTED_TRIP_COUNT
=
110 NUM_INTERVAL_FIRINGS
+ 1 /* for the first immediate firing */;
112 long id
= tq
->schedule (&ih
, 0 /* no act */, ACE_Time_Value::zero
, interval
);
113 ACE_TEST_ASSERT (id
!= -1);
119 while (tq
->gettimeofday () < loop_stop_time
);
122 ACE_TEXT("after interval loop, timer fired %d ")
123 ACE_TEXT("times out of %d expected: %s\n"),
124 ih
.trip_count_
, EXPECTED_TRIP_COUNT
,
125 ih
.trip_count_
== EXPECTED_TRIP_COUNT
126 ? ACE_TEXT ("success") : ACE_TEXT ("FAIL")
133 test_functionality (ACE_Timer_Queue
*tq
)
137 ACE_TEST_ASSERT (tq
->is_empty () != 0);
138 ACE_TEST_ASSERT (ACE_Time_Value::zero
== ACE_Time_Value (0));
142 // Do a test on earliest_time.
143 ACE_Time_Value earliest_time
= tq
->gettimeofday ();
145 const void *timer_act
= 0;
146 ACE_NEW (timer_act
, int (1));
147 timer_id
= tq
->schedule (&eh
, timer_act
, earliest_time
);
149 ACE_OS::sleep (ACE_Time_Value (0, 10));
151 ACE_NEW (timer_act
, int (1));
152 timer_id2
= tq
->schedule (&eh
, timer_act
, tq
->gettimeofday ());
154 long result
= tq
->earliest_time () == earliest_time
;
155 ACE_TEST_ASSERT (result
!= 0);
157 tq
->cancel (timer_id
, &timer_act
);
158 delete (int *) timer_act
;
159 tq
->cancel (timer_id2
, &timer_act
);
160 delete (int *) timer_act
;
162 ACE_TEST_ASSERT (tq
->is_empty () == 1);
163 ACE_TEST_ASSERT (eh
.close_count_
== 0);
165 ACE_NEW (timer_act
, int (1));
166 timer_id
= tq
->schedule (&eh
,
168 tq
->gettimeofday ());
169 ACE_TEST_ASSERT (timer_id
!= -1);
170 ACE_TEST_ASSERT (tq
->is_empty () == 0); //==
172 ACE_NEW (timer_act
, int (42));
173 result
= tq
->schedule (&eh
,
175 tq
->gettimeofday ());
176 ACE_TEST_ASSERT (result
!= -1);
177 ACE_TEST_ASSERT (tq
->is_empty () == 0); //==
179 ACE_NEW (timer_act
, int (42));
180 result
= tq
->schedule (&eh
,
182 tq
->gettimeofday ());
183 ACE_TEST_ASSERT (result
!= -1);
184 ACE_TEST_ASSERT (tq
->is_empty () == 0); //==
186 // The following method will trigger a call to <handle_close>.
187 ACE_TEST_ASSERT (eh
.close_count_
== 0);
188 result
= tq
->cancel (timer_id
, &timer_act
, 0);
189 ACE_TEST_ASSERT (result
== 1);
190 delete (int *) timer_act
;
192 ACE_TEST_ASSERT (tq
->is_empty () == 0);
193 ACE_TEST_ASSERT (eh
.close_count_
== 1);
195 result
= tq
->expire ();
196 ACE_TEST_ASSERT (result
== 2);
198 ACE_NEW (timer_act
, int (007));
199 result
= tq
->schedule (&eh
,
201 tq
->gettimeofday ());
202 ACE_TEST_ASSERT (result
!= -1);
204 const void *timer_act1
= 0;
205 ACE_NEW (timer_act1
, int (42));
206 result
= tq
->schedule (&eh
,
208 tq
->gettimeofday () + ACE_Time_Value (100));
209 ACE_TEST_ASSERT (result
!= -1);
211 const void *timer_act2
= 0;
212 ACE_NEW (timer_act2
, int (42));
213 result
= tq
->schedule (&eh
,
215 tq
->gettimeofday () + ACE_Time_Value (100));
216 ACE_TEST_ASSERT (result
!= -1);
218 // The following will trigger a call to <handle_close> when it
219 // cancels the second timer. This happens because the first timer
220 // has an <act> of 007, which causes eh.handle_timeout () to return
221 // -1. Since -1 is returned, all timers that use <eh> will be
222 // cancelled (and <handle_close> will only be called on the first
223 // timer that is cancelled).
224 ACE_TEST_ASSERT (eh
.close_count_
== 1);
226 result
= tq
->expire ();
227 ACE_TEST_ASSERT (result
== 1);
228 ACE_TEST_ASSERT (eh
.close_count_
== 2);
230 ACE_TEST_ASSERT (tq
->is_empty () != 0);
231 delete (int *) timer_act2
;
232 delete (int *) timer_act1
;
234 ACE_NEW (timer_act
, int (4));
235 timer_id
= tq
->schedule (&eh
,
237 tq
->gettimeofday ());
238 ACE_TEST_ASSERT (timer_id
!= -1);
240 ACE_NEW (timer_act
, int (4));
241 timer_id2
= tq
->schedule (&eh
,
243 tq
->gettimeofday ());
244 ACE_TEST_ASSERT (timer_id2
!= -1);
246 // The following method will trigger a call to <handle_close>.
247 ACE_TEST_ASSERT (eh
.close_count_
== 2);
248 result
= tq
->cancel (timer_id
, &timer_act
);
249 ACE_TEST_ASSERT (result
!= -1);
250 delete (int *) timer_act
;
252 result
= tq
->cancel (timer_id2
, &timer_act
);
253 ACE_TEST_ASSERT (result
!= -1);
254 delete (int *) timer_act
;
256 ACE_TEST_ASSERT (eh
.close_count_
== 2); // Only one call to handle_close() even though two timers
257 ACE_TEST_ASSERT (tq
->is_empty () != 0);
259 result
= tq
->expire ();
260 ACE_TEST_ASSERT (result
== 0);
262 // This tests to make sure that <handle_close> is called when there
263 // is only one timer of the type in the queue
264 ACE_TEST_ASSERT (eh
.close_count_
== 2);
266 ACE_NEW (timer_act
, int (007));
267 result
= tq
->schedule (&eh
,
269 tq
->gettimeofday ());
270 ACE_TEST_ASSERT (result
!= -1);
272 result
= tq
->expire ();
273 ACE_TEST_ASSERT (result
== 1);
274 ACE_TEST_ASSERT (eh
.close_count_
== 3);
276 ACE_NEW (timer_act
, int (6));
277 timer_id
= tq
->schedule (&eh
,
279 tq
->gettimeofday ());
280 ACE_TEST_ASSERT (timer_id
!= -1);
282 ACE_NEW (timer_act
, int (7));
283 timer_id2
= tq
->schedule (&eh
,
285 tq
->gettimeofday ());
286 ACE_TEST_ASSERT (timer_id2
!= -1);
288 ACE_TEST_ASSERT (eh
.close_count_
== 3);
290 result
= tq
->cancel (timer_id
, &timer_act
);
291 ACE_TEST_ASSERT (result
== 1);
292 ACE_TEST_ASSERT (eh
.close_count_
== 3);
293 delete (int *) timer_act
;
295 result
= tq
->cancel (timer_id2
, &timer_act
);
296 ACE_TEST_ASSERT (result
== 1);
297 ACE_TEST_ASSERT (eh
.close_count_
== 3);
298 delete (int *) timer_act
;
300 result
= tq
->expire ();
301 ACE_TEST_ASSERT (result
== 0);
302 ACE_TEST_ASSERT (eh
.close_count_
== 3);
306 test_performance (ACE_Timer_Queue
*tq
,
307 const ACE_TCHAR
*test_name
)
310 ACE_Profile_Timer timer
;
312 const void *timer_act
= 0;
314 ACE_TEST_ASSERT (tq
->is_empty () != 0);
315 ACE_TEST_ASSERT (ACE_Time_Value::zero
== ACE_Time_Value (0));
317 // Test the amount of time required to schedule all the timers.
319 ACE_Time_Value
*times
= 0;
320 ACE_NEW (times
, ACE_Time_Value
[max_iterations
]);
322 // Set up a bunch of times TIMER_DISTANCE ms apart.
323 for (i
= 0; i
< max_iterations
; ++i
)
325 times
[i
] = (tq
->gettimeofday()
326 + ACE_Time_Value(0, i
* TIMER_DISTANCE
* 1000));
329 ACE_Time_Value last_time
= times
[max_iterations
-1];
333 for (i
= 0; i
< max_iterations
; ++i
)
335 ACE_NEW (timer_act
, int (42));
336 timer_ids
[i
] = tq
->schedule (&eh
,
339 ACE_TEST_ASSERT (timer_ids
[i
] != -1);
342 ACE_TEST_ASSERT (tq
->is_empty () == 0);
346 ACE_Profile_Timer::ACE_Elapsed_Time et
;
348 timer
.elapsed_time (et
);
350 ACE_DEBUG ((LM_DEBUG
,
351 ACE_TEXT ("time to schedule %d timers for %s\n"),
352 max_iterations
, test_name
));
353 ACE_DEBUG ((LM_DEBUG
,
354 ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
355 et
.real_time
, et
.user_time
, et
.system_time
));
356 ACE_DEBUG ((LM_DEBUG
,
357 ACE_TEXT ("time per call = %f usecs\n"),
358 (et
.user_time
/ ACE_timer_t (max_iterations
)) * 1000000));
360 // Test the amount of time required to cancel all the timers.
364 for (i
= max_iterations
; i
-- != 0; )
366 tq
->cancel (timer_ids
[i
], &timer_act
);
367 delete (int *) timer_act
;
372 ACE_TEST_ASSERT (tq
->is_empty () != 0);
374 timer
.elapsed_time (et
);
376 ACE_DEBUG ((LM_DEBUG
,
377 ACE_TEXT ("time to cancel %d timers for %s\n"),
378 max_iterations
, test_name
));
379 ACE_DEBUG ((LM_DEBUG
,
380 ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
381 et
.real_time
, et
.user_time
, et
.system_time
));
382 ACE_DEBUG ((LM_DEBUG
,
383 ACE_TEXT ("time per call = %f usecs\n"),
384 (et
.user_time
/ ACE_timer_t (max_iterations
)) * 1000000));
386 // Test the amount of time required to schedule and expire all the
391 for (i
= 0; i
< max_iterations
; ++i
)
393 ACE_NEW (timer_act
, int (42));
394 long result
= tq
->schedule (&eh
, timer_act
, times
[i
]);
395 ACE_TEST_ASSERT (result
!= -1);
398 ACE_TEST_ASSERT (tq
->is_empty () == 0);
400 // Expire all the timers.
401 tq
->expire (last_time
+ ACE_Time_Value(1));
405 ACE_TEST_ASSERT (tq
->is_empty () != 0);
407 timer
.elapsed_time (et
);
409 ACE_DEBUG ((LM_DEBUG
,
410 ACE_TEXT ("time to schedule and expire %d timers for %s\n"),
411 max_iterations
, test_name
));
412 ACE_DEBUG ((LM_DEBUG
,
413 ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
414 et
.real_time
, et
.user_time
, et
.system_time
));
415 ACE_DEBUG ((LM_DEBUG
,
416 ACE_TEXT ("time per call = %f usecs\n"),
417 (et
.user_time
/ ACE_timer_t (max_iterations
)) * 1000000));
421 static_cast<unsigned int> (ACE_OS::time (0L)));
423 // Test the amount of time required to randomly cancel all the
426 for (i
= 0; i
< max_iterations
; ++i
)
428 ACE_NEW (timer_act
, int (42));
429 timer_ids
[i
] = tq
->schedule (&eh
,
432 ACE_TEST_ASSERT (timer_ids
[i
] != -1);
435 ACE_TEST_ASSERT (tq
->is_empty () == 0);
439 for (i
= max_iterations
- 1; i
>= 0; i
--)
441 tq
->cancel (timer_ids
[i
], &timer_act
);
442 delete (int *) timer_act
;
445 ACE_TEST_ASSERT (tq
->is_empty () != 0);
449 timer
.elapsed_time (et
);
451 ACE_DEBUG ((LM_DEBUG
,
452 ACE_TEXT ("time to randomly cancel %d timers for %s\n"),
455 ACE_DEBUG ((LM_DEBUG
,
456 ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
460 ACE_DEBUG ((LM_DEBUG
,
461 ACE_TEXT ("time per call = %f usecs\n"),
462 (et
.user_time
/ ACE_timer_t (max_iterations
)) * 1000000));
464 // Test the amount of time required to randomly schedule all the timers.
468 for (i
= 0; i
< max_iterations
; ++i
)
470 ACE_NEW (timer_act
, int (42));
471 timer_ids
[i
] = tq
->schedule (&eh
,
474 ACE_TEST_ASSERT (timer_ids
[i
] != -1);
479 ACE_TEST_ASSERT (tq
->is_empty () == 0);
481 timer
.elapsed_time (et
);
483 ACE_DEBUG ((LM_DEBUG
,
484 ACE_TEXT ("time to randomly schedule %d timers for %s\n"),
485 max_iterations
, test_name
));
486 ACE_DEBUG ((LM_DEBUG
,
487 ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
491 ACE_DEBUG ((LM_DEBUG
,
492 ACE_TEXT ("time per call = %f usecs\n"),
493 (et
.user_time
/ ACE_timer_t (max_iterations
)) * 1000000));
495 // Test the amount of time required to expire all the timers.
499 tq
->expire (last_time
+ ACE_Time_Value(1));
501 ACE_TEST_ASSERT (tq
->is_empty ());
505 timer
.elapsed_time (et
);
507 ACE_DEBUG ((LM_DEBUG
,
508 ACE_TEXT ("time to expire %d randomly scheduled timers for %s\n"),
509 max_iterations
, test_name
));
510 ACE_DEBUG ((LM_DEBUG
,
511 ACE_TEXT ("real time = %f secs, user time = %f secs, system time = %f secs\n"),
512 et
.real_time
, et
.user_time
, et
.system_time
));
513 ACE_DEBUG ((LM_DEBUG
,
514 ACE_TEXT ("time per call = %f usecs\n"),
515 (et
.user_time
/ ACE_timer_t (max_iterations
)) * 1000000));
520 // This test function was contributed with Bugzilla #2447 to test validity
521 // of ACE_Timer_Heap timer IDs around the boundary of having to enlarge
524 test_unique_timer_heap_ids ()
527 ACE_Timer_Heap
timer_heap (44);
528 ACE_Time_Value
anytime(1);
529 ACE_Bounded_Set
<long> timer_ids (max_iterations
);
531 bool all_unique
= true;
533 for (int i
= 0; i
< 100; ++i
)
535 timer_id
= timer_heap
.schedule (&eh
, 0, anytime
);
538 ACE_ERROR ((LM_ERROR
,
539 ACE_TEXT ("Schedule timer %d %p\n"),
541 ACE_TEXT ("test_unique_timer_heap_ids")));
544 ACE_DEBUG ((LM_DEBUG
,
545 ACE_TEXT ("Schedule timer %d. Timer id = %d\n"),
548 if (1 == timer_ids
.insert (timer_id
))
550 ACE_ERROR ((LM_ERROR
,
551 ACE_TEXT ("Pass %d, id %d is not unique\n"),
557 if (i
== 0 || i
== 1 || i
== 47 || i
== 48)
559 ACE_DEBUG ((LM_DEBUG
,
560 ACE_TEXT ("Free Timer %d. Timer Id = %d\n"),
563 timer_heap
.cancel (timer_id
);
565 ACE_ERROR ((LM_ERROR
,
567 ACE_TEXT ("Failed to cancel timer")));
569 timer_ids
.remove (timer_id
);
574 ACE_DEBUG ((LM_INFO
, ACE_TEXT ("All timer ids were unique.\n")));
580 * @class Timer_Queue_Stack
582 * @brief Keeps track of the <Timer_Queue>s that we're going to test.
584 * This data structure is organized as a stack to make it easy to implement.
586 class Timer_Queue_Stack
589 Timer_Queue_Stack (ACE_Timer_Queue
*queue
,
590 const ACE_TCHAR
*name
,
591 Timer_Queue_Stack
*next
= 0)
596 // "Push" a new <queue> on the stack of <queue>s.
598 /// Pointer to the subclass of <ACE_Timer_Queue> that we're testing.
599 ACE_Timer_Queue
*queue_
;
601 /// Name of the Queue that we're testing.
602 const ACE_TCHAR
*name_
;
604 /// Pointer to the next <Timer_Queue>.
605 Timer_Queue_Stack
*next_
;
609 run_main (int argc
, ACE_TCHAR
*argv
[])
611 ACE_START_TEST (ACE_TEXT ("Timer_Queue_Test"));
614 max_iterations
= ACE_OS::atoi (argv
[1]);
616 // = Perform initializations.
618 Timer_Queue_Stack
*tq_stack
= 0;
620 // Add new Timer_Queue implementations here. Note that these will
621 // be executed in "reverse order".
624 ACE_NEW_RETURN (tq_stack
,
625 Timer_Queue_Stack (new ACE_Timer_Hash_Heap
,
626 ACE_TEXT ("ACE_Timer_Hash (Heap)"),
631 ACE_NEW_RETURN (tq_stack
,
632 Timer_Queue_Stack (new ACE_Timer_Hash
,
633 ACE_TEXT ("ACE_Timer_Hash"),
638 ACE_NEW_RETURN (tq_stack
,
639 Timer_Queue_Stack (new ACE_Timer_List
,
640 ACE_TEXT ("ACE_Timer_List"),
644 // Timer_Wheel without preallocated memory
645 ACE_NEW_RETURN (tq_stack
,
646 Timer_Queue_Stack (new ACE_Timer_Wheel
,
647 ACE_TEXT ("ACE_Timer_Wheel (non-preallocated)"),
651 // Timer_Wheel with preallocated memory.
652 ACE_NEW_RETURN (tq_stack
,
653 Timer_Queue_Stack (new ACE_Timer_Wheel (ACE_DEFAULT_TIMER_WHEEL_SIZE
,
654 ACE_DEFAULT_TIMER_WHEEL_RESOLUTION
,
656 ACE_TEXT ("ACE_Timer_Wheel (preallocated)"),
659 // Timer_Heap without preallocated memory.
660 ACE_NEW_RETURN (tq_stack
,
661 Timer_Queue_Stack (new ACE_Timer_Heap
,
662 ACE_TEXT ("ACE_Timer_Heap (non-preallocated)"),
666 // Timer_Heap with preallocate memory.
667 ACE_NEW_RETURN (tq_stack
,
668 Timer_Queue_Stack (new ACE_Timer_Heap (max_iterations
, 1),
669 ACE_TEXT ("ACE_Timer_Heap (preallocated)"),
673 // Timer_Heap without preallocated memory, using high-res time.
675 (void) ACE_High_Res_Timer::global_scale_factor ();
677 ACE_Timer_Heap
*tq_heap
=
679 tq_heap
->gettimeofday(&ACE_High_Res_Timer::gettimeofday_hr
);
680 ACE_NEW_RETURN (tq_stack
,
681 Timer_Queue_Stack (tq_heap
,
682 ACE_TEXT ("ACE_Timer_Heap (high-res timer; deprecated version)"),
686 // new (optimized) version
687 using timer_heap_hr_type
= ACE_Timer_Heap_T
<ACE_Event_Handler
*, ACE_Event_Handler_Handle_Timeout_Upcall
, ACE_MT_SYNCH::RECURSIVE_MUTEX
, ACE_HR_Time_Policy
>;
688 ACE_NEW_RETURN (tq_stack
,
689 Timer_Queue_Stack (new timer_heap_hr_type
,
690 ACE_TEXT ("ACE_Timer_Heap (high-res timer)"),
695 // Create the Timer ID array
696 ACE_NEW_RETURN (timer_ids
,
697 long[max_iterations
],
700 Timer_Queue_Stack
*tq_ptr
= tq_stack
;
704 ACE_DEBUG ((LM_DEBUG
,
705 ACE_TEXT ("**** starting test of %s\n"),
707 test_interval_timer (tq_ptr
->queue_
);
708 test_functionality (tq_ptr
->queue_
);
709 test_performance (tq_ptr
->queue_
,
711 delete tq_ptr
->queue_
;
712 Timer_Queue_Stack
*temp
= tq_ptr
;
713 tq_ptr
= tq_ptr
->next_
;
720 ACE_TEXT ("**** starting unique IDs test for ACE_Timer_Heap\n")));
721 test_unique_timer_heap_ids ();