1 /*
2 * benchtest1.c
3 *
4 *
5 * --------------------------------------------------------------------------
6 *
7 * Pthreads-win32 - POSIX Threads Library for Win32
8 * Copyright(C) 1998 John E. Bossom
9 * Copyright(C) 1999,2005 Pthreads-win32 contributors
10 *
11 * Contact Email: rpj@callisto.canberra.edu.au
12 *
13 * The current list of contributors is contained
14 * in the file CONTRIBUTORS included with the source
15 * code distribution. The list can also be seen at the
16 * following World Wide Web location:
17 * http://sources.redhat.com/pthreads-win32/contributors.html
18 *
19 * This library is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU Lesser General Public
21 * License as published by the Free Software Foundation; either
22 * version 2 of the License, or (at your option) any later version.
23 *
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
28 *
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library in the file COPYING.LIB;
31 * if not, write to the Free Software Foundation, Inc.,
32 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
33 *
34 * --------------------------------------------------------------------------
35 *
36 * Measure time taken to complete an elementary operation.
37 *
38 * - Mutex
39 * Two threads iterate over lock/unlock for each mutex type.
40 * The two threads are forced into lock-step using two mutexes,
41 * forcing the threads to block on each lock operation. The
42 * time measured is therefore the worst case senario.
43 */
44
45 #include "test.h"
46 #include <sys/timeb.h>
47
48 #ifdef __GNUC__
49 #include <stdlib.h>
50 #endif
51
52 #include "benchtest.h"
53
54 #define PTW32_MUTEX_TYPES
55 #define ITERATIONS 100000L
56
57 pthread_mutex_t gate1, gate2;
58 old_mutex_t ox1, ox2;
59 CRITICAL_SECTION cs1, cs2;
60 pthread_mutexattr_t ma;
61 long durationMilliSecs;
62 long overHeadMilliSecs = 0;
63 struct _timeb currSysTimeStart;
64 struct _timeb currSysTimeStop;
65 pthread_t worker;
66 int running = 0;
67
68 #define GetDurationMilliSecs(_TStart, _TStop) ((_TStop.time*1000+_TStop.millitm) \
69 - (_TStart.time*1000+_TStart.millitm))
70
71 /*
72 * Dummy use of j, otherwise the loop may be removed by the optimiser
73 * when doing the overhead timing with an empty loop.
74 */
75 #define TESTSTART \
76 { int i, j = 0, k = 0; _ftime(&currSysTimeStart); for (i = 0; i < ITERATIONS; i++) { j++;
77
78 #define TESTSTOP \
79 }; _ftime(&currSysTimeStop); if (j + k == i) j++; }
80
81
82 void *
overheadThread(void * arg)83 overheadThread(void * arg)
84 {
85 do
86 {
87 sched_yield();
88 }
89 while (running);
90
91 return NULL;
92 }
93
94
95 void *
oldThread(void * arg)96 oldThread(void * arg)
97 {
98 do
99 {
100 (void) old_mutex_lock(&ox1);
101 (void) old_mutex_lock(&ox2);
102 (void) old_mutex_unlock(&ox1);
103 sched_yield();
104 (void) old_mutex_unlock(&ox2);
105 }
106 while (running);
107
108 return NULL;
109 }
110
111 void *
workerThread(void * arg)112 workerThread(void * arg)
113 {
114 do
115 {
116 (void) pthread_mutex_lock(&gate1);
117 (void) pthread_mutex_lock(&gate2);
118 (void) pthread_mutex_unlock(&gate1);
119 sched_yield();
120 (void) pthread_mutex_unlock(&gate2);
121 }
122 while (running);
123
124 return NULL;
125 }
126
127 void *
CSThread(void * arg)128 CSThread(void * arg)
129 {
130 do
131 {
132 EnterCriticalSection(&cs1);
133 EnterCriticalSection(&cs2);
134 LeaveCriticalSection(&cs1);
135 sched_yield();
136 LeaveCriticalSection(&cs2);
137 }
138 while (running);
139
140 return NULL;
141 }
142
143 void
runTest(char * testNameString,int mType)144 runTest (char * testNameString, int mType)
145 {
146 #ifdef PTW32_MUTEX_TYPES
147 assert(pthread_mutexattr_settype(&ma, mType) == 0);
148 #endif
149 assert(pthread_mutex_init(&gate1, &ma) == 0);
150 assert(pthread_mutex_init(&gate2, &ma) == 0);
151 assert(pthread_mutex_lock(&gate1) == 0);
152 assert(pthread_mutex_lock(&gate2) == 0);
153 running = 1;
154 assert(pthread_create(&worker, NULL, workerThread, NULL) == 0);
155 TESTSTART
156 (void) pthread_mutex_unlock(&gate1);
157 sched_yield();
158 (void) pthread_mutex_unlock(&gate2);
159 (void) pthread_mutex_lock(&gate1);
160 (void) pthread_mutex_lock(&gate2);
161 TESTSTOP
162 running = 0;
163 assert(pthread_mutex_unlock(&gate2) == 0);
164 assert(pthread_mutex_unlock(&gate1) == 0);
165 assert(pthread_join(worker, NULL) == 0);
166 assert(pthread_mutex_destroy(&gate2) == 0);
167 assert(pthread_mutex_destroy(&gate1) == 0);
168 durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs;
169 printf( "%-45s %15ld %15.3f\n",
170 testNameString,
171 durationMilliSecs,
172 (float) durationMilliSecs * 1E3 / ITERATIONS / 4 /* Four locks/unlocks per iteration */);
173 }
174
175
176 int
main(int argc,char * argv[])177 main (int argc, char *argv[])
178 {
179 assert(pthread_mutexattr_init(&ma) == 0);
180
181 printf( "=============================================================================\n");
182 printf( "\nLock plus unlock on a locked mutex.\n");
183 printf("%ld iterations, four locks/unlocks per iteration.\n\n", ITERATIONS);
184
185 printf( "%-45s %15s %15s\n",
186 "Test",
187 "Total(msec)",
188 "average(usec)");
189 printf( "-----------------------------------------------------------------------------\n");
190
191 /*
192 * Time the loop overhead so we can subtract it from the actual test times.
193 */
194
195 running = 1;
196 assert(pthread_create(&worker, NULL, overheadThread, NULL) == 0);
197 TESTSTART
198 sched_yield();
199 sched_yield();
200 TESTSTOP
201 running = 0;
202 assert(pthread_join(worker, NULL) == 0);
203 durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs;
204 overHeadMilliSecs = durationMilliSecs;
205
206
207 InitializeCriticalSection(&cs1);
208 InitializeCriticalSection(&cs2);
209 EnterCriticalSection(&cs1);
210 EnterCriticalSection(&cs2);
211 running = 1;
212 assert(pthread_create(&worker, NULL, CSThread, NULL) == 0);
213 TESTSTART
214 LeaveCriticalSection(&cs1);
215 sched_yield();
216 LeaveCriticalSection(&cs2);
217 EnterCriticalSection(&cs1);
218 EnterCriticalSection(&cs2);
219 TESTSTOP
220 running = 0;
221 LeaveCriticalSection(&cs2);
222 LeaveCriticalSection(&cs1);
223 assert(pthread_join(worker, NULL) == 0);
224 DeleteCriticalSection(&cs2);
225 DeleteCriticalSection(&cs1);
226 durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs;
227 printf( "%-45s %15ld %15.3f\n",
228 "Simple Critical Section",
229 durationMilliSecs,
230 (float) durationMilliSecs * 1E3 / ITERATIONS / 4 );
231
232
233 old_mutex_use = OLD_WIN32CS;
234 assert(old_mutex_init(&ox1, NULL) == 0);
235 assert(old_mutex_init(&ox2, NULL) == 0);
236 assert(old_mutex_lock(&ox1) == 0);
237 assert(old_mutex_lock(&ox2) == 0);
238 running = 1;
239 assert(pthread_create(&worker, NULL, oldThread, NULL) == 0);
240 TESTSTART
241 (void) old_mutex_unlock(&ox1);
242 sched_yield();
243 (void) old_mutex_unlock(&ox2);
244 (void) old_mutex_lock(&ox1);
245 (void) old_mutex_lock(&ox2);
246 TESTSTOP
247 running = 0;
248 assert(old_mutex_unlock(&ox1) == 0);
249 assert(old_mutex_unlock(&ox2) == 0);
250 assert(pthread_join(worker, NULL) == 0);
251 assert(old_mutex_destroy(&ox2) == 0);
252 assert(old_mutex_destroy(&ox1) == 0);
253 durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs;
254 printf( "%-45s %15ld %15.3f\n",
255 "Old PT Mutex using a Critical Section (WNT)",
256 durationMilliSecs,
257 (float) durationMilliSecs * 1E3 / ITERATIONS / 4);
258
259
260 old_mutex_use = OLD_WIN32MUTEX;
261 assert(old_mutex_init(&ox1, NULL) == 0);
262 assert(old_mutex_init(&ox2, NULL) == 0);
263 assert(old_mutex_lock(&ox1) == 0);
264 assert(old_mutex_lock(&ox2) == 0);
265 running = 1;
266 assert(pthread_create(&worker, NULL, oldThread, NULL) == 0);
267 TESTSTART
268 (void) old_mutex_unlock(&ox1);
269 sched_yield();
270 (void) old_mutex_unlock(&ox2);
271 (void) old_mutex_lock(&ox1);
272 (void) old_mutex_lock(&ox2);
273 TESTSTOP
274 running = 0;
275 assert(old_mutex_unlock(&ox1) == 0);
276 assert(old_mutex_unlock(&ox2) == 0);
277 assert(pthread_join(worker, NULL) == 0);
278 assert(old_mutex_destroy(&ox2) == 0);
279 assert(old_mutex_destroy(&ox1) == 0);
280 durationMilliSecs = GetDurationMilliSecs(currSysTimeStart, currSysTimeStop) - overHeadMilliSecs;
281 printf( "%-45s %15ld %15.3f\n",
282 "Old PT Mutex using a Win32 Mutex (W9x)",
283 durationMilliSecs,
284 (float) durationMilliSecs * 1E3 / ITERATIONS / 4);
285
286 printf( ".............................................................................\n");
287
288 /*
289 * Now we can start the actual tests
290 */
291 #ifdef PTW32_MUTEX_TYPES
292 runTest("PTHREAD_MUTEX_DEFAULT (W9x,WNT)", PTHREAD_MUTEX_DEFAULT);
293
294 runTest("PTHREAD_MUTEX_NORMAL (W9x,WNT)", PTHREAD_MUTEX_NORMAL);
295
296 runTest("PTHREAD_MUTEX_ERRORCHECK (W9x,WNT)", PTHREAD_MUTEX_ERRORCHECK);
297
298 runTest("PTHREAD_MUTEX_RECURSIVE (W9x,WNT)", PTHREAD_MUTEX_RECURSIVE);
299 #else
300 runTest("Blocking locks", 0);
301 #endif
302
303 printf( "=============================================================================\n");
304 /*
305 * End of tests.
306 */
307
308 pthread_mutexattr_destroy(&ma);
309
310 return 0;
311 }
312