1 // This example illustrates the performance impact of using the
2 // Double-Checked Locking pattern compared with using the "standard"
3 // practice of acquiring and releasing a lock on every instance()
4 // call. In addition, we compare the performance of using the
5 // ACE_Singleton (which encapsulates the Double-Check Locking pattern)
6 // vs. hand-coding the pattern.
8 // Here's the output from running this test on our SPARCstation 20, model 712s.
10 // ./test_singleton 1000000
11 // iterations = 1000000
13 // real time = 0.193731 secs, user time = 0.190416 secs, system time = 0.000549 secs
14 // time per call = 0.193731 usecs
16 // real time = 0.176208 secs, user time = 0.176045 secs, system time = 0.000092 secs
17 // time per call = 0.176208 usecs
19 // real time = 3.160998 secs, user time = 3.121434 secs, system time = 0.000109 secs
20 // time per call = 3.160998 usecs
22 // As you can see, both Double-Checked Locking implementations are about
23 // 15 times faster than the standard mutex version. Moreover,
24 // this test is run with only a single thread, so there's no contention
25 // for the lock. If there were multiple threads contending for the lock,
26 // the Mutex_Singleton performance would get increasing worse...
28 #include "ace/OS_main.h"
29 #include "ace/Guard_T.h"
30 #include "ace/Profile_Timer.h"
31 #include "ace/Singleton.h"
32 #include "ace/Synch_Traits.h"
33 #include "ace/Log_Msg.h"
35 #include "test_singleton.h"
37 #if defined (ACE_HAS_THREADS)
39 static const int DEFAULT_ITERATIONS
= 100000000;
46 static Mutex_Singleton
*instance ();
49 static ACE_SYNCH_MUTEX lock_
;
50 static Mutex_Singleton
*instance_
;
53 ACE_SYNCH_MUTEX
Mutex_Singleton::lock_
;
55 Mutex_Singleton
*Mutex_Singleton::instance_
;
58 Mutex_Singleton::instance ()
60 // Acquire the lock every time in.
61 ACE_GUARD_RETURN (ACE_SYNCH_MUTEX
, ace_mon
, Mutex_Singleton::lock_
, 0);
63 if (Mutex_Singleton::instance_
== 0)
64 ACE_NEW_RETURN (Mutex_Singleton::instance_
, Mutex_Singleton
, 0);
66 return Mutex_Singleton::instance_
;
69 ACE_SYNCH_MUTEX
DC_Singleton::lock_
;
71 DC_Singleton
*DC_Singleton::instance_
;
74 DC_Singleton::instance ()
76 if (DC_Singleton::instance_
== 0)
78 // Only lock if instance_ isn't 0.
79 ACE_GUARD_RETURN (ACE_SYNCH_MUTEX
, ace_mon
, DC_Singleton::lock_
, 0);
81 // Perform the Double-Check.
82 if (DC_Singleton::instance_
== 0)
83 ACE_NEW_RETURN (DC_Singleton::instance_
, DC_Singleton
, 0);
86 return DC_Singleton::instance_
;
89 typedef ACE_Singleton
<DC_Singleton
, ACE_SYNCH_MUTEX
> My_Singleton
;
92 ACE_TMAIN (int argc
, ACE_TCHAR
*argv
[])
94 ACE_Profile_Timer timer
;
95 int iterations
= argc
> 1 ? ACE_OS::atoi (argv
[1]) : DEFAULT_ITERATIONS
;
98 ACE_DEBUG ((LM_DEBUG
, "iterations = %d\n", iterations
));
100 // Test the ACE_Singleton performance (which uses Double-Checked
105 for (i
= 0; i
< iterations
; i
++)
106 My_Singleton::instance ()->svc ();
110 ACE_Profile_Timer::ACE_Elapsed_Time et
;
112 timer
.elapsed_time (et
);
114 ACE_DEBUG ((LM_DEBUG
, "ACE_Singleton\n"));
115 ACE_DEBUG ((LM_DEBUG
, "real time = %f secs, user time = %f secs, system time = %f secs\n",
116 et
.real_time
, et
.user_time
, et
.system_time
));
118 ACE_DEBUG ((LM_DEBUG
, "time per call = %f usecs\n",
119 (et
.real_time
/ double (iterations
)) * 1000000));
121 // Test the hand-coded Singleton performance (which uses
122 // Double-Checked Locking).
126 for (i
= 0; i
< iterations
; i
++)
127 DC_Singleton::instance ()->svc ();
131 timer
.elapsed_time (et
);
133 ACE_DEBUG ((LM_DEBUG
, "DC_Singleton\n"));
134 ACE_DEBUG ((LM_DEBUG
, "real time = %f secs, user time = %f secs, system time = %f secs\n",
135 et
.real_time
, et
.user_time
, et
.system_time
));
137 ACE_DEBUG ((LM_DEBUG
, "time per call = %f usecs\n",
138 (et
.real_time
/ double (iterations
)) * 1000000));
140 // Test the Mutex_Singleton implementation (which does not use
141 // Double-Checked Locking).
145 for (i
= 0; i
< iterations
; i
++)
146 Mutex_Singleton::instance ()->svc ();
150 timer
.elapsed_time (et
);
152 ACE_DEBUG ((LM_DEBUG
, "Mutex_Singleton\n"));
153 ACE_DEBUG ((LM_DEBUG
, "real time = %f secs, user time = %f secs, system time = %f secs\n",
154 et
.real_time
, et
.user_time
, et
.system_time
));
156 ACE_DEBUG ((LM_DEBUG
, "time per call = %f usecs\n",
157 (et
.real_time
/ double (iterations
)) * 1000000));
162 ACE_SINGLETON_TEMPLATE_INSTANTIATE(ACE_Singleton
, DC_Singleton
, ACE_SYNCH_MUTEX
);
166 ACE_TMAIN (int, ACE_TCHAR
*[])
168 ACE_ERROR ((LM_ERROR
, "threads not supported on this platform\n"));
171 #endif /* ACE_HAS_THREADS */