VirtualBox

Changeset 53085 in vbox for trunk/src


Ignore:
Timestamp:
Oct 17, 2014 12:23:54 PM (10 years ago)
Author:
vboxsync
Message:

HostDrivers/Support: Fixes to TSC frequency measurement. Also adds available TSC delta while taking the measurement if possible.

File:
1 edited

Legend:

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

    r53064 r53085  
    162162static bool                 supdrvIsInvariantTsc(void);
    163163static void                 supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys,
    164                                           uint64_t u64NanoTS, unsigned uUpdateHz, unsigned cCpus);
     164                                          uint64_t u64NanoTS, unsigned uUpdateHz, unsigned uUpdateIntervalNS, unsigned cCpus);
    165165static DECLCALLBACK(void)   supdrvGipInitOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2);
    166166static void                 supdrvGipTerm(PSUPGLOBALINFOPAGE pGip);
     
    59195919    uint32_t            u32SystemResolution;
    59205920    uint32_t            u32Interval;
     5921    uint32_t            u32MinInterval;
     5922    uint32_t            uMod;
    59215923    unsigned            cCpus;
    59225924    int                 rc;
     
    59545956    /*
    59555957     * Find a reasonable update interval and initialize the structure.
    5956      */
    5957     u32Interval = u32SystemResolution = RTTimerGetSystemGranularity();
    5958     while (u32Interval < 10000000 /* 10 ms */)
    5959         u32Interval += u32SystemResolution;
    5960 
    5961     supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), 1000000000 / u32Interval /*=Hz*/, cCpus);
     5958     *
     5959     * If we have an invariant TSC, use a larger update interval as then
     5960     * we get better accuracy along with lower host load.
     5961     */
     5962    u32MinInterval      = supdrvIsInvariantTsc() ? RT_NS_100MS : RT_NS_10MS;
     5963    u32SystemResolution = RTTimerGetSystemGranularity();
     5964    u32Interval         = u32MinInterval;
     5965    uMod                = u32MinInterval % u32SystemResolution;
     5966    if (uMod)
     5967        u32Interval += u32SystemResolution - uMod;
     5968
     5969    supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), RT_NS_1SEC / u32Interval /*=Hz*/, u32Interval, cCpus);
    59625970
    59635971#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     
    61046112{
    61056113    RTCCUINTREG     fOldFlags = ASMIntDisableFlags(); /* No interruptions please (real problem on S10). */
    6106     PSUPDRVDEVEXT   pDevExt   = (PSUPDRVDEVEXT)pvUser;
    61076114    uint64_t        u64TSC    = ASMReadTSC();
    61086115    uint64_t        NanoTS    = RTTimeSystemNanoTS();
     6116    PSUPDRVDEVEXT   pDevExt   = (PSUPDRVDEVEXT)pvUser;
     6117
     6118    if (supdrvIsInvariantTsc())
     6119    {
     6120        PSUPGIPCPU         pGipCpu;
     6121        PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     6122        unsigned           iCpu = pGip->aiCpuFromApicId[ASMGetApicId()];
     6123        AssertReturnVoid(iCpu < pGip->cCpus);
     6124        pGipCpu = &pGip->aCPUs[iCpu];
     6125        AssertReturnVoid(pGipCpu->idCpu == RTMpCpuId());
     6126
     6127        /*
     6128         * The calculations in supdrvGipUpdate() is very timing sensitive and doesn't handle
     6129         * missed timer ticks. So for now it is better to use a delta of 0 and have the TSC rate
     6130         * affected a bit until we get proper TSC deltas than implementing options like
     6131         * rescheduling the tick to be delivered on the right CPU or missing the tick entirely.
     6132         */
     6133        if (pGipCpu->i64TSCDelta != INT64_MAX)
     6134            u64TSC += pGipCpu->i64TSCDelta;
     6135    }
    61096136
    61106137    supdrvGipUpdate(pDevExt, NanoTS, u64TSC, NIL_RTCPUID, iTick);
     
    68986925static SUPGIPMODE supdrvGipDeterminTscMode(PSUPDRVDEVEXT pDevExt)
    68996926{
     6927    if (supdrvIsInvariantTsc())
     6928        return SUPGIPMODE_SYNC_TSC;     /** @todo Switch to SUPGIPMODE_INVARIANT_TSC later. */
     6929
    69006930    /*
    69016931     * On SMP we're faced with two problems:
     
    69887018 * Initializes the GIP data.
    69897019 *
    6990  * @param   pDevExt     Pointer to the device instance data.
    6991  * @param   pGip        Pointer to the read-write kernel mapping of the GIP.
    6992  * @param   HCPhys      The physical address of the GIP.
    6993  * @param   u64NanoTS   The current nanosecond timestamp.
    6994  * @param   uUpdateHz   The update frequency.
    6995  * @param   cCpus       The CPU count.
     7020 * @param   pDevExt             Pointer to the device instance data.
     7021 * @param   pGip                Pointer to the read-write kernel mapping of the GIP.
     7022 * @param   HCPhys              The physical address of the GIP.
     7023 * @param   u64NanoTS           The current nanosecond timestamp.
     7024 * @param   uUpdateHz           The update frequency.
     7025 * @param   uUpdateIntervalNS   The update interval in nanoseconds.
     7026 * @param   cCpus               The CPU count.
    69967027 */
    69977028static void supdrvGipInit(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, RTHCPHYS HCPhys,
    6998                           uint64_t u64NanoTS, unsigned uUpdateHz, unsigned cCpus)
     7029                          uint64_t u64NanoTS, unsigned uUpdateHz, unsigned uUpdateIntervalNS, unsigned cCpus)
    69997030{
    70007031    size_t const    cbGip = RT_ALIGN_Z(RT_OFFSETOF(SUPGLOBALINFOPAGE, aCPUs[cCpus]), PAGE_SIZE);
     
    70167047    pGip->cPages                = (uint16_t)(cbGip / PAGE_SIZE);
    70177048    pGip->u32UpdateHz           = uUpdateHz;
    7018     pGip->u32UpdateIntervalNS   = 1000000000 / uUpdateHz;
     7049    pGip->u32UpdateIntervalNS   = uUpdateIntervalNS;
    70197050    pGip->u64NanoTSLastUpdateHz = u64NanoTS;
    70207051    RTCpuSetEmpty(&pGip->OnlineCpuSet);
     
    71607191
    71617192    /*
     7193     * For invariant TSC support, we take only 1 interval as there is a problem on
     7194     * Windows where we have an occasional (but reccurring) sour value that messes up
     7195     * the history. Also, since the update interval is pretty long with the invariant
     7196     * TSC case this works accurately enough.
     7197     */
     7198    if (supdrvIsInvariantTsc())
     7199    {
     7200        u32UpdateIntervalTSC = (uint32_t)u64TSCDelta;
     7201        u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6;
     7202    }
     7203    /*
    71627204     * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ.
    71637205     */
    7164     if (pGip->u32UpdateHz >= 1000)
     7206    else if (pGip->u32UpdateHz >= 1000)
    71657207    {
    71667208        uint32_t u32;
     
    72027244     * CpuHz.
    72037245     */
    7204     u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, pGip->u32UpdateHz);
     7246    u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, RT_NS_1SEC_64);
     7247    u64CpuHz /= pGip->u32UpdateIntervalNS;
    72057248    ASMAtomicWriteU64(&pGipCpu->u64CpuHz, u64CpuHz);
    72067249}
     
    72587301#ifdef RT_ARCH_AMD64 /** @todo fix 64-bit div here to work on x86 linux. */
    72597302            uint64_t u64Delta = u64NanoTS - pGip->u64NanoTSLastUpdateHz;
    7260             uint32_t u32UpdateHz = (uint32_t)((UINT64_C(1000000000) * GIP_UPDATEHZ_RECALC_FREQ) / u64Delta);
     7303            uint32_t u32UpdateHz = (uint32_t)((RT_NS_1SEC_64 * GIP_UPDATEHZ_RECALC_FREQ) / u64Delta);
    72617304            if (u32UpdateHz <= 2000 && u32UpdateHz >= 30)
    72627305            {
    72637306                ASMAtomicWriteU32(&pGip->u32UpdateHz, u32UpdateHz);
    7264                 ASMAtomicWriteU32(&pGip->u32UpdateIntervalNS, 1000000000 / u32UpdateHz);
     7307                ASMAtomicWriteU32(&pGip->u32UpdateIntervalNS, RT_NS_1SEC / u32UpdateHz);
    72657308            }
    72667309#endif
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