Changeset 26334 in vbox
- Timestamp:
- Feb 8, 2010 6:58:55 PM (15 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/PDMAsyncCompletionFileCache.cpp
r26246 r26334 22 22 23 23 /** @page pg_pdm_async_completion_cache PDM Async Completion Cache - The file I/O cache 24 * This component implements an I/O cache for file endpoints based on the ARC algorithm. 25 * http://en.wikipedia.org/wiki/Adaptive_Replacement_Cache 26 * 27 * The algorithm uses four LRU (Least frequently used) lists to store data in the cache. 28 * Two of them contain data where one stores entries which were accessed recently and one 29 * which is used for frequently accessed data. 30 * The other two lists are called ghost lists and store information about the accessed range 31 * but do not contain data. They are used to track data access. If these entries are accessed 32 * they will push the data to a higher position in the cache preventing it from getting removed 33 * quickly again. 34 * 35 * The algorithm needs to be modified to meet our requirements. Like the implementation 36 * for the ZFS filesystem we need to handle pages with a variable size. It would 37 * be possible to use a fixed size but would increase the computational 38 * and memory overhead. 39 * Because we do I/O asynchronously we also need to mark entries which are currently accessed 40 * as non evictable to prevent removal of the entry while the data is being accessed. 24 * This component implements an I/O cache for file endpoints based on the 2Q cache algorithm. 41 25 */ 42 26 … … 74 58 do \ 75 59 { \ 76 AssertMsg(RTCritSectIsOwner(& pCache->CritSect), \60 AssertMsg(RTCritSectIsOwner(&Cache->CritSect), \ 77 61 ("Thread does not own critical section\n"));\ 78 62 } while(0); … … 168 152 } 169 153 154 #ifdef DEBUG 155 static void pdmacFileCacheValidate(PPDMACFILECACHEGLOBAL pCache) 156 { 157 /* Amount of cached data should never exceed the maximum amount. */ 158 AssertMsg(pCache->cbCached <= pCache->cbMax, 159 ("Current amount of cached data exceeds maximum\n")); 160 161 /* The amount of cached data in the LRU and FRU list should match cbCached */ 162 AssertMsg(pCache->LruRecentlyUsedIn.cbCached + pCache->LruFrequentlyUsed.cbCached == pCache->cbCached, 163 ("Amount of cached data doesn't match\n")); 164 165 AssertMsg(pCache->LruRecentlyUsedOut.cbCached <= pCache->cbRecentlyUsedOutMax, 166 ("Paged out list exceeds maximum\n")); 167 } 168 #endif 169 170 DECLINLINE(void) pdmacFileCacheLockEnter(PPDMACFILECACHEGLOBAL pCache) 171 { 172 RTCritSectEnter(&pCache->CritSect); 173 #ifdef DEBUG 174 pdmacFileCacheValidate(pCache); 175 #endif 176 } 177 178 DECLINLINE(void) pdmacFileCacheLockLeave(PPDMACFILECACHEGLOBAL pCache) 179 { 180 #ifdef DEBUG 181 pdmacFileCacheValidate(pCache); 182 #endif 183 RTCritSectLeave(&pCache->CritSect); 184 } 185 186 DECLINLINE(void) pdmacFileCacheSub(PPDMACFILECACHEGLOBAL pCache, uint32_t cbAmount) 187 { 188 PDMACFILECACHE_IS_CRITSECT_OWNER(pCache); 189 pCache->cbCached -= cbAmount; 190 } 191 192 DECLINLINE(void) pdmacFileCacheAdd(PPDMACFILECACHEGLOBAL pCache, uint32_t cbAmount) 193 { 194 PDMACFILECACHE_IS_CRITSECT_OWNER(pCache); 195 pCache->cbCached += cbAmount; 196 } 197 198 DECLINLINE(void) pdmacFileCacheListAdd(PPDMACFILELRULIST pList, uint32_t cbAmount) 199 { 200 pList->cbCached += cbAmount; 201 } 202 203 DECLINLINE(void) pdmacFileCacheListSub(PPDMACFILELRULIST pList, uint32_t cbAmount) 204 { 205 pList->cbCached -= cbAmount; 206 } 207 170 208 #ifdef PDMACFILECACHE_WITH_LRULIST_CHECKS 171 209 /** … … 251 289 pEntry->pPrev = NULL; 252 290 pEntry->pNext = NULL; 253 p List->cbCached -= pEntry->cbData;291 pdmacFileCacheListSub(pList, pEntry->cbData); 254 292 #ifdef PDMACFILECACHE_WITH_LRULIST_CHECKS 255 293 pdmacFileCacheCheckList(pList, pEntry); … … 287 325 pEntry->pPrev = NULL; 288 326 pList->pHead = pEntry; 289 p List->cbCached += pEntry->cbData;327 pdmacFileCacheListAdd(pList, pEntry->cbData); 290 328 pEntry->pList = pList; 291 329 #ifdef PDMACFILECACHE_WITH_LRULIST_CHECKS … … 345 383 346 384 AssertMsg(cbData > 0, ("Evicting 0 bytes not possible\n")); 347 #ifdef VBOX_WITH_2Q_CACHE348 385 AssertMsg( !pGhostListDst 349 386 || (pGhostListDst == &pCache->LruRecentlyUsedOut), 350 387 ("Destination list must be NULL or the recently used but paged out list\n")); 351 #else352 AssertMsg( !pGhostListDst353 || (pGhostListDst == &pCache->LruRecentlyGhost)354 || (pGhostListDst == &pCache->LruFrequentlyGhost),355 ("Destination list must be NULL or one of the ghost lists\n"));356 #endif357 388 358 389 if (fReuseBuffer) … … 400 431 cbEvicted += pCurr->cbData; 401 432 402 pCache->cbCached -= pCurr->cbData;403 404 433 pdmacFileCacheEntryRemoveFromList(pCurr); 434 pdmacFileCacheSub(pCache, pCurr->cbData); 405 435 406 436 if (pGhostListDst) 407 437 { 408 438 RTSemRWReleaseWrite(pEndpointCache->SemRWEntries); 409 #ifdef VBOX_WITH_2Q_CACHE 439 440 PPDMACFILECACHEENTRY pGhostEntFree = pGhostListDst->pTail; 441 410 442 /* We have to remove the last entries from the paged out list. */ 411 while (pGhostListDst->cbCached > pCache->cbRecentlyUsedOutMax) 443 while ( ((pGhostListDst->cbCached + pCurr->cbData) > pCache->cbRecentlyUsedOutMax) 444 && pGhostEntFree) 412 445 { 413 PPDMACFILECACHEENTRY pFree = pGhost ListDst->pTail;446 PPDMACFILECACHEENTRY pFree = pGhostEntFree; 414 447 PPDMACFILEENDPOINTCACHE pEndpointCacheFree = &pFree->pEndpoint->DataCache; 415 448 449 pGhostEntFree = pGhostEntFree->pPrev; 450 416 451 RTSemRWRequestWrite(pEndpointCacheFree->SemRWEntries, RT_INDEFINITE_WAIT); 417 452 418 pdmacFileCacheEntryRemoveFromList(pFree); 419 453 if (ASMAtomicReadU32(&pFree->cRefs) == 0) 454 { 455 pdmacFileCacheEntryRemoveFromList(pFree); 456 457 STAM_PROFILE_ADV_START(&pCache->StatTreeRemove, Cache); 458 RTAvlrFileOffsetRemove(pEndpointCacheFree->pTree, pFree->Core.Key); 459 STAM_PROFILE_ADV_STOP(&pCache->StatTreeRemove, Cache); 460 461 RTMemFree(pFree); 462 } 463 464 RTSemRWReleaseWrite(pEndpointCacheFree->SemRWEntries); 465 } 466 467 if (pGhostListDst->cbCached + pCurr->cbData > pCache->cbRecentlyUsedOutMax) 468 { 469 /* Couldn't remove enough entries. Delete */ 420 470 STAM_PROFILE_ADV_START(&pCache->StatTreeRemove, Cache); 421 RTAvlrFileOffsetRemove(p EndpointCacheFree->pTree, pFree->Core.Key);471 RTAvlrFileOffsetRemove(pCurr->pEndpoint->DataCache.pTree, pCurr->Core.Key); 422 472 STAM_PROFILE_ADV_STOP(&pCache->StatTreeRemove, Cache); 423 473 424 RTSemRWReleaseWrite(pEndpointCacheFree->SemRWEntries); 425 RTMemFree(pFree); 474 RTMemFree(pCurr); 426 475 } 427 #endif 428 429 pdmacFileCacheEntryAddToList(pGhostListDst, pCurr); 476 else 477 pdmacFileCacheEntryAddToList(pGhostListDst, pCurr); 430 478 } 431 479 else … … 449 497 } 450 498 451 #ifdef VBOX_WITH_2Q_CACHE452 499 static bool pdmacFileCacheReclaim(PPDMACFILECACHEGLOBAL pCache, size_t cbData, bool fReuseBuffer, uint8_t **ppbBuffer) 453 500 { … … 484 531 return (cbRemoved >= cbData); 485 532 } 486 487 #else488 489 static size_t pdmacFileCacheReplace(PPDMACFILECACHEGLOBAL pCache, size_t cbData, PPDMACFILELRULIST pEntryList,490 bool fReuseBuffer, uint8_t **ppbBuffer)491 {492 PDMACFILECACHE_IS_CRITSECT_OWNER(pCache);493 494 if ( (pCache->LruRecentlyUsed.cbCached)495 && ( (pCache->LruRecentlyUsed.cbCached > pCache->uAdaptVal)496 || ( (pEntryList == &pCache->LruFrequentlyGhost)497 && (pCache->LruRecentlyUsed.cbCached == pCache->uAdaptVal))))498 {499 /* We need to remove entry size pages from T1 and move the entries to B1 */500 return pdmacFileCacheEvictPagesFrom(pCache, cbData,501 &pCache->LruRecentlyUsed,502 &pCache->LruRecentlyGhost,503 fReuseBuffer, ppbBuffer);504 }505 else506 {507 /* We need to remove entry size pages from T2 and move the entries to B2 */508 return pdmacFileCacheEvictPagesFrom(pCache, cbData,509 &pCache->LruFrequentlyUsed,510 &pCache->LruFrequentlyGhost,511 fReuseBuffer, ppbBuffer);512 }513 }514 515 /**516 * Tries to evict the given amount of the data from the cache.517 *518 * @returns Bytes removed.519 * @param pCache The global cache data.520 * @param cbData Number of bytes to evict.521 */522 static size_t pdmacFileCacheEvict(PPDMACFILECACHEGLOBAL pCache, size_t cbData, bool fReuseBuffer, uint8_t **ppbBuffer)523 {524 size_t cbRemoved = ~0;525 526 PDMACFILECACHE_IS_CRITSECT_OWNER(pCache);527 528 if ((pCache->LruRecentlyUsed.cbCached + pCache->LruRecentlyGhost.cbCached) >= pCache->cbMax)529 {530 /* Delete desired pages from the cache. */531 if (pCache->LruRecentlyUsed.cbCached < pCache->cbMax)532 {533 cbRemoved = pdmacFileCacheEvictPagesFrom(pCache, cbData,534 &pCache->LruRecentlyGhost,535 NULL,536 fReuseBuffer, ppbBuffer);537 }538 else539 {540 cbRemoved = pdmacFileCacheEvictPagesFrom(pCache, cbData,541 &pCache->LruRecentlyUsed,542 NULL,543 fReuseBuffer, ppbBuffer);544 }545 }546 else547 {548 uint32_t cbUsed = pCache->LruRecentlyUsed.cbCached + pCache->LruRecentlyGhost.cbCached +549 pCache->LruFrequentlyUsed.cbCached + pCache->LruFrequentlyGhost.cbCached;550 551 if (cbUsed >= pCache->cbMax)552 {553 if (cbUsed == 2*pCache->cbMax)554 cbRemoved = pdmacFileCacheEvictPagesFrom(pCache, cbData,555 &pCache->LruFrequentlyGhost,556 NULL,557 fReuseBuffer, ppbBuffer);558 559 if (cbRemoved >= cbData)560 cbRemoved = pdmacFileCacheReplace(pCache, cbData, NULL, fReuseBuffer, ppbBuffer);561 }562 }563 564 return cbRemoved;565 }566 567 /**568 * Updates the cache parameters569 *570 * @returns nothing.571 * @param pCache The global cache data.572 * @param pEntry The entry usign for the update.573 */574 static void pdmacFileCacheUpdate(PPDMACFILECACHEGLOBAL pCache, PPDMACFILECACHEENTRY pEntry)575 {576 int32_t uUpdateVal = 0;577 578 PDMACFILECACHE_IS_CRITSECT_OWNER(pCache);579 580 /* Update parameters */581 if (pEntry->pList == &pCache->LruRecentlyGhost)582 {583 if (pCache->LruRecentlyGhost.cbCached >= pCache->LruFrequentlyGhost.cbCached)584 uUpdateVal = 1;585 else586 uUpdateVal = pCache->LruFrequentlyGhost.cbCached / pCache->LruRecentlyGhost.cbCached;587 588 pCache->uAdaptVal = RT_MIN(pCache->uAdaptVal + uUpdateVal, pCache->cbMax);589 }590 else if (pEntry->pList == &pCache->LruFrequentlyGhost)591 {592 if (pCache->LruFrequentlyGhost.cbCached >= pCache->LruRecentlyGhost.cbCached)593 uUpdateVal = 1;594 else595 uUpdateVal = pCache->LruRecentlyGhost.cbCached / pCache->LruFrequentlyGhost.cbCached;596 597 pCache->uAdaptVal = RT_MIN(pCache->uAdaptVal - uUpdateVal, 0);598 }599 else600 AssertMsgFailed(("Invalid list type\n"));601 }602 #endif603 533 604 534 /** … … 799 729 800 730 /* Initialize members */ 801 #ifdef VBOX_WITH_2Q_CACHE802 731 pCache->LruRecentlyUsedIn.pHead = NULL; 803 732 pCache->LruRecentlyUsedIn.pTail = NULL; … … 815 744 pCache->cbRecentlyUsedOutMax = (pCache->cbMax / 100) * 50; /* 50% of the buffer size */ 816 745 LogFlowFunc((": cbRecentlyUsedInMax=%u cbRecentlyUsedOutMax=%u\n", pCache->cbRecentlyUsedInMax, pCache->cbRecentlyUsedOutMax)); 817 #else818 pCache->LruRecentlyUsed.pHead = NULL;819 pCache->LruRecentlyUsed.pTail = NULL;820 pCache->LruRecentlyUsed.cbCached = 0;821 822 pCache->LruFrequentlyUsed.pHead = NULL;823 pCache->LruFrequentlyUsed.pTail = NULL;824 pCache->LruFrequentlyUsed.cbCached = 0;825 826 pCache->LruRecentlyGhost.pHead = NULL;827 pCache->LruRecentlyGhost.pTail = NULL;828 pCache->LruRecentlyGhost.cbCached = 0;829 830 pCache->LruFrequentlyGhost.pHead = NULL;831 pCache->LruFrequentlyGhost.pTail = NULL;832 pCache->LruFrequentlyGhost.cbCached = 0;833 834 pCache->uAdaptVal = 0;835 #endif836 746 837 747 STAMR3Register(pClassFile->Core.pVM, &pCache->cbMax, … … 845 755 STAMUNIT_BYTES, 846 756 "Currently used cache"); 847 #ifdef VBOX_WITH_2Q_CACHE848 757 STAMR3Register(pClassFile->Core.pVM, &pCache->LruRecentlyUsedIn.cbCached, 849 758 STAMTYPE_U32, STAMVISIBILITY_ALWAYS, … … 861 770 STAMUNIT_BYTES, 862 771 "Number of bytes cached in FRU ghost list"); 863 #else864 STAMR3Register(pClassFile->Core.pVM, &pCache->LruRecentlyUsed.cbCached,865 STAMTYPE_U32, STAMVISIBILITY_ALWAYS,866 "/PDM/AsyncCompletion/File/cbCachedMru",867 STAMUNIT_BYTES,868 "Number of bytes cached in Mru list");869 STAMR3Register(pClassFile->Core.pVM, &pCache->LruFrequentlyUsed.cbCached,870 STAMTYPE_U32, STAMVISIBILITY_ALWAYS,871 "/PDM/AsyncCompletion/File/cbCachedFru",872 STAMUNIT_BYTES,873 "Number of bytes cached in Fru list");874 STAMR3Register(pClassFile->Core.pVM, &pCache->LruRecentlyGhost.cbCached,875 STAMTYPE_U32, STAMVISIBILITY_ALWAYS,876 "/PDM/AsyncCompletion/File/cbCachedMruGhost",877 STAMUNIT_BYTES,878 "Number of bytes cached in Mru ghost list");879 STAMR3Register(pClassFile->Core.pVM, &pCache->LruFrequentlyGhost.cbCached,880 STAMTYPE_U32, STAMVISIBILITY_ALWAYS,881 "/PDM/AsyncCompletion/File/cbCachedFruGhost",882 STAMUNIT_BYTES, "Number of bytes cached in Fru ghost list");883 #endif884 772 885 773 #ifdef VBOX_WITH_STATISTICS … … 920 808 "/PDM/AsyncCompletion/File/CacheBuffersReused", 921 809 STAMUNIT_COUNT, "Number of times a buffer could be reused"); 922 #ifndef VBOX_WITH_2Q_CACHE923 STAMR3Register(pClassFile->Core.pVM, &pCache->uAdaptVal,924 STAMTYPE_U32, STAMVISIBILITY_ALWAYS,925 "/PDM/AsyncCompletion/File/CacheAdaptValue",926 STAMUNIT_COUNT,927 "Adaption value of the cache");928 #endif929 810 #endif 930 811 … … 949 830 950 831 /* Make sure no one else uses the cache now */ 951 RTCritSectEnter(&pCache->CritSect); 952 953 #ifdef VBOX_WITH_2Q_CACHE 832 pdmacFileCacheLockEnter(pCache); 833 954 834 /* Cleanup deleting all cache entries waiting for in progress entries to finish. */ 955 835 pdmacFileCacheDestroyList(&pCache->LruRecentlyUsedIn); 956 836 pdmacFileCacheDestroyList(&pCache->LruRecentlyUsedOut); 957 837 pdmacFileCacheDestroyList(&pCache->LruFrequentlyUsed); 958 #else 959 /* Cleanup deleting all cache entries waiting for in progress entries to finish. */ 960 pdmacFileCacheDestroyList(&pCache->LruRecentlyUsed); 961 pdmacFileCacheDestroyList(&pCache->LruFrequentlyUsed); 962 pdmacFileCacheDestroyList(&pCache->LruRecentlyGhost); 963 pdmacFileCacheDestroyList(&pCache->LruFrequentlyGhost); 964 #endif 965 966 RTCritSectLeave(&pCache->CritSect); 838 839 pdmacFileCacheLockLeave(pCache); 967 840 968 841 RTCritSectDelete(&pCache->CritSect); … … 1020 893 PPDMACFILEENDPOINTCACHE pEndpointCache = &pEntry->pEndpoint->DataCache; 1021 894 1022 while ( pEntry->fFlags& (PDMACFILECACHE_ENTRY_IO_IN_PROGRESS | PDMACFILECACHE_ENTRY_IS_DIRTY))895 while (ASMAtomicReadU32(&pEntry->fFlags) & (PDMACFILECACHE_ENTRY_IO_IN_PROGRESS | PDMACFILECACHE_ENTRY_IS_DIRTY)) 1023 896 { 1024 897 RTSemRWReleaseWrite(pEndpointCache->SemRWEntries); … … 1030 903 ("Entry is dirty and/or still in progress fFlags=%#x\n", pEntry->fFlags)); 1031 904 905 bool fUpdateCache = pEntry->pList == &pCache->LruFrequentlyUsed 906 || pEntry->pList == &pCache->LruRecentlyUsedIn; 907 1032 908 pdmacFileCacheEntryRemoveFromList(pEntry); 1033 pCache->cbCached -= pEntry->cbData; 909 910 if (fUpdateCache) 911 pdmacFileCacheSub(pCache, pEntry->cbData); 1034 912 1035 913 RTMemPageFree(pEntry->pbData); … … 1051 929 1052 930 /* Make sure nobody is accessing the cache while we delete the tree. */ 1053 RTCritSectEnter(&pCache->CritSect);931 pdmacFileCacheLockEnter(pCache); 1054 932 RTSemRWRequestWrite(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT); 1055 933 RTAvlrFileOffsetDestroy(pEndpointCache->pTree, pdmacFileEpCacheEntryDestroy, pCache); 1056 934 RTSemRWReleaseWrite(pEndpointCache->SemRWEntries); 1057 RTCritSectLeave(&pCache->CritSect);935 pdmacFileCacheLockLeave(pCache); 1058 936 1059 937 RTSemRWDestroy(pEndpointCache->SemRWEntries); … … 1206 1084 uint32_t fSet, uint32_t fClear) 1207 1085 { 1208 bool fPassed = ((pEntry->fFlags & fSet) && !(pEntry->fFlags & fClear)); 1086 uint32_t fFlags = ASMAtomicReadU32(&pEntry->fFlags); 1087 bool fPassed = ((fFlags & fSet) && !(fFlags & fClear)); 1209 1088 1210 1089 if (fPassed) … … 1213 1092 RTSemRWRequestWrite(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT); 1214 1093 1215 fPassed = ((pEntry->fFlags & fSet) && !(pEntry->fFlags & fClear)); 1094 fFlags = ASMAtomicReadU32(&pEntry->fFlags); 1095 fPassed = ((fFlags & fSet) && !(fFlags & fClear)); 1216 1096 1217 1097 /* Drop the lock if we didn't passed the test. */ … … 1421 1301 1422 1302 cbRead -= cbToRead; 1423 off += cbToRead;1424 1303 1425 1304 if (!cbRead) … … 1431 1310 1432 1311 /* Ghost lists contain no data. */ 1433 #ifdef VBOX_WITH_2Q_CACHE1434 1312 if ( (pEntry->pList == &pCache->LruRecentlyUsedIn) 1435 1313 || (pEntry->pList == &pCache->LruFrequentlyUsed)) 1436 1314 { 1437 #else1438 if ( (pEntry->pList == &pCache->LruRecentlyUsed)1439 || (pEntry->pList == &pCache->LruFrequentlyUsed))1440 {1441 #endif1442 1315 if (pdmacFileEpCacheEntryFlagIsSetClearAcquireLock(pEndpointCache, pEntry, 1443 1316 PDMACFILECACHE_ENTRY_IS_DEPRECATED, … … 1471 1344 1472 1345 /* Move this entry to the top position */ 1473 #ifdef VBOX_WITH_2Q_CACHE1474 1346 if (pEntry->pList == &pCache->LruFrequentlyUsed) 1475 1347 { 1476 RTCritSectEnter(&pCache->CritSect);1348 pdmacFileCacheLockEnter(pCache); 1477 1349 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1478 RTCritSectLeave(&pCache->CritSect);1350 pdmacFileCacheLockLeave(pCache); 1479 1351 } 1480 #else 1481 RTCritSectEnter(&pCache->CritSect); 1482 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1483 RTCritSectLeave(&pCache->CritSect); 1484 #endif 1352 /* Release the entry */ 1353 pdmacFileEpCacheEntryRelease(pEntry); 1485 1354 } 1486 1355 else … … 1490 1359 LogFlow(("Fetching data for ghost entry %#p from file\n", pEntry)); 1491 1360 1492 #ifdef VBOX_WITH_2Q_CACHE 1493 RTCritSectEnter(&pCache->CritSect); 1361 pdmacFileCacheLockEnter(pCache); 1494 1362 pdmacFileCacheEntryRemoveFromList(pEntry); /* Remove it before we remove data, otherwise it may get freed when evicting data. */ 1495 pdmacFileCacheReclaim(pCache, pEntry->cbData, true, &pbBuffer);1363 bool fEnough = pdmacFileCacheReclaim(pCache, pEntry->cbData, true, &pbBuffer); 1496 1364 1497 1365 /* Move the entry to Am and fetch it to the cache. */ 1498 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1499 RTCritSectLeave(&pCache->CritSect); 1500 #else 1501 RTCritSectEnter(&pCache->CritSect); 1502 pdmacFileCacheUpdate(pCache, pEntry); 1503 pdmacFileCacheReplace(pCache, pEntry->cbData, pEntry->pList, true, &pbBuffer); 1504 1505 /* Move the entry to T2 and fetch it to the cache. */ 1506 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1507 RTCritSectLeave(&pCache->CritSect); 1508 #endif 1509 1510 if (pbBuffer) 1511 pEntry->pbData = pbBuffer; 1366 if (fEnough) 1367 { 1368 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1369 pdmacFileCacheAdd(pCache, pEntry->cbData); 1370 pdmacFileCacheLockLeave(pCache); 1371 1372 if (pbBuffer) 1373 pEntry->pbData = pbBuffer; 1374 else 1375 pEntry->pbData = (uint8_t *)RTMemPageAlloc(pEntry->cbData); 1376 AssertPtr(pEntry->pbData); 1377 1378 pdmacFileEpCacheEntryWaitersAdd(pEntry, pTask, 1379 &IoMemCtx, 1380 OffDiff, cbToRead, 1381 false /* fWrite */); 1382 pdmacFileCacheReadFromEndpoint(pEntry); 1383 /* Release the entry */ 1384 pdmacFileEpCacheEntryRelease(pEntry); 1385 } 1512 1386 else 1513 pEntry->pbData = (uint8_t *)RTMemPageAlloc(pEntry->cbData); 1514 AssertPtr(pEntry->pbData); 1515 1516 pdmacFileEpCacheEntryWaitersAdd(pEntry, pTask, 1517 &IoMemCtx, 1518 OffDiff, cbToRead, 1519 false /* fWrite */); 1520 pdmacFileCacheReadFromEndpoint(pEntry); 1387 { 1388 RTSemRWRequestWrite(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT); 1389 STAM_PROFILE_ADV_START(&pCache->StatTreeRemove, Cache); 1390 RTAvlrFileOffsetRemove(pEndpointCache->pTree, pEntry->Core.Key); 1391 STAM_PROFILE_ADV_STOP(&pCache->StatTreeRemove, Cache); 1392 RTSemRWReleaseWrite(pEndpointCache->SemRWEntries); 1393 1394 pdmacFileCacheLockLeave(pCache); 1395 1396 RTMemFree(pEntry); 1397 1398 pdmacFileEpCacheRequestPassthrough(pEndpoint, pTask, 1399 &IoMemCtx, off, cbToRead, 1400 PDMACTASKFILETRANSFER_READ); 1401 } 1521 1402 } 1522 1523 /* Release the entry finally. */1524 pdmacFileEpCacheEntryRelease(pEntry);1525 1403 } 1526 1404 else … … 1574 1452 uint8_t *pbBuffer = NULL; 1575 1453 1576 #ifdef VBOX_WITH_2Q_CACHE 1577 RTCritSectEnter(&pCache->CritSect); 1454 pdmacFileCacheLockEnter(pCache); 1578 1455 bool fEnough = pdmacFileCacheReclaim(pCache, cbToReadAligned, true, &pbBuffer); 1579 RTCritSectLeave(&pCache->CritSect);1580 1456 1581 1457 if (fEnough) 1582 1458 { 1583 1459 LogFlow(("Evicted enough bytes (%u requested). Creating new cache entry\n", cbToReadAligned)); 1584 #else 1585 RTCritSectEnter(&pCache->CritSect); 1586 size_t cbRemoved = pdmacFileCacheEvict(pCache, cbToReadAligned, true, &pbBuffer); 1587 RTCritSectLeave(&pCache->CritSect); 1588 1589 if (cbRemoved >= cbToReadAligned) 1590 { 1591 LogFlow(("Evicted %u bytes (%u requested). Creating new cache entry\n", cbRemoved, cbToReadAligned)); 1592 #endif 1460 1593 1461 PPDMACFILECACHEENTRY pEntryNew = pdmacFileCacheEntryAlloc(pCache, pEndpoint, off, cbToReadAligned, pbBuffer); 1594 1462 AssertPtr(pEntryNew); 1595 1463 1596 RTCritSectEnter(&pCache->CritSect);1597 #ifdef VBOX_WITH_2Q_CACHE1598 1464 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsedIn, pEntryNew); 1599 #else 1600 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsed, pEntryNew); 1601 #endif 1602 pCache->cbCached += cbToReadAligned; 1603 RTCritSectLeave(&pCache->CritSect); 1465 pdmacFileCacheAdd(pCache, cbToReadAligned); 1466 pdmacFileCacheLockLeave(pCache); 1604 1467 1605 1468 pdmacFileEpCacheInsertEntry(pEndpointCache, pEntryNew); 1606 1469 1607 1470 AssertMsg( (off >= pEntryNew->Core.Key) 1608 && (off + (RTFOFF)cbToRead <= pEntryNew->Core.Key + pEntryNew->Core.KeyLast ),1471 && (off + (RTFOFF)cbToRead <= pEntryNew->Core.Key + pEntryNew->Core.KeyLast + 1), 1609 1472 ("Overflow in calculation off=%RTfoff OffsetAligned=%RTfoff\n", 1610 off, pEntry ->Core.Key));1473 off, pEntryNew->Core.Key)); 1611 1474 1612 1475 pdmacFileEpCacheEntryWaitersAdd(pEntryNew, pTask, 1613 1476 &IoMemCtx, 0, cbToRead, 1614 1477 false /* fWrite */); 1615 off += cbToRead;1616 1617 1478 pdmacFileCacheReadFromEndpoint(pEntryNew); 1618 1479 pdmacFileEpCacheEntryRelease(pEntryNew); /* it is protected by the I/O in progress flag now. */ … … 1620 1481 else 1621 1482 { 1483 pdmacFileCacheLockLeave(pCache); 1484 1622 1485 /* 1623 1486 * There is not enough free space in the cache. … … 1629 1492 &IoMemCtx, off, cbToRead, 1630 1493 PDMACTASKFILETRANSFER_READ); 1631 off += cbToRead;1632 1494 } 1633 1495 } 1496 off += cbToRead; 1634 1497 } 1635 1498 … … 1697 1560 cbToWrite = RT_MIN(pEntry->cbData - OffDiff, cbWrite); 1698 1561 cbWrite -= cbToWrite; 1699 off += cbToWrite;1700 1562 1701 1563 if (!cbWrite) … … 1707 1569 1708 1570 /* Ghost lists contain no data. */ 1709 #ifdef VBOX_WITH_2Q_CACHE1710 1571 if ( (pEntry->pList == &pCache->LruRecentlyUsedIn) 1711 1572 || (pEntry->pList == &pCache->LruFrequentlyUsed)) 1712 #else1713 if ( (pEntry->pList == &pCache->LruRecentlyUsed)1714 || (pEntry->pList == &pCache->LruFrequentlyUsed))1715 #endif1716 1573 { 1717 1574 /* Check if the buffer is deprecated. */ … … 1721 1578 { 1722 1579 AssertMsg(pEntry->fFlags & PDMACFILECACHE_ENTRY_IO_IN_PROGRESS, 1723 1580 ("Entry is deprecated but not in progress\n")); 1724 1581 AssertPtr(pEntry->pbDataReplace); 1725 1582 … … 1816 1673 1817 1674 /* Move this entry to the top position */ 1818 #ifdef VBOX_WITH_2Q_CACHE 1819 if (pEntry->pList == &pCache->LruFrequentlyUsed) 1820 { 1821 RTCritSectEnter(&pCache->CritSect); 1822 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1823 RTCritSectLeave(&pCache->CritSect); 1824 } /* Deprecated flag not set. */ 1825 #else 1826 RTCritSectEnter(&pCache->CritSect); 1827 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1828 RTCritSectLeave(&pCache->CritSect); 1829 #endif 1675 if (pEntry->pList == &pCache->LruFrequentlyUsed) 1676 { 1677 pdmacFileCacheLockEnter(pCache); 1678 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1679 pdmacFileCacheLockLeave(pCache); 1680 } /* Deprecated flag not set. */ 1830 1681 } 1682 pdmacFileEpCacheEntryRelease(pEntry); 1831 1683 } 1832 1684 else /* Entry is on the ghost list */ … … 1834 1686 uint8_t *pbBuffer = NULL; 1835 1687 1836 #ifdef VBOX_WITH_2Q_CACHE 1837 RTCritSectEnter(&pCache->CritSect); 1688 pdmacFileCacheLockEnter(pCache); 1838 1689 pdmacFileCacheEntryRemoveFromList(pEntry); /* Remove it before we remove data, otherwise it may get freed when evicting data. */ 1839 pdmacFileCacheReclaim(pCache, pEntry->cbData, true, &pbBuffer); 1840 1841 /* Move the entry to Am and fetch it to the cache. */ 1842 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1843 RTCritSectLeave(&pCache->CritSect); 1844 #else 1845 RTCritSectEnter(&pCache->CritSect); 1846 pdmacFileCacheUpdate(pCache, pEntry); 1847 pdmacFileCacheReplace(pCache, pEntry->cbData, pEntry->pList, true, &pbBuffer); 1848 1849 /* Move the entry to T2 and fetch it to the cache. */ 1850 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1851 RTCritSectLeave(&pCache->CritSect); 1852 #endif 1853 1854 if (pbBuffer) 1855 pEntry->pbData = pbBuffer; 1690 bool fEnough = pdmacFileCacheReclaim(pCache, pEntry->cbData, true, &pbBuffer); 1691 1692 if (fEnough) 1693 { 1694 /* Move the entry to Am and fetch it to the cache. */ 1695 pdmacFileCacheEntryAddToList(&pCache->LruFrequentlyUsed, pEntry); 1696 pdmacFileCacheAdd(pCache, pEntry->cbData); 1697 pdmacFileCacheLockLeave(pCache); 1698 1699 if (pbBuffer) 1700 pEntry->pbData = pbBuffer; 1701 else 1702 pEntry->pbData = (uint8_t *)RTMemPageAlloc(pEntry->cbData); 1703 AssertPtr(pEntry->pbData); 1704 1705 pdmacFileEpCacheEntryWaitersAdd(pEntry, pTask, 1706 &IoMemCtx, 1707 OffDiff, cbToWrite, 1708 true /* fWrite */); 1709 STAM_COUNTER_INC(&pEndpointCache->StatWriteDeferred); 1710 pdmacFileCacheReadFromEndpoint(pEntry); 1711 1712 /* Release the reference. If it is still needed the I/O in progress flag should protect it now. */ 1713 pdmacFileEpCacheEntryRelease(pEntry); 1714 } 1856 1715 else 1857 pEntry->pbData = (uint8_t *)RTMemPageAlloc(pEntry->cbData); 1858 AssertPtr(pEntry->pbData); 1859 1860 pdmacFileEpCacheEntryWaitersAdd(pEntry, pTask, 1861 &IoMemCtx, 1862 OffDiff, cbToWrite, 1863 true /* fWrite */); 1864 STAM_COUNTER_INC(&pEndpointCache->StatWriteDeferred); 1865 pdmacFileCacheReadFromEndpoint(pEntry); 1716 { 1717 RTSemRWRequestWrite(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT); 1718 STAM_PROFILE_ADV_START(&pCache->StatTreeRemove, Cache); 1719 RTAvlrFileOffsetRemove(pEndpointCache->pTree, pEntry->Core.Key); 1720 STAM_PROFILE_ADV_STOP(&pCache->StatTreeRemove, Cache); 1721 RTSemRWReleaseWrite(pEndpointCache->SemRWEntries); 1722 1723 pdmacFileCacheLockLeave(pCache); 1724 1725 RTMemFree(pEntry); 1726 pdmacFileEpCacheRequestPassthrough(pEndpoint, pTask, 1727 &IoMemCtx, off, cbToWrite, 1728 PDMACTASKFILETRANSFER_WRITE); 1729 } 1866 1730 } 1867 1868 /* Release the reference. If it is still needed the I/O in progress flag should protect it now. */1869 pdmacFileEpCacheEntryRelease(pEntry);1870 1731 } 1871 1732 else /* No entry found */ … … 1900 1761 1901 1762 STAM_COUNTER_INC(&pCache->cMisses); 1902 STAM_COUNTER_ADD(&pCache->StatWritten, cbToWrite);1903 1763 1904 1764 uint8_t *pbBuffer = NULL; 1905 1765 1906 #ifdef VBOX_WITH_2Q_CACHE 1907 RTCritSectEnter(&pCache->CritSect); 1766 pdmacFileCacheLockEnter(pCache); 1908 1767 bool fEnough = pdmacFileCacheReclaim(pCache, cbToWrite, true, &pbBuffer); 1909 RTCritSectLeave(&pCache->CritSect);1910 1768 1911 1769 if (fEnough) 1912 1770 { 1913 1771 LogFlow(("Evicted enough bytes (%u requested). Creating new cache entry\n", cbToWrite)); 1914 #else 1915 RTCritSectEnter(&pCache->CritSect); 1916 size_t cbRemoved = pdmacFileCacheEvict(pCache, cbToWrite, true, &pbBuffer); 1917 RTCritSectLeave(&pCache->CritSect); 1918 1919 if (cbRemoved >= cbToWrite) 1920 { 1921 LogFlow(("Evicted %u bytes (%u requested). Creating new cache entry\n", cbRemoved, cbToWrite)); 1922 1923 #endif 1772 1924 1773 uint8_t *pbBuf; 1925 1774 PPDMACFILECACHEENTRY pEntryNew; … … 1928 1777 AssertPtr(pEntryNew); 1929 1778 1930 RTCritSectEnter(&pCache->CritSect);1931 #ifdef VBOX_WITH_2Q_CACHE1932 1779 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsedIn, pEntryNew); 1933 #else 1934 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsed, pEntryNew); 1935 #endif 1936 pCache->cbCached += cbToWrite; 1937 RTCritSectLeave(&pCache->CritSect); 1780 pdmacFileCacheAdd(pCache, cbToWrite); 1781 pdmacFileCacheLockLeave(pCache); 1938 1782 1939 1783 pdmacFileEpCacheInsertEntry(pEndpointCache, pEntryNew); … … 1942 1786 pEntryNew->pbData, 1943 1787 cbToWrite); 1944 off += cbToWrite;1945 1788 ASMAtomicSubS32(&pTask->cbTransferLeft, cbToWrite); 1946 1789 … … 1948 1791 pdmacFileCacheWriteToEndpoint(pEntryNew); 1949 1792 pdmacFileEpCacheEntryRelease(pEntryNew); /* it is protected by the I/O in progress flag now. */ 1793 STAM_COUNTER_ADD(&pCache->StatWritten, cbToWrite); 1950 1794 } 1951 1795 else 1952 1796 { 1797 pdmacFileCacheLockLeave(pCache); 1798 1953 1799 /* 1954 1800 * There is not enough free space in the cache. … … 1960 1806 &IoMemCtx, off, cbToWrite, 1961 1807 PDMACTASKFILETRANSFER_WRITE); 1962 off += cbToWrite;1963 1808 } 1964 1809 } 1810 1811 off += cbToWrite; 1965 1812 } 1966 1813 -
trunk/src/VBox/VMM/PDMAsyncCompletionFileInternal.h
r25147 r26334 225 225 PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint; 226 226 /** Flags for this entry. Combinations of PDMACFILECACHE_* #defines */ 227 uint32_tfFlags;227 volatile uint32_t fFlags; 228 228 /** Reference counter. Prevents eviction of the entry if > 0. */ 229 229 volatile uint32_t cRefs;
Note:
See TracChangeset
for help on using the changeset viewer.