VirtualBox

Changeset 102557 in vbox


Ignore:
Timestamp:
Dec 8, 2023 10:13:00 PM (15 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
160703
Message:

VMM/IEM: Try deal with running out of executable memory. bugref:10371

Location:
trunk/src/VBox/VMM
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAllInstPython.py

    r102471 r102557  
    30643064    'IEM_MC_POP_U32':                                            (McBlock.parseMcGeneric,           True,  False, ),
    30653065    'IEM_MC_POP_U64':                                            (McBlock.parseMcGeneric,           True,  False, ),
    3066     'IEM_MC_PREPARE_AVX_USAGE':                                  (McBlock.parseMcGeneric,           False, False, ),
    3067     'IEM_MC_PREPARE_FPU_USAGE':                                  (McBlock.parseMcGeneric,           False, False, ),
    3068     'IEM_MC_PREPARE_SSE_USAGE':                                  (McBlock.parseMcGeneric,           False, False, ),
     3066    'IEM_MC_PREPARE_AVX_USAGE':                                  (McBlock.parseMcGeneric,           False, True),
     3067    'IEM_MC_PREPARE_FPU_USAGE':                                  (McBlock.parseMcGeneric,           False, True),
     3068    'IEM_MC_PREPARE_SSE_USAGE':                                  (McBlock.parseMcGeneric,           False, True),
    30693069    'IEM_MC_PUSH_FPU_RESULT':                                    (McBlock.parseMcGeneric,           True,  False, ),
    30703070    'IEM_MC_PUSH_FPU_RESULT_MEM_OP':                             (McBlock.parseMcGeneric,           True,  False, ),
  • trunk/src/VBox/VMM/VMMAll/IEMAllN8veRecompiler.cpp

    r102555 r102557  
    512512    AssertMsgReturn(cbReq > 32 && cbReq < _512K, ("%#x\n", cbReq), NULL);
    513513
    514     /*
    515      * Adjust the request size so it'll fit the allocator alignment/whatnot.
    516      *
    517      * For the RTHeapSimple allocator this means to follow the logic described
    518      * in iemExecMemAllocatorGrow and attempt to allocate it from one of the
    519      * existing chunks if we think we've got sufficient free memory around.
    520      *
    521      * While for the alternative one we just align it up to a whole unit size.
    522      */
     514
     515    for (unsigned iIteration = 0;; iIteration++)
     516    {
     517        /*
     518         * Adjust the request size so it'll fit the allocator alignment/whatnot.
     519         *
     520         * For the RTHeapSimple allocator this means to follow the logic described
     521         * in iemExecMemAllocatorGrow and attempt to allocate it from one of the
     522         * existing chunks if we think we've got sufficient free memory around.
     523         *
     524         * While for the alternative one we just align it up to a whole unit size.
     525         */
    523526#ifdef IEMEXECMEM_USE_ALT_SUB_ALLOCATOR
    524     cbReq = RT_ALIGN_32(cbReq, IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE);
     527        cbReq = RT_ALIGN_32(cbReq, IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE);
    525528#else
    526     cbReq = RT_ALIGN_32(cbReq + pExecMemAllocator->cbHeapBlockHdr, 64) - pExecMemAllocator->cbHeapBlockHdr;
    527 #endif
    528     if (cbReq <= pExecMemAllocator->cbFree)
    529     {
    530         uint32_t const cChunks      = pExecMemAllocator->cChunks;
    531         uint32_t const idxChunkHint = pExecMemAllocator->idxChunkHint < cChunks ? pExecMemAllocator->idxChunkHint : 0;
    532         for (uint32_t idxChunk = idxChunkHint; idxChunk < cChunks; idxChunk++)
     529        cbReq = RT_ALIGN_32(cbReq + pExecMemAllocator->cbHeapBlockHdr, 64) - pExecMemAllocator->cbHeapBlockHdr;
     530#endif
     531        if (cbReq <= pExecMemAllocator->cbFree)
    533532        {
     533            uint32_t const cChunks      = pExecMemAllocator->cChunks;
     534            uint32_t const idxChunkHint = pExecMemAllocator->idxChunkHint < cChunks ? pExecMemAllocator->idxChunkHint : 0;
     535            for (uint32_t idxChunk = idxChunkHint; idxChunk < cChunks; idxChunk++)
     536            {
     537                void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq);
     538                if (pvRet)
     539                    return pvRet;
     540            }
     541            for (uint32_t idxChunk = 0; idxChunk < idxChunkHint; idxChunk++)
     542            {
     543                void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq);
     544                if (pvRet)
     545                    return pvRet;
     546            }
     547        }
     548
     549        /*
     550         * Can we grow it with another chunk?
     551         */
     552        if (pExecMemAllocator->cChunks < pExecMemAllocator->cMaxChunks)
     553        {
     554            int rc = iemExecMemAllocatorGrow(pVCpu, pExecMemAllocator);
     555            AssertLogRelRCReturn(rc, NULL);
     556
     557            uint32_t const idxChunk = pExecMemAllocator->cChunks - 1;
    534558            void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq);
    535559            if (pvRet)
    536560                return pvRet;
     561            AssertFailed();
    537562        }
    538         for (uint32_t idxChunk = 0; idxChunk < idxChunkHint; idxChunk++)
     563
     564        /*
     565         * Try prune native TBs once.
     566         */
     567        if (iIteration == 0)
     568            iemTbAllocatorFreeupNativeSpace(pVCpu, cbReq / sizeof(IEMNATIVEINSTR));
     569        else
    539570        {
    540             void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq);
    541             if (pvRet)
    542                 return pvRet;
     571            /** @todo stats...   */
     572            return NULL;
    543573        }
    544574    }
    545575
    546     /*
    547      * Can we grow it with another chunk?
    548      */
    549     if (pExecMemAllocator->cChunks < pExecMemAllocator->cMaxChunks)
    550     {
    551         int rc = iemExecMemAllocatorGrow(pVCpu, pExecMemAllocator);
    552         AssertLogRelRCReturn(rc, NULL);
    553 
    554         uint32_t const idxChunk = pExecMemAllocator->cChunks - 1;
    555         void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq);
    556         if (pvRet)
    557             return pvRet;
    558         AssertFailed();
    559     }
    560 
    561     /* What now? Prune native translation blocks from the cache? */
    562     AssertFailed();
    563     return NULL;
    564576}
    565577
  • trunk/src/VBox/VMM/VMMAll/IEMAllThrdRecompiler.cpp

    r102394 r102557  
    967967 * function before making any TB or executable memory allocations respectively.
    968968 */
    969 void iemTbAllocatorProcessDelayedFrees(PVMCPU pVCpu, PIEMTBALLOCATOR pTbAllocator)
     969void iemTbAllocatorProcessDelayedFrees(PVMCPUCC pVCpu, PIEMTBALLOCATOR pTbAllocator)
    970970{
    971971    PIEMTB pTb = pTbAllocator->pDelayedFreeHead;
     
    975975        PIEMTB const pTbNext = pTb->pNext;
    976976        Assert(pVCpu->iem.s.pCurTbR3 != pTb);
    977         iemTbAlloctorScheduleForFree(pVCpu, pTb);
     977        iemTbAllocatorFree(pVCpu, pTb);
    978978        pTb = pTbNext;
    979979    }
     
    11691169}
    11701170
     1171
     1172/**
     1173 * This is called when we're out of space for native TBs.
     1174 *
     1175 * This uses a variation on the pruning in iemTbAllocatorAllocSlow.
     1176 * The difference is that we only prune native TBs and will only free any if
     1177 * there are least two in a group.  The conditions under which we're called are
     1178 * different - there will probably be free TBs in the table when we're called.
     1179 * Therefore we increase the group size and max scan length, though we'll stop
     1180 * scanning once we've reached the requested size (@a cNeededInstrs) and freed
     1181 * up at least 8 TBs.
     1182 */
     1183void iemTbAllocatorFreeupNativeSpace(PVMCPUCC pVCpu, uint32_t cNeededInstrs)
     1184{
     1185    PIEMTBALLOCATOR const pTbAllocator = pVCpu->iem.s.pTbAllocatorR3;
     1186    AssertReturnVoid(pTbAllocator && pTbAllocator->uMagic == IEMTBALLOCATOR_MAGIC);
     1187
     1188    STAM_REL_PROFILE_START(&pTbAllocator->StatPruneNative, a);
     1189
     1190    /*
     1191     * Flush the delayed free list before we start freeing TBs indiscriminately.
     1192     */
     1193    iemTbAllocatorProcessDelayedFrees(pVCpu, pTbAllocator);
     1194
     1195    /*
     1196     * Scan and free TBs.
     1197     */
     1198    uint32_t const msNow          = pVCpu->iem.s.msRecompilerPollNow;
     1199    uint32_t const cTbsToPrune    = 128 * 8;
     1200    uint32_t const cTbsPerGroup   = 4   * 4;
     1201    uint32_t       cFreedTbs      = 0;
     1202    uint32_t       cMaxInstrs     = 0;
     1203    uint32_t       idxTbPruneFrom = pTbAllocator->iPruneNativeFrom & ~(uint32_t)(cTbsPerGroup - 1);
     1204    for (uint32_t i = 0; i < cTbsToPrune; i += cTbsPerGroup, idxTbPruneFrom += cTbsPerGroup)
     1205    {
     1206        if (idxTbPruneFrom >= pTbAllocator->cTotalTbs)
     1207            idxTbPruneFrom = 0;
     1208        uint32_t idxChunk   = IEMTBALLOC_IDX_TO_CHUNK(pTbAllocator, idxTbPruneFrom);
     1209        uint32_t idxInChunk = IEMTBALLOC_IDX_TO_INDEX_IN_CHUNK(pTbAllocator, idxTbPruneFrom, idxChunk);
     1210        PIEMTB   pTb        = &pTbAllocator->aChunks[idxChunk].paTbs[idxInChunk];
     1211        uint32_t cMsAge     = pTb->fFlags & IEMTB_F_TYPE_NATIVE ? msNow - pTb->msLastUsed : msNow;
     1212        uint8_t  cNativeTbs = (pTb->fFlags & IEMTB_F_TYPE_NATIVE) != 0;
     1213
     1214        for (uint32_t j = 1, idxChunk2 = idxChunk, idxInChunk2 = idxInChunk + 1; j < cTbsPerGroup; j++, idxInChunk2++)
     1215        {
     1216            if (idxInChunk2 < pTbAllocator->cTbsPerChunk)
     1217            { /* likely */ }
     1218            else
     1219            {
     1220                idxInChunk2 = 0;
     1221                idxChunk2  += 1;
     1222                if (idxChunk2 >= pTbAllocator->cAllocatedChunks)
     1223                    idxChunk2 = 0;
     1224            }
     1225            PIEMTB const pTb2 = &pTbAllocator->aChunks[idxChunk2].paTbs[idxInChunk2];
     1226            if (pTb2->fFlags & IEMTB_F_TYPE_NATIVE)
     1227            {
     1228                cNativeTbs += 1;
     1229                uint32_t const cMsAge2 = msNow - pTb2->msLastUsed;
     1230                if (   cMsAge2 > cMsAge
     1231                    || (   cMsAge2 == cMsAge
     1232                        && (   pTb2->cUsed < pTb->cUsed
     1233                            || (   pTb2->cUsed == pTb->cUsed
     1234                                && pTb2->Native.cInstructions > pTb->Native.cInstructions)))
     1235                    || !(pTb->fFlags & IEMTB_F_TYPE_NATIVE))
     1236                {
     1237                    pTb        = pTb2;
     1238                    idxChunk   = idxChunk2;
     1239                    idxInChunk = idxInChunk2;
     1240                    cMsAge     = cMsAge2;
     1241                }
     1242            }
     1243        }
     1244
     1245        /* Free the TB if we found at least two native one in this group. */
     1246        if (cNativeTbs >= 2)
     1247        {
     1248            cMaxInstrs = RT_MAX(cMaxInstrs, pTb->Native.cInstructions);
     1249            iemTbAllocatorFreeInner(pVCpu, pTbAllocator, pTb, idxChunk, idxInChunk);
     1250            cFreedTbs++;
     1251            if (cFreedTbs >= 8 && cMaxInstrs >= cNeededInstrs)
     1252                break;
     1253        }
     1254    }
     1255    pTbAllocator->iPruneNativeFrom = idxTbPruneFrom;
     1256
     1257    STAM_REL_PROFILE_STOP(&pTbAllocator->StatPruneNative, a);
     1258}
    11711259
    11721260
  • trunk/src/VBox/VMM/VMMR3/IEMR3.cpp

    r102077 r102557  
    335335                        "Time spent freeing up TBs when full at alloc", "/IEM/CPU%u/re/TbPruningAlloc", idCpu);
    336336# endif
     337        STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatPruneNative,    STAMTYPE_PROFILE,   STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
     338                        "Time spent freeing up native TBs when out of executable memory", "/IEM/CPU%u/re/TbPruningNative", idCpu);
    337339        STAMR3RegisterF(pVM, (void *)&pTbAllocator->cAllocatedChunks,   STAMTYPE_U16,   STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    338340                        "Populated TB chunks",                          "/IEM/CPU%u/re/cTbChunks", idCpu);
  • trunk/src/VBox/VMM/include/IEMInternal.h

    r102528 r102557  
    12131213    /** Hint about which bit to start scanning the bitmap from. */
    12141214    uint32_t        iStartHint;
     1215    /** Where to start pruning native TBs from when we're out of executable memory.
     1216     *  See iemTbAllocatorFreeupNativeSpace for details. */
     1217    uint32_t        iPruneNativeFrom;
     1218    uint32_t        uPadding;
    12151219
    12161220    /** Statistics: Number of TB allocation calls. */
     
    12201224    /** Statistics: Time spend pruning. */
    12211225    STAMPROFILE     StatPrune;
     1226    /** Statistics: Time spend pruning native TBs. */
     1227    STAMPROFILE     StatPruneNative;
    12221228
    12231229    /** The delayed free list (see iemTbAlloctorScheduleForFree). */
     
    55875593                              uint64_t cbInitialExec, uint64_t cbMaxExec, uint32_t cbChunkExec);
    55885594void                iemThreadedTbObsolete(PVMCPUCC pVCpu, PIEMTB pTb, bool fSafeToFree);
    5589 void                iemTbAllocatorProcessDelayedFrees(PVMCPU pVCpu, PIEMTBALLOCATOR pTbAllocator);
     5595void                iemTbAllocatorProcessDelayedFrees(PVMCPUCC pVCpu, PIEMTBALLOCATOR pTbAllocator);
     5596void                iemTbAllocatorFreeupNativeSpace(PVMCPUCC pVCpu, uint32_t cNeededInstrs);
    55905597
    55915598
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