VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTMemCache.cpp@ 61311

Last change on this file since 61311 was 59747, checked in by vboxsync, 9 years ago

iprt/asm.h: Cleaned up the ASMMemIsAll8/U32 mess and implmeneted the former in assembly. (Found inverted usage due to bad naming in copyUtf8Block, but it is fortunately an unused method.) Replaces the complicated ASMBitFirstSet based scanning in RTSgBufIsZero with a simple call to the new ASMMemIsZero function.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.7 KB
Line 
1/* $Id: tstRTMemCache.cpp 59747 2016-02-19 23:18:18Z vboxsync $ */
2/** @file
3 * IPRT Testcase - RTMemCache.
4 */
5
6/*
7 * Copyright (C) 2010-2015 Oracle Corporation
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
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <iprt/memcache.h>
32
33#include <iprt/asm.h>
34#include <iprt/err.h>
35#include <iprt/initterm.h>
36#include <iprt/mem.h>
37#include <iprt/param.h>
38#include <iprt/rand.h>
39#include <iprt/string.h>
40#include <iprt/semaphore.h>
41#include <iprt/test.h>
42#include <iprt/time.h>
43#include <iprt/thread.h>
44
45
46/*********************************************************************************************************************************
47* Structures and Typedefs *
48*********************************************************************************************************************************/
49typedef struct TST3THREAD
50{
51 RTTHREAD hThread;
52 RTSEMEVENTMULTI hEvt;
53 uint64_t volatile cIterations;
54 uint32_t cbObject;
55 bool fUseCache;
56} TST3THREAD, *PTST3THREAD;
57
58
59/*********************************************************************************************************************************
60* Global Variables *
61*********************************************************************************************************************************/
62/** The test handle */
63static RTTEST g_hTest;
64/** Global mem cache handle for use in some of the testcases. */
65static RTMEMCACHE g_hMemCache;
66/** Stop indicator for tst3 threads. */
67static bool volatile g_fTst3Stop;
68
69
70/**
71 * Basic API checks.
72 * We'll return if any of these fails.
73 */
74static void tst1(void)
75{
76 RTTestISub("Basics");
77
78 /* Create one without constructor or destructor. */
79 uint32_t const cObjects = PAGE_SIZE * 2 / 256;
80 RTMEMCACHE hMemCache;
81 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&hMemCache, 256, cObjects, 32, NULL, NULL, NULL, 0 /*fFlags*/), VINF_SUCCESS);
82 RTTESTI_CHECK_RETV(hMemCache != NIL_RTMEMCACHE);
83
84 /* Allocate a bit and free it again. */
85 void *pv = NULL;
86 RTTESTI_CHECK_RC_RETV(RTMemCacheAllocEx(hMemCache, &pv), VINF_SUCCESS);
87 RTTESTI_CHECK_RETV(pv != NULL);
88 RTTESTI_CHECK_RETV(RT_ALIGN_P(pv, 32) == pv);
89 RTMemCacheFree(hMemCache, pv);
90
91 RTTESTI_CHECK((pv = RTMemCacheAlloc(hMemCache)) != NULL);
92 RTMemCacheFree(hMemCache, pv);
93
94 /* Allocate everything and free it again, checking size constraints. */
95 for (uint32_t iLoop = 0; iLoop < 20; iLoop++)
96 {
97 /* Allocate everything. */
98 void *apv[cObjects];
99 for (uint32_t i = 0; i < cObjects; i++)
100 {
101 apv[i] = NULL;
102 RTTESTI_CHECK_RC(RTMemCacheAllocEx(hMemCache, &apv[i]), VINF_SUCCESS);
103 }
104
105 /* Check that we've got it all. */
106 int rc;
107 RTTESTI_CHECK_RC(rc = RTMemCacheAllocEx(hMemCache, &pv), VERR_MEM_CACHE_MAX_SIZE);
108 if (RT_SUCCESS(rc))
109 RTMemCacheFree(hMemCache, pv);
110
111 RTTESTI_CHECK((pv = RTMemCacheAlloc(hMemCache)) == NULL);
112 RTMemCacheFree(hMemCache, pv);
113
114 /* Free all the allocations. */
115 for (uint32_t i = 0; i < cObjects; i++)
116 {
117 RTMemCacheFree(hMemCache, apv[i]);
118
119 RTTESTI_CHECK((pv = RTMemCacheAlloc(hMemCache)) != NULL);
120 RTMemCacheFree(hMemCache, pv);
121 }
122 }
123
124 /* Destroy it. */
125 RTTESTI_CHECK_RC(RTMemCacheDestroy(hMemCache), VINF_SUCCESS);
126 RTTESTI_CHECK_RC(RTMemCacheDestroy(NIL_RTMEMCACHE), VINF_SUCCESS);
127}
128
129
130
131/** Constructor for tst2. */
132static DECLCALLBACK(int) tst2Ctor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)
133{
134 RTTESTI_CHECK(hMemCache == g_hMemCache);
135 RTTESTI_CHECK(ASMMemIsZero(pvObj, 256));
136
137 if (*(bool *)pvUser)
138 return VERR_RESOURCE_BUSY;
139
140 strcat((char *)pvObj, "ctor was called\n");
141 return VINF_SUCCESS;
142}
143
144
145/** Destructor for tst2. Checks that it was constructed and used twice. */
146static DECLCALLBACK(void) tst2Dtor(RTMEMCACHE hMemCache, void *pvObj, void *pvUser)
147{
148 RTTESTI_CHECK(!strcmp((char *)pvObj, "ctor was called\nused\nused\n"));
149 strcat((char *)pvObj, "dtor was called\n");
150}
151
152/**
153 * Test constructor / destructor.
154 */
155static void tst2(void)
156{
157 RTTestISub("Ctor/Dtor");
158
159 /* Create one without constructor or destructor. */
160 bool fFail = false;
161 uint32_t const cObjects = PAGE_SIZE * 2 / 256;
162 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&g_hMemCache, 256, cObjects, 32, tst2Ctor, tst2Dtor, &fFail, 0 /*fFlags*/), VINF_SUCCESS);
163
164 /* A failure run first. */
165 fFail = true;
166 void *pv = (void *)0x42;
167 RTTESTI_CHECK_RC_RETV(RTMemCacheAllocEx(g_hMemCache, &pv), VERR_RESOURCE_BUSY);
168 RTTESTI_CHECK(pv == (void *)0x42);
169 fFail = false;
170
171 /* To two rounds where we allocate all the objects and free them again. */
172 for (uint32_t iLoop = 0; iLoop < 2; iLoop++)
173 {
174 void *apv[cObjects];
175 for (uint32_t i = 0; i < cObjects; i++)
176 {
177 apv[i] = NULL;
178 RTTESTI_CHECK_RC_RETV(RTMemCacheAllocEx(g_hMemCache, &apv[i]), VINF_SUCCESS);
179 if (iLoop == 0)
180 RTTESTI_CHECK(!strcmp((char *)apv[i], "ctor was called\n"));
181 else
182 RTTESTI_CHECK(!strcmp((char *)apv[i], "ctor was called\nused\n"));
183 strcat((char *)apv[i], "used\n");
184 }
185
186 RTTESTI_CHECK_RETV((pv = RTMemCacheAlloc(g_hMemCache)) == NULL);
187 RTMemCacheFree(g_hMemCache, pv);
188
189 for (uint32_t i = 0; i < cObjects; i++)
190 RTMemCacheFree(g_hMemCache, apv[i]);
191 }
192
193 /* Cone, destroy the cache. */
194 RTTESTI_CHECK_RC(RTMemCacheDestroy(g_hMemCache), VINF_SUCCESS);
195}
196
197
198/**
199 * Thread that allocates
200 * @returns
201 * @param hThreadSelf The thread.
202 * @param pvArg Pointer to fUseCache.
203 */
204static DECLCALLBACK(int) tst3Thread(RTTHREAD hThreadSelf, void *pvArg)
205{
206 PTST3THREAD pThread = (PTST3THREAD)(pvArg);
207 size_t cbObject = pThread->cbObject;
208 uint64_t cIterations = 0;
209
210 /* wait for the kick-off */
211 RTTEST_CHECK_RC_OK(g_hTest, RTSemEventMultiWait(pThread->hEvt, RT_INDEFINITE_WAIT));
212
213 /* allocate and free loop */
214 if (pThread->fUseCache)
215 {
216 while (!g_fTst3Stop)
217 {
218 void *apv[64];
219 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
220 {
221 apv[i] = RTMemCacheAlloc(g_hMemCache);
222 RTTEST_CHECK(g_hTest, apv[i] != NULL);
223 }
224 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
225 RTMemCacheFree(g_hMemCache, apv[i]);
226
227 cIterations += RT_ELEMENTS(apv);
228 }
229 }
230 else
231 {
232 while (!g_fTst3Stop)
233 {
234 void *apv[64];
235
236 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
237 {
238 apv[i] = RTMemAlloc(cbObject);
239 RTTEST_CHECK(g_hTest, apv[i] != NULL);
240 }
241
242 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++)
243 RTMemFree(apv[i]);
244
245 cIterations += RT_ELEMENTS(apv);
246 }
247 }
248
249 /* report back the status */
250 pThread->cIterations = cIterations;
251 return VINF_SUCCESS;
252}
253
254/**
255 * Time constrained test with and unlimited N threads.
256 */
257static void tst3(uint32_t cThreads, uint32_t cbObject, int iMethod, uint32_t cSecs)
258{
259 RTTestISubF("Benchmark - %u threads, %u bytes, %u secs, %s", cThreads, cbObject, cSecs,
260 iMethod == 0 ? "RTMemCache"
261 : "RTMemAlloc");
262
263 /*
264 * Create a cache with unlimited space, a start semaphore and line up
265 * the threads.
266 */
267 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&g_hMemCache, cbObject, 0 /*cbAlignment*/, UINT32_MAX, NULL, NULL, NULL, 0 /*fFlags*/), VINF_SUCCESS);
268
269 RTSEMEVENTMULTI hEvt;
270 RTTESTI_CHECK_RC_OK_RETV(RTSemEventMultiCreate(&hEvt));
271
272 TST3THREAD aThreads[64];
273 RTTESTI_CHECK_RETV(cThreads < RT_ELEMENTS(aThreads));
274
275 ASMAtomicWriteBool(&g_fTst3Stop, false);
276 for (uint32_t i = 0; i < cThreads; i++)
277 {
278 aThreads[i].hThread = NIL_RTTHREAD;
279 aThreads[i].cIterations = 0;
280 aThreads[i].fUseCache = iMethod == 0;
281 aThreads[i].cbObject = cbObject;
282 aThreads[i].hEvt = hEvt;
283 RTTESTI_CHECK_RC_OK_RETV(RTThreadCreateF(&aThreads[i].hThread, tst3Thread, &aThreads[i], 0,
284 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, "tst3-%u", i));
285 }
286
287 /*
288 * Start the race.
289 */
290 RTTimeNanoTS(); /* warmup */
291
292 uint64_t uStartTS = RTTimeNanoTS();
293 RTTESTI_CHECK_RC_OK_RETV(RTSemEventMultiSignal(hEvt));
294 RTThreadSleep(cSecs * 1000);
295 ASMAtomicWriteBool(&g_fTst3Stop, true);
296 for (uint32_t i = 0; i < cThreads; i++)
297 RTTESTI_CHECK_RC_OK_RETV(RTThreadWait(aThreads[i].hThread, 60*1000, NULL));
298 uint64_t cElapsedNS = RTTimeNanoTS() - uStartTS;
299
300 /*
301 * Sum up the counts.
302 */
303 uint64_t cIterations = 0;
304 for (uint32_t i = 0; i < cThreads; i++)
305 cIterations += aThreads[i].cIterations;
306
307 RTTestIPrintf(RTTESTLVL_ALWAYS, "%'8u iterations per second, %'llu ns on avg\n",
308 (unsigned)((long double)cIterations * 1000000000.0 / cElapsedNS),
309 cElapsedNS / cIterations);
310
311 /* clean up */
312 RTTESTI_CHECK_RC(RTMemCacheDestroy(g_hMemCache), VINF_SUCCESS);
313 RTTESTI_CHECK_RC_OK(RTSemEventMultiDestroy(hEvt));
314}
315
316static void tst3AllMethods(uint32_t cThreads, uint32_t cbObject, uint32_t cSecs)
317{
318 tst3(cThreads, cbObject, 0, cSecs);
319 tst3(cThreads, cbObject, 1, cSecs);
320}
321
322
323int main(int argc, char **argv)
324{
325 RTTEST hTest;
326 int rc = RTTestInitAndCreate("tstRTMemCache", &hTest);
327 if (rc)
328 return rc;
329 RTTestBanner(hTest);
330 g_hTest = hTest;
331
332 tst1();
333 tst2();
334 if (RTTestIErrorCount() == 0)
335 {
336 uint32_t cSecs = argc == 1 ? 5 : 2;
337 /* threads, cbObj, cSecs */
338 tst3AllMethods( 1, 256, cSecs);
339 tst3AllMethods( 1, 32, cSecs);
340 tst3AllMethods( 1, 8, cSecs);
341 tst3AllMethods( 1, 2, cSecs);
342 tst3AllMethods( 1, 1, cSecs);
343
344 tst3AllMethods( 3, 256, cSecs);
345 tst3AllMethods( 3, 128, cSecs);
346 tst3AllMethods( 3, 64, cSecs);
347 tst3AllMethods( 3, 32, cSecs);
348 tst3AllMethods( 3, 2, cSecs);
349 tst3AllMethods( 3, 1, cSecs);
350
351 tst3AllMethods( 16, 32, cSecs);
352 }
353
354 /*
355 * Summary.
356 */
357 return RTTestSummaryAndDestroy(hTest);
358}
359
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