Changeset 27521 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Mar 19, 2010 11:04:41 AM (15 years ago)
- svn:sync-xref-src-repo-rev:
- 59026
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/PDMAsyncCompletionFileCache.cpp
r26956 r27521 539 539 */ 540 540 if (!cbRemoved) 541 cbRemoved += pdmacFileCacheEvictPagesFrom(pCache, cbData - cbRemoved, &pCache->LruFrequentlyUsed,541 cbRemoved += pdmacFileCacheEvictPagesFrom(pCache, cbData, &pCache->LruFrequentlyUsed, 542 542 NULL, fReuseBuffer, ppbBuffer); 543 543 else … … 1212 1212 } 1213 1213 1214 static PPDMACFILECACHEENTRY pdmacFileEpCacheGetCacheBestFitEntryByOffset(PPDMACFILEENDPOINTCACHE pEndpointCache, RTFOFF off) 1214 /** 1215 * Return the best fit cache entries for the given offset. 1216 * 1217 * @returns nothing. 1218 * @param pEndpointCache The endpoint cache. 1219 * @param off The offset. 1220 * @param pEntryAbove Where to store the pointer to the best fit entry above the 1221 * the given offset. NULL if not required. 1222 * @param pEntryBelow Where to store the pointer to the best fit entry below the 1223 * the given offset. NULL if not required. 1224 */ 1225 static void pdmacFileEpCacheGetCacheBestFitEntryByOffset(PPDMACFILEENDPOINTCACHE pEndpointCache, RTFOFF off, 1226 PPDMACFILECACHEENTRY *ppEntryAbove, 1227 PPDMACFILECACHEENTRY *ppEntryBelow) 1215 1228 { 1216 1229 PPDMACFILECACHEGLOBAL pCache = pEndpointCache->pCache; 1217 PPDMACFILECACHEENTRY pEntry = NULL;1218 1230 1219 1231 STAM_PROFILE_ADV_START(&pCache->StatTreeGet, Cache); 1220 1232 1221 1233 RTSemRWRequestRead(pEndpointCache->SemRWEntries, RT_INDEFINITE_WAIT); 1222 pEntry = (PPDMACFILECACHEENTRY)RTAvlrFileOffsetGetBestFit(pEndpointCache->pTree, off, true /*fAbove*/); 1223 if (pEntry) 1224 pdmacFileEpCacheEntryRef(pEntry); 1234 if (ppEntryAbove) 1235 { 1236 *ppEntryAbove = (PPDMACFILECACHEENTRY)RTAvlrFileOffsetGetBestFit(pEndpointCache->pTree, off, true /*fAbove*/); 1237 if (*ppEntryAbove) 1238 pdmacFileEpCacheEntryRef(*ppEntryAbove); 1239 } 1240 1241 if (ppEntryBelow) 1242 { 1243 *ppEntryBelow = (PPDMACFILECACHEENTRY)RTAvlrFileOffsetGetBestFit(pEndpointCache->pTree, off, false /*fAbove*/); 1244 if (*ppEntryBelow) 1245 pdmacFileEpCacheEntryRef(*ppEntryBelow); 1246 } 1225 1247 RTSemRWReleaseRead(pEndpointCache->SemRWEntries); 1226 1248 1227 1249 STAM_PROFILE_ADV_STOP(&pCache->StatTreeGet, Cache); 1228 1229 return pEntry;1230 1250 } 1231 1251 … … 1484 1504 pdmacFileEpAddTask(pEndpoint, pIoTask); 1485 1505 } 1506 } 1507 1508 /** 1509 * Calculate aligned offset and size for a new cache entry 1510 * which do not intersect with an already existing entry and the 1511 * file end. 1512 * 1513 * @returns The number of bytes the entry can hold of the requested amount 1514 * of byte. 1515 * @param pEndpoint The endpoint. 1516 * @param pEndpointCache The endpoint cache. 1517 * @param off The start offset. 1518 * @param cb The number of bytes the entry needs to hold at least. 1519 * @param uAlignment Alignment of the boundary sizes. 1520 * @param poffAligned Where to store the aligned offset. 1521 * @param pcbAligned Where to store the aligned size of the entry. 1522 */ 1523 static size_t pdmacFileEpCacheEntryBoundariesCalc(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, 1524 PPDMACFILEENDPOINTCACHE pEndpointCache, 1525 RTFOFF off, size_t cb, 1526 unsigned uAlignment, 1527 RTFOFF *poffAligned, size_t *pcbAligned) 1528 { 1529 size_t cbAligned; 1530 size_t cbInEntry = 0; 1531 RTFOFF offAligned; 1532 PPDMACFILECACHEENTRY pEntryAbove = NULL; 1533 PPDMACFILECACHEENTRY pEntryBelow = NULL; 1534 1535 /* Get the best fit entries around the offset */ 1536 pdmacFileEpCacheGetCacheBestFitEntryByOffset(pEndpointCache, off, 1537 &pEntryAbove, &pEntryBelow); 1538 1539 /* Log the info */ 1540 LogFlow(("%sest fit entry below off=%RTfoff (BestFit=%RTfoff BestFitEnd=%RTfoff BestFitSize=%u)\n", 1541 pEntryBelow ? "B" : "No b", 1542 off, 1543 pEntryBelow ? pEntryBelow->Core.Key : 0, 1544 pEntryBelow ? pEntryBelow->Core.KeyLast : 0, 1545 pEntryBelow ? pEntryBelow->cbData : 0)); 1546 1547 LogFlow(("%sest fit entry above off=%RTfoff (BestFit=%RTfoff BestFitEnd=%RTfoff BestFitSize=%u)\n", 1548 pEntryAbove ? "B" : "No b", 1549 off, 1550 pEntryAbove ? pEntryAbove->Core.Key : 0, 1551 pEntryAbove ? pEntryAbove->Core.KeyLast : 0, 1552 pEntryAbove ? pEntryAbove->cbData : 0)); 1553 1554 /* Align the offset first. */ 1555 offAligned = off & ~(RTFOFF)(512-1); 1556 if ( pEntryBelow 1557 && offAligned <= pEntryBelow->Core.KeyLast) 1558 offAligned = pEntryBelow->Core.KeyLast; 1559 1560 if ( pEntryAbove 1561 && off + (RTFOFF)cb > pEntryAbove->Core.Key) 1562 { 1563 cbInEntry = pEntryAbove->Core.Key - off; 1564 cbAligned = pEntryAbove->Core.Key - offAligned; 1565 } 1566 else 1567 { 1568 /* 1569 * Align the size to a 4KB boundary. 1570 * Memory size is aligned to a page boundary 1571 * and memory is wasted if the size is rather small. 1572 * (For example reads with a size of 512 bytes). 1573 */ 1574 cbInEntry = cb; 1575 cbAligned = RT_ALIGN_Z(cb + (off - offAligned), uAlignment); 1576 1577 /* 1578 * Clip to file size if the original request doesn't 1579 * exceed the file (not an appending write) 1580 */ 1581 uint64_t cbReq = off + (RTFOFF)cb; 1582 if (cbReq >= pEndpoint->cbFile) 1583 cbAligned = cbReq - offAligned; 1584 else 1585 cbAligned = RT_MIN(pEndpoint->cbFile - offAligned, cbAligned); 1586 if (pEntryAbove) 1587 { 1588 Assert(pEntryAbove->Core.Key >= off); 1589 cbAligned = RT_MIN(cbAligned, (uint64_t)pEntryAbove->Core.Key - offAligned); 1590 } 1591 } 1592 1593 /* A few sanity checks */ 1594 AssertMsg(!pEntryBelow || pEntryBelow->Core.KeyLast < offAligned, 1595 ("Aligned start offset intersects with another cache entry\n")); 1596 AssertMsg(!pEntryAbove || (offAligned + (RTFOFF)cbAligned) <= pEntryAbove->Core.Key, 1597 ("Aligned size intersects with another cache entry\n")); 1598 Assert(cbInEntry <= cbAligned); 1599 AssertMsg( ( offAligned + (RTFOFF)cbAligned <= (RTFOFF)pEndpoint->cbFile 1600 && off + (RTFOFF)cb <= (RTFOFF)pEndpoint->cbFile) 1601 || (offAligned + (RTFOFF)cbAligned <= off + (RTFOFF)cb), 1602 ("Unwanted file size increase\n")); 1603 1604 if (pEntryBelow) 1605 pdmacFileEpCacheEntryRelease(pEntryBelow); 1606 if (pEntryAbove) 1607 pdmacFileEpCacheEntryRelease(pEntryAbove); 1608 1609 LogFlow(("offAligned=%RTfoff cbAligned=%u\n", offAligned, cbAligned)); 1610 1611 *poffAligned = offAligned; 1612 *pcbAligned = cbAligned; 1613 1614 return cbInEntry; 1615 } 1616 1617 /** 1618 * Create a new cache entry evicting data from the cache if required. 1619 * 1620 * @returns Pointer to the new cache entry or NULL 1621 * if not enough bytes could be evicted from the cache. 1622 * @param pEndpoint The endpoint. 1623 * @param pEndpointCache The endpoint cache. 1624 * @param off The offset. 1625 * @param cb Number of bytes the cache entry should have. 1626 * @param uAlignment Alignment the size of the entry should have. 1627 * @param pcbData Where to store the number of bytes the new 1628 * entry can hold. May be lower than actually requested 1629 * due to another entry intersecting the access range. 1630 */ 1631 static PPDMACFILECACHEENTRY pdmacFileEpCacheEntryCreate(PPDMASYNCCOMPLETIONENDPOINTFILE pEndpoint, 1632 PPDMACFILEENDPOINTCACHE pEndpointCache, 1633 RTFOFF off, size_t cb, 1634 unsigned uAlignment, 1635 size_t *pcbData) 1636 { 1637 RTFOFF offStart = 0; 1638 size_t cbEntry = 0; 1639 PPDMACFILECACHEENTRY pEntryNew = NULL; 1640 PPDMACFILECACHEGLOBAL pCache = pEndpointCache->pCache; 1641 uint8_t *pbBuffer = NULL; 1642 1643 *pcbData = pdmacFileEpCacheEntryBoundariesCalc(pEndpoint, 1644 pEndpointCache, 1645 off, cb, 1646 uAlignment, 1647 &offStart, &cbEntry); 1648 1649 pdmacFileCacheLockEnter(pCache); 1650 bool fEnough = pdmacFileCacheReclaim(pCache, cbEntry, true, &pbBuffer); 1651 1652 if (fEnough) 1653 { 1654 LogFlow(("Evicted enough bytes (%u requested). Creating new cache entry\n", cbEntry)); 1655 1656 pEntryNew = pdmacFileCacheEntryAlloc(pCache, pEndpoint, 1657 offStart, cbEntry, 1658 pbBuffer); 1659 if (RT_LIKELY(pEntryNew)) 1660 { 1661 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsedIn, pEntryNew); 1662 pdmacFileCacheAdd(pCache, cbEntry); 1663 pdmacFileCacheLockLeave(pCache); 1664 1665 pdmacFileEpCacheInsertEntry(pEndpointCache, pEntryNew); 1666 1667 AssertMsg( (off >= pEntryNew->Core.Key) 1668 && (off + (RTFOFF)cb <= pEntryNew->Core.Key + pEntryNew->Core.KeyLast + 1), 1669 ("Overflow in calculation off=%RTfoff OffsetAligned=%RTfoff\n", 1670 off, pEntryNew->Core.Key)); 1671 } 1672 else 1673 pdmacFileCacheLockLeave(pCache); 1674 } 1675 else 1676 pdmacFileCacheLockLeave(pCache); 1677 1678 return pEntryNew; 1486 1679 } 1487 1680 … … 1654 1847 else 1655 1848 { 1656 /* No entry found for this offset. Get best fit entry and fetch the data to the cache. */ 1657 size_t cbToReadAligned; 1658 PPDMACFILECACHEENTRY pEntryBestFit = pdmacFileEpCacheGetCacheBestFitEntryByOffset(pEndpointCache, off); 1659 1660 LogFlow(("%sbest fit entry for off=%RTfoff (BestFit=%RTfoff BestFitEnd=%RTfoff BestFitSize=%u)\n", 1661 pEntryBestFit ? "" : "No ", 1662 off, 1663 pEntryBestFit ? pEntryBestFit->Core.Key : 0, 1664 pEntryBestFit ? pEntryBestFit->Core.KeyLast : 0, 1665 pEntryBestFit ? pEntryBestFit->cbData : 0)); 1666 1667 if ( pEntryBestFit 1668 && off + (RTFOFF)cbRead > pEntryBestFit->Core.Key) 1849 /* No entry found for this offset. Create a new entry and fetch the data to the cache. */ 1850 PPDMACFILECACHEENTRY pEntryNew = pdmacFileEpCacheEntryCreate(pEndpoint, 1851 pEndpointCache, 1852 off, cbRead, 1853 PAGE_SIZE, 1854 &cbToRead); 1855 1856 cbRead -= cbToRead; 1857 1858 if (pEntryNew) 1669 1859 { 1670 cbToRead = pEntryBestFit->Core.Key - off; 1671 pdmacFileEpCacheEntryRelease(pEntryBestFit); 1672 cbToReadAligned = cbToRead; 1673 } 1674 else 1675 { 1676 /* 1677 * Align the size to a 4KB boundary. 1678 * Memory size is aligned to a page boundary 1679 * and memory is wasted if the size is rahter small. 1680 * (For example reads with a size of 512 bytes. 1681 */ 1682 cbToRead = cbRead; 1683 cbToReadAligned = RT_ALIGN_Z(cbRead, PAGE_SIZE); 1684 1685 /* Clip read to file size */ 1686 cbToReadAligned = RT_MIN(pEndpoint->cbFile - off, cbToReadAligned); 1687 if (pEntryBestFit) 1688 { 1689 Assert(pEntryBestFit->Core.Key >= off); 1690 cbToReadAligned = RT_MIN(cbToReadAligned, (uint64_t)pEntryBestFit->Core.Key - off); 1691 pdmacFileEpCacheEntryRelease(pEntryBestFit); 1692 } 1693 } 1694 1695 cbRead -= cbToRead; 1696 1697 if (!cbRead) 1698 STAM_COUNTER_INC(&pCache->cMisses); 1699 else 1700 STAM_COUNTER_INC(&pCache->cPartialHits); 1701 1702 uint8_t *pbBuffer = NULL; 1703 1704 pdmacFileCacheLockEnter(pCache); 1705 bool fEnough = pdmacFileCacheReclaim(pCache, cbToReadAligned, true, &pbBuffer); 1706 1707 if (fEnough) 1708 { 1709 LogFlow(("Evicted enough bytes (%u requested). Creating new cache entry\n", cbToReadAligned)); 1710 1711 PPDMACFILECACHEENTRY pEntryNew = pdmacFileCacheEntryAlloc(pCache, pEndpoint, off, cbToReadAligned, pbBuffer); 1712 AssertPtr(pEntryNew); 1713 1714 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsedIn, pEntryNew); 1715 pdmacFileCacheAdd(pCache, cbToReadAligned); 1716 pdmacFileCacheLockLeave(pCache); 1717 1718 pdmacFileEpCacheInsertEntry(pEndpointCache, pEntryNew); 1719 1720 AssertMsg( (off >= pEntryNew->Core.Key) 1721 && (off + (RTFOFF)cbToRead <= pEntryNew->Core.Key + pEntryNew->Core.KeyLast + 1), 1722 ("Overflow in calculation off=%RTfoff OffsetAligned=%RTfoff\n", 1723 off, pEntryNew->Core.Key)); 1860 if (!cbRead) 1861 STAM_COUNTER_INC(&pCache->cMisses); 1862 else 1863 STAM_COUNTER_INC(&pCache->cPartialHits); 1724 1864 1725 1865 pdmacFileEpCacheEntryWaitersAdd(pEntryNew, pTask, 1726 &IoMemCtx, 0, cbToRead, 1866 &IoMemCtx, 1867 off - pEntryNew->Core.Key, 1868 cbToRead, 1727 1869 false /* fWrite */); 1728 1870 pdmacFileCacheReadFromEndpoint(pEntryNew); … … 1731 1873 else 1732 1874 { 1733 pdmacFileCacheLockLeave(pCache);1734 1735 1875 /* 1736 1876 * There is not enough free space in the cache. … … 1994 2134 * write directly to the file. 1995 2135 */ 1996 PPDMACFILECACHEENTRY pEntryBestFit = pdmacFileEpCacheGetCacheBestFitEntryByOffset(pEndpointCache, off); 1997 1998 LogFlow(("%sest fit entry for off=%RTfoff (BestFit=%RTfoff BestFitEnd=%RTfoff BestFitSize=%u)\n", 1999 pEntryBestFit ? "B" : "No b", 2000 off, 2001 pEntryBestFit ? pEntryBestFit->Core.Key : 0, 2002 pEntryBestFit ? pEntryBestFit->Core.KeyLast : 0, 2003 pEntryBestFit ? pEntryBestFit->cbData : 0)); 2004 2005 if (pEntryBestFit && ((off + (RTFOFF)cbWrite) > pEntryBestFit->Core.Key)) 2136 PPDMACFILECACHEENTRY pEntryNew = pdmacFileEpCacheEntryCreate(pEndpoint, 2137 pEndpointCache, 2138 off, cbWrite, 2139 512, 2140 &cbToWrite); 2141 2142 cbWrite -= cbToWrite; 2143 2144 STAM_COUNTER_INC(&pCache->cMisses); 2145 2146 if (pEntryNew) 2006 2147 { 2007 cbToWrite = pEntryBestFit->Core.Key - off; 2008 pdmacFileEpCacheEntryRelease(pEntryBestFit); 2148 RTFOFF offDiff = off - pEntryNew->Core.Key; 2149 2150 /* 2151 * Check if it is possible to just write the data without waiting 2152 * for it to get fetched first. 2153 */ 2154 if (!offDiff && pEntryNew->cbData == cbToWrite) 2155 { 2156 pdmacFileEpCacheCopyFromIoMemCtx(&IoMemCtx, 2157 pEntryNew->pbData, 2158 cbToWrite); 2159 ASMAtomicSubS32(&pTask->cbTransferLeft, cbToWrite); 2160 2161 bool fCommit = pdmacFileCacheAddDirtyEntry(pEndpointCache, pEntryNew); 2162 if (fCommit) 2163 pdmacFileCacheCommitDirtyEntries(pCache); 2164 STAM_COUNTER_ADD(&pCache->StatWritten, cbToWrite); 2165 } 2166 else 2167 { 2168 /* Defer the write and fetch the data from the endpoint. */ 2169 pdmacFileEpCacheEntryWaitersAdd(pEntryNew, pTask, 2170 &IoMemCtx, 2171 offDiff, cbToWrite, 2172 true /* fWrite */); 2173 STAM_COUNTER_INC(&pEndpointCache->StatWriteDeferred); 2174 pdmacFileCacheReadFromEndpoint(pEntryNew); 2175 } 2176 2177 pdmacFileEpCacheEntryRelease(pEntryNew); 2009 2178 } 2010 2179 else 2011 2180 { 2012 if (pEntryBestFit)2013 pdmacFileEpCacheEntryRelease(pEntryBestFit);2014 2015 cbToWrite = cbWrite;2016 }2017 2018 cbWrite -= cbToWrite;2019 2020 STAM_COUNTER_INC(&pCache->cMisses);2021 2022 uint8_t *pbBuffer = NULL;2023 2024 pdmacFileCacheLockEnter(pCache);2025 bool fEnough = pdmacFileCacheReclaim(pCache, cbToWrite, true, &pbBuffer);2026 2027 if (fEnough)2028 {2029 LogFlow(("Evicted enough bytes (%u requested). Creating new cache entry\n", cbToWrite));2030 2031 PPDMACFILECACHEENTRY pEntryNew;2032 2033 pEntryNew = pdmacFileCacheEntryAlloc(pCache, pEndpoint, off, cbToWrite, pbBuffer);2034 AssertPtr(pEntryNew);2035 2036 pdmacFileCacheEntryAddToList(&pCache->LruRecentlyUsedIn, pEntryNew);2037 pdmacFileCacheAdd(pCache, cbToWrite);2038 pdmacFileCacheLockLeave(pCache);2039 2040 pdmacFileEpCacheInsertEntry(pEndpointCache, pEntryNew);2041 2042 pdmacFileEpCacheCopyFromIoMemCtx(&IoMemCtx,2043 pEntryNew->pbData,2044 cbToWrite);2045 ASMAtomicSubS32(&pTask->cbTransferLeft, cbToWrite);2046 2047 bool fCommit = pdmacFileCacheAddDirtyEntry(pEndpointCache, pEntryNew);2048 if (fCommit)2049 pdmacFileCacheCommitDirtyEntries(pCache);2050 pdmacFileEpCacheEntryRelease(pEntryNew);2051 STAM_COUNTER_ADD(&pCache->StatWritten, cbToWrite);2052 }2053 else2054 {2055 pdmacFileCacheLockLeave(pCache);2056 2057 2181 /* 2058 2182 * There is not enough free space in the cache.
Note:
See TracChangeset
for help on using the changeset viewer.