VirtualBox

Ignore:
Timestamp:
Nov 7, 2014 5:41:01 PM (10 years ago)
Author:
vboxsync
Message:

HostDrivers/Support: Enabled global TSC rate calculation and implemented TSC calibration over a longer interval for invariant hosts.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.c

    r53230 r53269  
    205205 *  or offline. */
    206206static volatile uint32_t    g_cMpOnOffEvents;
     207/** TSC reading during start of TSC frequency refinement phase. */
     208uint64_t                    g_u64TSCAnchor;
     209/** Timestamp (in nanosec) during start of TSC frequency refinement phase. */
     210uint64_t                    g_u64NanoTSAnchor;
    207211
    208212/**
     
    59215925
    59225926
    5923 #if 0
    5924 /**
    5925  * Measures the nominal TSC frequency.
     5927/**
     5928 * Measures the TSC frequency of the system.
    59265929 *
    59275930 * Uses a busy-wait method for the async. case as it is intended to help push
    59285931 * the CPU frequency up, while for the invariant cases using a sleeping method.
    59295932 *
     5933 * The TSC frequency can vary on systems that are not reported as invariant.
     5934 * However, on such systems the object of this function is to find out what the
     5935 * nominal, maximum TSC frequency under normal CPU operation.
     5936 *
    59305937 * @returns VBox status code.
    59315938 * @param   pGip        Pointer to the GIP.
     
    59335940 * @remarks Must be called only after measuring the TSC deltas.
    59345941 */
    5935 static int supdrvGipMeasureNominalTscFreq(PSUPGLOBALINFOPAGE pGip)
     5942static int supdrvGipMeasureTscFreq(PSUPGLOBALINFOPAGE pGip)
    59365943{
    59375944    int cTriesLeft = 4;
     
    59445951    {
    59455952        RTCCUINTREG uFlags;
    5946         uint64_t    u64NanoTs;
     5953        uint64_t    u64NanoTsBefore;
    59475954        uint64_t    u64NanoTsAfter;
    59485955        uint64_t    u64TscBefore;
     
    59555962         * Especially important on Windows where the granularity is terrible.
    59565963         */
    5957         u64NanoTs = RTTimeSystemNanoTS();
    5958         while (RTTimeSystemNanoTS() == u64NanoTs)
     5964        u64NanoTsBefore = RTTimeSystemNanoTS();
     5965        while (RTTimeSystemNanoTS() == u64NanoTsBefore)
    59595966            ASMNopPause();
    59605967
    5961         uFlags       = ASMIntDisableFlags();
    5962         idApicBefore = ASMGetApicId();
    5963         u64TscBefore = ASMReadTSC();
    5964         u64NanoTs    = RTTimeSystemNanoTS();
     5968        uFlags          = ASMIntDisableFlags();
     5969        idApicBefore    = ASMGetApicId();
     5970        u64TscBefore    = ASMReadTSC();
     5971        u64NanoTsBefore = RTTimeSystemNanoTS();
    59655972        ASMSetFlags(uFlags);
    59665973
     
    59715978             * Shorter interval produces more variance in the frequency (esp. Windows).
    59725979             */
    5973             RTThreadSleep(200);   /* Sleeping shorter produces a tad more variance in the frequency than I'd like. */
     5980            RTThreadSleep(200);
    59745981            u64NanoTsAfter = RTTimeSystemNanoTS();
    59755982            while (RTTimeSystemNanoTS() == u64NanoTsAfter)
     
    59795986        else
    59805987        {
    5981             /* Busy wait, ramps up the CPU frequency on async systems. */
     5988            /* Busy-wait keeping the frequency up and measure. */
    59825989            for (;;)
    59835990            {
    59845991                u64NanoTsAfter = RTTimeSystemNanoTS();
    5985                 if (u64NanoTsAfter < RT_NS_100MS + u64NanoTs)
     5992                if (u64NanoTsAfter < RT_NS_100MS + u64NanoTsBefore)
    59865993                    ASMNopPause();
    59875994                else
     
    59915998
    59925999        uFlags      = ASMIntDisableFlags();
     6000        idApicAfter = ASMGetApicId();
    59936001        u64TscAfter = ASMReadTSC();
    5994         idApicAfter = ASMGetApicId();
    59956002        ASMSetFlags(uFlags);
    59966003
     
    59986005        if (supdrvIsInvariantTsc())
    59996006        {
    6000             PSUPGIPCPU pGipCpuBefore;
    6001             PSUPGIPCPU pGipCpuAfter;
    6002 
    6003             uint16_t iCpuBefore = pGip->aiCpuFromApicId[idApicBefore];
    6004             uint16_t iCpuAfter  = pGip->aiCpuFromApicId[idApicAfter];
    6005             AssertMsgReturn(iCpuBefore < pGip->cCpus, ("iCpuBefore=%u cCpus=%u\n", iCpuBefore, pGip->cCpus), VERR_INVALID_CPU_INDEX);
    6006             AssertMsgReturn(iCpuAfter  < pGip->cCpus, ("iCpuAfter=%u cCpus=%u\n", iCpuAfter, pGip->cCpus), VERR_INVALID_CPU_INDEX);
    6007             pGipCpuBefore = &pGip->aCPUs[iCpuBefore];
    6008             pGipCpuAfter  = &pGip->aCPUs[iCpuAfter];
    6009 
    6010             if (   pGipCpuBefore->i64TSCDelta != INT64_MAX
    6011                 && pGipCpuAfter->i64TSCDelta  != INT64_MAX)
    6012             {
    6013                 u64TscBefore -= pGipCpuBefore->i64TSCDelta;
    6014                 u64TscAfter  -= pGipCpuAfter->i64TSCDelta;
    6015 
    6016                 SUPR0Printf("vboxdrv: TSC frequency is %lu Hz - invariant, kernel timer granularity is %lu Ns\n",
    6017                             ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTs),
    6018                             RTTimerGetSystemGranularity());
    6019                 return VINF_SUCCESS;
    6020             }
    6021             else
    6022             {
    6023                 SUPR0Printf("vboxdrv: supdrvGipMeasureNominalTscFreq: iCpuBefore=%u iCpuAfter=%u cTriesLeft=%u\n", iCpuBefore,
    6024                             iCpuAfter, cTriesLeft);
    6025             }
    6026         }
    6027         else
    6028         {
    6029             SUPR0Printf("vboxdrv: TSC frequency is %lu Hz - maybe variant, kernel timer granularity is %lu Ns\n",
    6030                         ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTs),
    6031                         RTTimerGetSystemGranularity());
    6032             return VINF_SUCCESS;
    6033         }
     6007            int rc;
     6008            bool fAppliedBefore;
     6009            bool fAppliedAfter;
     6010            rc = SUPTscDeltaApply(pGip, &u64TscBefore, idApicBefore, &fAppliedBefore);   AssertRCReturn(rc, rc);
     6011            rc = SUPTscDeltaApply(pGip, &u64TscAfter,  idApicAfter,  &fAppliedAfter);    AssertRCReturn(rc, rc);
     6012
     6013            if (   !fAppliedBefore
     6014                || !fAppliedAfter)
     6015            {
     6016                SUPR0Printf("vboxdrv: supdrvGipMeasureTscFreq: idApicBefore=%u idApicAfter=%u cTriesLeft=%u\n",
     6017                            idApicBefore, idApicAfter, cTriesLeft);
     6018                continue;
     6019            }
     6020        }
     6021
     6022        /*
     6023         * Update GIP.
     6024         */
     6025        pGip->u64CpuHz = ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTsBefore);
     6026        return VINF_SUCCESS;
    60346027    }
    60356028
    60366029    return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED;
    60376030}
    6038 #endif
    60396031
    60406032
     
    61286120#endif
    61296121
    6130 #if 0
    6131                 /** @todo refactor later and use the nominal TSC rate for invariant case as
    6132                  *        the real and constant TSC rate. */
    6133                 supdrvGipMeasureNominalTscFreq(pGip);
    6134 #endif
    6135 
    6136                 /*
    6137                  * Create the timer.
    6138                  * If CPU_ALL isn't supported we'll have to fall back to synchronous mode.
    6139                  */
    6140                 if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
    6141                 {
    6142                     rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, RTTIMER_FLAGS_CPU_ALL, supdrvGipAsyncTimer, pDevExt);
    6143                     if (rc == VERR_NOT_SUPPORTED)
    6144                     {
    6145                         OSDBGPRINT(("supdrvGipCreate: omni timer not supported, falling back to synchronous mode\n"));
    6146                         pGip->u32Mode = SUPGIPMODE_SYNC_TSC;
    6147                     }
    6148                 }
    6149                 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
    6150                     rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, supdrvGipSyncTimer, pDevExt);
     6122                rc = supdrvGipMeasureTscFreq(pGip);
    61516123                if (RT_SUCCESS(rc))
    61526124                {
     6125                    if (supdrvIsInvariantTsc())
     6126                    {
     6127                        for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
     6128                            pGip->aCPUs[iCpu].u64CpuHz = pGip->u64CpuHz;
     6129                    }
     6130
    61536131                    /*
    6154                      * We're good.
     6132                     * Create the timer.
     6133                     * If CPU_ALL isn't supported we'll have to fall back to synchronous mode.
    61556134                     */
    6156                     Log(("supdrvGipCreate: %u ns interval.\n", u32Interval));
    6157                     g_pSUPGlobalInfoPage = pGip;
    6158                     return VINF_SUCCESS;
    6159                 }
    6160                 else
    6161                 {
    6162                     OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %u ns interval. rc=%Rrc\n", u32Interval, rc));
    6163                     Assert(!pDevExt->pGipTimer);
     6135                    if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC)
     6136                    {
     6137                        rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, RTTIMER_FLAGS_CPU_ALL, supdrvGipAsyncTimer, pDevExt);
     6138                        if (rc == VERR_NOT_SUPPORTED)
     6139                        {
     6140                            OSDBGPRINT(("supdrvGipCreate: omni timer not supported, falling back to synchronous mode\n"));
     6141                            pGip->u32Mode = SUPGIPMODE_SYNC_TSC;
     6142                        }
     6143                    }
     6144                    if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     6145                        rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, supdrvGipSyncTimer, pDevExt);
     6146                    if (RT_SUCCESS(rc))
     6147                    {
     6148                        /*
     6149                         * We're good.
     6150                         */
     6151                        Log(("supdrvGipCreate: %u ns interval.\n", u32Interval));
     6152                        g_pSUPGlobalInfoPage = pGip;
     6153                        return VINF_SUCCESS;
     6154                    }
     6155                    else
     6156                    {
     6157                        OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %u ns interval. rc=%Rrc\n", u32Interval, rc));
     6158                        Assert(!pDevExt->pGipTimer);
     6159                    }
    61646160                }
    61656161            }
     
    62816277
    62826278    ASMSetFlags(fOldFlags);
     6279
     6280    if (supdrvIsInvariantTsc())
     6281    {
     6282        /*
     6283         * Refine the TSC frequency measurement over a longer interval. Ideally, we want to keep the
     6284         * interval as small as possible while gaining the most consistent and accurate frequency
     6285         * (compared to what the host OS might have measured).
     6286         *
     6287         * In theory, we gain more accuracy with  longer intervals, but we want VMs to startup with the
     6288         * same TSC frequency whenever possible so we need to keep the interval short.
     6289         */
     6290        uint8_t            idApic;
     6291        uint64_t           u64NanoTS;
     6292        PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     6293        const int          cSeconds = 3;
     6294        if (RT_UNLIKELY(iTick == 3))    /* Helps with more consistent values across multiple runs (esp. Windows). */
     6295        {
     6296            u64NanoTS = RTTimeSystemNanoTS();
     6297            while (RTTimeSystemNanoTS() == u64NanoTS)
     6298                ASMNopPause();
     6299            fOldFlags         = ASMIntDisableFlags();
     6300            idApic            = ASMGetApicId();
     6301            g_u64TSCAnchor    = ASMReadTSC();
     6302            g_u64NanoTSAnchor = RTTimeSystemNanoTS();
     6303            ASMSetFlags(fOldFlags);
     6304            SUPTscDeltaApply(pGip, &g_u64TSCAnchor, idApic, NULL /* pfDeltaApplied */);
     6305            ++g_u64TSCAnchor;
     6306        }
     6307        else if (g_u64TSCAnchor)
     6308        {
     6309            uint64_t u64DeltaNanoTS;
     6310            u64NanoTS = RTTimeSystemNanoTS();
     6311            while (RTTimeSystemNanoTS() == u64NanoTS)
     6312                ASMNopPause();
     6313            fOldFlags = ASMIntDisableFlags();
     6314            idApic    = ASMGetApicId();
     6315            u64TSC    = ASMReadTSC();
     6316            u64NanoTS = RTTimeSystemNanoTS();
     6317            ASMSetFlags(fOldFlags);
     6318            SUPTscDeltaApply(pGip, &u64TSC, idApic, NULL /* pfDeltaApplied */);
     6319            u64DeltaNanoTS = u64NanoTS - g_u64NanoTSAnchor;
     6320            if (u64DeltaNanoTS >= cSeconds * RT_NS_1SEC_64)
     6321            {
     6322                uint16_t iCpu;
     6323                if (u64DeltaNanoTS < UINT32_MAX)
     6324                    pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64TSC - g_u64TSCAnchor, RT_NS_1SEC, u64DeltaNanoTS);
     6325                else
     6326                    pGip->u64CpuHz = (u64TSC - g_u64TSCAnchor) / (u64DeltaNanoTS / RT_NS_1SEC);
     6327
     6328                for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
     6329                    pGip->aCPUs[iCpu].u64CpuHz = pGip->u64CpuHz;
     6330                g_u64TSCAnchor = 0;
     6331            }
     6332        }
     6333    }
    62836334}
    62846335
     
    70697120 * @param   pDevExt     Pointer to the device instance data.
    70707121 */
    7071 static SUPGIPMODE supdrvGipDeterminTscMode(PSUPDRVDEVEXT pDevExt)
     7122static SUPGIPMODE supdrvGipDetermineTscMode(PSUPDRVDEVEXT pDevExt)
    70727123{
    70737124#if 0
     
    71917242    pGip->u32Magic              = SUPGLOBALINFOPAGE_MAGIC;
    71927243    pGip->u32Version            = SUPGLOBALINFOPAGE_VERSION;
    7193     pGip->u32Mode               = supdrvGipDeterminTscMode(pDevExt);
     7244    pGip->u32Mode               = supdrvGipDetermineTscMode(pDevExt);
    71947245    pGip->cCpus                 = (uint16_t)cCpus;
    71957246    pGip->cPages                = (uint16_t)(cbGip / PAGE_SIZE);
     
    73847435    ASMAtomicWriteU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack);
    73857436
     7437    if (supdrvIsInvariantTsc())
     7438        return;
     7439
    73867440    /*
    73877441     * CpuHz.
    73887442     */
    7389     u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, RT_NS_1SEC_64);
     7443    u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, RT_NS_1SEC);
    73907444    u64CpuHz /= pGip->u32UpdateIntervalNS;
    73917445    ASMAtomicWriteU64(&pGipCpu->u64CpuHz, u64CpuHz);
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