VirtualBox

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

Last change on this file since 20554 was 20443, checked in by vboxsync, 16 years ago

Runtime: testcase for RW semaphores

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.4 KB
Line 
1/* $Id: tstSemRW.cpp 20443 2009-06-09 15:00:20Z 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 fWrite = (c100 < g_uWritePercent);
82 if (fWrite)
83 {
84 rc = RTSemRWRequestWriteNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
85 if (RT_FAILURE(rc))
86 {
87 PrintError("%x: RTSemRWRequestWriteNoResume failed with %Rrc\n", rc);
88 break;
89 }
90 if (ASMAtomicIncU32(&g_cbConcurrentWrite) != 1)
91 {
92 PrintError("g_cbConcurrentWrite=%d after request!\n", g_cbConcurrentWrite);
93 break;
94 }
95 if (g_cbConcurrentRead != 0)
96 {
97 PrintError("g_cbConcurrentRead=%d after request!\n", g_cbConcurrentRead);
98 break;
99 }
100 }
101 else
102 {
103 rc = RTSemRWRequestReadNoResume(g_hSemRW, RT_INDEFINITE_WAIT);
104 if (RT_FAILURE(rc))
105 {
106 PrintError("%x: RTSemRWRequestReadNoResume failed with %Rrc\n", rc);
107 break;
108 }
109 ASMAtomicIncU32(&g_cbConcurrentRead);
110 if (g_cbConcurrentWrite != 0)
111 {
112 PrintError("g_cbConcurrentWrite=%d after request!\n", g_cbConcurrentWrite);
113 break;
114 }
115 }
116
117 /*
118 * Check for fairness: The values of the threads should not differ too much
119 */
120 (*pu64)++;
121
122 /*
123 * Check for correctness: Give other threads a chance. If the implementation is
124 * correct, no other thread will be able to enter this lock now.
125 */
126 if (g_fYield)
127 RTThreadYield();
128
129 if (fWrite)
130 {
131 if (ASMAtomicDecU32(&g_cbConcurrentWrite) != 0)
132 {
133 PrintError("g_cbConcurrentWrite=%d before release!\n", g_cbConcurrentWrite);
134 break;
135 }
136 if (g_cbConcurrentRead != 0)
137 {
138 PrintError("g_cbConcurrentRead=%d before release!\n", g_cbConcurrentRead);
139 break;
140 }
141 rc = RTSemRWReleaseWrite(g_hSemRW);
142 if (RT_FAILURE(rc))
143 {
144 PrintError("%x: RTSemRWReleaseWrite failed with %Rrc\n", rc);
145 break;
146 }
147 }
148 else
149 {
150 if (g_cbConcurrentWrite != 0)
151 {
152 PrintError("g_cbConcurrentWrite=%d before release!\n", g_cbConcurrentWrite);
153 break;
154 }
155 ASMAtomicDecU32(&g_cbConcurrentRead);
156 rc = RTSemRWReleaseRead(g_hSemRW);
157 if (RT_FAILURE(rc))
158 {
159 PrintError("%x: RTSemRWReleaseRead failed with %Rrc\n", rc);
160 break;
161 }
162 }
163
164 if (g_fTerminate)
165 break;
166
167 c100++;
168 c100 %= 100;
169 }
170 if (!g_fQuiet)
171 RTPrintf("tstSemRW: Thread %08x exited with %lld\n", ThreadSelf, *pu64);
172 return VINF_SUCCESS;
173}
174
175
176static int Test1(unsigned cThreads, unsigned cSeconds, unsigned uWritePercent, bool fYield, bool fQuiet)
177{
178 int rc;
179 unsigned i;
180 uint64_t g_au64[32];
181 RTTHREAD aThreads[RT_ELEMENTS(g_au64)];
182 AssertRelease(cThreads <= RT_ELEMENTS(g_au64));
183
184 /*
185 * Init globals.
186 */
187 g_fYield = fYield;
188 g_fQuiet = fQuiet;
189 g_fTerminate = false;
190 g_uWritePercent = uWritePercent;
191 g_cbConcurrentWrite = 0;
192 g_cbConcurrentRead = 0;
193
194 rc = RTSemRWCreate(&g_hSemRW);
195 if (RT_FAILURE(rc))
196 return PrintError("RTSemRWCreate failed (rc=%Rrc)\n", rc);
197
198 /*
199 * Create the threads and let them block on the semrw.
200 */
201 rc = RTSemRWRequestWrite(g_hSemRW, RT_INDEFINITE_WAIT);
202 if (RT_FAILURE(rc))
203 return PrintError("RTSemRWRequestWrite failed (rc=%Rrc)\n", rc);
204
205 for (i = 0; i < cThreads; i++)
206 {
207 g_au64[i] = 0;
208 rc = RTThreadCreate(&aThreads[i], ThreadTest1, &g_au64[i], 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "test");
209 if (RT_FAILURE(rc))
210 return PrintError("RTThreadCreate failed for thread %u (rc=%Rrc)\n", i, rc);
211 }
212
213 if (!fQuiet)
214 RTPrintf("tstSemRW: %zu Threads created. Racing them for %u seconds (%s) ...\n",
215 cThreads, cSeconds, g_fYield ? "yielding" : "no yielding");
216
217 uint64_t u64StartTS = RTTimeNanoTS();
218 rc = RTSemRWReleaseWrite(g_hSemRW);
219 if (RT_FAILURE(rc))
220 PrintError("RTSemRWReleaseWrite failed (rc=%Rrc)\n", rc);
221 RTThreadSleep(cSeconds * 1000);
222 ASMAtomicXchgBool(&g_fTerminate, true);
223 uint64_t ElapsedNS = RTTimeNanoTS() - u64StartTS;
224
225 for (i = 0; i < cThreads; i++)
226 {
227 rc = RTThreadWait(aThreads[i], 5000, NULL);
228 if (RT_FAILURE(rc))
229 PrintError("RTThreadWait failed for thread %u (rc=%Rrc)\n", i, rc);
230 }
231
232 if (g_cbConcurrentWrite != 0)
233 PrintError("g_cbConcurrentWrite=%d at end of test!\n", g_cbConcurrentWrite);
234 if (g_cbConcurrentRead != 0)
235 PrintError("g_cbConcurrentRead=%d at end of test!\n", g_cbConcurrentRead);
236
237 rc = RTSemRWDestroy(g_hSemRW);
238 if (RT_FAILURE(rc))
239 PrintError("RTSemRWDestroy failed - %Rrc\n", rc);
240 g_hSemRW = NIL_RTSEMRW;
241 if (g_cErrors)
242 RTThreadSleep(100);
243
244 /*
245 * Collect and display the results.
246 */
247 uint64_t Total = g_au64[0];
248 for (i = 1; i < cThreads; i++)
249 Total += g_au64[i];
250
251 uint64_t Normal = Total / cThreads;
252 uint64_t MaxDeviation = 0;
253 for (i = 0; i < cThreads; i++)
254 {
255 uint64_t Delta = RT_ABS((int64_t)(g_au64[i] - Normal));
256 if (Delta > Normal / 2)
257 RTPrintf("tstSemRW: Warning! Thread %d deviates by more than 50%% - %llu (it) vs. %llu (avg)\n",
258 i, g_au64[i], Normal);
259 if (Delta > MaxDeviation)
260 MaxDeviation = Delta;
261
262 }
263
264 RTPrintf("tstSemRW: Threads: %u Total: %llu Per Sec: %llu Avg: %llu ns Max dev: %llu%%\n",
265 cThreads,
266 Total,
267 Total / cSeconds,
268 ElapsedNS / Total,
269 MaxDeviation * 100 / Normal
270 );
271 return 0;
272}
273
274
275int main(int argc, char **argv)
276{
277 int rc = RTR3Init();
278 if (RT_FAILURE(rc))
279 {
280 RTPrintf("tstSemRW: RTR3Init failed (rc=%Rrc)\n", rc);
281 return 1;
282 }
283 RTPrintf("tstSemRW: TESTING...\n");
284
285 if (argc == 1)
286 {
287 /* threads, seconds, writePercent, yield, quiet */
288 Test1( 1, 1, 0, true, false);
289 Test1( 1, 1, 1, true, false);
290 Test1( 1, 1, 5, true, false);
291 Test1( 2, 1, 3, true, false);
292 Test1( 10, 1, 5, true, false);
293 Test1( 10, 10, 10, false, false);
294
295 RTPrintf("tstSemRW: benchmarking...\n");
296 for (unsigned cThreads = 1; cThreads < 32; cThreads++)
297 Test1(cThreads, 2, 1, false, true);
298
299 /** @todo add a testcase where some stuff times out. */
300 }
301 else
302 {
303 /* threads, seconds, writePercent, yield, quiet */
304 RTPrintf("tstSemRW: benchmarking...\n");
305 Test1( 1, 3, 1, false, true);
306 Test1( 1, 3, 1, false, true);
307 Test1( 1, 3, 1, false, true);
308 Test1( 2, 3, 1, false, true);
309 Test1( 2, 3, 1, false, true);
310 Test1( 2, 3, 1, false, true);
311 Test1( 3, 3, 1, false, true);
312 Test1( 3, 3, 1, false, true);
313 Test1( 3, 3, 1, false, true);
314 }
315
316 if (!g_cErrors)
317 RTPrintf("tstSemRW: SUCCESS\n");
318 else
319 RTPrintf("tstSemRW: FAILURE - %u errors\n", g_cErrors);
320 return g_cErrors != 0;
321}
322
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