Changeset 26452 in vbox for trunk/src/VBox/Runtime
- Timestamp:
- Feb 11, 2010 6:41:06 PM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 57599
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/alloc/memcache.cpp
r26428 r26452 53 53 /** Pointer to a cache page. */ 54 54 typedef struct RTMEMCACHEPAGE *PRTMEMCACHEPAGE; 55 56 57 58 /** 59 * A free object. 60 * 61 * @remarks This only works if the objects don't have a constructor or 62 * destructor and are big enough. 63 */ 64 typedef struct RTMEMCACHEFREEOBJ 65 { 66 /** Pointer to the next free object */ 67 struct RTMEMCACHEFREEOBJ * volatile pNext; 68 } RTMEMCACHEFREEOBJ; 69 /** Pointer to a free object. */ 70 typedef RTMEMCACHEFREEOBJ *PRTMEMCACHEFREEOBJ; 55 71 56 72 … … 107 123 /** The maximum number of objects. */ 108 124 uint32_t cMax; 125 /** Whether to the use the free list or not. */ 126 bool fUseFreeList; 109 127 /** Head of the page list. */ 110 128 PRTMEMCACHEPAGE pPageHead; … … 124 142 /** This may point to a page with free entries. */ 125 143 PRTMEMCACHEPAGE volatile pPageHint; 144 /** Stack of free items. 145 * These are marked as used in the allocation bitmaps. 146 * 147 * @todo This doesn't scale well when several threads are beating on the 148 * cache. Also, it totally doesn't work when we've got a 149 * constructor/destructor around or the objects are too small. */ 150 PRTMEMCACHEFREEOBJ volatile pFreeTop; 126 151 } RTMEMCACHEINT; 127 152 … … 129 154 130 155 RTDECL(int) RTMemCacheCreate(PRTMEMCACHE phMemCache, size_t cbObject, size_t cbAlignment, uint32_t cMaxObjects, 131 PFNMEMCACHECTOR pfnCtor, PFNMEMCACHEDTOR pfnDtor, void *pvUser) 156 PFNMEMCACHECTOR pfnCtor, PFNMEMCACHEDTOR pfnDtor, void *pvUser, uint32_t fFlags) 157 132 158 { 133 159 AssertPtr(phMemCache); 134 160 AssertPtrNull(pfnCtor); 135 161 AssertPtrNull(pfnDtor); 162 AssertReturn(!pfnDtor || pfnCtor, VERR_INVALID_PARAMETER); 136 163 AssertReturn(cbObject > 0, VERR_INVALID_PARAMETER); 137 164 AssertReturn(cbObject <= PAGE_SIZE / 8, VERR_INVALID_PARAMETER); 165 AssertReturn(!fFlags, VERR_INVALID_PARAMETER); 138 166 139 167 if (cbAlignment == 0) … … 173 201 pThis->cBits = RT_ALIGN(pThis->cPerPage, 64); 174 202 pThis->cMax = cMaxObjects; 175 pThis->cTotal = 0; 176 pThis->cFree = 0; 203 pThis->fUseFreeList = cbObject >= sizeof(RTMEMCACHEFREEOBJ) 204 && !pfnCtor 205 && !pfnDtor; 177 206 pThis->pPageHead = NULL; 178 pThis->pPageHint = NULL;179 207 pThis->pfnCtor = pfnCtor; 180 208 pThis->pfnDtor = pfnDtor; 181 209 pThis->pvUser = pvUser; 210 pThis->cTotal = 0; 211 pThis->cFree = 0; 212 pThis->pPageHint = NULL; 213 pThis->pFreeTop = NULL; 182 214 183 215 *phMemCache = pThis; … … 193 225 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 194 226 AssertReturn(pThis->u32Magic == RTMEMCACHE_MAGIC, VERR_INVALID_HANDLE); 195 AssertMsg((uint32_t)pThis->cFree == pThis->cTotal, ("cFree=%u cTotal=%u\n", pThis->cFree, pThis->cTotal)); 227 #ifdef RT_STRICT 228 uint32_t cFree = pThis->cFree; 229 for (PRTMEMCACHEFREEOBJ pFree = pThis->pFreeTop; pFree; pFree = pFree->pNext) 230 cFree++; 231 AssertMsg(cFree == pThis->cTotal, ("cFree=%u cTotal=%u\n", cFree, pThis->cTotal)); 232 #endif 196 233 197 234 /* … … 268 305 pb = (uint8_t *)((uintptr_t)pb & ~(uintptr_t)7); 269 306 pPage->pbmAlloc = pb; 270 Assert((uintptr_t)pPage->pbmCtor + pThis->cBits / 8 < (uintptr_t)pPage->pbmCtor);307 Assert((uintptr_t)pPage->pbmCtor + pThis->cBits / 8 <= (uintptr_t)pPage->pbmAlloc); 271 308 272 309 /* Mark the bitmap padding and any unused objects as allocated. */ … … 322 359 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); 323 360 AssertReturn(pThis->u32Magic == RTMEMCACHE_MAGIC, VERR_INVALID_PARAMETER); 361 362 /* 363 * Try grab a free object from the stack. 364 */ 365 PRTMEMCACHEFREEOBJ pObj = (PRTMEMCACHEFREEOBJ)ASMAtomicUoReadPtr((void * volatile *)&pThis->pFreeTop); 366 if (pObj) 367 { 368 PRTMEMCACHEFREEOBJ pNext; 369 do 370 { 371 pNext = (PRTMEMCACHEFREEOBJ)ASMAtomicUoReadPtr((void * volatile *)&pObj->pNext); 372 if (ASMAtomicCmpXchgPtr((void * volatile *)&pThis->pFreeTop, pNext, pObj)) 373 { 374 *ppvObj = pObj; 375 return VINF_SUCCESS; 376 } 377 pObj = (PRTMEMCACHEFREEOBJ)ASMAtomicUoReadPtr((void * volatile *)&pThis->pFreeTop); 378 } while (pObj); 379 } 324 380 325 381 /* … … 438 494 Assert(RT_ALIGN_P(pvObj, pThis->cbAlignment) == pvObj); 439 495 440 /* Note: Do *NOT* attempt to poison the object if we have a constructor 441 or/and destructor! */ 442 443 /* 444 * Find the cache page. The page structure is at the start of the page. 445 */ 446 PRTMEMCACHEPAGE pPage = (PRTMEMCACHEPAGE)(((uintptr_t)pvObj) & ~(uintptr_t)PAGE_OFFSET_MASK); 447 Assert(pPage->pCache == pThis); 448 Assert(ASMAtomicUoReadS32(&pPage->cFree) < (int32_t)pThis->cPerPage); 449 450 /* 451 * Clear the bitmap bit and update the two object counter. Order matters! 452 */ 453 uintptr_t offObj = (uintptr_t)pvObj - (uintptr_t)pPage->pbObjects; 454 uintptr_t iObj = offObj / pThis->cbObject; 455 Assert(iObj * pThis->cbObject == offObj); 456 Assert(iObj < pThis->cPerPage); 457 AssertReturnVoid(ASMAtomicBitTestAndClear(pPage->pbmAlloc, iObj)); 458 459 ASMAtomicIncS32(&pPage->cFree); 460 ASMAtomicIncS32(&pThis->cFree); 461 } 462 496 if (pThis->fUseFreeList) 497 { 498 # ifdef RT_STRICT 499 /* This is the same as the other branch, except it's not actually freed. */ 500 PRTMEMCACHEPAGE pPage = (PRTMEMCACHEPAGE)(((uintptr_t)pvObj) & ~(uintptr_t)PAGE_OFFSET_MASK); 501 Assert(pPage->pCache == pThis); 502 Assert(ASMAtomicUoReadS32(&pPage->cFree) < (int32_t)pThis->cPerPage); 503 uintptr_t offObj = (uintptr_t)pvObj - (uintptr_t)pPage->pbObjects; 504 uintptr_t iObj = offObj / pThis->cbObject; 505 Assert(iObj * pThis->cbObject == offObj); 506 Assert(iObj < pThis->cPerPage); 507 AssertReturnVoid(ASMBitTest(pPage->pbmAlloc, iObj)); 508 # endif 509 510 /* 511 * Push it onto the free stack. 512 */ 513 PRTMEMCACHEFREEOBJ pObj = (PRTMEMCACHEFREEOBJ)pvObj; 514 PRTMEMCACHEFREEOBJ pNext; 515 do 516 { 517 pNext = (PRTMEMCACHEFREEOBJ)ASMAtomicUoReadPtr((void * volatile *)&pThis->pFreeTop); 518 pObj->pNext = pNext; 519 } while (!ASMAtomicCmpXchgPtr((void * volatile *)&pThis->pFreeTop, pObj, pNext)); 520 } 521 else 522 { 523 /* Note: Do *NOT* attempt to poison the object if we have a constructor 524 or/and destructor! */ 525 526 /* 527 * Find the cache page. The page structure is at the start of the page. 528 */ 529 PRTMEMCACHEPAGE pPage = (PRTMEMCACHEPAGE)(((uintptr_t)pvObj) & ~(uintptr_t)PAGE_OFFSET_MASK); 530 Assert(pPage->pCache == pThis); 531 Assert(ASMAtomicUoReadS32(&pPage->cFree) < (int32_t)pThis->cPerPage); 532 533 /* 534 * Clear the bitmap bit and update the two object counter. Order matters! 535 */ 536 uintptr_t offObj = (uintptr_t)pvObj - (uintptr_t)pPage->pbObjects; 537 uintptr_t iObj = offObj / pThis->cbObject; 538 Assert(iObj * pThis->cbObject == offObj); 539 Assert(iObj < pThis->cPerPage); 540 AssertReturnVoid(ASMAtomicBitTestAndClear(pPage->pbmAlloc, iObj)); 541 542 ASMAtomicIncS32(&pPage->cFree); 543 ASMAtomicIncS32(&pThis->cFree); 544 } 545 } 546 -
trunk/src/VBox/Runtime/testcase/tstRTMemCache.cpp
r26420 r26452 36 36 #include <iprt/asm.h> 37 37 #include <iprt/err.h> 38 #include <iprt/cache.h> 38 39 #include <iprt/initterm.h> 39 40 #include <iprt/mem.h> … … 57 58 uint32_t cbObject; 58 59 bool fUseCache; 60 bool fUseOldCache; 59 61 } TST3THREAD, *PTST3THREAD; 60 62 … … 67 69 /** Global mem cache handle for use in some of the testcases. */ 68 70 static RTMEMCACHE g_hMemCache; 71 /** For testcase 3. */ 72 static PRTOBJCACHE g_pOldCacheTst3; 69 73 /** Stop indicator for tst3 threads. */ 70 74 static bool volatile g_fTst3Stop; … … 82 86 uint32_t const cObjects = PAGE_SIZE * 2 / 256; 83 87 RTMEMCACHE hMemCache; 84 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&hMemCache, 256, cObjects, 32, NULL, NULL, NULL ), VINF_SUCCESS);88 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&hMemCache, 256, cObjects, 32, NULL, NULL, NULL, 0 /*fFlags*/), VINF_SUCCESS); 85 89 RTTESTI_CHECK_RETV(hMemCache != NIL_RTMEMCACHE); 86 90 … … 163 167 bool fFail = false; 164 168 uint32_t const cObjects = PAGE_SIZE * 2 / 256; 165 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&g_hMemCache, 256, cObjects, 32, tst2Ctor, tst2Dtor, &fFail ), VINF_SUCCESS);169 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&g_hMemCache, 256, cObjects, 32, tst2Ctor, tst2Dtor, &fFail, 0 /*fFlags*/), VINF_SUCCESS); 166 170 167 171 /* A failure run first. */ … … 208 212 { 209 213 PTST3THREAD pThread = (PTST3THREAD)(pvArg); 210 bool fUseCache = pThread->fUseCache;211 214 size_t cbObject = pThread->cbObject; 212 215 uint64_t cIterations = 0; … … 216 219 217 220 /* allocate and free loop */ 218 while (!g_fTst3Stop) 219 { 220 void *apv[64]; 221 222 if (fUseCache) 223 { 221 if (pThread->fUseCache) 222 { 223 while (!g_fTst3Stop) 224 { 225 void *apv[64]; 224 226 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) 225 227 { … … 229 231 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) 230 232 RTMemCacheFree(g_hMemCache, apv[i]); 231 } 232 else 233 { 233 234 cIterations += RT_ELEMENTS(apv); 235 } 236 } 237 else if (pThread->fUseOldCache) 238 { 239 while (!g_fTst3Stop) 240 { 241 void *apv[64]; 242 243 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) 244 { 245 apv[i] = NULL; 246 RTTEST_CHECK_RC_OK(g_hTest, RTCacheRequest(g_pOldCacheTst3, &apv[i])); 247 } 248 249 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) 250 RTCacheInsert(g_pOldCacheTst3, apv[i]); 251 252 cIterations += RT_ELEMENTS(apv); 253 } 254 } 255 else 256 { 257 while (!g_fTst3Stop) 258 { 259 void *apv[64]; 260 234 261 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) 235 262 { … … 240 267 for (unsigned i = 0; i < RT_ELEMENTS(apv); i++) 241 268 RTMemFree(apv[i]); 242 } 243 cIterations += RT_ELEMENTS(apv); 269 270 cIterations += RT_ELEMENTS(apv); 271 } 244 272 } 245 273 … … 252 280 * Time constrained test with and unlimited N threads. 253 281 */ 254 static void tst3(uint32_t cThreads, uint32_t cbObject, bool fUseCache, uint32_t cSecs) 255 { 256 RTTestISubF("Benchmark - %u threads, %u bytes, %u secs, %s", cThreads, cbObject, cSecs, fUseCache ? "RTMemCache" : "RTMemAlloc"); 282 static void tst3(uint32_t cThreads, uint32_t cbObject, int iMethod, uint32_t cSecs) 283 { 284 RTTestISubF("Benchmark - %u threads, %u bytes, %u secs, %s", cThreads, cbObject, cSecs, 285 iMethod == 0 ? "RTMemCache" 286 : iMethod == 1 ? "RTCache" 287 : "RTMemAlloc"); 257 288 258 289 /* … … 260 291 * the threads. 261 292 */ 262 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&g_hMemCache, cbObject, 0 /*cbAlignment*/, UINT32_MAX, NULL, NULL, NULL), VINF_SUCCESS); 293 RTTESTI_CHECK_RC_RETV(RTMemCacheCreate(&g_hMemCache, cbObject, 0 /*cbAlignment*/, UINT32_MAX, NULL, NULL, NULL, 0 /*fFlags*/), VINF_SUCCESS); 294 RTTESTI_CHECK_RC_RETV(RTCacheCreate(&g_pOldCacheTst3, 0, cbObject, RTOBJCACHE_PROTECT_INSERT | RTOBJCACHE_PROTECT_REQUEST), VINF_SUCCESS); 263 295 264 296 RTSEMEVENTMULTI hEvt; … … 273 305 aThreads[i].hThread = NIL_RTTHREAD; 274 306 aThreads[i].cIterations = 0; 275 aThreads[i].fUseCache = fUseCache; 307 aThreads[i].fUseCache = iMethod == 0; 308 aThreads[i].fUseOldCache= iMethod == 1; 276 309 aThreads[i].cbObject = cbObject; 277 310 aThreads[i].hEvt = hEvt; … … 305 338 306 339 /* clean up */ 340 RTTESTI_CHECK_RC(RTCacheDestroy(g_pOldCacheTst3), VINF_SUCCESS); 307 341 RTTESTI_CHECK_RC(RTMemCacheDestroy(g_hMemCache), VINF_SUCCESS); 308 342 RTTESTI_CHECK_RC_OK(RTSemEventMultiDestroy(hEvt)); 309 343 } 310 344 311 int main() 345 static void tst3AllMethods(uint32_t cThreads, uint32_t cbObject, uint32_t cSecs) 346 { 347 tst3(cThreads, cbObject, 0, cSecs); 348 tst3(cThreads, cbObject, 1, cSecs); 349 tst3(cThreads, cbObject, 2, cSecs); 350 } 351 352 353 int main(int argc, char **argv) 312 354 { 313 355 RTTEST hTest; … … 322 364 if (RTTestIErrorCount() == 0) 323 365 { 324 /* threads, cbObj, fUseCache, cSecs */ 325 tst3( 1, 256, true, 5); 326 tst3( 1, 256, false, 5); 327 tst3( 1, 32, true, 5); 328 tst3( 1, 32, false, 5); 329 tst3( 1, 8, true, 5); 330 tst3( 1, 8, false, 5); 331 tst3( 1, 2, true, 5); 332 tst3( 1, 2, false, 5); 333 tst3( 1, 1, true, 5); 334 tst3( 1, 1, false, 5); 335 336 tst3( 3, 256, true, 5); 337 tst3( 3, 256, false, 5); 338 tst3( 3, 128, true, 5); 339 tst3( 3, 128, false, 5); 340 tst3( 3, 64, true, 5); 341 tst3( 3, 64, false, 5); 342 tst3( 3, 32, true, 5); 343 tst3( 3, 32, false, 5); 344 tst3( 3, 2, true, 5); 345 tst3( 3, 2, false, 5); 346 tst3( 3, 1, true, 5); 347 tst3( 3, 1, false, 5); 348 349 tst3( 16, 32, true, 5); 350 tst3( 16, 32, false, 5); 366 uint32_t cSecs = argc == 1 ? 5 : 2; 367 /* threads, cbObj, cSecs */ 368 tst3AllMethods( 1, 256, cSecs); 369 tst3AllMethods( 1, 32, cSecs); 370 tst3AllMethods( 1, 8, cSecs); 371 tst3AllMethods( 1, 2, cSecs); 372 tst3AllMethods( 1, 1, cSecs); 373 374 tst3AllMethods( 3, 256, cSecs); 375 tst3AllMethods( 3, 128, cSecs); 376 tst3AllMethods( 3, 64, cSecs); 377 tst3AllMethods( 3, 32, cSecs); 378 tst3AllMethods( 3, 2, cSecs); 379 tst3AllMethods( 3, 1, cSecs); 380 381 tst3AllMethods( 16, 32, cSecs); 351 382 } 352 383
Note:
See TracChangeset
for help on using the changeset viewer.