2 //=============================================================================
4 * @file Upgradable_RW_Test.cpp
6 * This test program verifies the functionality of the ACE_OS
7 * implementation of readers/writer locks on Win32 and Posix
8 * pthreads. Use the RW_Mutex define switch to use
9 * readers/writer mutexes or regular mutexes.
11 * @author Michael Kircher <mk1@cs.wustl.edu>
13 //=============================================================================
16 #include "Upgradable_RW_Test.h"
17 #include "ace/OS_NS_stdio.h"
18 #include "ace/OS_NS_sys_time.h"
19 #include "ace/Atomic_Op.h"
22 #if defined (ACE_HAS_THREADS)
24 // Default number of iterations.
25 static int n_iterations
= 50;
27 // Maximum string length used
28 static const size_t MAX_STRING_SIZE
= 200;
30 // switch on RW mutexes, else use ordinary mutexes
33 // Default number of readers.
34 static u_int n_readers
= 10;
36 // Default number of writers.
37 static u_int n_writers
= 0;
39 // Number of entries in the hash map
40 static u_int n_entries
= 10;
42 // Try to upgrade to a write lock, by default don't try.
43 static u_int use_try_upgrade
= 0;
45 // number of readers, which were able to upgrade
46 static u_int upgraded
= 0;
48 // count the number of find calls
49 static u_int find_called
= 0;
51 // number of readers, failing or not allowed to upgrade
52 static u_int not_upgraded
= 0;
54 // Thread creation flags.
55 static long thr_flags
= THR_NEW_LWP
;
57 // Lock for shared_data (upgraded, not_upgraded, hash_Map)
58 #if defined (RW_MUTEX)
59 static ACE_RW_Thread_Mutex rw_mutex
;
61 static ACE_Thread_Mutex mutex
;
64 // Count of the number of readers and writers.
65 static ACE_Atomic_Op
<ACE_Thread_Mutex
, int> current_readers
;
66 static ACE_Atomic_Op
<ACE_Thread_Mutex
, int> current_writers
;
68 static Linked_List
*linked_list_ptr
;
70 // Returns 1 if found,
78 char search_string
[MAX_STRING_SIZE
];
79 ACE_OS::snprintf (search_string
, MAX_STRING_SIZE
, "%d", n_entries
- 1);
80 ACE_CString
cString (search_string
);
81 Element
*element_ptr
= 0;
83 for (ACE_Double_Linked_List_Iterator
<Element
> iterator (*linked_list_ptr
);
87 element_ptr
= iterator
.next ();
89 if (*element_ptr
->value () == cString
)
96 // Explain usage and exit.
98 print_usage_and_die ()
100 ACE_DEBUG ((LM_DEBUG
,
101 ACE_TEXT ("usage: %n [-r n_readers] [-w n_writers]\n")
102 ACE_TEXT (" [-e max_entries] [-u try update] ")
103 ACE_TEXT ("[-n iteration_count] [-f for FIFO threads]\n")));
108 parse_args (int argc
, ACE_TCHAR
*argv
[])
110 ACE_Get_Opt
get_opt (argc
, argv
, ACE_TEXT ("e:fr:w:n:u"));
114 while ((c
= get_opt ()) != -1)
118 n_entries
= ACE_OS::atoi (get_opt
.opt_arg ());
121 thr_flags
= THR_BOUND
| THR_SCHED_FIFO
;
124 n_readers
= ACE_OS::atoi (get_opt
.opt_arg ());
127 n_writers
= ACE_OS::atoi (get_opt
.opt_arg ());
130 n_iterations
= ACE_OS::atoi (get_opt
.opt_arg ());
136 print_usage_and_die ();
141 // Iterate <n_iterations> each time checking that nobody modifies the data
142 // while we have a read lock.
147 ACE_Profile_Timer timer
;
148 ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time
;
151 // Wait at the barrier.
153 // We start an ACE_Profile_Timer here...
156 for (int iterations
= 1;
157 iterations
<= n_iterations
;
160 ACE_Thread::yield ();
165 #if defined (RW_MUTEX)
166 ACE_READ_GUARD_RETURN (ACE_RW_Thread_Mutex
, g
, rw_mutex
, 1);
168 ACE_GUARD_RETURN (ACE_Thread_Mutex
, g
, mutex
, 1);
169 #endif /* RW_MUTEX */
171 #if defined (RW_MUTEX)
174 rw_mutex
.tryacquire_write_upgrade ();
175 #endif /* RW_MUTEX */
177 // True, when we were able to upgrade.
178 if (result
== 0 && use_try_upgrade
)
180 //find_last (); try to find something which is not in
187 if ((result
== -1 && errno
== EBUSY
) // we tried and failed
188 || !use_try_upgrade
) // we did not try at all
190 #if defined (RW_MUTEX)
191 ACE_WRITE_GUARD (ACE_RW_Thread_Mutex
, g
, rw_mutex
, 1);
193 ACE_GUARD_RETURN (ACE_Thread_Mutex
, g
, mutex
, 1);
194 #endif /* RW_MUTEX */
199 else if (result
== -1 && errno
!= EBUSY
)
201 ACE_ERROR ((LM_ERROR
,
202 ACE_TEXT (" (%t) failure in upgrading to write lock!\n"),
209 timer
.elapsed_time (elapsed_time
);
211 this->time_Calculation_
.report_time (elapsed_time
);
216 // Iterate <n_iterations> each time modifying the global data and
217 // checking that nobody steps on it while we can write it.
222 ACE_Profile_Timer timer
;
223 ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time
;
226 // Wait at the barrier
228 // We start an ACE_Profile_Timer here...
231 for (int iterations
= 1;
232 iterations
<= n_iterations
;
235 ACE_Thread::yield ();
237 #if defined (RW_MUTEX)
238 ACE_WRITE_GUARD (ACE_RW_Thread_Mutex
, g
, rw_mutex
, 0);
240 ACE_GUARD_RETURN (ACE_Thread_Mutex
, g
, mutex
, 0);
241 #endif /* RW_MUTEX */
250 timer
.elapsed_time (elapsed_time
);
252 this->time_Calculation_
.report_time (elapsed_time
);
258 Time_Calculation::report_time (ACE_Profile_Timer::ACE_Elapsed_Time
&elapsed_time
)
260 ACE_GUARD (ACE_Thread_Mutex
, g
, mutex_
);
262 this->times_
.real_time
+= elapsed_time
.real_time
;
263 this->times_
.user_time
+= elapsed_time
.user_time
;
264 this->times_
.system_time
+= elapsed_time
.system_time
;
266 this->reported_times_
++;
270 Time_Calculation ::print_stats ()
272 ACE_Profile_Timer::ACE_Elapsed_Time elapsed_time
= this->times_
;
273 u_int iterations
= 1;
277 elapsed_time
.real_time
*= ACE_ONE_SECOND_IN_MSECS
;
278 elapsed_time
.user_time
*= ACE_ONE_SECOND_IN_MSECS
;
279 elapsed_time
.system_time
*= ACE_ONE_SECOND_IN_MSECS
;
281 elapsed_time
.real_time
/= iterations
;
282 elapsed_time
.user_time
/= iterations
;
283 elapsed_time
.system_time
/= iterations
;
287 if (!ACE::is_equal (elapsed_time
.real_time
, 0.0))
288 tmp
= 1000 / elapsed_time
.real_time
;
290 ACE_DEBUG ((LM_DEBUG
,
292 ACE_TEXT ("\treal_time\t = %0.06f ms,\n")
293 ACE_TEXT ("\tuser_time\t = %0.06f ms,\n")
294 ACE_TEXT ("\tsystem_time\t = %0.06f ms,\n")
295 ACE_TEXT ("\t%0.00f calls/second\n"),
296 elapsed_time
.real_time
< 0.0 ? 0.0 : elapsed_time
.real_time
,
297 elapsed_time
.user_time
< 0.0 ? 0.0 : elapsed_time
.user_time
,
298 elapsed_time
.system_time
< 0.0 ? 0.0 : elapsed_time
.system_time
,
299 tmp
< 0.0 ? 0.0 : tmp
));
301 ACE_DEBUG ((LM_DEBUG
,
302 ACE_TEXT ("Number of reported times: %d\n"),
303 this->reported_times_
));
306 ACE_ERROR ((LM_ERROR
,
307 ACE_TEXT ("\tNo time stats printed. Zero iterations or error occurred.\n")));
313 char entry
[MAX_STRING_SIZE
];
314 ACE_CString
*cString_ptr
= 0;
315 Element
*element_ptr
= 0;
317 ACE_NEW_RETURN (linked_list_ptr
,
321 for (u_int i
= 0; i
< n_entries
; i
++)
323 ACE_OS::snprintf (entry
, MAX_STRING_SIZE
, "%d", i
);
324 ACE_NEW_RETURN (cString_ptr
,
327 ACE_NEW_RETURN (element_ptr
,
328 Element (cString_ptr
),
330 linked_list_ptr
->insert_tail (element_ptr
);
335 #endif /* ACE_HAS_THREADS */
337 // Spawn off threads.
340 run_main (int argc
, ACE_TCHAR
*argv
[])
342 ACE_START_TEST (ACE_TEXT ("Upgradable_RW_Test"));
345 #if defined (ACE_HAS_THREADS)
346 parse_args (argc
, argv
);
347 #if !defined (RW_MUTEX)
349 // make sure that we have to acquire the write lock
350 #endif /* RW_MUTEX */
352 current_readers
= 0; // Possibly already done
353 current_writers
= 0; // Possibly already done
357 ACE_DEBUG ((LM_DEBUG
,
358 ACE_TEXT (" (%t) main thread starting\n")));
360 Time_Calculation time_Calculation
;
361 // for the time calculation
363 ACE_Barrier
thread_barrier (n_readers
+ n_writers
);
364 // for a nice start of all threads (for much contention)
366 // Initialize the readers.
367 Reader_Task
**reader_tasks
= 0;
369 ACE_NEW_RETURN (reader_tasks
,
370 Reader_Task
*[n_readers
],
378 ACE_NEW_RETURN (reader_tasks
[i
],
379 Reader_Task (time_Calculation
,
383 reader_tasks
[i
]->activate (thr_flags
,
386 ACE_DEFAULT_THREAD_PRIORITY
);
389 // Create all the writers
390 Writer_Task
**writer_tasks
= 0;
392 ACE_NEW_RETURN (writer_tasks
,
393 Writer_Task
*[n_writers
],
400 ACE_NEW_RETURN (writer_tasks
[i
],
401 Writer_Task (time_Calculation
,
405 writer_tasks
[i
]->activate (thr_flags
,
408 ACE_DEFAULT_THREAD_PRIORITY
);
411 // Wait a maximum of 1 second per iteration.
412 const ACE_Time_Value
max_wait (n_iterations
* 1);
413 const ACE_Time_Value
wait_time (ACE_OS::gettimeofday () + max_wait
);
414 if (ACE_Thread_Manager::instance ()->wait (&wait_time
) == -1)
417 ACE_ERROR ((LM_ERROR
,
418 ACE_TEXT ("maximum wait time of %d msec exceeded\n"),
421 ACE_OS::perror (ACE_TEXT ("wait"));
426 // compute average time.
427 time_Calculation
.print_stats ();
429 if (not_upgraded
!= 0 || upgraded
!= 0)
430 ACE_DEBUG ((LM_DEBUG
,
431 ACE_TEXT ("upgraded to not upgraded ratio = %f\n"),
432 (float) upgraded
/ (float) (not_upgraded
+ upgraded
)));
434 ACE_DEBUG ((LM_DEBUG
,
435 ACE_TEXT ("Number of times, that find was called: %d\n"),
439 ACE_DEBUG ((LM_DEBUG
,
440 ACE_TEXT (" (%t) exiting main thread\n")));
442 // Delete the memory of the Double_Linked_List
443 ACE_CString
*cString_ptr
= 0;
444 Element
*element_ptr
= 0;
450 if (0 != (element_ptr
= linked_list_ptr
->delete_head ()))
452 cString_ptr
= element_ptr
->value ();
458 delete linked_list_ptr
;
463 delete writer_tasks
[i
];
465 delete [] writer_tasks
;
470 delete reader_tasks
[i
];
472 delete [] reader_tasks
;
474 ACE_UNUSED_ARG (argc
);
475 ACE_UNUSED_ARG (argv
);
477 ACE_TEXT ("threads not supported on this platform\n")));
478 #endif /* ACE_HAS_THREADS */