VirtualBox

Changeset 27521 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Mar 19, 2010 11:04:41 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
59026
Message:

I/O cache: Optimize 1-byte writes done by VMDK

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/PDMAsyncCompletionFileCache.cpp

    r26956 r27521  
    539539             */
    540540            if (!cbRemoved)
    541                 cbRemoved += pdmacFileCacheEvictPagesFrom(pCache, cbData - cbRemoved, &pCache->LruFrequentlyUsed,
     541                cbRemoved += pdmacFileCacheEvictPagesFrom(pCache, cbData, &pCache->LruFrequentlyUsed,
    542542                                                          NULL, fReuseBuffer, ppbBuffer);
    543543            else
     
    12121212}
    12131213
    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 */
     1225static void pdmacFileEpCacheGetCacheBestFitEntryByOffset(PPDMACFILEENDPOINTCACHE pEndpointCache, RTFOFF off,
     1226                                                         PPDMACFILECACHEENTRY *ppEntryAbove,
     1227                                                         PPDMACFILECACHEENTRY *ppEntryBelow)
    12151228{
    12161229    PPDMACFILECACHEGLOBAL pCache = pEndpointCache->pCache;
    1217     PPDMACFILECACHEENTRY pEntry = NULL;
    12181230
    12191231    STAM_PROFILE_ADV_START(&pCache->StatTreeGet, Cache);
    12201232
    12211233    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    }
    12251247    RTSemRWReleaseRead(pEndpointCache->SemRWEntries);
    12261248
    12271249    STAM_PROFILE_ADV_STOP(&pCache->StatTreeGet, Cache);
    1228 
    1229     return pEntry;
    12301250}
    12311251
     
    14841504        pdmacFileEpAddTask(pEndpoint, pIoTask);
    14851505    }
     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 */
     1523static 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 */
     1631static 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;
    14861679}
    14871680
     
    16541847        else
    16551848        {
    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)
    16691859            {
    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);
    17241864
    17251865                pdmacFileEpCacheEntryWaitersAdd(pEntryNew, pTask,
    1726                                                 &IoMemCtx, 0, cbToRead,
     1866                                                &IoMemCtx,
     1867                                                off - pEntryNew->Core.Key,
     1868                                                cbToRead,
    17271869                                                false /* fWrite */);
    17281870                pdmacFileCacheReadFromEndpoint(pEntryNew);
     
    17311873            else
    17321874            {
    1733                 pdmacFileCacheLockLeave(pCache);
    1734 
    17351875                /*
    17361876                 * There is not enough free space in the cache.
     
    19942134             * write directly to the file.
    19952135             */
    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)
    20062147            {
    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);
    20092178            }
    20102179            else
    20112180            {
    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             else
    2054             {
    2055                 pdmacFileCacheLockLeave(pCache);
    2056 
    20572181                /*
    20582182                 * There is not enough free space in the cache.
Note: See TracChangeset for help on using the changeset viewer.

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