VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/testcase/tstVbglR0PhysHeap-1.cpp@ 97937

最後變更 在這個檔案從97937是 97937,由 vboxsync 提交於 2 年 前

Add/VBoxGuestR0LibPhysHeap.cpp: Reworked the block management so we can merge with both the preceeding and succeeding blocks when freeing, rather than having expensive hacks for doing this. This raises the minimum alocation to sizeof(uintptr_t) * 2, which makes not differences to the heap users which has a minimum allocation size of 24 bytes.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 15.4 KB
 
1/* $Id: tstVbglR0PhysHeap-1.cpp 97937 2023-01-02 15:08:43Z vboxsync $ */
2/** @file
3 * IPRT Testcase - Offset Based Heap.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.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/assert.h>
42#include <iprt/errcore.h>
43#include <iprt/initterm.h>
44#include <iprt/log.h>
45#include <iprt/mem.h>
46#include <iprt/rand.h>
47#include <iprt/stream.h>
48#include <iprt/string.h>
49#include <iprt/param.h>
50#include <iprt/test.h>
51#include <iprt/time.h>
52
53#define IN_TESTCASE
54#define IN_RING0 /* pretend we're in ring-0 so we get access to the functions */
55#include "../VBoxGuestR0LibInternal.h"
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61typedef struct
62{
63 uint32_t cb;
64 void *pv;
65} TSTHISTORYENTRY;
66
67
68/*********************************************************************************************************************************
69* Global Variables *
70*********************************************************************************************************************************/
71VBGLDATA g_vbgldata;
72
73int g_cChunks = 0;
74size_t g_cbChunks = 0;
75
76/** Drop-in replacement for RTMemContAlloc */
77static void *tstMemContAlloc(PRTCCPHYS pPhys, size_t cb)
78{
79 RTTESTI_CHECK(cb > 0);
80
81#define TST_MAX_CHUNKS 24
82 if (g_cChunks < TST_MAX_CHUNKS)
83 {
84 void *pvRet = RTMemAlloc(cb);
85 if (pvRet)
86 {
87 g_cChunks++;
88 g_cbChunks += cb;
89 *pPhys = (uint32_t)(uintptr_t)pvRet ^ (UINT32_C(0xf0f0f0f0) & ~(uint32_t)PAGE_OFFSET_MASK);
90
91 /* Avoid problematic values that won't happen in real life: */
92 if (!*pPhys)
93 *pPhys = 4U << PAGE_SHIFT;
94 if (UINT32_MAX - *pPhys < cb)
95 *pPhys -= RT_ALIGN_32(cb, PAGE_SIZE);
96
97 return pvRet;
98 }
99 }
100
101 *pPhys = NIL_RTCCPHYS;
102 return NULL;
103}
104
105
106/** Drop-in replacement for RTMemContFree */
107static void tstMemContFree(void *pv, size_t cb)
108{
109 RTTESTI_CHECK(RT_VALID_PTR(pv));
110 RTTESTI_CHECK(cb > 0);
111 RTTESTI_CHECK(g_cChunks > 0);
112 RTMemFree(pv);
113 g_cChunks--;
114 g_cbChunks -= cb;
115}
116
117
118#define RTMemContAlloc tstMemContAlloc
119#define RTMemContFree tstMemContFree
120#include "../VBoxGuestR0LibPhysHeap.cpp"
121
122
123static void PrintStats(TSTHISTORYENTRY const *paHistory, size_t cHistory, const char *pszDesc)
124{
125 size_t cbAllocated = 0;
126 unsigned cLargeBlocks = 0;
127 unsigned cAllocated = 0;
128 for (size_t i = 0; i < cHistory; i++)
129 if (paHistory[i].pv)
130 {
131 cAllocated += 1;
132 cbAllocated += paHistory[i].cb;
133 cLargeBlocks += paHistory[i].cb > _1K;
134 }
135
136 size_t const cbOverhead = g_cChunks * sizeof(VBGLPHYSHEAPCHUNK) + cAllocated * sizeof(VBGLPHYSHEAPBLOCK);
137 size_t const cbFragmentation = g_cbChunks - cbOverhead - cbAllocated;
138 RTTestIPrintf(RTTESTLVL_ALWAYS,
139 "%s: %'9zu bytes in %2d chunks; %'9zu bytes in %4u blocks (%2u large)\n"
140 " => int-frag %'9zu (%2zu.%1zu%%) overhead %'9zu (%1zu.%02zu%%)\n",
141 pszDesc,
142 g_cbChunks, g_cChunks,
143 cbAllocated, cAllocated, cLargeBlocks,
144 cbFragmentation, cbFragmentation * 100 / g_cbChunks, (cbFragmentation * 1000 / g_cbChunks) % 10,
145 cbOverhead, cbOverhead * 100 / g_cbChunks, (cbOverhead * 10000 / g_cbChunks) % 100);
146}
147
148
149int main(int argc, char **argv)
150{
151 RT_NOREF_PV(argc); RT_NOREF_PV(argv);
152
153 /*
154 * Init runtime.
155 */
156 RTTEST hTest;
157 int rc = RTTestInitAndCreate("tstVbglR0PhysHeap-1", &hTest);
158 if (rc)
159 return rc;
160 RTTestBanner(hTest);
161
162 /*
163 * Arguments are taken to be random seeding.
164 */
165 uint64_t uRandSeed = RTTimeNanoTS();
166 for (int i = 1; i < argc; i++)
167 {
168 rc = RTStrToUInt64Full(argv[i], 0, &uRandSeed);
169 if (rc != VINF_SUCCESS)
170 {
171 RTTestIFailed("Invalid parameter: %Rrc: %s\n", rc, argv[i]);
172 return RTTestSummaryAndDestroy(hTest);
173 }
174 }
175
176 /*
177 * Create a heap.
178 */
179 RTTestSub(hTest, "Basics");
180 RTTESTI_CHECK_RC(rc = VbglR0PhysHeapInit(), VINF_SUCCESS);
181 if (RT_FAILURE(rc))
182 return RTTestSummaryAndDestroy(hTest);
183 RTTESTI_CHECK_RC_OK(VbglR0PhysHeapCheck(NULL));
184
185#define CHECK_PHYS_ADDR(a_pv) do { \
186 uint32_t const uPhys = VbglR0PhysHeapGetPhysAddr(a_pv); \
187 if (uPhys == 0 || uPhys == UINT32_MAX || (uPhys & PAGE_OFFSET_MASK) != ((uintptr_t)(a_pv) & PAGE_OFFSET_MASK)) \
188 RTTestIFailed("line %u: %s=%p: uPhys=%#x\n", __LINE__, #a_pv, (a_pv), uPhys); \
189 } while (0)
190
191 /*
192 * Try allocate.
193 */
194 static struct TstPhysHeapOps
195 {
196 uint32_t cb;
197 unsigned iFreeOrder;
198 void *pvAlloc;
199 } s_aOps[] =
200 {
201 { 16, 0, NULL }, // 0
202 { 16, 1, NULL },
203 { 16, 2, NULL },
204 { 16, 5, NULL },
205 { 16, 4, NULL },
206 { 32, 3, NULL }, // 5
207 { 31, 6, NULL },
208 { 1024, 8, NULL },
209 { 1024, 10, NULL },
210 { 1024, 12, NULL },
211 { PAGE_SIZE, 13, NULL }, // 10
212 { 1024, 9, NULL },
213 { PAGE_SIZE, 11, NULL },
214 { PAGE_SIZE, 14, NULL },
215 { 16, 15, NULL },
216 { 9, 7, NULL }, // 15
217 { 16, 7, NULL },
218 { 36, 7, NULL },
219 { 16, 7, NULL },
220 { 12344, 7, NULL },
221 { 50, 7, NULL }, // 20
222 { 16, 7, NULL },
223 };
224 uint32_t i;
225 //RTHeapOffsetDump(Heap, (PFNRTHEAPOFFSETPRINTF)(uintptr_t)RTPrintf); /** @todo Add some detail info output with a signature identical to RTPrintf. */
226 //size_t cbBefore = VbglR0PhysHeapGetFreeSize();
227 static char const s_szFill[] = "01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
228
229 /* allocate */
230 for (i = 0; i < RT_ELEMENTS(s_aOps); i++)
231 {
232 s_aOps[i].pvAlloc = VbglR0PhysHeapAlloc(s_aOps[i].cb);
233 RTTESTI_CHECK_MSG(s_aOps[i].pvAlloc, ("VbglR0PhysHeapAlloc(%#x) -> NULL i=%d\n", s_aOps[i].cb, i));
234 if (!s_aOps[i].pvAlloc)
235 return RTTestSummaryAndDestroy(hTest);
236
237 memset(s_aOps[i].pvAlloc, s_szFill[i], s_aOps[i].cb);
238 RTTESTI_CHECK_MSG(RT_ALIGN_P(s_aOps[i].pvAlloc, sizeof(void *)) == s_aOps[i].pvAlloc,
239 ("VbglR0PhysHeapAlloc(%#x) -> %p\n", s_aOps[i].cb, i));
240
241 CHECK_PHYS_ADDR(s_aOps[i].pvAlloc);
242
243 /* Check heap integrity: */
244 RTTESTI_CHECK_RC_OK(VbglR0PhysHeapCheck(NULL));
245 }
246
247 /* free and allocate the same node again. */
248 for (i = 0; i < RT_ELEMENTS(s_aOps); i++)
249 {
250 if (!s_aOps[i].pvAlloc)
251 continue;
252 //RTPrintf("debug: i=%d pv=%#x cb=%#zx align=%#zx cbReal=%#zx\n", i, s_aOps[i].pvAlloc,
253 // s_aOps[i].cb, s_aOps[i].uAlignment, RTHeapOffsetSize(Heap, s_aOps[i].pvAlloc));
254 size_t cbBeforeSub = VbglR0PhysHeapGetFreeSize();
255 VbglR0PhysHeapFree(s_aOps[i].pvAlloc);
256 size_t cbAfterSubFree = VbglR0PhysHeapGetFreeSize();
257 RTTESTI_CHECK_RC_OK(VbglR0PhysHeapCheck(NULL));
258
259 void *pv;
260 pv = VbglR0PhysHeapAlloc(s_aOps[i].cb);
261 RTTESTI_CHECK_MSG(pv, ("VbglR0PhysHeapAlloc(%#x) -> NULL i=%d\n", s_aOps[i].cb, i));
262 if (!pv)
263 return RTTestSummaryAndDestroy(hTest);
264 CHECK_PHYS_ADDR(pv);
265 RTTESTI_CHECK_RC_OK(VbglR0PhysHeapCheck(NULL));
266
267 //RTPrintf("debug: i=%d pv=%p cbReal=%#zx cbBeforeSub=%#zx cbAfterSubFree=%#zx cbAfterSubAlloc=%#zx \n", i, pv, RTHeapOffsetSize(Heap, pv),
268 // cbBeforeSub, cbAfterSubFree, VbglR0PhysHeapGetFreeSize());
269
270 if (pv != s_aOps[i].pvAlloc)
271 RTTestIPrintf(RTTESTLVL_ALWAYS, "Warning: Free+Alloc returned different address. new=%p old=%p i=%d\n", pv, s_aOps[i].pvAlloc, i);
272 s_aOps[i].pvAlloc = pv;
273 size_t cbAfterSubAlloc = VbglR0PhysHeapGetFreeSize();
274 if (cbBeforeSub != cbAfterSubAlloc)
275 {
276 RTTestIPrintf(RTTESTLVL_ALWAYS, "Warning: cbBeforeSub=%#zx cbAfterSubFree=%#zx cbAfterSubAlloc=%#zx. i=%d\n",
277 cbBeforeSub, cbAfterSubFree, cbAfterSubAlloc, i);
278 //return 1; - won't work correctly until we start creating free block instead of donating memory on alignment.
279 }
280 }
281
282 VbglR0PhysHeapTerminate();
283 RTTESTI_CHECK_MSG(g_cChunks == 0, ("g_cChunks=%d\n", g_cChunks));
284
285
286 /*
287 * Use random allocation pattern
288 */
289 RTTestSub(hTest, "Random Test");
290 RTTESTI_CHECK_RC(rc = VbglR0PhysHeapInit(), VINF_SUCCESS);
291 if (RT_FAILURE(rc))
292 return RTTestSummaryAndDestroy(hTest);
293
294 RTRAND hRand;
295 RTTESTI_CHECK_RC(rc = RTRandAdvCreateParkMiller(&hRand), VINF_SUCCESS);
296 if (RT_FAILURE(rc))
297 return RTTestSummaryAndDestroy(hTest);
298 RTRandAdvSeed(hRand, uRandSeed);
299 RTTestValue(hTest, "RandSeed", uRandSeed, RTTESTUNIT_NONE);
300
301 static TSTHISTORYENTRY s_aHistory[3072];
302 RT_ZERO(s_aHistory);
303
304 for (unsigned iTest = 0; iTest < 131072; iTest++)
305 {
306 i = RTRandAdvU32Ex(hRand, 0, RT_ELEMENTS(s_aHistory) - 1);
307 if (!s_aHistory[i].pv)
308 {
309 s_aHistory[i].cb = RTRandAdvU32Ex(hRand, 8, 1024);
310 s_aHistory[i].pv = VbglR0PhysHeapAlloc(s_aHistory[i].cb);
311 if (!s_aHistory[i].pv)
312 {
313 s_aHistory[i].cb = 9;
314 s_aHistory[i].pv = VbglR0PhysHeapAlloc(s_aHistory[i].cb);
315 }
316 if (s_aHistory[i].pv)
317 {
318 memset(s_aHistory[i].pv, 0xbb, s_aHistory[i].cb);
319 CHECK_PHYS_ADDR(s_aHistory[i].pv);
320 }
321 }
322 else
323 {
324 VbglR0PhysHeapFree(s_aHistory[i].pv);
325 s_aHistory[i].pv = NULL;
326 }
327
328#if 1
329 /* Check heap integrity: */
330 RTTESTI_CHECK_RC_OK(VbglR0PhysHeapCheck(NULL));
331 int cChunks = 0;
332 for (VBGLPHYSHEAPCHUNK *pCurChunk = g_vbgldata.pChunkHead; pCurChunk; pCurChunk = pCurChunk->pNext)
333 cChunks++;
334 RTTESTI_CHECK_MSG(cChunks == g_cChunks, ("g_cChunks=%u, but only %u chunks in the list!\n", g_cChunks, cChunks));
335#endif
336
337 if ((iTest % 7777) == 7776)
338 {
339 /* exhaust the heap */
340 PrintStats(s_aHistory, RT_ELEMENTS(s_aHistory), "Exhaust-pre ");
341
342 for (i = 0; i < RT_ELEMENTS(s_aHistory) && (VbglR0PhysHeapGetFreeSize() >= 256 || g_cChunks < TST_MAX_CHUNKS); i++)
343 if (!s_aHistory[i].pv)
344 {
345 s_aHistory[i].cb = RTRandAdvU32Ex(hRand, VBGL_PH_CHUNKSIZE / 8, VBGL_PH_CHUNKSIZE / 2 + VBGL_PH_CHUNKSIZE / 4);
346 s_aHistory[i].pv = VbglR0PhysHeapAlloc(s_aHistory[i].cb);
347 if (s_aHistory[i].pv)
348 {
349 memset(s_aHistory[i].pv, 0x55, s_aHistory[i].cb);
350 CHECK_PHYS_ADDR(s_aHistory[i].pv);
351 }
352 }
353
354 size_t cbFree = VbglR0PhysHeapGetFreeSize();
355 if (cbFree)
356 for (i = 0; i < RT_ELEMENTS(s_aHistory); i++)
357 if (!s_aHistory[i].pv)
358 {
359 s_aHistory[i].cb = RTRandAdvU32Ex(hRand, 1, (uint32_t)cbFree);
360 s_aHistory[i].pv = VbglR0PhysHeapAlloc(s_aHistory[i].cb);
361 while (s_aHistory[i].pv == NULL && s_aHistory[i].cb > 2)
362 {
363 s_aHistory[i].cb >>= 1;
364 s_aHistory[i].pv = VbglR0PhysHeapAlloc(s_aHistory[i].cb);
365 }
366 if (s_aHistory[i].pv)
367 {
368 memset(s_aHistory[i].pv, 0x55, s_aHistory[i].cb);
369 CHECK_PHYS_ADDR(s_aHistory[i].pv);
370 }
371
372 cbFree = VbglR0PhysHeapGetFreeSize();
373 if (!cbFree)
374 break;
375 }
376
377 RTTESTI_CHECK_MSG(VbglR0PhysHeapGetFreeSize() == 0, ("%zu\n", VbglR0PhysHeapGetFreeSize()));
378 PrintStats(s_aHistory, RT_ELEMENTS(s_aHistory), "Exhaust-post");
379 }
380 else if ((iTest % 7777) == 1111)
381 {
382 /* free all */
383 RTTestIPrintf(RTTESTLVL_ALWAYS, "Free-all-pre: cFreeBlocks=%u cAllocedBlocks=%u in %u chunk(s)\n",
384 g_vbgldata.cFreeBlocks, g_vbgldata.cBlocks - g_vbgldata.cFreeBlocks, g_cChunks);
385 for (i = 0; i < RT_ELEMENTS(s_aHistory); i++)
386 {
387 VbglR0PhysHeapFree(s_aHistory[i].pv);
388 s_aHistory[i].pv = NULL;
389 }
390 RTTestIPrintf(RTTESTLVL_ALWAYS, "Free-all-post: cFreeBlocks=%u in %u chunk(s)\n", g_vbgldata.cFreeBlocks, g_cChunks);
391 RTTESTI_CHECK_MSG(g_cChunks == 1, ("g_cChunks=%d\n", g_cChunks));
392 RTTESTI_CHECK_MSG(g_vbgldata.cFreeBlocks == g_vbgldata.cBlocks,
393 ("g_vbgldata.cFreeBlocks=%d cBlocks=%d\n", g_vbgldata.cFreeBlocks, g_vbgldata.cBlocks));
394
395 //size_t cbAfterRand = VbglR0PhysHeapGetFreeSize();
396 //RTTESTI_CHECK_MSG(cbAfterRand == cbAfter, ("cbAfterRand=%zu cbAfter=%zu\n", cbAfterRand, cbAfter));
397 }
398 }
399
400 /* free the rest. */
401 for (i = 0; i < RT_ELEMENTS(s_aHistory); i++)
402 {
403 VbglR0PhysHeapFree(s_aHistory[i].pv);
404 s_aHistory[i].pv = NULL;
405 }
406
407 RTTESTI_CHECK_MSG(g_cChunks == 1, ("g_cChunks=%d\n", g_cChunks));
408
409 VbglR0PhysHeapTerminate();
410 RTTESTI_CHECK_MSG(g_cChunks == 0, ("g_cChunks=%d\n", g_cChunks));
411
412 RTTESTI_CHECK_RC(rc = RTRandAdvDestroy(hRand), VINF_SUCCESS);
413 return RTTestSummaryAndDestroy(hTest);
414}
415
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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