1 // This test program illustrates the performance difference between
2 // three versions of wrappers for thread mutexes. These three
3 // versions exercise various combinations of the following classes:
6 // This version is just like ACE_Thread_Mutex, which doesn't use
7 // inheritance and dynamic binding.
10 // This is an abstract base class that defines the
11 // acquire()/release() interface.
13 // Thread_Mutex_Derived --
14 // This derived from Mutex_Base and uses inheritance and
17 // The following are the results I got when running this on our
18 // SPARCstation 20 model 712:
20 // ./test_mutex 1000000
21 // iterations = 1000000
23 // real time = 1.727843 secs, user time = 1.729262 secs, system time = 0.000325 secs
24 // time per call = 1.747843 usecs
25 // Thread_Mutex_Derived
26 // real time = 1.730225 secs, user time = 1.724744 secs, system time = 0.000096 secs
27 // time per call = 1.730225 usecs
29 // real time = 2.112831 secs, user time = 2.104245 secs, system time = 0.000095 secs
30 // time per call = 2.112831 usecs
32 // My conclusions are as follows:
34 // 1. If your C++ compiler optimizes calls to virtual functions that
35 // are made through instances of derived classes, then the
36 // performance of the Thread_Mutex and Thread_Mutex_Derived are
37 // essentially identical.
39 // 2. The overhead from using virtual functions is approximately
40 // 20%. Naturally, as the amount of contention goes up, the
41 // relative overhead of the virtual function calls will decrease.
43 // Keep in mind, however, that using virtual functions to implement
44 // the Thread_Mutex will make it infeasible to put instances of
45 // Thread_Mutex into shared memory since the vptrs won't point to the
48 #include "ace/Log_Msg.h"
49 #include "ace/Profile_Timer.h"
50 #include "ace/OS_main.h"
51 #include "ace/OS_NS_Thread.h"
53 #if defined (ACE_HAS_THREADS)
55 static const int DEFAULT_ITERATIONS
= 100000000;
57 // A thread mutex that doesn't use virtual functions.
70 Thread_Mutex::Thread_Mutex ()
72 ACE_OS::mutex_init (&this->mutex_
);
75 Thread_Mutex::~Thread_Mutex ()
77 ACE_OS::mutex_destroy (&this->mutex_
);
81 Thread_Mutex::acquire ()
83 return ACE_OS::mutex_lock (&this->mutex_
);
87 Thread_Mutex::release ()
89 return ACE_OS::mutex_unlock (&this->mutex_
);
92 // Base class for mutex, declares pure virtual functions.
96 virtual ~Mutex_Base ();
97 virtual int acquire () = 0;
98 virtual int release () = 0;
101 Mutex_Base::~Mutex_Base ()
105 // Subclass for threaded mutex, defines virtual functions.
106 class Thread_Mutex_Derived
: public Mutex_Base
109 Thread_Mutex_Derived ();
110 virtual ~Thread_Mutex_Derived ();
111 virtual int acquire ();
112 virtual int release ();
118 Thread_Mutex_Derived::Thread_Mutex_Derived ()
120 ACE_OS::mutex_init (&this->mutex_
);
123 Thread_Mutex_Derived::~Thread_Mutex_Derived ()
125 ACE_OS::mutex_destroy (&this->mutex_
);
129 Thread_Mutex_Derived::acquire ()
131 return ACE_OS::mutex_lock (&this->mutex_
);
135 Thread_Mutex_Derived::release ()
137 return ACE_OS::mutex_unlock (&this->mutex_
);
140 static Thread_Mutex thread_mutex
;
141 static Thread_Mutex_Derived thread_mutex_derived
;
142 static Mutex_Base
*mutex_base
= &thread_mutex_derived
;
145 ACE_TMAIN (int argc
, ACE_TCHAR
*argv
[])
147 ACE_Profile_Timer timer
;
148 int iterations
= argc
> 1 ? ACE_OS::atoi (argv
[1]) : DEFAULT_ITERATIONS
;
151 ACE_DEBUG ((LM_DEBUG
, "iterations = %d\n", iterations
));
155 // Test the thread mutex (which doesn't use inheritance or dynamic
158 for (i
= 0; i
< iterations
; i
++)
160 thread_mutex
.acquire ();
161 thread_mutex
.release ();
166 ACE_Profile_Timer::ACE_Elapsed_Time et
;
168 timer
.elapsed_time (et
);
170 ACE_DEBUG ((LM_DEBUG
, "Thread_Mutex\n"));
171 ACE_DEBUG ((LM_DEBUG
, "real time = %f secs, user time = %f secs, system time = %f secs\n",
172 et
.real_time
, et
.user_time
, et
.system_time
));
174 ACE_DEBUG ((LM_DEBUG
, "time per call = %f usecs\n",
175 (et
.real_time
/ double (iterations
)) * 1000000));
177 // Test the thread mutex derived (which does use inheritance or
178 // dynamic binding). Note that we call this via an instance of the
179 // derived class, so good C++ compilers should optimize the virtual
180 // function calls in this case.
184 for (i
= 0; i
< iterations
; i
++)
186 thread_mutex_derived
.acquire ();
187 thread_mutex_derived
.release ();
192 timer
.elapsed_time (et
);
194 ACE_DEBUG ((LM_DEBUG
, "Thread_Mutex_Derived\n"));
195 ACE_DEBUG ((LM_DEBUG
, "real time = %f secs, user time = %f secs, system time = %f secs\n",
196 et
.real_time
, et
.user_time
, et
.system_time
));
198 ACE_DEBUG ((LM_DEBUG
, "time per call = %f usecs\n",
199 (et
.real_time
/ double (iterations
)) * 1000000));
201 // Test the thread mutex derived (which does use inheritance or
202 // dynamic binding). Note that we call this via a pointer to the
203 // base class, which points to an instance of the derived class.
204 // Thus, C++ compilers won't be able to optimize the virtual
205 // function calls in this case.
209 for (i
= 0; i
< iterations
; i
++)
211 mutex_base
->acquire ();
212 mutex_base
->release ();
217 timer
.elapsed_time (et
);
219 ACE_DEBUG ((LM_DEBUG
, "Mutex_Base\n"));
220 ACE_DEBUG ((LM_DEBUG
, "real time = %f secs, user time = %f secs, system time = %f secs\n",
221 et
.real_time
, et
.user_time
, et
.system_time
));
223 ACE_DEBUG ((LM_DEBUG
, "time per call = %f usecs\n",
224 (et
.real_time
/ double (iterations
)) * 1000000));
229 ACE_TMAIN (int, ACE_TCHAR
*[])
231 ACE_ERROR ((LM_ERROR
, "threads not supported on this platform\n"));
234 #endif /* ACE_HAS_THREADS */