VirtualBox

Changeset 64674 in vbox for trunk/src/VBox/Devices/Storage


Ignore:
Timestamp:
Nov 15, 2016 2:09:23 PM (8 years ago)
Author:
vboxsync
Message:

IOBufMgmt: Defrag the I/O memory buffer if everything is free and an allocation couldn't be satisfied from one of the larger bins

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/IOBufMgmt.cpp

    r64411 r64674  
    7777    void               *pvMem;
    7878    /** Number of bins for free objects. */
    79     unsigned            cBins;
     79    uint32_t            cBins;
     80    /** Flag whether allocation is on hold waiting for everything to be free
     81     * to be able to defragment the memory. */
     82    bool                fAllocSuspended;
    8083    /** Array of bins. */
    8184    PIOBUFMGRBIN        paBins;
     
    8891#include "IOBufMgmt.h"
    8992
    90 DECLINLINE(unsigned) iobufMgrGetBinCount(size_t cbMin, size_t cbMax)
    91 {
    92     unsigned u32Max = ASMBitLastSetU32((uint32_t)cbMax);
    93     unsigned u32Min = ASMBitLastSetU32((uint32_t)cbMin);
     93/**
     94 * Gets the number of bins required between the given minimum and maximum size
     95 * to have a bin for every power of two size inbetween.
     96 *
     97 * @returns The number of bins required.
     98 * @param   cbMin       The size of the smallest bin.
     99 * @param   cbMax       The size of the largest bin.
     100 */
     101DECLINLINE(uint32_t) iobufMgrGetBinCount(uint32_t cbMin, uint32_t cbMax)
     102{
     103    uint32_t u32Max = ASMBitLastSetU32(cbMax);
     104    uint32_t u32Min = ASMBitLastSetU32(cbMin);
    94105
    95106    Assert(cbMax >= cbMin && cbMax != 0 && cbMin != 0);
     
    97108}
    98109
     110/**
     111 * Returns the number of entries required in the object array to cover all bins.
     112 *
     113 * @returns Number of entries required in the object array.
     114 * @param   cbMem       Size of the memory buffer.
     115 * @param   cBins       Number of bins available.
     116 * @param   cbBinMin    Minimum object size.
     117 */
    99118DECLINLINE(uint32_t) iobufMgrGetObjCount(size_t cbMem, unsigned cBins, size_t cbMinBin)
    100119{
     
    112131}
    113132
    114 DECLHIDDEN(int) IOBUFMgrCreate(PIOBUFMGR phIoBufMgr, size_t cbMax, uint32_t fFlags)
    115 {
    116     int rc = VINF_SUCCESS;
    117 
    118     AssertPtrReturn(phIoBufMgr, VERR_INVALID_POINTER);
    119     AssertReturn(cbMax, VERR_NOT_IMPLEMENTED);
    120 
    121     /* Allocate the basic structure in one go. */
    122     unsigned cBins = iobufMgrGetBinCount(IOBUFMGR_BIN_SIZE_MIN, IOBUFMGR_BIN_SIZE_MAX);
    123     uint32_t cObjs = iobufMgrGetObjCount(cbMax, cBins, IOBUFMGR_BIN_SIZE_MIN);
    124     PIOBUFMGRINT pThis = (PIOBUFMGRINT)RTMemAllocZ(RT_OFFSETOF(IOBUFMGRINT, apvObj[cObjs]) + cBins * sizeof(IOBUFMGRBIN));
    125     if (RT_LIKELY(pThis))
    126     {
    127         pThis->fFlags = fFlags;
    128         pThis->cbMax  = cbMax;
    129         pThis->cbFree = cbMax;
    130         pThis->cBins  = cBins;
    131         pThis->u32OrderMin = ASMBitLastSetU32(IOBUFMGR_BIN_SIZE_MIN) - 1;
    132         pThis->u32OrderMax = ASMBitLastSetU32(IOBUFMGR_BIN_SIZE_MAX) - 1;
    133         pThis->paBins = (PIOBUFMGRBIN)((uint8_t *)pThis + RT_OFFSETOF(IOBUFMGRINT, apvObj[cObjs]));
    134 
    135         rc = RTCritSectInit(&pThis->CritSectAlloc);
    136         if (RT_SUCCESS(rc))
    137         {
    138             if (pThis->fFlags & IOBUFMGR_F_REQUIRE_NOT_PAGABLE)
    139                 rc = RTMemSaferAllocZEx(&pThis->pvMem, RT_ALIGN_Z(pThis->cbMax, _4K),
    140                                         RTMEMSAFER_F_REQUIRE_NOT_PAGABLE);
    141             else
    142                 pThis->pvMem = RTMemPageAllocZ(RT_ALIGN_Z(pThis->cbMax, _4K));
    143 
    144             if (   RT_LIKELY(pThis->pvMem)
    145                 && RT_SUCCESS(rc))
     133/**
     134 * Resets the bins to factory default (memory resigin in the largest bin).
     135 *
     136 * @returns nothing.
     137 * @param   pThis       The I/O buffer manager instance.
     138 */
     139static void iobufMgrResetBins(PIOBUFMGRINT pThis)
     140{
     141    /* Init the bins. */
     142    size_t   cbMax = pThis->cbMax;
     143    size_t   iObj  = 0;
     144    uint32_t cbBin = IOBUFMGR_BIN_SIZE_MIN;
     145    for (unsigned i = 0; i < pThis->cBins; i++)
     146    {
     147        PIOBUFMGRBIN pBin = &pThis->paBins[i];
     148        pBin->iFree = 0;
     149        pBin->papvFree = &pThis->apvObj[iObj];
     150        iObj += cbMax / cbBin;
     151
     152        /* Init the biggest possible bin with the free objects. */
     153        if (   (cbBin << 1) > cbMax
     154            || i == pThis->cBins - 1)
     155        {
     156            uint8_t *pbMem = (uint8_t *)pThis->pvMem;
     157            while (cbMax)
    146158            {
    147                 /* Init the bins. */
    148                 size_t   iObj  = 0;
    149                 uint32_t cbBin = IOBUFMGR_BIN_SIZE_MIN;
    150                 for (unsigned i = 0; i < cBins; i++)
    151                 {
    152                     PIOBUFMGRBIN pBin = &pThis->paBins[i];
    153                     pBin->iFree = 0;
    154                     pBin->papvFree = &pThis->apvObj[iObj];
    155                     iObj += cbMax / cbBin;
    156 
    157                     /* Init the biggest possible bin with the free objects. */
    158                     if (   (cbBin << 1) > cbMax
    159                         || i == cBins - 1)
    160                     {
    161                         uint8_t *pbMem = (uint8_t *)pThis->pvMem;
    162                         while (cbMax)
    163                         {
    164                             pBin->papvFree[pBin->iFree] = pbMem;
    165                             cbMax -= cbBin;
    166                             pbMem += cbBin;
    167                             pBin->iFree++;
    168 
    169                             if (cbMax < cbBin) /** @todo Populate smaller bins and don't waste memory. */
    170                                 break;
    171                         }
    172 
    173                         /* Limit the number of available bins. */
    174                         pThis->cBins = i + 1;
    175                         break;
    176                     }
    177 
    178                     cbBin <<= 1;
    179                 }
    180 
    181                 *phIoBufMgr = pThis;
    182                 return VINF_SUCCESS;
     159                pBin->papvFree[pBin->iFree] = pbMem;
     160                cbMax -= cbBin;
     161                pbMem += cbBin;
     162                pBin->iFree++;
     163
     164                if (cbMax < cbBin) /** @todo Populate smaller bins and don't waste memory. */
     165                    break;
    183166            }
    184             else
    185                 rc = VERR_NO_MEMORY;
    186 
    187             RTCritSectDelete(&pThis->CritSectAlloc);
    188         }
    189 
    190         RTMemFree(pThis);
    191     }
    192     else
    193         rc = VERR_NO_MEMORY;
    194 
    195     return rc;
    196 }
    197 
    198 DECLHIDDEN(int) IOBUFMgrDestroy(IOBUFMGR hIoBufMgr)
    199 {
    200     PIOBUFMGRINT pThis = hIoBufMgr;
    201 
    202     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    203 
    204     int rc = RTCritSectEnter(&pThis->CritSectAlloc);
    205     if (RT_SUCCESS(rc))
    206     {
    207         if (pThis->cbFree == pThis->cbMax)
    208         {
    209             if (pThis->fFlags & IOBUFMGR_F_REQUIRE_NOT_PAGABLE)
    210                 RTMemSaferFree(pThis->pvMem, RT_ALIGN_Z(pThis->cbMax, _4K));
    211             else
    212                 RTMemPageFree(pThis->pvMem, RT_ALIGN_Z(pThis->cbMax, _4K));
    213 
    214             RTCritSectLeave(&pThis->CritSectAlloc);
    215             RTCritSectDelete(&pThis->CritSectAlloc);
    216             RTMemFree(pThis);
    217         }
    218         else
    219         {
    220             rc = VERR_INVALID_STATE;
    221             RTCritSectLeave(&pThis->CritSectAlloc);
    222         }
    223     }
    224 
    225     return rc;
    226 }
    227 
     167
     168            /* Limit the number of available bins. */
     169            pThis->cBins = i + 1;
     170            break;
     171        }
     172
     173        cbBin <<= 1;
     174    }
     175}
     176
     177/**
     178 * Allocate one segment from the manager.
     179 *
     180 * @returns Number of bytes allocated, 0 if there is no free memory.
     181 * @param   pThis       The I/O buffer manager instance.
     182 * @param   pSeg        The segment to fill in on success.
     183 * @param   cb          Maximum number of bytes to allocate.
     184 */
    228185static size_t iobufMgrAllocSegment(PIOBUFMGRINT pThis, PRTSGSEG pSeg, size_t cb)
    229186{
     
    282239     * If we didn't find something in the higher bins try to accumulate as much as possible from the smaller bins.
    283240     */
    284     /** @todo Defragment in case there is enough memory free but we can't find something in our bin. */
    285241    if (   pBin->iFree == 0
    286242        && iBin > 0)
    287243    {
     244#if 1
     245        pThis->fAllocSuspended = true;
     246#else
    288247        do
    289248        {
     
    302261        }
    303262        while (iBin > 0);
     263#endif
    304264    }
    305265    else if (pBin->iFree != 0)
     
    315275}
    316276
     277DECLHIDDEN(int) IOBUFMgrCreate(PIOBUFMGR phIoBufMgr, size_t cbMax, uint32_t fFlags)
     278{
     279    int rc = VINF_SUCCESS;
     280
     281    AssertPtrReturn(phIoBufMgr, VERR_INVALID_POINTER);
     282    AssertReturn(cbMax, VERR_NOT_IMPLEMENTED);
     283
     284    /* Allocate the basic structure in one go. */
     285    unsigned cBins = iobufMgrGetBinCount(IOBUFMGR_BIN_SIZE_MIN, IOBUFMGR_BIN_SIZE_MAX);
     286    uint32_t cObjs = iobufMgrGetObjCount(cbMax, cBins, IOBUFMGR_BIN_SIZE_MIN);
     287    PIOBUFMGRINT pThis = (PIOBUFMGRINT)RTMemAllocZ(RT_OFFSETOF(IOBUFMGRINT, apvObj[cObjs]) + cBins * sizeof(IOBUFMGRBIN));
     288    if (RT_LIKELY(pThis))
     289    {
     290        pThis->fFlags          = fFlags;
     291        pThis->cbMax           = cbMax;
     292        pThis->cbFree          = cbMax;
     293        pThis->cBins           = cBins;
     294        pThis->fAllocSuspended = false;
     295        pThis->u32OrderMin     = ASMBitLastSetU32(IOBUFMGR_BIN_SIZE_MIN) - 1;
     296        pThis->u32OrderMax     = ASMBitLastSetU32(IOBUFMGR_BIN_SIZE_MAX) - 1;
     297        pThis->paBins = (PIOBUFMGRBIN)((uint8_t *)pThis + RT_OFFSETOF(IOBUFMGRINT, apvObj[cObjs]));
     298
     299        rc = RTCritSectInit(&pThis->CritSectAlloc);
     300        if (RT_SUCCESS(rc))
     301        {
     302            if (pThis->fFlags & IOBUFMGR_F_REQUIRE_NOT_PAGABLE)
     303                rc = RTMemSaferAllocZEx(&pThis->pvMem, RT_ALIGN_Z(pThis->cbMax, _4K),
     304                                        RTMEMSAFER_F_REQUIRE_NOT_PAGABLE);
     305            else
     306                pThis->pvMem = RTMemPageAllocZ(RT_ALIGN_Z(pThis->cbMax, _4K));
     307
     308            if (   RT_LIKELY(pThis->pvMem)
     309                && RT_SUCCESS(rc))
     310            {
     311                iobufMgrResetBins(pThis);
     312
     313                *phIoBufMgr = pThis;
     314                return VINF_SUCCESS;
     315            }
     316            else
     317                rc = VERR_NO_MEMORY;
     318
     319            RTCritSectDelete(&pThis->CritSectAlloc);
     320        }
     321
     322        RTMemFree(pThis);
     323    }
     324    else
     325        rc = VERR_NO_MEMORY;
     326
     327    return rc;
     328}
     329
     330DECLHIDDEN(int) IOBUFMgrDestroy(IOBUFMGR hIoBufMgr)
     331{
     332    PIOBUFMGRINT pThis = hIoBufMgr;
     333
     334    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     335
     336    int rc = RTCritSectEnter(&pThis->CritSectAlloc);
     337    if (RT_SUCCESS(rc))
     338    {
     339        if (pThis->cbFree == pThis->cbMax)
     340        {
     341            if (pThis->fFlags & IOBUFMGR_F_REQUIRE_NOT_PAGABLE)
     342                RTMemSaferFree(pThis->pvMem, RT_ALIGN_Z(pThis->cbMax, _4K));
     343            else
     344                RTMemPageFree(pThis->pvMem, RT_ALIGN_Z(pThis->cbMax, _4K));
     345
     346            RTCritSectLeave(&pThis->CritSectAlloc);
     347            RTCritSectDelete(&pThis->CritSectAlloc);
     348            RTMemFree(pThis);
     349        }
     350        else
     351        {
     352            rc = VERR_INVALID_STATE;
     353            RTCritSectLeave(&pThis->CritSectAlloc);
     354        }
     355    }
     356
     357    return rc;
     358}
     359
    317360DECLHIDDEN(int) IOBUFMgrAllocBuf(IOBUFMGR hIoBufMgr, PIOBUFDESC pIoBufDesc, size_t cbIoBuf,
    318361                                 size_t *pcbIoBufAllocated)
     
    388431            pThis->cbFree += (size_t)RT_BIT_32(u32Order);
    389432        }
     433
     434        if (   pThis->cbFree == pThis->cbMax
     435            && pThis->fAllocSuspended)
     436        {
     437            iobufMgrResetBins(pThis);
     438            pThis->fAllocSuspended = false;
     439        }
     440
    390441        RTCritSectLeave(&pThis->CritSectAlloc);
    391442    }
Note: See TracChangeset for help on using the changeset viewer.

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