VirtualBox

Changeset 54257 in vbox


Ignore:
Timestamp:
Feb 17, 2015 11:24:45 PM (10 years ago)
Author:
vboxsync
Message:

SUPReadTscWithDelta: Optimized via fGetGipCpu and more.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPLibAll.cpp

    r54226 r54257  
    2929*******************************************************************************/
    3030#include <VBox/sup.h>
     31#ifdef IN_RC
     32# include <VBox/vmm/vm.h>
     33# include <VBox/vmm/vmm.h>
     34#endif
    3135#ifdef IN_RING0
    3236# include <iprt/mp.h>
     
    5458SUPDECL(uint64_t) SUPReadTscWithDelta(void)
    5559{
    56     PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
     60    PSUPGLOBALINFOPAGE  pGip = g_pSUPGlobalInfoPage;
     61    uint64_t            uTsc;
     62    uint16_t            iGipCpu;
     63    AssertCompile(RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS));
     64    AssertCompile(RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx) >= RTCPUSET_MAX_CPUS);
    5765    Assert(GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));
    5866
    59     /** @todo Check out the rdtscp optimization, ASMGetApicId is very expensive. */
     67    /*
     68     * Read the TSC and get the corresponding aCPUs index.
     69     */
     70    if (pGip->fGetGipCpu & SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS)
     71    {
     72        /* RDTSCP gives us all we need, no loops/cli. */
     73        uint32_t iCpuSet;
     74        uTsc      = ASMReadTscWithAux(&iCpuSet);
     75        iCpuSet  &= RTCPUSET_MAX_CPUS - 1;
     76        iGipCpu   = pGip->aiCpuFromCpuSetIdx[iCpuSet];
     77    }
     78# ifndef IN_RING0
     79    else if (pGip->fGetGipCpu & SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS)
     80    {
     81        /* Storing the IDTR is normally very quick, but we need to loop. */
     82        uint32_t cTries = 0;
     83        for (;;)
     84        {
     85            uint16_t cbLim = ASMGetIdtrLimit();
     86            uTsc = ASMReadTSC();
     87            if (RT_LIKELY(ASMGetIdtrLimit() == cbLim))
     88            {
     89                uint16_t iCpuSet = cbLim - 256 * (ARCH_BITS == 64 ? 16 : 8);
     90                iCpuSet &= RTCPUSET_MAX_CPUS - 1;
     91                iGipCpu  = pGip->aiCpuFromCpuSetIdx[iCpuSet];
     92                break;
     93            }
     94            if (cTries >= 16)
     95            {
     96                iGipCpu = UINT16_MAX;
     97                break;
     98            }
     99            cTries++;
     100        }
     101    }
     102# endif /* !IN_RING0 */
     103    else
     104    {
     105# ifdef IN_RING3
     106        /* Ring-3: Get APIC ID via the slow CPUID instruction, requires looping. */
     107        uint32_t cTries = 0;
     108        for (;;)
     109        {
     110            uint8_t idApic = ASMGetApicId();
     111            uTsc = ASMReadTSC();
     112            if (RT_LIKELY(ASMGetApicId() == idApic))
     113            {
     114                iGipCpu = pGip->aiCpuFromApicId[idApic];
     115                break;
     116            }
     117            if (cTries >= 16)
     118            {
     119                iGipCpu = UINT16_MAX;
     120                break;
     121            }
     122            cTries++;
     123        }
     124
     125# elif defined(IN_RING0)
     126        /* Ring-0: Use use RTMpCpuId(), no loops. */
     127        RTCCUINTREG uFlags  = ASMIntDisableFlags();
     128        int         iCpuSet = RTMpCpuIdToSetIndex(RTMpCpuId());
     129        if (RT_LIKELY((unsigned)iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)))
     130            iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet];
     131        else
     132            iGipCpu = UINT16_MAX;
     133        uTsc = ASMReadTSC();
     134        ASMSetFlags(uFlags);
     135
     136# elif defined(IN_RC)
     137        /* Raw-mode context: We can get the host CPU set index via VMCPU, no loops. */
     138        RTCCUINTREG uFlags  = ASMIntDisableFlags(); /* Are already disable, but play safe. */
     139        uint32_t    iCpuSet = VMMGetCpu(&g_VM)->iHostCpuSet;
     140        if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)))
     141            iGipCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet];
     142        else
     143            iGipCpu = UINT16_MAX;
     144        uTsc = ASMReadTSC();
     145        ASMSetFlags(uFlags);
     146# else
     147#  error "IN_RING3, IN_RC or IN_RING0 must be defined!"
     148# endif
     149    }
     150
     151    /*
     152     * If the delta is valid, apply it.
     153     */
     154    if (RT_LIKELY(iGipCpu < pGip->cCpus))
     155    {
     156        int64_t iTscDelta = pGip->aCPUs[iGipCpu].i64TSCDelta;
     157        if (RT_LIKELY(iTscDelta != INT64_MAX))
     158            return uTsc + iTscDelta;
    60159
    61160# ifdef IN_RING3
    62     /*
    63      * Read the TSC and delta.
    64      */
    65     uint32_t cTries = 0;
    66     for (;;)
    67     {
    68         uint8_t  idApic    = ASMGetApicId();
    69         uint64_t uTsc      = ASMReadTSC();
    70         int64_t  iTscDelta = pGip->aCPUs[pGip->aiCpuFromApicId[idApic]].i64TSCDelta;
    71         if (RT_LIKELY(   idApic == ASMGetApicId()
    72                       || cTries >= 10))
    73         {
    74             /*
    75              * If the delta is valid, apply it.
    76              */
    77             if (RT_LIKELY(iTscDelta != INT64_MAX))
    78                 return uTsc - iTscDelta;
    79 
    80             /*
    81              * The delta needs calculating, call supdrv to get the TSC.
    82              */
    83             int rc = SUPR3ReadTsc(&uTsc, NULL);
    84             if (RT_SUCCESS(rc))
    85                 return uTsc;
    86             AssertMsgFailed(("SUPR3ReadTsc -> %Rrc\n", rc));
    87 
    88             /* That didn't work, just return something half useful... */
    89             return ASMReadTSC();
    90         }
    91         cTries++;
     161        /*
     162         * The delta needs calculating, call supdrv to get the TSC.
     163         */
     164        int rc = SUPR3ReadTsc(&uTsc, NULL);
     165        if (RT_SUCCESS(rc))
     166            return uTsc;
     167        AssertMsgFailed(("SUPR3ReadTsc -> %Rrc\n", rc));
     168        uTsc = ASMReadTSC();
     169# endif /* IN_RING3 */
    92170    }
    93 # else
    94     /*
    95      * Read the TSC and delta.
    96      */
    97     RTCCUINTREG uFlags    = ASMIntDisableFlags();
    98 #  ifdef IN_RING0
    99     int         iCpuSet   = RTMpCpuIdToSetIndex(RTMpCpuId());
    100     uint16_t    iGipCpu   = (unsigned)iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
    101                           ? pGip->aiCpuFromCpuSetIdx[iCpuSet] : UINT16_MAX;
    102 #  else
    103     uint16_t    idApic    = ASMGetApicId();  /** @todo this could probably be eliminated in RC if we really wanted to... */
    104     uint16_t    iGipCpu   = (unsigned)idApic < RT_ELEMENTS(pGip->aiCpuFromApicId) /* for the future */
    105                           ? pGip->aiCpuFromApicId[idApic] : UINT16_MAX;
    106 #  endif
    107     int64_t     iTscDelta = (unsigned)iGipCpu < pGip->cCpus ? pGip->aCPUs[iGipCpu].i64TSCDelta : INT64_MAX;
    108     uint64_t    uTsc      = ASMReadTSC();
    109     ASMSetFlags(uFlags);
    110171
    111172    /*
    112      * If the delta is valid, apply it, otherwise ignore it (really shouldn't
    113      * happen in these contexts!).
     173     * This shouldn't happen, especially not in ring-3 and raw-mode context.
     174     * But if it does, return something that's half useful.
    114175     */
    115     if (RT_LIKELY(iTscDelta != INT64_MAX))
    116         return uTsc - iTscDelta;
    117 #  ifdef IN_RING0
    118     AssertMsgFailed(("iCpuSet=%d (%#x) iGipCpu=%#x\n", iCpuSet, iCpuSet, iGipCpu));
    119 #  else
    120     AssertMsgFailed(("idApic=%#x iGipCpu=%#x\n", idApic, iGipCpu));
    121 #  endif
     176    AssertMsgFailed(("iGipCpu=%d (%#x) cCpus=%d fGetGipCpu=%#x\n", iGipCpu, iGipCpu, pGip->cCpus, pGip->fGetGipCpu));
    122177    return uTsc;
    123 # endif
    124178}
    125179
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