VirtualBox

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


Ignore:
Timestamp:
Oct 14, 2024 10:45:56 PM (7 weeks ago)
Author:
vboxsync
Message:

VMM/IEM: Back off earlier if chunks or the allocator is very full, don't waste time finding the last free location. Reduces the pointless full chunk bitmap search quite a bit. bugref:10720

Location:
trunk/src/VBox/VMM/VMMAll
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAllN8veExecMem.cpp

    r106310 r106313  
    294294    /** Total amount of memory not being usable currently due to IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE. */
    295295    uint64_t                cbUnusable;
     296    /** Allocation size distribution (in alloc units; 0 is the slop bucket). */
     297    STAMCOUNTER             aStatSizes[16];
    296298#endif
    297299
     
    501503             *
    502504             * The complicated code below is a bit faster on arm. Reducing the per TB cost
    503              * from 4255ns to 4106ns (best run out of 10).  On win/x86 the gain isn't so
    504              * marked, despite more full bitmap scans.
     505             * from 4255ns to 4106ns (best run out of 10).  On win/amd64 there isn't an
     506             * obvious gain here, at least not with the data currently being profiled.
    505507             */
    506508#if 1
     
    639641        }
    640642
     643        /*
     644         * If we get down here, we have a word that isn't UINT64_MAX.
     645         */
    641646        if (uWord != 0)
    642647        {
    643648            /*
    644              * Fend of large request we cannot satisfy before first.
     649             * Fend of large request we cannot satisfy before the first set bit.
    645650             */
    646651            if (!a_fBig || cReqUnits < 64 + cPrevLeadingZeros)
     
    648653#ifdef __GNUC__
    649654                unsigned cZerosInWord = __builtin_popcountl(~uWord);
     655#elif defined(_MSC_VER) && defined(RT_ARCH_AMD64)
     656                unsigned cZerosInWord = __popcnt64(~uWord);
     657#elif defined(_MSC_VER) && defined(RT_ARCH_ARM64)
     658                unsigned cZerosInWord = _CountOneBits64(~uWord);
    650659#else
    651 # ifdef RT_ARCH_AMD64
    652                 unsigned cZerosInWord = __popcnt64(~uWord);
    653 # elif defined(RT_ARCH_ARM64)
    654                 unsigned cZerosInWord = _CountOneBits64(~uWord);
    655 # else
    656 #  pragma message("need popcount intrinsic or something...") /** @todo port me: Win/ARM. */
     660# pragma message("need popcount intrinsic or something...")
    657661                unsigned cZerosInWord = 0;
    658662                for (uint64_t uTmp = ~uWords; uTmp; cZerosInWord++)
    659663                    uTmp &= uTmp - 1; /* Clears the least significant bit set. */
    660 # endif
    661664#endif
    662665                if (cZerosInWord + cPrevLeadingZeros >= cReqUnits)
     
    737740            if RT_CONSTEXPR_IF(!a_fBig)
    738741                return off * 64 - cPrevLeadingZeros;
    739             else
     742            else /* keep else */
    740743            {
    741744                if (cPrevLeadingZeros + 64 >= cReqUnits)
     
    890893                                                            RT_ALIGN_32(idxHint + cReqUnits, 64*4)),
    891894                                                     cReqUnits, idxChunk, pTb, (void **)ppaExec, ppChunkCtx);
    892     if (!pvRet)
    893         pExecMemAllocator->cFruitlessChunkScans += 1;
    894     return (PIEMNATIVEINSTR)pvRet;
    895 }
    896 
    897 
    898 DECL_FORCE_INLINE(PIEMNATIVEINSTR)
    899 iemExecMemAllocatorAllocUnitsInChunk(PIEMEXECMEMALLOCATOR pExecMemAllocator, uint32_t idxChunk, uint32_t cReqUnits, PIEMTB pTb,
    900                                      PIEMNATIVEINSTR *ppaExec, PCIEMNATIVEPERCHUNKCTX *ppChunkCtx)
    901 {
    902     if (cReqUnits <= pExecMemAllocator->aChunks[idxChunk].cFreeUnits)
    903         return iemExecMemAllocatorAllocUnitsInChunkInner(pExecMemAllocator, idxChunk, cReqUnits, pTb, ppaExec, ppChunkCtx);
     895    if (pvRet)
     896        return (PIEMNATIVEINSTR)pvRet;
     897
     898    pExecMemAllocator->cFruitlessChunkScans += 1;
    904899    return NULL;
    905900}
     
    910905                                     PIEMNATIVEINSTR *ppaExec)
    911906{
    912     return iemExecMemAllocatorAllocUnitsInChunk(pExecMemAllocator, idxChunk, iemExecMemAllocBytesToUnits(cbReq), NULL /*pTb*/,
    913                                                 ppaExec, NULL /*ppChunkCtx*/);
     907    uint32_t const cReqUnits = iemExecMemAllocBytesToUnits(cbReq);
     908    if (cReqUnits <= pExecMemAllocator->aChunks[idxChunk].cFreeUnits)
     909        return iemExecMemAllocatorAllocUnitsInChunkInner(pExecMemAllocator, idxChunk, cReqUnits, NULL /*pTb*/,
     910                                                         ppaExec, NULL /*ppChunkCtx*/);
     911    return NULL;
    914912}
    915913
     
    938936
    939937    uint32_t const cReqUnits = iemExecMemAllocBytesToUnits(cbReq);
     938    STAM_COUNTER_INC(&pExecMemAllocator->aStatSizes[cReqUnits < RT_ELEMENTS(pExecMemAllocator->aStatSizes) ? cReqUnits : 0]);
    940939    for (unsigned iIteration = 0;; iIteration++)
    941940    {
    942         if (cbReq <= pExecMemAllocator->cbFree)
     941        if (   cbReq * 2 <= pExecMemAllocator->cbFree
     942            || (cReqUnits == 1 || pExecMemAllocator->cbFree >= IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE) )
    943943        {
    944             uint32_t const cChunks      = pExecMemAllocator->cChunks;
    945             uint32_t const idxChunkHint = pExecMemAllocator->idxChunkHint < cChunks ? pExecMemAllocator->idxChunkHint : 0;
    946             for (uint32_t idxChunk = idxChunkHint; idxChunk < cChunks; idxChunk++)
     944            uint32_t const cChunks       = pExecMemAllocator->cChunks;
     945            uint32_t const idxChunkHint  = pExecMemAllocator->idxChunkHint < cChunks ? pExecMemAllocator->idxChunkHint : 0;
     946
     947            /*
     948             * We do two passes here, the first pass we skip chunks with fewer than cReqUnits * 16,
     949             * the 2nd pass we skip chunks. The second pass checks the one skipped in the first pass.
     950             */
     951            for (uint32_t cMinFreePass = cReqUnits == 1 ? cReqUnits : cReqUnits * 16, cMaxFreePass = UINT32_MAX;;)
    947952            {
    948                 PIEMNATIVEINSTR const pRet = iemExecMemAllocatorAllocUnitsInChunk(pExecMemAllocator, idxChunk, cReqUnits, pTb,
    949                                                                                   ppaExec, ppChunkCtx);
    950                 if (pRet)
    951                 {
    952                     STAM_PROFILE_STOP(&pExecMemAllocator->StatAlloc, a);
     953                for (uint32_t idxChunk = idxChunkHint; idxChunk < cChunks; idxChunk++)
     954                    if (   pExecMemAllocator->aChunks[idxChunk].cFreeUnits >= cMinFreePass
     955                        && pExecMemAllocator->aChunks[idxChunk].cFreeUnits <= cMaxFreePass)
     956                    {
     957                        PIEMNATIVEINSTR const pRet = iemExecMemAllocatorAllocUnitsInChunkInner(pExecMemAllocator, idxChunk,
     958                                                                                               cReqUnits, pTb, ppaExec, ppChunkCtx);
     959                        if (pRet)
     960                        {
     961                            STAM_PROFILE_STOP(&pExecMemAllocator->StatAlloc, a);
    953962#ifdef VBOX_WITH_STATISTICS
    954                     pExecMemAllocator->cbUnusable += (cReqUnits << IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT) - cbReq;
    955 #endif
    956                     return pRet;
    957                 }
    958             }
    959             for (uint32_t idxChunk = 0; idxChunk < idxChunkHint; idxChunk++)
    960             {
    961                 PIEMNATIVEINSTR const pRet = iemExecMemAllocatorAllocUnitsInChunk(pExecMemAllocator, idxChunk, cReqUnits, pTb,
    962                                                                                   ppaExec, ppChunkCtx);
    963                 if (pRet)
    964                 {
    965                     STAM_PROFILE_STOP(&pExecMemAllocator->StatAlloc, a);
     963                            pExecMemAllocator->cbUnusable += (cReqUnits << IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT) - cbReq;
     964#endif
     965                            return pRet;
     966                        }
     967                    }
     968                for (uint32_t idxChunk = 0; idxChunk < idxChunkHint; idxChunk++)
     969                    if (   pExecMemAllocator->aChunks[idxChunk].cFreeUnits >= cMinFreePass
     970                        && pExecMemAllocator->aChunks[idxChunk].cFreeUnits <= cMaxFreePass)
     971                    {
     972                        PIEMNATIVEINSTR const pRet = iemExecMemAllocatorAllocUnitsInChunkInner(pExecMemAllocator, idxChunk,
     973                                                                                               cReqUnits, pTb, ppaExec, ppChunkCtx);
     974                        if (pRet)
     975                        {
     976                            STAM_PROFILE_STOP(&pExecMemAllocator->StatAlloc, a);
    966977#ifdef VBOX_WITH_STATISTICS
    967                     pExecMemAllocator->cbUnusable += (cReqUnits << IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT) - cbReq;
    968 #endif
    969                     return pRet;
    970                 }
     978                            pExecMemAllocator->cbUnusable += (cReqUnits << IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT) - cbReq;
     979#endif
     980                            return pRet;
     981                        }
     982                    }
     983                if (cMinFreePass <= cReqUnits * 2)
     984                    break;
     985                cMaxFreePass = cMinFreePass - 1;
     986                cMinFreePass = cReqUnits * 2;
    971987            }
    972988        }
     
    981997
    982998            uint32_t const idxChunk = pExecMemAllocator->cChunks - 1;
    983             PIEMNATIVEINSTR const pRet = iemExecMemAllocatorAllocUnitsInChunk(pExecMemAllocator, idxChunk, cReqUnits, pTb,
    984                                                                               ppaExec, ppChunkCtx);
     999            PIEMNATIVEINSTR const pRet = iemExecMemAllocatorAllocUnitsInChunkInner(pExecMemAllocator, idxChunk, cReqUnits, pTb,
     1000                                                                                   ppaExec, ppChunkCtx);
    9851001            if (pRet)
    9861002            {
     
    21242140    STAMR3RegisterFU(pUVM, &pExecMemAllocator->StatAlloc,       STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
    21252141                     "Profiling the allocator",                 "/IEM/CPU%u/re/ExecMem/ProfAlloc", pVCpu->idCpu);
     2142    for (unsigned i = 1; i < RT_ELEMENTS(pExecMemAllocator->aStatSizes); i++)
     2143        STAMR3RegisterFU(pUVM, &pExecMemAllocator->aStatSizes[i], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
     2144                         "Number of allocations of this number of allocation units",
     2145                         "/IEM/CPU%u/re/ExecMem/aSize%02u", pVCpu->idCpu, i);
     2146    STAMR3RegisterFU(pUVM, &pExecMemAllocator->aStatSizes[0], STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
     2147                     "Number of allocations 16 units or larger", "/IEM/CPU%u/re/ExecMem/aSize16OrLarger", pVCpu->idCpu);
    21262148#endif
    21272149#ifdef IEMEXECMEM_ALT_SUB_WITH_ALT_PRUNING
  • trunk/src/VBox/VMM/VMMAll/IEMAllThrdRecompiler.cpp

    r106296 r106313  
    31913191                         pTb = pTb->pNext)
    31923192                    {
    3193                         PIEMTB pTbCopy = iemThreadedTbDuplicate(pVM, pVCpu, pTbHead);
     3193                        PIEMTB pTbCopy = iemThreadedTbDuplicate(pVM, pVCpu, pTb);
    31943194                        if (!pTbCopy)
    31953195                            break;
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