VirtualBox

Changeset 92499 in vbox


Ignore:
Timestamp:
Nov 18, 2021 4:07:42 PM (3 years ago)
Author:
vboxsync
Message:

VMM/NEMR3Native-darwin.cpp: Fix TPR shadowing configuration (huge speedup for Windows 10 guests) and add some statistics, bugref:9044

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/NEMR3Native-darwin.cpp

    r92475 r92499  
    818818    } while(0)
    819819
     820    STAM_PROFILE_ADV_START(&pVCpu->nem.s.StatProfGstStateImport, x);
     821
    820822    RT_NOREF(pVM);
    821823    fWhat &= pVCpu->cpum.GstCtx.fExtrn;
     
    960962        }
    961963    }
     964
     965#if 0 /* Always done. */
    962966    if (fWhat & CPUMCTX_EXTRN_APIC_TPR)
    963967    {
     
    967971        APICSetTpr(pVCpu, u64Cr8 << 4);
    968972    }
     973#endif
     974
    969975    if (fWhat & CPUMCTX_EXTRN_XCRx)
    970976        READ_GREG(HV_X86_XCR0, pVCpu->cpum.GstCtx.aXcr[0]);
     
    10101016        { /* likely */ }
    10111017        else
     1018        {
     1019            STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
    10121020            return nemR3DarwinHvSts2Rc(hrc);
     1021        }
    10131022    }
    10141023
     
    10951104    /* Typical. */
    10961105    if (!fMaybeChangedMode && !fUpdateCr3)
     1106    {
     1107        STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
    10971108        return VINF_SUCCESS;
     1109    }
    10981110
    10991111    /*
     
    11141126            AssertMsgFailedReturn(("rc=%Rrc\n", rc), RT_FAILURE_NP(rc) ? rc : VERR_NEM_IPE_2);
    11151127    }
     1128
     1129    STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateImport, x);
    11161130
    11171131    return VINF_SUCCESS;
     
    15511565#endif
    15521566
     1567    STAM_PROFILE_ADV_START(&pVCpu->nem.s.StatProfGstStateExport, x);
     1568
    15531569    uint64_t const fWhat = ~pVCpu->cpum.GstCtx.fExtrn & CPUMCTX_EXTRN_ALL;
    15541570    if (!fWhat)
     
    15911607    if (fWhat & CPUMCTX_EXTRN_APIC_TPR)
    15921608    {
    1593         WRITE_GREG(HV_X86_TPR, CPUMGetGuestCR8(pVCpu));
     1609        Assert(pVCpu->nem.s.fCtxChanged & HM_CHANGED_GUEST_APIC_TPR);
     1610        vmxHCExportGuestApicTpr(pVCpu, pVmxTransient);
     1611
     1612        rc = APICGetTpr(pVCpu, &pVmxTransient->u8GuestTpr, NULL /*pfPending*/, NULL /*pu8PendingIntr*/);
     1613        AssertRC(rc);
     1614
     1615        WRITE_GREG(HV_X86_TPR, pVmxTransient->u8GuestTpr);
    15941616        ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_APIC_TPR);
    15951617    }
     
    16541676    if (fWhat & CPUMCTX_EXTRN_OTHER_MSRS)
    16551677    {
     1678#if 0
    16561679        hv_return_t hrc = hv_vmx_vcpu_set_apic_address(pVCpu->nem.s.hVCpuId, APICGetBaseMsrNoCheck(pVCpu) & PAGE_BASE_GC_MASK);
    16571680        if (RT_UNLIKELY(hrc != HV_SUCCESS))
    16581681            return nemR3DarwinHvSts2Rc(hrc);
     1682#endif
    16591683
    16601684        ASMAtomicUoAndU64(&pVCpu->nem.s.fCtxChanged, ~HM_CHANGED_GUEST_OTHER_MSRS);
     
    17051729                                                   | (HM_CHANGED_KEEPER_STATE_MASK & ~HM_CHANGED_VMX_MASK)));
    17061730
     1731    STAM_PROFILE_ADV_STOP(&pVCpu->nem.s.StatProfGstStateExport, x);
    17071732    return VINF_SUCCESS;
    17081733#undef WRITE_GREG
     
    17391764    rc = nemR3DarwinCopyStateFromHv(pVM, pVCpu, CPUMCTX_EXTRN_ALL);
    17401765    AssertRCReturn(rc, rc);
     1766
     1767    STAM_COUNTER_INC(&pVCpu->nem.s.pVmxStats->aStatExitReason[pVmxTransient->uExitReason & MASK_EXITREASON_STAT]);
     1768    STAM_REL_COUNTER_INC(&pVCpu->nem.s.pVmxStats->StatExitAll);
    17411769
    17421770#ifndef HMVMX_USE_FUNCTION_TABLE
     
    21412169    }
    21422170
    2143     /* Use TPR shadowing if supported by the CPU. */
    2144     if (   PDMHasApic(pVM)
    2145         && (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
    2146     {
    2147         fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW;                /* CR8 reads from the Virtual-APIC page. */
    2148                                                              /* CR8 writes cause a VM-exit based on TPR threshold. */
    2149         Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
    2150         Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
    2151     }
    2152     else
    2153     {
    2154         fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT             /* CR8 reads cause a VM-exit. */
    2155              |  VMX_PROC_CTLS_CR8_LOAD_EXIT;             /* CR8 writes cause a VM-exit. */
    2156     }
    2157 
    21582171    /* Use the secondary processor-based VM-execution controls if supported by the CPU. */
    21592172    if (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_SECONDARY_CTLS)
     
    23032316
    23042317/**
     2318 * Registers statistics for the given vCPU.
     2319 *
     2320 * @returns VBox status code.
     2321 * @param   pVM             The cross context VM structure.
     2322 * @param   idCpu           The CPU ID.
     2323 * @param   pNemCpu         The NEM CPU structure.
     2324 */
     2325static int nemR3DarwinStatisticsRegister(PVM pVM, VMCPUID idCpu, PNEMCPU pNemCpu)
     2326{
     2327#define NEM_REG_STAT(a_pVar, a_enmType, s_enmVisibility, a_enmUnit, a_szNmFmt, a_szDesc) do { \
     2328                int rc = STAMR3RegisterF(pVM, a_pVar, a_enmType, s_enmVisibility, a_enmUnit, a_szDesc, a_szNmFmt, idCpu); \
     2329                AssertRC(rc); \
     2330            } while (0)
     2331#define NEM_REG_PROFILE(a_pVar, a_szNmFmt, a_szDesc) \
     2332           NEM_REG_STAT(a_pVar, STAMTYPE_PROFILE, STAMVISIBILITY_USED, STAMUNIT_TICKS_PER_CALL, a_szNmFmt, a_szDesc)
     2333#define NEM_REG_COUNTER(a, b, desc) NEM_REG_STAT(a, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, b, desc)
     2334
     2335    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR0Read,  "/NEM/CPU%u/Exit/Instr/CR-Read/CR0", "CR0 read.");
     2336    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR2Read,  "/NEM/CPU%u/Exit/Instr/CR-Read/CR2", "CR2 read.");
     2337    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR3Read,  "/NEM/CPU%u/Exit/Instr/CR-Read/CR3", "CR3 read.");
     2338    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR4Read,  "/NEM/CPU%u/Exit/Instr/CR-Read/CR4", "CR4 read.");
     2339    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR8Read,  "/NEM/CPU%u/Exit/Instr/CR-Read/CR8", "CR8 read.");
     2340    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR0Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR0", "CR0 write.");
     2341    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR2Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR2", "CR2 write.");
     2342    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR3Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR3", "CR3 write.");
     2343    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR4Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR4", "CR4 write.");
     2344    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitCR8Write, "/NEM/CPU%u/Exit/Instr/CR-Write/CR8", "CR8 write.");
     2345
     2346    NEM_REG_COUNTER(&pNemCpu->pVmxStats->StatExitAll, "/NEM/CPU%u/Exit/All",         "Total exits (including nested-guest exits).");
     2347
     2348#ifdef VBOX_WITH_STATISTICS
     2349    NEM_REG_PROFILE(&pNemCpu->StatProfGstStateImport, "/NEM/CPU%u/ImportGuestState", "Profiling of importing guest state from hardware after VM-exit.");
     2350    NEM_REG_PROFILE(&pNemCpu->StatProfGstStateExport, "/NEM/CPU%u/ExportGuestState", "Profiling of exporting guest state from hardware after VM-exit.");
     2351
     2352    for (int j = 0; j < MAX_EXITREASON_STAT; j++)
     2353    {
     2354        const char *pszExitName = HMGetVmxExitName(j);
     2355        if (pszExitName)
     2356        {
     2357            int rc = STAMR3RegisterF(pVM, &pNemCpu->pVmxStats->aStatExitReason[j], STAMTYPE_COUNTER, STAMVISIBILITY_USED,
     2358                                     STAMUNIT_OCCURENCES, pszExitName, "/NEM/CPU%u/Exit/Reason/%02x", idCpu, j);
     2359            AssertRCReturn(rc, rc);
     2360        }
     2361    }
     2362#endif
     2363
     2364    return VINF_SUCCESS;
     2365
     2366#undef NEM_REG_COUNTER
     2367#undef NEM_REG_PROFILE
     2368#undef NEM_REG_STAT
     2369}
     2370
     2371
     2372/**
    23052373 * Try initialize the native API.
    23062374 *
     
    23542422                PVMXSTATISTICS pVmxStats = (PVMXSTATISTICS)RTMemAllocZ(sizeof(*pVmxStats));
    23552423                if (RT_LIKELY(pVmxStats))
     2424                {
    23562425                        pNemCpu->pVmxStats = pVmxStats;
     2426                        rc = nemR3DarwinStatisticsRegister(pVM, idCpu, pNemCpu);
     2427                        AssertRC(rc);
     2428                }
    23572429                else
    23582430                {
     
    24432515
    24442516/**
     2517 * Worker to setup the TPR shadowing feature if available on the CPU and the VM has an APIC enabled.
     2518 *
     2519 * @returns VBox status code
     2520 * @param   pVM                 The VM handle.
     2521 * @param   pVCpu               The vCPU handle.
     2522 * @param   idCpu               ID of the CPU to create.
     2523 */
     2524static DECLCALLBACK(int) nemR3DarwinNativeInitTprShadowing(PVM pVM, PVMCPU pVCpu, VMCPUID idCpu)
     2525{
     2526    PVMXVMCSINFO pVmcsInfo = &pVCpu->nem.s.VmcsInfo;
     2527    uint32_t fVal = pVmcsInfo->u32ProcCtls;
     2528
     2529    /* Use TPR shadowing if supported by the CPU. */
     2530    if (   PDMHasApic(pVM)
     2531        && (g_HmMsrs.u.vmx.ProcCtls.n.allowed1 & VMX_PROC_CTLS_USE_TPR_SHADOW))
     2532    {
     2533        fVal |= VMX_PROC_CTLS_USE_TPR_SHADOW;                /* CR8 reads from the Virtual-APIC page. */
     2534                                                             /* CR8 writes cause a VM-exit based on TPR threshold. */
     2535        Assert(!(fVal & VMX_PROC_CTLS_CR8_STORE_EXIT));
     2536        Assert(!(fVal & VMX_PROC_CTLS_CR8_LOAD_EXIT));
     2537    }
     2538    else
     2539    {
     2540        fVal |= VMX_PROC_CTLS_CR8_STORE_EXIT             /* CR8 reads cause a VM-exit. */
     2541             |  VMX_PROC_CTLS_CR8_LOAD_EXIT;             /* CR8 writes cause a VM-exit. */
     2542    }
     2543
     2544    /* Commit it to the VMCS and update our cache. */
     2545    int rc = nemR3DarwinWriteVmcs32(pVCpu, VMX_VMCS32_CTRL_PROC_EXEC, fVal);
     2546    AssertRC(rc);
     2547    pVmcsInfo->u32ProcCtls = fVal;
     2548
     2549    return VINF_SUCCESS;
     2550}
     2551
     2552
     2553/**
    24452554 * This is called after CPUMR3Init is done.
    24462555 *
     
    24812590int nemR3NativeInitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
    24822591{
    2483     NOREF(pVM); NOREF(enmWhat);
     2592    if (enmWhat == VMINITCOMPLETED_RING3)
     2593    {
     2594        /* Now that PDM is initialized the APIC state is known in order to enable the TPR shadowing feature on all EMTs. */
     2595        for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++)
     2596        {
     2597            PVMCPU pVCpu = pVM->apCpusR3[idCpu];
     2598
     2599            int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)nemR3DarwinNativeInitTprShadowing, 3, pVM, pVCpu, idCpu);
     2600            if (RT_FAILURE(rc))
     2601                return VMSetError(pVM, VERR_NEM_VM_CREATE_FAILED, RT_SRC_POS, "Call to hv_vcpu_create failed: %Rrc", rc);
     2602        }
     2603    }
    24842604    return VINF_SUCCESS;
    24852605}
     
    26582778            && !VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_HM_TO_R3_MASK))
    26592779        {
    2660             if (VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM_WAIT, VMCPUSTATE_STARTED_EXEC_NEM))
     2780            LogFlowFunc(("Running vCPU\n"));
     2781            pVCpu->nem.s.Event.fPending = false;
     2782
     2783            TMNotifyStartOfExecution(pVM, pVCpu);
     2784
     2785            Assert(!pVCpu->nem.s.fCtxChanged);
     2786            hv_return_t hrc;
     2787            if (hv_vcpu_run_until)
     2788                hrc = hv_vcpu_run_until(pVCpu->nem.s.hVCpuId, HV_DEADLINE_FOREVER);
     2789            else
     2790                hrc = hv_vcpu_run(pVCpu->nem.s.hVCpuId);
     2791
     2792            TMNotifyEndOfExecution(pVM, pVCpu, ASMReadTSC());
     2793
     2794            /*
     2795             * Sync the TPR shadow with our APIC state.
     2796             */
     2797            if (   !VmxTransient.fIsNestedGuest
     2798                && (pVCpu->nem.s.VmcsInfo.u32ProcCtls & VMX_PROC_CTLS_USE_TPR_SHADOW))
    26612799            {
    2662                 LogFlowFunc(("Running vCPU\n"));
    2663                 pVCpu->nem.s.Event.fPending = false;
    2664 
    2665                 TMNotifyStartOfExecution(pVM, pVCpu);
    2666 
    2667                 Assert(!pVCpu->nem.s.fCtxChanged);
    2668                 hv_return_t hrc;
    2669                 if (hv_vcpu_run_until)
    2670                     hrc = hv_vcpu_run_until(pVCpu->nem.s.hVCpuId, HV_DEADLINE_FOREVER);
    2671                 else
    2672                     hrc = hv_vcpu_run(pVCpu->nem.s.hVCpuId);
    2673 
    2674                 VMCPU_CMPXCHG_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC_NEM, VMCPUSTATE_STARTED_EXEC_NEM_WAIT);
    2675                 TMNotifyEndOfExecution(pVM, pVCpu, ASMReadTSC());
    2676 
    2677                 if (hrc == HV_SUCCESS)
     2800                uint64_t u64Tpr;
     2801                hrc = hv_vcpu_read_register(pVCpu->nem.s.hVCpuId, HV_X86_TPR, &u64Tpr);
     2802                Assert(hrc == HV_SUCCESS);
     2803
     2804                if (VmxTransient.u8GuestTpr != (uint8_t)u64Tpr)
    26782805                {
    2679                     /*
    2680                      * Deal with the message.
    2681                      */
    2682                     rcStrict = nemR3DarwinHandleExit(pVM, pVCpu, &VmxTransient);
    2683                     if (rcStrict == VINF_SUCCESS)
    2684                     { /* hopefully likely */ }
    2685                     else
    2686                     {
    2687                         LogFlow(("NEM/%u: breaking: nemR3DarwinHandleExit -> %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict) ));
    2688                         STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnStatus);
    2689                         break;
    2690                     }
    2691                     //Assert(!pVCpu->cpum.GstCtx.fExtrn);
     2806                    rc = APICSetTpr(pVCpu, (uint8_t)u64Tpr);
     2807                    AssertRC(rc);
     2808                    ASMAtomicUoOrU64(&pVCpu->nem.s.fCtxChanged, HM_CHANGED_GUEST_APIC_TPR);
    26922809                }
     2810            }
     2811
     2812            if (hrc == HV_SUCCESS)
     2813            {
     2814                /*
     2815                 * Deal with the message.
     2816                 */
     2817                rcStrict = nemR3DarwinHandleExit(pVM, pVCpu, &VmxTransient);
     2818                if (rcStrict == VINF_SUCCESS)
     2819                { /* hopefully likely */ }
    26932820                else
    26942821                {
    2695                     AssertLogRelMsgFailedReturn(("hv_vcpu_run()) failed for CPU #%u: %#x %u\n",
    2696                                                 pVCpu->idCpu, hrc, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)),
    2697                                                 VERR_NEM_IPE_0);
     2822                    LogFlow(("NEM/%u: breaking: nemR3DarwinHandleExit -> %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict) ));
     2823                    STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnStatus);
     2824                    break;
    26982825                }
    2699 
    2700                 /*
    2701                  * If no relevant FFs are pending, loop.
    2702                  */
    2703                 if (   !VM_FF_IS_ANY_SET(   pVM,   !fSingleStepping ? VM_FF_HP_R0_PRE_HM_MASK    : VM_FF_HP_R0_PRE_HM_STEP_MASK)
    2704                     && !VMCPU_FF_IS_ANY_SET(pVCpu, !fSingleStepping ? VMCPU_FF_HP_R0_PRE_HM_MASK : VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
    2705                     continue;
    2706 
    2707                 /** @todo Try handle pending flags, not just return to EM loops.  Take care
    2708                  *        not to set important RCs here unless we've handled a message. */
    2709                 LogFlow(("NEM/%u: breaking: pending FF (%#x / %#RX64)\n",
    2710                          pVCpu->idCpu, pVM->fGlobalForcedActions, (uint64_t)pVCpu->fLocalForcedActions));
    2711                 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnFFPost);
     2826                //Assert(!pVCpu->cpum.GstCtx.fExtrn);
    27122827            }
    27132828            else
    27142829            {
    2715                 LogFlow(("NEM/%u: breaking: canceled %d (pre exec)\n", pVCpu->idCpu, VMCPU_GET_STATE(pVCpu) ));
    2716                 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnCancel);
     2830                AssertLogRelMsgFailedReturn(("hv_vcpu_run()) failed for CPU #%u: %#x %u\n",
     2831                                            pVCpu->idCpu, hrc, vmxHCCheckGuestState(pVCpu, &pVCpu->nem.s.VmcsInfo)),
     2832                                            VERR_NEM_IPE_0);
    27172833            }
     2834
     2835            /*
     2836             * If no relevant FFs are pending, loop.
     2837             */
     2838            if (   !VM_FF_IS_ANY_SET(   pVM,   !fSingleStepping ? VM_FF_HP_R0_PRE_HM_MASK    : VM_FF_HP_R0_PRE_HM_STEP_MASK)
     2839                && !VMCPU_FF_IS_ANY_SET(pVCpu, !fSingleStepping ? VMCPU_FF_HP_R0_PRE_HM_MASK : VMCPU_FF_HP_R0_PRE_HM_STEP_MASK) )
     2840                continue;
     2841
     2842            /** @todo Try handle pending flags, not just return to EM loops.  Take care
     2843             *        not to set important RCs here unless we've handled a message. */
     2844            LogFlow(("NEM/%u: breaking: pending FF (%#x / %#RX64)\n",
     2845                     pVCpu->idCpu, pVM->fGlobalForcedActions, (uint64_t)pVCpu->fLocalForcedActions));
     2846            STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnFFPost);
    27182847        }
    27192848        else
     
    29263055                                               void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange)
    29273056{
    2928     RT_NOREF(pVM);
     3057    RT_NOREF(pVM, puNemRange);
    29293058
    29303059    Log5(("NEMR3NotifyPhysMmioExUnmap: %RGp LB %RGp fFlags=%#x pvRam=%p pvMmio2=%p pu2State=%p uNemRange=%#x (%#x)\n",
  • trunk/src/VBox/VMM/include/NEMInternal.h

    r92495 r92499  
    559559    /** @name Statistics
    560560     * @{ */
     561    STAMCOUNTER                 StatExitAll;
    561562    STAMCOUNTER                 StatBreakOnCancel;
    562563    STAMCOUNTER                 StatBreakOnFFPre;
     
    567568    STAMCOUNTER                 StatImportOnReturnSkipped;
    568569    STAMCOUNTER                 StatQueryCpuTick;
     570#ifdef VBOX_WITH_STATISTICS
     571    STAMPROFILEADV              StatProfGstStateImport;
     572    STAMPROFILEADV              StatProfGstStateExport;
     573#endif
    569574    /** @} */
    570575
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