VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstSemRW.cpp@ 23501

Last change on this file since 23501 was 20597, checked in by vboxsync, 16 years ago

Runtime: improve SemRW testcase to also do recursion testing

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.6 KB
Line 
1/* $Id: tstSemRW.cpp 20597 2009-06-15 17:54:06Z vboxsync $ */
2/** @file
3 * IPRT Testcase - Reader/Writer Semaphore Test.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31/*******************************************************************************
32* Header Files *
33*******************************************************************************/
34#include <iprt/semaphore.h>
35#include <iprt/string.h>
36#include <iprt/thread.h>
37#include <iprt/stream.h>
38#include <iprt/time.h>
39#include <iprt/initterm.h>
40#include <iprt/rand.h>
41#include <iprt/asm.h>
42#include <iprt/assert.h>
43
44
45/*******************************************************************************
46* Global Variables *
47*******************************************************************************/
48static RTSEMRW g_hSemRW = NIL_RTSEMRW;
49static bool volatile g_fTerminate;
50static bool g_fYield;
51static bool g_fQuiet;
52static unsigned g_uWritePercent;
53static uint32_t volatile g_cbConcurrentWrite;
54static uint32_t volatile g_cbConcurrentRead;
55static uint32_t volatile g_cErrors;
56
57
58int PrintError(const char *pszFormat, ...)
59{
60 ASMAtomicIncU32(&g_cErrors);
61
62 RTPrintf("tstSemRW: FAILURE - ");
63 va_list va;
64 va_start(va, pszFormat);
65 RTPrintfV(pszFormat, va);
66 va_end(va);
67
68 return 1;
69}
70
71
72int ThreadTest1(RTTHREAD ThreadSelf, void *pvUser)
73{
74 // Use randomization to get a little more variation of the sync pattern
75 unsigned c100 = RTRandU32Ex(0, 99);
76 uint64_t *pu64 = (uint64_t *)pvUser;
77 bool fWrite;
78 for (;;)
79 {
80 int rc;
81 unsigned readrec = RTRandU32Ex(0, 3);
82 unsigned writerec = RTRandU32Ex(0, 3);
83 /* Don't overdo recursion testing. */
84 if (readrec > 1)
85 readrec--;
86 if (writerec > 1)
87 writerec--;
88
89 fWrite = (c100 < g_uWritePercent);
90 if (fWrite)
91 {
92 for (unsigned i = 0; i <= writerec; i++)
93 {
94 rc = RTSemRWRequestWriteNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
95 if (RT_FAILURE(rc))
96 {
97 PrintError("%x: RTSemRWRequestWriteNoResume failed with %Rrc\n", rc);
98 break;
99 }
100 }
101 if (RT_FAILURE(rc))
102 break;
103 if (ASMAtomicIncU32(&g_cbConcurrentWrite) != 1)
104 {
105 PrintError("g_cbConcurrentWrite=%d after request!\n", g_cbConcurrentWrite);
106 break;
107 }
108 if (g_cbConcurrentRead != 0)
109 {
110 PrintError("g_cbConcurrentRead=%d after request!\n", g_cbConcurrentRead);
111 break;
112 }
113 }
114 else
115 {
116 rc = RTSemRWRequestReadNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
117 if (RT_FAILURE(rc))
118 {
119 PrintError("%x: RTSemRWRequestReadNoResume failed with %Rrc\n", rc);
120 break;
121 }
122 ASMAtomicIncU32(&g_cbConcurrentRead);
123 if (g_cbConcurrentWrite != 0)
124 {
125 PrintError("g_cbConcurrentWrite=%d after request!\n", g_cbConcurrentWrite);
126 break;
127 }
128 }
129 for (unsigned i = 0; i < readrec; i++)
130 {
131 rc = RTSemRWRequestReadNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
132 if (RT_FAILURE(rc))
133 {
134 PrintError("%x: RTSemRWRequestReadNoResume failed with %Rrc\n", rc);
135 break;
136 }
137 }
138 if (RT_FAILURE(rc))
139 break;
140
141 /*
142 * Check for fairness: The values of the threads should not differ too much
143 */
144 (*pu64)++;
145
146 /*
147 * Check for correctness: Give other threads a chance. If the implementation is
148 * correct, no other thread will be able to enter this lock now.
149 */
150 if (g_fYield)
151 RTThreadYield();
152
153 for (unsigned i = 0; i < readrec; i++)
154 {
155 rc = RTSemRWReleaseRead(g_hSemRW);
156 if (RT_FAILURE(rc))
157 {
158 PrintError("%x: RTSemRWReleaseRead failed with %Rrc\n", rc);
159 break;
160 }
161 }
162 if (RT_FAILURE(rc))
163 break;
164
165 if (fWrite)
166 {
167 if (ASMAtomicDecU32(&g_cbConcurrentWrite) != 0)
168 {
169 PrintError("g_cbConcurrentWrite=%d before release!\n", g_cbConcurrentWrite);
170 break;
171 }
172 if (g_cbConcurrentRead != 0)
173 {
174 PrintError("g_cbConcurrentRead=%d before release!\n", g_cbConcurrentRead);
175 break;
176 }
177 for (unsigned i = 0; i <= writerec; i++)
178 {
179 rc = RTSemRWReleaseWrite(g_hSemRW);
180 if (RT_FAILURE(rc))
181 {
182 PrintError("%x: RTSemRWReleaseWrite failed with %Rrc\n", rc);
183 break;
184 }
185 }
186 }
187 else
188 {
189 if (g_cbConcurrentWrite != 0)
190 {
191 PrintError("g_cbConcurrentWrite=%d before release!\n", g_cbConcurrentWrite);
192 break;
193 }
194 ASMAtomicDecU32(&g_cbConcurrentRead);
195 rc = RTSemRWReleaseRead(g_hSemRW);
196 if (RT_FAILURE(rc))
197 {
198 PrintError("%x: RTSemRWReleaseRead failed with %Rrc\n", rc);
199 break;
200 }
201 }
202
203 if (g_fTerminate)
204 break;
205
206 c100++;
207 c100 %= 100;
208 }
209 if (!g_fQuiet)
210 RTPrintf("tstSemRW: Thread %08x exited with %lld\n", ThreadSelf, *pu64);
211 return VINF_SUCCESS;
212}
213
214
215static int Test1(unsigned cThreads, unsigned cSeconds, unsigned uWritePercent, bool fYield, bool fQuiet)
216{
217 int rc;
218 unsigned i;
219 uint64_t g_au64[32];
220 RTTHREAD aThreads[RT_ELEMENTS(g_au64)];
221 AssertRelease(cThreads <= RT_ELEMENTS(g_au64));
222
223 /*
224 * Init globals.
225 */
226 g_fYield = fYield;
227 g_fQuiet = fQuiet;
228 g_fTerminate = false;
229 g_uWritePercent = uWritePercent;
230 g_cbConcurrentWrite = 0;
231 g_cbConcurrentRead = 0;
232
233 rc = RTSemRWCreate(&g_hSemRW);
234 if (RT_FAILURE(rc))
235 return PrintError("RTSemRWCreate failed (rc=%Rrc)\n", rc);
236
237 /*
238 * Create the threads and let them block on the semrw.
239 */
240 rc = RTSemRWRequestWrite(g_hSemRW, RT_INDEFINITE_WAIT);
241 if (RT_FAILURE(rc))
242 return PrintError("RTSemRWRequestWrite failed (rc=%Rrc)\n", rc);
243
244 for (i = 0; i < cThreads; i++)
245 {
246 g_au64[i] = 0;
247 rc = RTThreadCreate(&aThreads[i], ThreadTest1, &g_au64[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test");
248 if (RT_FAILURE(rc))
249 return PrintError("RTThreadCreate failed for thread %u (rc=%Rrc)\n", i, rc);
250 }
251
252 if (!fQuiet)
253 RTPrintf("tstSemRW: %zu Threads created. Racing them for %u seconds (%s) ...\n",
254 cThreads, cSeconds, g_fYield ? "yielding" : "no yielding");
255
256 uint64_t u64StartTS = RTTimeNanoTS();
257 rc = RTSemRWReleaseWrite(g_hSemRW);
258 if (RT_FAILURE(rc))
259 PrintError("RTSemRWReleaseWrite failed (rc=%Rrc)\n", rc);
260 RTThreadSleep(cSeconds * 1000);
261 ASMAtomicXchgBool(&g_fTerminate, true);
262 uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS;
263
264 for (i = 0; i < cThreads; i++)
265 {
266 rc = RTThreadWait(aThreads[i], 5000, NULL);
267 if (RT_FAILURE(rc))
268 PrintError("RTThreadWait failed for thread %u (rc=%Rrc)\n", i, rc);
269 }
270
271 if (g_cbConcurrentWrite != 0)
272 PrintError("g_cbConcurrentWrite=%d at end of test!\n", g_cbConcurrentWrite);
273 if (g_cbConcurrentRead != 0)
274 PrintError("g_cbConcurrentRead=%d at end of test!\n", g_cbConcurrentRead);
275
276 rc = RTSemRWDestroy(g_hSemRW);
277 if (RT_FAILURE(rc))
278 PrintError("RTSemRWDestroy failed - %Rrc\n", rc);
279 g_hSemRW = NIL_RTSEMRW;
280 if (g_cErrors)
281 RTThreadSleep(100);
282
283 /*
284 * Collect and display the results.
285 */
286 uint64_t Total = g_au64[0];
287 for (i = 1; i < cThreads; i++)
288 Total += g_au64[i];
289
290 uint64_t Normal = Total / cThreads;
291 uint64_t MaxDeviation = 0;
292 for (i = 0; i < cThreads; i++)
293 {
294 uint64_t Delta = RT_ABS((int64_t)(g_au64[i] - Normal));
295 if (Delta > Normal / 2)
296 RTPrintf("tstSemRW: Warning! Thread %d deviates by more than 50%% - %llu (it) vs. %llu (avg)\n",
297 i, g_au64[i], Normal);
298 if (Delta > MaxDeviation)
299 MaxDeviation = Delta;
300
301 }
302
303 RTPrintf("tstSemRW: Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n",
304 cThreads,
305 Total,
306 Total / cSeconds,
307 ElapsedNS / Total,
308 MaxDeviation * 100 / Normal
309 );
310 return 0;
311}
312
313
314int main(int argc, char **argv)
315{
316 int rc = RTR3Init();
317 if (RT_FAILURE(rc))
318 {
319 RTPrintf("tstSemRW: RTR3Init failed (rc=%Rrc)\n", rc);
320 return 1;
321 }
322 RTPrintf("tstSemRW: TESTING...\n");
323
324 if (argc == 1)
325 {
326 /* threads, seconds, writePercent, yield, quiet */
327 Test1( 1, 1, 0, true, false);
328 Test1( 1, 1, 1, true, false);
329 Test1( 1, 1, 5, true, false);
330 Test1( 2, 1, 3, true, false);
331 Test1( 10, 1, 5, true, false);
332 Test1( 10, 10, 10, false, false);
333
334 RTPrintf("tstSemRW: benchmarking...\n");
335 for (unsigned cThreads = 1; cThreads < 32; cThreads++)
336 Test1(cThreads, 2, 1, false, true);
337
338 /** @todo add a testcase where some stuff times out. */
339 }
340 else
341 {
342 /* threads, seconds, writePercent, yield, quiet */
343 RTPrintf("tstSemRW: benchmarking...\n");
344 Test1( 1, 3, 1, false, true);
345 Test1( 1, 3, 1, false, true);
346 Test1( 1, 3, 1, false, true);
347 Test1( 2, 3, 1, false, true);
348 Test1( 2, 3, 1, false, true);
349 Test1( 2, 3, 1, false, true);
350 Test1( 3, 3, 1, false, true);
351 Test1( 3, 3, 1, false, true);
352 Test1( 3, 3, 1, false, true);
353 }
354
355 if (!g_cErrors)
356 RTPrintf("tstSemRW: SUCCESS\n");
357 else
358 RTPrintf("tstSemRW: FAILURE - %u errors\n", g_cErrors);
359 return g_cErrors != 0;
360}
361
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette