VirtualBox

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

Last change on this file since 105589 was 103005, checked in by vboxsync, 10 months ago

iprt/asm.h,*: Split out the ASMMem* and related stuff into a separate header, asm-mem.h, so that we can get the RT_ASM_PAGE_SIZE stuff out of the way.

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