VirtualBox

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


Ignore:
Timestamp:
Aug 14, 2023 12:37:33 PM (18 months ago)
Author:
vboxsync
Message:

VMM/IEM: Use a fixed maxed-out TB during threaded compilation and duplicate this into the resulting TB but with optimial table sizes. bugref:10369

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

Legend:

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

    r100803 r100869  
    458458 * Allocate a translation block for threadeded recompilation.
    459459 *
     460 * This is allocated with maxed out call table and storage for opcode bytes,
     461 * because it's only supposed to be called once per EMT to allocate the TB
     462 * pointed to by IEMCPU::pThrdCompileTbR3.
     463 *
    460464 * @returns Pointer to the translation block on success, NULL on failure.
    461465 * @param   pVM         The cross context virtual machine structure.
     
    467471static PIEMTB iemThreadedTbAlloc(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysPc, uint32_t fExtraFlags)
    468472{
    469     /*
    470      * Just using the heap for now.  Will make this more efficient and
    471      * complicated later, don't worry. :-)
    472      */
    473473    PIEMTB pTb = (PIEMTB)RTMemAlloc(sizeof(IEMTB));
    474474    if (pTb)
    475475    {
    476         unsigned const cCalls = 128;
     476        unsigned const cCalls = 256;
    477477        pTb->Thrd.paCalls = (PIEMTHRDEDCALLENTRY)RTMemAlloc(sizeof(IEMTHRDEDCALLENTRY) * cCalls);
    478478        if (pTb->Thrd.paCalls)
    479479        {
    480             pTb->pabOpcodes = (uint8_t *)RTMemAlloc(cCalls * 16); /* This will be reallocated later. */
     480            pTb->pabOpcodes = (uint8_t *)RTMemAlloc(cCalls * 16);
    481481            if (pTb->pabOpcodes)
    482482            {
     
    515515
    516516/**
    517  * Frees pTb.
    518  *
    519  * @param   pVM     The cross context virtual machine structure.
    520  * @param   pVCpu   The cross context virtual CPU structure of the calling
    521  *                  thread.
    522  * @param   pTb     The translation block to free..
    523  */
    524 static void iemThreadedTbFree(PVMCC pVM, PVMCPUCC pVCpu, PIEMTB pTb)
    525 {
     517 * Called on the TB that are dedicated for recompilation before it's reused.
     518 *
     519 * @param   pVCpu       The cross context virtual CPU structure of the calling
     520 *                      thread.
     521 * @param   pTb         The translation block to reuse.
     522 * @param   GCPhysPc    The physical address corresponding to RIP + CS.BASE.
     523 * @param   fExtraFlags Extra flags (IEMTB_F_XXX).
     524 */
     525static void iemThreadedTbReuse(PVMCPUCC pVCpu, PIEMTB pTb, RTGCPHYS GCPhysPc, uint32_t fExtraFlags)
     526{
     527    pTb->GCPhysPc               = GCPhysPc;
     528    pTb->fFlags                 = (pVCpu->iem.s.fExec & IEMTB_F_IEM_F_MASK) | fExtraFlags;
     529    pTb->x86.fAttr              = (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u;
     530    pTb->Thrd.cCalls            = 0;
     531    pTb->cbOpcodes              = 0;
     532    pTb->cInstructions          = 0;
     533
     534    /* Init the first opcode range. */
     535    pTb->cRanges                = 1;
     536    pTb->aRanges[0].cbOpcodes   = 0;
     537    pTb->aRanges[0].offOpcodes  = 0;
     538    pTb->aRanges[0].offPhysPage = GCPhysPc & GUEST_PAGE_OFFSET_MASK;
     539    pTb->aRanges[0].u2Unused    = 0;
     540    pTb->aRanges[0].idxPhysPage = 0;
     541    pTb->aGCPhysPages[0]        = NIL_RTGCPHYS;
     542    pTb->aGCPhysPages[1]        = NIL_RTGCPHYS;
     543}
     544
     545
     546/**
     547 * Used to duplicate a threded translation block after recompilation is done.
     548 *
     549 * @returns Pointer to the translation block on success, NULL on failure.
     550 * @param   pVM         The cross context virtual machine structure.
     551 * @param   pVCpu       The cross context virtual CPU structure of the calling
     552 *                      thread.
     553 * @param   pTbSrc      The TB to duplicate.
     554 */
     555static PIEMTB iemThreadedTbDuplicate(PVMCC pVM, PVMCPUCC pVCpu, PCIEMTB pTbSrc)
     556{
     557    /*
     558     * Just using the heap for now.  Will make this more efficient and
     559     * complicated later, don't worry. :-)
     560     */
     561    PIEMTB pTb = (PIEMTB)RTMemAlloc(sizeof(IEMTB));
     562    if (pTb)
     563    {
     564        memcpy(pTb, pTbSrc, sizeof(*pTb));
     565
     566        unsigned const cCalls = pTbSrc->Thrd.cCalls;
     567        Assert(cCalls > 0);
     568        pTb->Thrd.paCalls = (PIEMTHRDEDCALLENTRY)RTMemDup(pTbSrc->Thrd.paCalls, sizeof(IEMTHRDEDCALLENTRY) * cCalls);
     569        if (pTb->Thrd.paCalls)
     570        {
     571            unsigned const cbOpcodes = pTbSrc->cbOpcodes;
     572            Assert(cbOpcodes > 0);
     573            pTb->pabOpcodes = (uint8_t *)RTMemDup(pTbSrc->pabOpcodes, cbOpcodes);
     574            if (pTb->pabOpcodes)
     575            {
     576                pTb->Thrd.cAllocated        = cCalls;
     577                pTb->cbOpcodesAllocated     = cbOpcodes;
     578                pTb->pNext                  = NULL;
     579                RTListInit(&pTb->LocalList);
     580                pTb->fFlags                 = (pTbSrc->fFlags & ~IEMTB_F_STATE_MASK) | IEMTB_F_STATE_READY;
     581
     582                pVCpu->iem.s.cTbAllocs++;
     583                return pTb;
     584            }
     585            RTMemFree(pTb->Thrd.paCalls);
     586        }
     587        RTMemFree(pTb);
     588    }
    526589    RT_NOREF(pVM);
    527     AssertPtr(pTb);
    528 
    529     AssertCompile(IEMTB_F_STATE_OBSOLETE == IEMTB_F_STATE_MASK);
    530     pTb->fFlags |= IEMTB_F_STATE_OBSOLETE; /* works, both bits set */
    531 
    532     /* Unlink it from the hash table: */
    533     uint32_t const idxHash = IEMTBCACHE_HASH(&g_TbCache, pTb->fFlags, pTb->GCPhysPc);
    534     PIEMTB pTbCur = g_TbCache.apHash[idxHash];
    535     if (pTbCur == pTb)
    536         g_TbCache.apHash[idxHash] = pTb->pNext;
    537     else
    538         while (pTbCur)
    539         {
    540             PIEMTB const pNextTb = pTbCur->pNext;
    541             if (pNextTb == pTb)
    542             {
    543                 pTbCur->pNext = pTb->pNext;
    544                 break;
    545             }
    546             pTbCur = pNextTb;
    547         }
    548 
    549     /* Free it. */
    550     RTMemFree(pTb->Thrd.paCalls);
    551     pTb->Thrd.paCalls = NULL;
    552 
    553     RTMemFree(pTb->pabOpcodes);
    554     pTb->pabOpcodes = NULL;
    555 
    556     RTMemFree(pTb);
    557     pVCpu->iem.s.cTbFrees++;
     590    return NULL;
     591
    558592}
    559593
    560594
    561595/**
    562  * Called by opcode verifier functions when they detect a problem.
    563  */
    564 void iemThreadedTbObsolete(PVMCPUCC pVCpu, PIEMTB pTb)
    565 {
    566     iemThreadedTbFree(pVCpu->CTX_SUFF(pVM), pVCpu, pTb);
    567 }
    568 
    569 
    570 static PIEMTB iemThreadedTbLookup(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysPc, uint32_t fExtraFlags) IEM_NOEXCEPT_MAY_LONGJMP
    571 {
    572     uint32_t const fFlags  = (pVCpu->iem.s.fExec & IEMTB_F_IEM_F_MASK) | fExtraFlags | IEMTB_F_STATE_READY;
    573     uint32_t const idxHash = IEMTBCACHE_HASH(&g_TbCache, fFlags, GCPhysPc);
    574     Log10(("TB lookup: idxHash=%#x fFlags=%#x GCPhysPc=%RGp\n", idxHash, fFlags, GCPhysPc));
    575     PIEMTB pTb = g_TbCache.apHash[idxHash];
    576     while (pTb)
    577     {
    578         if (pTb->GCPhysPc == GCPhysPc)
    579         {
    580             if (pTb->fFlags == fFlags)
    581             {
    582                 if (pTb->x86.fAttr == (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u)
    583                 {
    584 #ifdef VBOX_WITH_STATISTICS
    585                     pVCpu->iem.s.cTbLookupHits++;
    586 #endif
    587                     return pTb;
    588                 }
    589                 Log11(("TB miss: CS: %#x, wanted %#x\n", pTb->x86.fAttr, (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u));
    590             }
    591             else
    592                 Log11(("TB miss: fFlags: %#x, wanted %#x\n", pTb->fFlags, fFlags));
    593         }
    594         else
    595             Log11(("TB miss: GCPhysPc: %#x, wanted %#x\n", pTb->GCPhysPc, GCPhysPc));
    596 
    597         pTb = pTb->pNext;
    598     }
    599     RT_NOREF(pVM);
    600     pVCpu->iem.s.cTbLookupMisses++;
    601     return pTb;
    602 }
    603 
    604 
     596 * Adds the given TB to the hash table.
     597 *
     598 * @param   pVM         The cross context virtual machine structure.
     599 * @param   pVCpu       The cross context virtual CPU structure of the calling
     600 *                      thread.
     601 * @param   pTb         The translation block to add.
     602 */
    605603static void iemThreadedTbAdd(PVMCC pVM, PVMCPUCC pVCpu, PIEMTB pTb)
    606604{
     
    622620    }
    623621    RT_NOREF(pVM);
     622}
     623
     624
     625/**
     626 * Frees the given TB.
     627 *
     628 * @param   pVM     The cross context virtual machine structure.
     629 * @param   pVCpu   The cross context virtual CPU structure of the calling
     630 *                  thread.
     631 * @param   pTb     The translation block to free..
     632 */
     633static void iemThreadedTbFree(PVMCC pVM, PVMCPUCC pVCpu, PIEMTB pTb)
     634{
     635    RT_NOREF(pVM);
     636    AssertPtr(pTb);
     637
     638    AssertCompile(IEMTB_F_STATE_OBSOLETE == IEMTB_F_STATE_MASK);
     639    pTb->fFlags |= IEMTB_F_STATE_OBSOLETE; /* works, both bits set */
     640
     641    /* Unlink it from the hash table: */
     642    uint32_t const idxHash = IEMTBCACHE_HASH(&g_TbCache, pTb->fFlags, pTb->GCPhysPc);
     643    PIEMTB pTbCur = g_TbCache.apHash[idxHash];
     644    if (pTbCur == pTb)
     645        g_TbCache.apHash[idxHash] = pTb->pNext;
     646    else
     647        while (pTbCur)
     648        {
     649            PIEMTB const pNextTb = pTbCur->pNext;
     650            if (pNextTb == pTb)
     651            {
     652                pTbCur->pNext = pTb->pNext;
     653                break;
     654            }
     655            pTbCur = pNextTb;
     656        }
     657
     658    /* Free it. */
     659    RTMemFree(pTb->Thrd.paCalls);
     660    pTb->Thrd.paCalls = NULL;
     661
     662    RTMemFree(pTb->pabOpcodes);
     663    pTb->pabOpcodes = NULL;
     664
     665    RTMemFree(pTb);
     666    pVCpu->iem.s.cTbFrees++;
     667}
     668
     669
     670/**
     671 * Called by opcode verifier functions when they detect a problem.
     672 */
     673void iemThreadedTbObsolete(PVMCPUCC pVCpu, PIEMTB pTb)
     674{
     675    iemThreadedTbFree(pVCpu->CTX_SUFF(pVM), pVCpu, pTb);
     676}
     677
     678
     679static PIEMTB iemThreadedTbLookup(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhysPc, uint32_t fExtraFlags) IEM_NOEXCEPT_MAY_LONGJMP
     680{
     681    uint32_t const fFlags  = (pVCpu->iem.s.fExec & IEMTB_F_IEM_F_MASK) | fExtraFlags | IEMTB_F_STATE_READY;
     682    uint32_t const idxHash = IEMTBCACHE_HASH(&g_TbCache, fFlags, GCPhysPc);
     683    Log10(("TB lookup: idxHash=%#x fFlags=%#x GCPhysPc=%RGp\n", idxHash, fFlags, GCPhysPc));
     684    PIEMTB pTb = g_TbCache.apHash[idxHash];
     685    while (pTb)
     686    {
     687        if (pTb->GCPhysPc == GCPhysPc)
     688        {
     689            if (pTb->fFlags == fFlags)
     690            {
     691                if (pTb->x86.fAttr == (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u)
     692                {
     693#ifdef VBOX_WITH_STATISTICS
     694                    pVCpu->iem.s.cTbLookupHits++;
     695#endif
     696                    return pTb;
     697                }
     698                Log11(("TB miss: CS: %#x, wanted %#x\n", pTb->x86.fAttr, (uint16_t)pVCpu->cpum.GstCtx.cs.Attr.u));
     699            }
     700            else
     701                Log11(("TB miss: fFlags: %#x, wanted %#x\n", pTb->fFlags, fFlags));
     702        }
     703        else
     704            Log11(("TB miss: GCPhysPc: %#x, wanted %#x\n", pTb->GCPhysPc, GCPhysPc));
     705
     706        pTb = pTb->pNext;
     707    }
     708    RT_NOREF(pVM);
     709    pVCpu->iem.s.cTbLookupMisses++;
     710    return pTb;
    624711}
    625712
     
    13621449{
    13631450    /*
    1364      * Allocate a new translation block.
    1365      */
    1366     PIEMTB pTb = iemThreadedTbAlloc(pVM, pVCpu, GCPhysPc, fExtraFlags | IEMTB_F_STATE_COMPILING);
    1367     AssertReturn(pTb, VERR_IEM_TB_ALLOC_FAILED);
     1451     * Get the TB we use for the recompiling.  This is a maxed-out TB so
     1452     * that'll we'll make a more efficient copy of when we're done compiling.
     1453     */
     1454    PIEMTB pTb = pVCpu->iem.s.pThrdCompileTbR3;
     1455    if (pTb)
     1456        iemThreadedTbReuse(pVCpu, pTb, GCPhysPc, fExtraFlags | IEMTB_F_STATE_COMPILING);
     1457    else
     1458    {
     1459        pTb = iemThreadedTbAlloc(pVM, pVCpu, GCPhysPc, fExtraFlags | IEMTB_F_STATE_COMPILING);
     1460        AssertReturn(pTb, VERR_IEM_TB_ALLOC_FAILED);
     1461        pVCpu->iem.s.pThrdCompileTbR3 = pTb;
     1462    }
    13681463
    13691464    /* Set the current TB so iemThreadedCompileLongJumped and the CIMPL
     
    14211516
    14221517            pVCpu->iem.s.pCurTbR3 = NULL;
    1423             iemThreadedTbFree(pVM, pVCpu, pTb);
    14241518            return iemExecStatusCodeFiddling(pVCpu, rcStrict);
    14251519        }
     
    14451539
    14461540    /*
    1447      * Complete the TB and link it.
    1448      */
    1449     pTb->fFlags = (pTb->fFlags & ~IEMTB_F_STATE_MASK) | IEMTB_F_STATE_READY;
     1541     * Duplicate the TB into a completed one and link it.
     1542     */
     1543    pTb = iemThreadedTbDuplicate(pVM, pVCpu, pTb);
     1544    AssertReturn(pTb, VERR_IEM_TB_ALLOC_FAILED);
     1545
    14501546    iemThreadedTbAdd(pVM, pVCpu, pTb);
    14511547
  • trunk/src/VBox/VMM/include/IEMInternal.h

    r100863 r100869  
    11771177     * This can either be one being executed or one being compiled. */
    11781178    R3PTRTYPE(PIEMTB)       pCurTbR3;
     1179    /** Fixed TB used for threaded recompilation.
     1180     * This is allocated once with maxed-out sizes and re-used afterwards. */
     1181    R3PTRTYPE(PIEMTB)       pThrdCompileTbR3;
     1182    /** Fixed TB used for native recompilation.
     1183     * This is allocated once and re-used afterwards, growing individual
     1184     * components as needed. */
     1185    R3PTRTYPE(PIEMTB)       pNativeCompileTbR3;
    11791186    /** The PC (RIP) at the start of pCurTbR3/pCurTbR0.
    11801187     * The TBs are based on physical addresses, so this is needed to correleated
    11811188     * RIP to opcode bytes stored in the TB (AMD-V / VT-x). */
    11821189    uint64_t                uCurTbStartPc;
    1183     /** Statistics: Number of TB allocation calls. */
    1184     uint64_t                cTbAllocs;
    1185     /** Statistics: Number of TB free calls. */
    1186     uint64_t                cTbFrees;
    11871190    /** Statistics: Number of TB lookup misses. */
    11881191    uint64_t                cTbLookupMisses;
     
    12221225    uint64_t                GCVirtTbBranchSrcBuf;
    12231226    /* Alignment. */
     1227    uint64_t                auAlignment10[6];
     1228    /** Statistics: Number of TB allocation calls. */
     1229    uint64_t                cTbAllocs;
     1230    /** Statistics: Number of TB free calls. */
     1231    uint64_t                cTbFrees;
    12241232    /** Statistics: Times TB execution was broken off before reaching the end. */
    12251233    STAMCOUNTER             StatTbExecBreaks;
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