VirtualBox

Changeset 104108 in vbox for trunk/src


Ignore:
Timestamp:
Mar 28, 2024 9:50:41 PM (10 months ago)
Author:
vboxsync
Message:

VMM/IEM: Slap a header on the exec mem allocations. This simplifies freeing and will help implementing defraging and more localized pruning. Statistics. bugref:10370

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

Legend:

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

    r104101 r104108  
    159159/** The chunk sub-allocation unit size as a shift factor. */
    160160#define IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT     7
     161/** Enables adding a header to the sub-allocator allocations.
     162 * This is useful for freeing up executable memory among other things.  */
     163#define IEMEXECMEM_ALT_SUB_WITH_ALLOC_HEADER
     164
    161165
    162166#if defined(IN_RING3) && !defined(RT_OS_WINDOWS)
     
    344348     * portion corresponding to an chunk). */
    345349    uint32_t                cBitmapElementsPerChunk;
     350# ifdef VBOX_WITH_STATISTICS
     351    STAMPROFILE             StatAlloc;
     352# endif
    346353#else
    347354    /** @name Tweaks to get 64 byte aligned allocats w/o unnecessary fragmentation.
     
    378385
    379386
     387#ifdef IEMEXECMEM_ALT_SUB_WITH_ALLOC_HEADER
     388/**
     389 * Allocation header.
     390 */
     391typedef struct IEMEXECMEMALLOCHDR
     392{
     393    /** Magic value / eyecatcher (IEMEXECMEMALLOCHDR_MAGIC). */
     394    uint32_t        uMagic;
     395    /** The allocation chunk (for speeding up freeing). */
     396    uint32_t        idxChunk;
     397    /** Pointer to the translation block the allocation belongs to.
     398     * This is the whole point of the header. */
     399    PIEMTB          pTb;
     400} IEMEXECMEMALLOCHDR;
     401/** Pointer to an allocation header. */
     402typedef  IEMEXECMEMALLOCHDR *PIEMEXECMEMALLOCHDR;
     403/** Magic value for IEMEXECMEMALLOCHDR ('ExeM'). */
     404# define IEMEXECMEMALLOCHDR_MAGIC       UINT32_C(0x4d657845)
     405#endif
     406
     407
    380408static int iemExecMemAllocatorGrow(PVMCPUCC pVCpu, PIEMEXECMEMALLOCATOR pExecMemAllocator);
    381409
     
    385413 * the heap statistics.
    386414 */
    387 static void * iemExecMemAllocatorAllocTailCode(PIEMEXECMEMALLOCATOR pExecMemAllocator, void *pvRet,
    388                                                uint32_t cbReq, uint32_t idxChunk)
     415static void *iemExecMemAllocatorAllocTailCode(PIEMEXECMEMALLOCATOR pExecMemAllocator, void *pvRet,
     416                                              uint32_t cbReq, uint32_t idxChunk)
    389417{
    390418    pExecMemAllocator->cAllocations += 1;
     
    419447#ifdef IEMEXECMEM_USE_ALT_SUB_ALLOCATOR
    420448static void *iemExecMemAllocatorAllocInChunkInt(PIEMEXECMEMALLOCATOR pExecMemAllocator, uint64_t *pbmAlloc, uint32_t idxFirst,
    421                                                 uint32_t cToScan, uint32_t cReqUnits, uint32_t idxChunk)
     449                                                uint32_t cToScan, uint32_t cReqUnits, uint32_t idxChunk, PIEMTB pTb)
    422450{
    423451    /*
     
    447475            pChunk->idxFreeHint = (uint32_t)iBit + cReqUnits;
    448476
     477# ifdef IEMEXECMEM_ALT_SUB_WITH_ALLOC_HEADER
     478            PIEMEXECMEMALLOCHDR pHdr = (PIEMEXECMEMALLOCHDR)((uint8_t *)pChunk->pvChunk
     479                                                             + (   (idxFirst + (uint32_t)iBit)
     480                                                                << IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT));
     481            pHdr->uMagic   = IEMEXECMEMALLOCHDR_MAGIC;
     482            pHdr->idxChunk = idxChunk;
     483            pHdr->pTb      = pTb;
     484            return iemExecMemAllocatorAllocTailCode(pExecMemAllocator, pHdr + 1,
     485                                                    cReqUnits << IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT, idxChunk);
     486#else
     487            RT_NOREF(pTb);
    449488            void * const pvRet  = (uint8_t *)pChunk->pvChunk
    450489                                + ((idxFirst + (uint32_t)iBit) << IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT);
    451 
    452490            return iemExecMemAllocatorAllocTailCode(pExecMemAllocator, pvRet,
    453491                                                    cReqUnits << IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT, idxChunk);
     492#endif
    454493        }
    455494
     
    461500
    462501
    463 static void *iemExecMemAllocatorAllocInChunk(PIEMEXECMEMALLOCATOR pExecMemAllocator, uint32_t idxChunk, uint32_t cbReq)
     502static void *
     503iemExecMemAllocatorAllocInChunk(PIEMEXECMEMALLOCATOR pExecMemAllocator, uint32_t idxChunk, uint32_t cbReq, PIEMTB pTb)
    464504{
    465505#ifdef IEMEXECMEM_USE_ALT_SUB_ALLOCATOR
     
    467507     * Figure out how much to allocate.
    468508     */
    469     uint32_t const cReqUnits = (cbReq + IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE - 1) >> IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT;
     509# ifdef IEMEXECMEM_ALT_SUB_WITH_ALLOC_HEADER
     510    uint32_t const cReqUnits = (cbReq + sizeof(IEMEXECMEMALLOCHDR) + IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE - 1)
     511# else
     512    uint32_t const cReqUnits = (cbReq + IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE - 1)
     513# endif
     514                            >> IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SHIFT;
    470515    if (cReqUnits <= pExecMemAllocator->aChunks[idxChunk].cFreeUnits)
    471516    {
     
    475520        {
    476521            void *pvRet = iemExecMemAllocatorAllocInChunkInt(pExecMemAllocator, pbmAlloc, idxHint,
    477                                                              pExecMemAllocator->cUnitsPerChunk - idxHint, cReqUnits, idxChunk);
     522                                                             pExecMemAllocator->cUnitsPerChunk - idxHint,
     523                                                             cReqUnits, idxChunk, pTb);
    478524            if (pvRet)
    479525                return pvRet;
     
    481527        return iemExecMemAllocatorAllocInChunkInt(pExecMemAllocator, pbmAlloc, 0,
    482528                                                  RT_MIN(pExecMemAllocator->cUnitsPerChunk, RT_ALIGN_32(idxHint + cReqUnits, 64)),
    483                                                   cReqUnits, idxChunk);
     529                                                  cReqUnits, idxChunk, pTb);
    484530    }
    485531#else
     
    487533    if (pvRet)
    488534        return iemExecMemAllocatorAllocTailCode(pExecMemAllocator, pvRet, cbReq, idxChunk);
     535    RT_NOREF(pTb);
    489536#endif
    490537    return NULL;
     
    501548 *                  thread.
    502549 * @param   cbReq   How many bytes are required.
    503  */
    504 static void *iemExecMemAllocatorAlloc(PVMCPU pVCpu, uint32_t cbReq)
     550 * @param   pTb     The translation block that will be using the allocation.
     551 */
     552static void *iemExecMemAllocatorAlloc(PVMCPU pVCpu, uint32_t cbReq, PIEMTB pTb)
    505553{
    506554    PIEMEXECMEMALLOCATOR pExecMemAllocator = pVCpu->iem.s.pExecMemAllocatorR3;
    507555    AssertReturn(pExecMemAllocator && pExecMemAllocator->uMagic == IEMEXECMEMALLOCATOR_MAGIC, NULL);
    508556    AssertMsgReturn(cbReq > 32 && cbReq < _512K, ("%#x\n", cbReq), NULL);
     557    STAM_PROFILE_START(&pExecMemAllocator->StatAlloc, a);
    509558
    510559    /*
     
    531580            for (uint32_t idxChunk = idxChunkHint; idxChunk < cChunks; idxChunk++)
    532581            {
    533                 void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq);
     582                void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq, pTb);
    534583                if (pvRet)
     584                {
     585                    STAM_PROFILE_STOP(&pExecMemAllocator->StatAlloc, a);
    535586                    return pvRet;
     587                }
    536588            }
    537589            for (uint32_t idxChunk = 0; idxChunk < idxChunkHint; idxChunk++)
    538590            {
    539                 void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq);
     591                void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq, pTb);
    540592                if (pvRet)
     593                {
     594                    STAM_PROFILE_STOP(&pExecMemAllocator->StatAlloc, a);
    541595                    return pvRet;
     596                }
    542597            }
    543598        }
     
    552607
    553608            uint32_t const idxChunk = pExecMemAllocator->cChunks - 1;
    554             void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq);
     609            void *pvRet = iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbReq, pTb);
    555610            if (pvRet)
     611            {
     612                STAM_PROFILE_STOP(&pExecMemAllocator->StatAlloc, a);
    556613                return pvRet;
     614            }
    557615            AssertFailed();
    558616        }
     
    566624        {
    567625            STAM_REL_COUNTER_INC(&pVCpu->iem.s.StatNativeExecMemInstrBufAllocFailed);
     626            STAM_PROFILE_STOP(&pExecMemAllocator->StatAlloc, a);
    568627            return NULL;
    569628        }
    570629    }
    571 
    572630}
    573631
     
    601659    PIEMEXECMEMALLOCATOR pExecMemAllocator = pVCpu->iem.s.pExecMemAllocatorR3;
    602660    Assert(pExecMemAllocator && pExecMemAllocator->uMagic == IEMEXECMEMALLOCATOR_MAGIC);
    603     Assert(pv);
    604 #ifdef IEMEXECMEM_USE_ALT_SUB_ALLOCATOR
     661    AssertPtr(pv);
     662#ifndef IEMEXECMEM_USE_ALT_SUB_ALLOCATOR
     663    Assert(!((uintptr_t)pv & 63));
     664#else
     665# ifndef IEMEXECMEM_ALT_SUB_WITH_ALLOC_HEADER
    605666    Assert(!((uintptr_t)pv & (IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE - 1)));
    606 #else
    607     Assert(!((uintptr_t)pv & 63));
     667# else
     668    PIEMEXECMEMALLOCHDR pHdr = (PIEMEXECMEMALLOCHDR)pv - 1;
     669    Assert(!((uintptr_t)pHdr & (IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE - 1)));
     670    AssertReturnVoid(pHdr->uMagic == IEMEXECMEMALLOCHDR_MAGIC);
     671    uint32_t const idxChunk = pHdr->idxChunk;
     672    AssertReturnVoid(idxChunk < pExecMemAllocator->cChunks);
     673    pv = pHdr;
     674# endif
    608675#endif
    609676
     
    617684    /* Free it / assert sanity. */
    618685#if defined(VBOX_STRICT) || defined(IEMEXECMEM_USE_ALT_SUB_ALLOCATOR)
     686    bool           fFound  = false;
     687    uint32_t const cbChunk = pExecMemAllocator->cbChunk;
     688# ifndef IEMEXECMEM_ALT_SUB_WITH_ALLOC_HEADER
    619689    uint32_t const cChunks = pExecMemAllocator->cChunks;
    620     uint32_t const cbChunk = pExecMemAllocator->cbChunk;
    621     bool           fFound  = false;
    622690    for (uint32_t idxChunk = 0; idxChunk < cChunks; idxChunk++)
     691# endif
    623692    {
    624693        uintptr_t const offChunk = (uintptr_t)pv - (uintptr_t)pExecMemAllocator->aChunks[idxChunk].pvChunk;
     
    636705                AssertReturnVoid(ASMBitTest(pbmAlloc, idxFirst + i));
    637706            ASMBitClearRange(pbmAlloc, idxFirst, idxFirst + cReqUnits);
    638 
     707# ifdef IEMEXECMEM_ALT_SUB_WITH_ALLOC_HEADER
     708            pHdr->uMagic    = 0;
     709            pHdr->idxChunk  = 0;
     710            pHdr->pTb       = NULL;
     711# endif
    639712            pExecMemAllocator->aChunks[idxChunk].cFreeUnits  += cReqUnits;
    640713            pExecMemAllocator->aChunks[idxChunk].idxFreeHint  = idxFirst;
     
    738811    unsigned const cbNeededAligned  = RT_ALIGN_32(cbNeeded, IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE);
    739812    PIMAGE_RUNTIME_FUNCTION_ENTRY const paFunctions
    740         = (PIMAGE_RUNTIME_FUNCTION_ENTRY)iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbNeededAligned);
     813        = (PIMAGE_RUNTIME_FUNCTION_ENTRY)iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbNeededAligned, NULL);
    741814#  else
    742815    unsigned const cbNeededAligned  = RT_ALIGN_32(cbNeeded + pExecMemAllocator->cbHeapBlockHdr, 64)
     
    9821055#   ifdef IEMEXECMEM_USE_ALT_SUB_ALLOCATOR
    9831056    unsigned const cbNeededAligned = RT_ALIGN_32(cbNeeded, IEMEXECMEM_ALT_SUB_ALLOC_UNIT_SIZE);
    984     GDBJITSYMFILE * const pSymFile = (GDBJITSYMFILE *)iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk, cbNeededAligned);
     1057    GDBJITSYMFILE * const pSymFile = (GDBJITSYMFILE *)iemExecMemAllocatorAllocInChunk(pExecMemAllocator, idxChunk,
     1058                                                                                      cbNeededAligned, NULL);
    9851059#   else
    9861060    unsigned const cbNeededAligned = RT_ALIGN_32(cbNeeded + pExecMemAllocator->cbHeapBlockHdr, 64)
     
    15591633
    15601634    pExecMemAllocator->idxChunkHint = 0;
     1635
     1636    /*
     1637     * Register statistics.
     1638     */
     1639    PUVM const pUVM = pVCpu->pUVCpu->pUVM;
     1640    STAMR3RegisterFU(pUVM, &pExecMemAllocator->cAllocations,    STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
     1641                     "Current number of allocations",           "/IEM/CPU%u/re/ExecMem/cAllocations", pVCpu->idCpu);
     1642    STAMR3RegisterFU(pUVM, &pExecMemAllocator->cChunks,         STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
     1643                     "Currently allocated chunks",              "/IEM/CPU%u/re/ExecMem/cChunks", pVCpu->idCpu);
     1644    STAMR3RegisterFU(pUVM, &pExecMemAllocator->cMaxChunks,      STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
     1645                     "Maximum number of chunks",                "/IEM/CPU%u/re/ExecMem/cMaxChunks", pVCpu->idCpu);
     1646    STAMR3RegisterFU(pUVM, &pExecMemAllocator->cbChunk,         STAMTYPE_U32, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
     1647                     "Allocation chunk size",                   "/IEM/CPU%u/re/ExecMem/cbChunk", pVCpu->idCpu);
     1648    STAMR3RegisterFU(pUVM, &pExecMemAllocator->cbAllocated,     STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
     1649                     "Number of bytes current allocated",       "/IEM/CPU%u/re/ExecMem/cbAllocated", pVCpu->idCpu);
     1650    STAMR3RegisterFU(pUVM, &pExecMemAllocator->cbFree,          STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
     1651                     "Number of bytes current free",            "/IEM/CPU%u/re/ExecMem/cbFree", pVCpu->idCpu);
     1652    STAMR3RegisterFU(pUVM, &pExecMemAllocator->cbTotal,         STAMTYPE_U64, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES,
     1653                     "Total number of byte",                    "/IEM/CPU%u/re/ExecMem/cbTotal", pVCpu->idCpu);
     1654#ifdef VBOX_WITH_STATISTICS
     1655    STAMR3RegisterFU(pUVM, &pExecMemAllocator->StatAlloc,       STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
     1656                     "Profiling the allocator",                 "/IEM/CPU%u/re/ExecMem/ProfAlloc", pVCpu->idCpu);
     1657#endif
    15611658
    15621659    return VINF_SUCCESS;
     
    1070310800        iemTbAllocatorProcessDelayedFrees(pVCpu, pVCpu->iem.s.pTbAllocatorR3);
    1070410801
    10705     PIEMNATIVEINSTR const paFinalInstrBuf = (PIEMNATIVEINSTR)iemExecMemAllocatorAlloc(pVCpu, off * sizeof(IEMNATIVEINSTR));
     10802    PIEMNATIVEINSTR const paFinalInstrBuf = (PIEMNATIVEINSTR)iemExecMemAllocatorAlloc(pVCpu, off * sizeof(IEMNATIVEINSTR), pTb);
    1070610803    AssertReturn(paFinalInstrBuf, pTb);
    1070710804    memcpy(paFinalInstrBuf, pReNative->pInstrBuf, off * sizeof(paFinalInstrBuf[0]));
  • trunk/src/VBox/VMM/VMMR3/IEMR3.cpp

    r104095 r104108  
    396396# endif
    397397        STAMR3RegisterF(pVM, (void *)&pTbAllocator->StatPruneNative,    STAMTYPE_PROFILE,   STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL,
    398                         "Time spent freeing up native TBs when out of executable memory", "/IEM/CPU%u/re/TbPruningNative", idCpu);
     398                        "Time spent freeing up native TBs when out of executable memory", "/IEM/CPU%u/re/ExecMem/TbPruningNative", idCpu);
    399399        STAMR3RegisterF(pVM, (void *)&pTbAllocator->cAllocatedChunks,   STAMTYPE_U16,   STAMVISIBILITY_ALWAYS, STAMUNIT_COUNT,
    400400                        "Populated TB chunks",                          "/IEM/CPU%u/re/cTbChunks", idCpu);
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