VirtualBox

Changeset 54352 in vbox


Ignore:
Timestamp:
Feb 22, 2015 1:32:45 AM (10 years ago)
Author:
vboxsync
Message:

SUPDrv,TM: Overhauled the CPU/TSC frequency a little, making it possible to run it early and skpping the 200 ms variant for the invariant tsc by executing the refinement timer several times.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/sup.h

    r54339 r54352  
    496496 * Gets the TSC frequency of the calling CPU.
    497497 *
    498  * @returns TSC frequency, UINT64_MAX on failure.
     498 * @returns TSC frequency, UINT64_MAX on failure (asserted).
    499499 * @param   pGip        The GIP pointer.
    500500 */
     
    502502{
    503503    if (RT_LIKELY(   pGip
    504                   && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
    505                   && pGip->u64CpuHz))
     504                  && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC))
    506505    {
    507506        switch (pGip->u32Mode)
     
    523522 * Gets the TSC frequency of the specified CPU.
    524523 *
    525  * @returns TSC frequency, UINT64_MAX on failure.
     524 * @returns TSC frequency, UINT64_MAX on failure (asserted).
    526525 * @param   pGip        The GIP pointer.
    527526 * @param   iCpuSet     The CPU set index of the CPU in question.
     
    530529{
    531530    if (RT_LIKELY(   pGip
    532                   && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC
    533                   && pGip->u64CpuHz))
     531                  && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC))
    534532    {
    535533        switch (pGip->u32Mode)
     
    554552
    555553
     554#if 0 /* Not used anywhere.  Unsure where this would be useful. */
    556555/**
    557556 * Checks if the provided TSC frequency is close enough to the computed TSC
     
    580579    return false;
    581580}
     581#endif
    582582
    583583#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
  • trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp

    r54345 r54352  
    8989/** The number of loops until we keep computing the minumum read time. */
    9090#define GIP_TSC_DELTA_READ_TIME_LOOPS       24
     91
     92/** @name Master / worker synchronization values.
     93 * @{ */
    9194/** Stop measurement of TSC delta. */
    92 #define GIP_TSC_DELTA_SYNC_STOP             0
     95#define GIP_TSC_DELTA_SYNC_STOP             UINT32_C(0)
    9396/** Start measurement of TSC delta. */
    94 #define GIP_TSC_DELTA_SYNC_START            1
     97#define GIP_TSC_DELTA_SYNC_START            UINT32_C(1)
    9598/** Worker thread is ready for reading the TSC. */
    96 #define GIP_TSC_DELTA_SYNC_WORKER_READY     2
     99#define GIP_TSC_DELTA_SYNC_WORKER_READY     UINT32_C(2)
    97100/** Worker thread is done updating TSC delta info. */
    98 #define GIP_TSC_DELTA_SYNC_WORKER_DONE      3
     101#define GIP_TSC_DELTA_SYNC_WORKER_DONE      UINT32_C(3)
    99102/** When IPRT is isn't concurrent safe: Master is ready and will wait for worker
    100103 *  with a timeout. */
    101 #define GIP_TSC_DELTA_SYNC_PRESTART_MASTER  4
     104#define GIP_TSC_DELTA_SYNC_PRESTART_MASTER  UINT32_C(4)
     105/** @} */
     106
    102107/** When IPRT is isn't concurrent safe: Worker is ready after waiting for
    103108 *  master with a timeout. */
    104109#define GIP_TSC_DELTA_SYNC_PRESTART_WORKER  5
    105110/** The TSC-refinement interval in seconds. */
    106 #define GIP_TSC_REFINE_INTERVAL             5
     111#define GIP_TSC_REFINE_PREIOD_IN_SECS       5
    107112/** The TSC-delta threshold for the SUPGIPUSETSCDELTA_PRACTICALLY_ZERO rating */
    108113#define GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO    32
     
    136141static DECLCALLBACK(void)   supdrvGipSyncAndInvariantTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
    137142static DECLCALLBACK(void)   supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
    138 static void                 supdrvGipInitCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS);
     143static void                 supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz);
    139144#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    140145static int                  supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt);
     
    763768 */
    764769
     770static void supdrvGipInitSetCpuFreq(PSUPGLOBALINFOPAGE pGip, uint64_t nsElapsed, uint64_t cElapsedTscTicks)
     771{
     772    /*
     773     * Calculate the frequency.
     774     */
     775    uint64_t uCpuHz;
     776    if (   cElapsedTscTicks < UINT64_MAX / RT_NS_1SEC
     777        && nsElapsed < UINT32_MAX)
     778        uCpuHz = ASMMultU64ByU32DivByU32(cElapsedTscTicks, RT_NS_1SEC, (uint32_t)nsElapsed);
     779    else
     780    {
     781        RTUINT128U CpuHz, Tmp, Divisor;
     782        CpuHz.s.Lo = CpuHz.s.Hi = 0;
     783        RTUInt128MulU64ByU64(&Tmp, cElapsedTscTicks, RT_NS_1SEC_64);
     784        RTUInt128Div(&CpuHz, &Tmp, RTUInt128AssignU64(&Divisor, nsElapsed));
     785        uCpuHz = CpuHz.s.Lo;
     786    }
     787
     788    /*
     789     * Update the GIP.
     790     */
     791    ASMAtomicWriteU64(&pGip->u64CpuHz, uCpuHz);
     792    if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     793        ASMAtomicWriteU64(&pGip->aCPUs[0].u64CpuHz, uCpuHz);
     794}
     795
    765796
    766797/**
    767798 * Timer callback function for TSC frequency refinement in invariant GIP mode.
     799 *
     800 * This is started during driver init and fires once
     801 * GIP_TSC_REFINE_PREIOD_IN_SECS seconds later.
    768802 *
    769803 * @param   pTimer      The timer.
     
    771805 * @param   iTick       The timer tick.
    772806 */
    773 static DECLCALLBACK(void) supdrvInitAsyncRefineTscTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
    774 {
    775     PSUPDRVDEVEXT      pDevExt = (PSUPDRVDEVEXT)pvUser;
    776     PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    777     bool               fDeltaApplied = false;
    778     uint8_t            idApic;
    779     uint64_t           u64DeltaNanoTS;
    780     uint64_t           u64DeltaTsc;
    781     uint64_t           u64NanoTS;
    782     uint64_t           u64Tsc;
    783     RTCCUINTREG        uFlags;
     807static DECLCALLBACK(void) supdrvInitRefineInvariantTscTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
     808{
     809    PSUPDRVDEVEXT       pDevExt = (PSUPDRVDEVEXT)pvUser;
     810    PSUPGLOBALINFOPAGE  pGip = pDevExt->pGip;
     811    RTCPUID             idCpu;
     812    uint64_t            cNsElapsed;
     813    uint64_t            cTscTicksElapsed;
     814    uint64_t            nsNow;
     815    uint64_t            uTsc;
     816    RTCCUINTREG         uFlags;
    784817
    785818    /* Paranoia. */
    786     Assert(pGip);
    787     Assert(pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC);
    788 
    789 #if !defined(RT_OS_OS2) /* PORTME: Disable if timers are called from clock interrupt handler or with interrupts disabled. */
     819    AssertReturnVoid(pGip);
     820    AssertReturnVoid(pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC);
     821
     822    /*
     823     * Try get close to the next clock tick as usual.
     824     *
     825     * PORTME: If timers are called from the clock interrupt handler, or
     826     *         an interrupt handler with higher priority than the clock
     827     *         interrupt, or spinning for ages in timer handlers is frowned
     828     *         upon, this look must be disabled!
     829     *
     830     * Darwin, FreeBSD, Linux, Solaris, Windows 8.1+:
     831     *      High RTTimeSystemNanoTS resolution should prevent any noticable
     832     *      spinning her.
     833     *
     834     * Windows 8.0 and earlier:
     835     *      We're running in a DPC here, so we may trigger the DPC watchdog?
     836     *
     837     * OS/2:
     838     *      Timer callbacks are done in the clock interrupt, so skip it.
     839     */
     840#if !defined(RT_OS_OS2)
     841    nsNow = RTTimeSystemNanoTS();
     842    while (RTTimeSystemNanoTS() == nsNow)
     843        ASMNopPause();
     844#endif
     845
     846    uFlags  = ASMIntDisableFlags();
     847    uTsc    = ASMReadTSC();
     848    nsNow   = RTTimeSystemNanoTS();
     849    idCpu   = RTMpCpuId();
     850    ASMSetFlags(uFlags);
     851
     852    cNsElapsed          = nsNow - pDevExt->nsStartInvarTscRefine;
     853    cTscTicksElapsed    = uTsc  - pDevExt->uTscStartInvarTscRefine;
     854
     855    /*
     856     * If the above measurement was taken on a different CPU than the one we
     857     * started the rprocess on, cTscTicksElapsed will need to be adjusted with
     858     * the TSC deltas of both the CPUs.
     859     *
     860     * We ASSUME that the delta calculation process takes less time than the
     861     * TSC frequency refinement timer.  If it doesn't, we'll complain and
     862     * drop the frequency refinement.
     863     *
     864     * Note! We cannot entirely trust enmUseTscDelta here because it's
     865     *       downgraded after each delta calculation.
     866     */
     867    if (   idCpu != pDevExt->idCpuInvarTscRefine
     868        && pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
     869    {
     870        uint32_t iStartCpuSet   = RTMpCpuIdToSetIndex(pDevExt->idCpuInvarTscRefine);
     871        uint32_t iStopCpuSet    = RTMpCpuIdToSetIndex(idCpu);
     872        uint16_t iStartGipCpu   = iStartCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
     873                                ? pGip->aiCpuFromCpuSetIdx[iStartCpuSet] : UINT16_MAX;
     874        uint16_t iStopGipCpu    = iStopCpuSet  < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
     875                                ? pGip->aiCpuFromCpuSetIdx[iStopCpuSet]  : UINT16_MAX;
     876        int64_t  iStartTscDelta = iStartGipCpu < pGip->cCpus ? pGip->aCPUs[iStartGipCpu].i64TSCDelta : INT64_MAX;
     877        int64_t  iStopTscDelta  = iStopGipCpu  < pGip->cCpus ? pGip->aCPUs[iStopGipCpu].i64TSCDelta  : INT64_MAX;
     878        if (RT_LIKELY(iStartTscDelta != INT64_MAX && iStopGipCpu != INT64_MAX))
     879        {
     880            if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
     881            {
     882                /* cTscTicksElapsed = (uTsc - iStopTscDelta) - (pDevExt->uTscStartInvarTscRefine - iStartTscDelta); */
     883                cTscTicksElapsed += iStartTscDelta - iStopTscDelta;
     884            }
     885        }
     886        /*
     887         * Allow 5 times the refinement period to elapse before we give up on the TSC delta
     888         * calculations.
     889         */
     890        else if (cNsElapsed <= GIP_TSC_REFINE_PREIOD_IN_SECS * 5 * RT_NS_1SEC_64)
     891        {
     892            int rc = RTTimerStart(pTimer, RT_NS_1SEC);
     893            AssertRC(rc);
     894            return;
     895        }
     896        else
     897        {
     898            SUPR0Printf("vboxdrv: Failed to refine invariant TSC frequency because deltas are unavailable after %u (%u) seconds\n",
     899                        (uint32_t)(cNsElapsed / RT_NS_1SEC), GIP_TSC_REFINE_PREIOD_IN_SECS);
     900            SUPR0Printf("vboxdrv: start: %u, %u, %#llx  stop: %u, %u, %#llx\n",
     901                        iStartCpuSet, iStartGipCpu, iStartTscDelta, iStopCpuSet, iStopGipCpu, iStopTscDelta);
     902            return;
     903        }
     904    }
     905
     906    /*
     907     * Calculate and update the CPU frequency variables in GIP.
     908     *
     909     * If there is a GIP user already and we've already refined the frequency
     910     * a couple of times, don't update it as we want a stable frequency value
     911     * for all VMs.
     912     */
     913    if (   pDevExt->cGipUsers == 0
     914        || cNsElapsed < RT_NS_1SEC * 2)
     915    {
     916        supdrvGipInitSetCpuFreq(pGip, cNsElapsed, cTscTicksElapsed);
     917
     918        /*
     919         * Reschedule the timer if we haven't yet reached the defined refinement period.
     920         */
     921        if (cNsElapsed < GIP_TSC_REFINE_PREIOD_IN_SECS * RT_NS_1SEC_64)
     922        {
     923            int rc = RTTimerStart(pTimer, RT_NS_1SEC);
     924            AssertRC(rc);
     925        }
     926    }
     927}
     928
     929
     930/**
     931 * Start the TSC-frequency refinment timer for the invariant TSC GIP mode.
     932 *
     933 * We cannot use this in the synchronous and asynchronous tsc GIP modes because
     934 * the CPU may change the TSC frequence between now and when the timer fires
     935 * (supdrvInitAsyncRefineTscTimer).
     936 *
     937 * @param   pDevExt         Pointer to the device instance data.
     938 * @param   pGip            Pointer to the GIP.
     939 *
     940 * @remarks We cannot use this
     941 */
     942static void supdrvGipInitStartTimerForRefiningInvariantTscFreq(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip)
     943{
     944    uint64_t    u64NanoTS;
     945    RTCCUINTREG uFlags;
     946    int         rc;
     947
     948    /*
     949     * Record the TSC and NanoTS as the starting anchor point for refinement
     950     * of the TSC.  We try get as close to a clock tick as possible on systems
     951     * which does not provide high resolution time.
     952     */
    790953    u64NanoTS = RTTimeSystemNanoTS();
    791954    while (RTTimeSystemNanoTS() == u64NanoTS)
    792955        ASMNopPause();
    793 #endif
    794     uFlags    = ASMIntDisableFlags();
    795     idApic    = ASMGetApicId();
    796     u64Tsc    = ASMReadTSC();
    797     u64NanoTS = RTTimeSystemNanoTS();
     956
     957    uFlags = ASMIntDisableFlags();
     958    pDevExt->uTscStartInvarTscRefine = ASMReadTSC();
     959    pDevExt->nsStartInvarTscRefine   = RTTimeSystemNanoTS();
     960    pDevExt->idCpuInvarTscRefine     = RTMpCpuId();
    798961    ASMSetFlags(uFlags);
    799     if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
    800         supdrvTscDeltaApply(pGip, &u64Tsc, idApic, &fDeltaApplied);
    801     u64DeltaNanoTS = u64NanoTS - pDevExt->u64NanoTSAnchor;
    802     u64DeltaTsc = u64Tsc - pDevExt->u64TscAnchor;
    803 
    804     if (RT_UNLIKELY(   pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO
    805                     && !fDeltaApplied))
    806     {
    807         Log(("vboxdrv: failed to refine TSC frequency as TSC-deltas unavailable after %d seconds!\n",
    808                     GIP_TSC_REFINE_INTERVAL));
    809         return;
    810     }
    811 
    812     /* Calculate the TSC frequency. */
    813     if (   u64DeltaTsc < UINT64_MAX / RT_NS_1SEC
    814         && u64DeltaNanoTS < UINT32_MAX)
    815         pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_1SEC, (uint32_t)u64DeltaNanoTS);
    816     else
    817     {
    818         RTUINT128U CpuHz, Tmp, Divisor;
    819         CpuHz.s.Lo = CpuHz.s.Hi = 0;
    820         RTUInt128MulU64ByU64(&Tmp, u64DeltaTsc, RT_NS_1SEC_64);
    821         RTUInt128Div(&CpuHz, &Tmp, RTUInt128AssignU64(&Divisor, u64DeltaNanoTS));
    822         pGip->u64CpuHz = CpuHz.s.Lo;
    823     }
    824 
    825     /* Update rest of GIP. */
    826     Assert(pGip->u32Mode != SUPGIPMODE_ASYNC_TSC); /* See SUPGetCpuHzFromGIP().*/
    827     pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
    828 }
    829 
    830 
    831 /**
    832  * Starts the TSC-frequency refinement phase asynchronously.
    833  *
    834  * @param   pDevExt        Pointer to the device instance data.
    835  */
    836 static void supdrvGipInitAsyncRefineTscFreq(PSUPDRVDEVEXT pDevExt)
    837 {
    838     uint64_t            u64NanoTS;
    839     RTCCUINTREG         uFlags;
    840     uint8_t             idApic;
    841     int                 rc;
    842     PSUPGLOBALINFOPAGE  pGip;
    843 
    844     /* Validate. */
    845     Assert(pDevExt);
    846     Assert(pDevExt->pGip);
    847     pGip = pDevExt->pGip;
    848 
    849 #ifdef SUPDRV_USE_TSC_DELTA_THREAD
    850     /*
    851      * If the TSC-delta thread is created, wait until it's done calculating
    852      * the TSC-deltas on the relevant online CPUs before we start the TSC refinement.
    853      */
    854     if (   pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED
    855         && ASMAtomicReadS32(&pDevExt->rcTscDelta) == VERR_NOT_AVAILABLE)
    856     {
    857         rc = supdrvTscDeltaThreadWaitForOnlineCpus(pDevExt);
    858         if (rc == VERR_TIMEOUT)
    859         {
    860             SUPR0Printf("vboxdrv: Skipping refinement of TSC frequency as TSC-delta measurement timed out!\n");
     962
     963    /*
     964     * Create a timer that runs on the same CPU so we won't have a depencency
     965     * on the TSC-delta and can run in parallel to it. On systems that does not
     966     * implement CPU specific timers we'll apply deltas in the timer callback,
     967     * just like we do for CPUs going offline.
     968     *
     969     * The longer the refinement interval the better the accuracy, at least in
     970     * theory.  If it's too long though, ring-3 may already be starting its
     971     * first VMs before we're done.  On most systems we will be loading the
     972     * support driver during boot and VMs won't be started for a while yet,
     973     * it is really only a problem during development (especiall with
     974     * on-demand driver starting on windows).
     975     *
     976     * To avoid wasting time doing a long supdrvGipInitMeasureTscFreq call
     977     * to calculate the frequencey during driver loading, the timer is set
     978     * to fire after 200 ms the first time. It will then reschedule itself
     979     * to fire every second until GIP_TSC_REFINE_PREIOD_IN_SECS has been
     980     * reached or it notices that there is a user land client with GIP
     981     * mapped (we want a stable frequency for all VMs).
     982     */
     983    rc = RTTimerCreateEx(&pDevExt->pInvarTscRefineTimer, 0 /* one-shot */,
     984                         RTTIMER_FLAGS_CPU(RTMpCpuIdToSetIndex(pDevExt->idCpuInvarTscRefine)),
     985                         supdrvInitRefineInvariantTscTimer, pDevExt);
     986    if (RT_SUCCESS(rc))
     987    {
     988        rc = RTTimerStart(pDevExt->pInvarTscRefineTimer, 2*RT_NS_100MS);
     989        if (RT_SUCCESS(rc))
    861990            return;
    862         }
    863     }
    864 #endif
    865 
    866     /*
    867      * Record the TSC and NanoTS as the starting anchor point for refinement of the
    868      * TSC. We deliberately avoid using SUPReadTSC() here as we want to keep the
    869      * reading of the TSC and the NanoTS as close as possible.
    870      */
    871     u64NanoTS = RTTimeSystemNanoTS();
    872     while (RTTimeSystemNanoTS() == u64NanoTS)
    873         ASMNopPause();
    874     uFlags                   = ASMIntDisableFlags();
    875     idApic                   = ASMGetApicId();
    876     pDevExt->u64TscAnchor    = ASMReadTSC();
    877     pDevExt->u64NanoTSAnchor = RTTimeSystemNanoTS();
     991        RTTimerDestroy(pDevExt->pInvarTscRefineTimer);
     992    }
     993
     994    if (rc == VERR_CPU_OFFLINE || rc == VERR_NOT_SUPPORTED)
     995    {
     996        rc = RTTimerCreateEx(&pDevExt->pInvarTscRefineTimer, 0 /* one-shot */, RTTIMER_FLAGS_CPU_ANY,
     997                             supdrvInitRefineInvariantTscTimer, pDevExt);
     998        if (RT_SUCCESS(rc))
     999        {
     1000            rc = RTTimerStart(pDevExt->pInvarTscRefineTimer, 2*RT_NS_100MS);
     1001            if (RT_SUCCESS(rc))
     1002                return;
     1003            RTTimerDestroy(pDevExt->pInvarTscRefineTimer);
     1004        }
     1005    }
     1006
     1007    pDevExt->pInvarTscRefineTimer = NULL;
     1008    OSDBGPRINT(("vboxdrv: Failed to create or start TSC frequency refinement timer: rc=%Rrc\n", rc));
     1009}
     1010
     1011
     1012/**
     1013 * @callback_method_impl{PFNRTMPWORKER,
     1014 *      RTMpOnSpecific callback for reading TSC and time on the CPU we started
     1015 *      the measurements on.}
     1016 */
     1017DECLCALLBACK(void) supdrvGipInitReadTscAndNanoTsOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
     1018{
     1019    RTCCUINTREG uFlags    = ASMIntDisableFlags();
     1020    uint64_t   *puTscStop = (uint64_t *)pvUser1;
     1021    uint64_t   *pnsStop   = (uint64_t *)pvUser2;
     1022
     1023    *puTscStop = ASMReadTSC();
     1024    *pnsStop   = RTTimeSystemNanoTS();
     1025
    8781026    ASMSetFlags(uFlags);
    879     if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
    880         supdrvTscDeltaApply(pGip, &pDevExt->u64TscAnchor, idApic, NULL /* pfDeltaApplied */);
    881 
    882     rc = RTTimerCreateEx(&pDevExt->pTscRefineTimer, 0 /* one-shot */, RTTIMER_FLAGS_CPU_ANY,
    883                          supdrvInitAsyncRefineTscTimer, pDevExt);
    884     if (RT_SUCCESS(rc))
    885     {
    886         /*
    887          * Refine the TSC frequency measurement over a long interval. Ideally, we want to keep the
    888          * interval as small as possible while gaining the most consistent and accurate frequency
    889          * (compared to what the host OS might have measured).
    890          *
    891          * In theory, we gain more accuracy with longer intervals, but we want VMs to startup with the
    892          * same TSC frequency whenever possible so we need to keep the interval short.
    893          */
    894         rc = RTTimerStart(pDevExt->pTscRefineTimer, GIP_TSC_REFINE_INTERVAL * RT_NS_1SEC_64);
    895         AssertRC(rc);
    896     }
    897     else
    898         OSDBGPRINT(("RTTimerCreateEx failed to create one-shot timer. rc=%Rrc\n", rc));
    8991027}
    9001028
     
    9021030/**
    9031031 * Measures the TSC frequency of the system.
    904  *
    905  * Uses a busy-wait method for the async. case as it is intended to help push
    906  * the CPU frequency up, while for the invariant cases using a sleeping method.
    9071032 *
    9081033 * The TSC frequency can vary on systems which are not reported as invariant.
     
    9111036 *
    9121037 * @returns VBox status code.
    913  * @param   pDevExt        Pointer to the device instance.
    914  *
    915  * @remarks Must be called only -after- measuring the TSC deltas.
    916  */
    917 static int supdrvGipInitMeasureTscFreq(PSUPDRVDEVEXT pDevExt)
    918 {
    919     int cTriesLeft = 4;
    920     PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    921 
    922     /* Assert order. */
    923     AssertReturn(pGip, VERR_INVALID_PARAMETER);
    924     AssertReturn(pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC, VERR_WRONG_ORDER);
    925 
     1038 * @param   pDevExt         Pointer to the device instance.
     1039 * @param   pGip            Pointer to the GIP.
     1040 * @param   fRough          Set if we're doing the rough calculation that the
     1041 *                          TSC measuring code needs, where accuracy isn't all
     1042 *                          that important (too high is better than to low).
     1043 *                          When clear we try for best accuracy that we can
     1044 *                          achieve in reasonably short time.
     1045 */
     1046static int supdrvGipInitMeasureTscFreq(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, bool fRough)
     1047{
     1048    uint32_t nsTimerIncr = RTTimerGetSystemGranularity();
     1049    int      cTriesLeft = fRough ? 4 : 2;
    9261050    while (cTriesLeft-- > 0)
    9271051    {
    9281052        RTCCUINTREG uFlags;
    929         uint64_t    u64NanoTsBefore;
    930         uint64_t    u64NanoTsAfter;
    931         uint64_t    u64TscBefore;
    932         uint64_t    u64TscAfter;
    933         uint8_t     idApicBefore;
    934         uint8_t     idApicAfter;
     1053        uint64_t    nsStart;
     1054        uint64_t    nsStop;
     1055        uint64_t    uTscStart;
     1056        uint64_t    uTscStop;
     1057        RTCPUID     idCpuStart;
     1058        RTCPUID     idCpuStop;
    9351059
    9361060        /*
    937          * Synchronize with the host OS clock tick before reading the TSC.
    938          * Especially important on older Windows version where the granularity is terrible.
     1061         * Synchronize with the host OS clock tick on systems without high
     1062         * resolution time API (older Windows version for example).
    9391063         */
    940         u64NanoTsBefore = RTTimeSystemNanoTS();
    941         while (RTTimeSystemNanoTS() == u64NanoTsBefore)
     1064        nsStart = RTTimeSystemNanoTS();
     1065        while (RTTimeSystemNanoTS() == nsStart)
    9421066            ASMNopPause();
    9431067
    944         uFlags          = ASMIntDisableFlags();
    945         idApicBefore    = ASMGetApicId();
    946         u64TscBefore    = ASMReadTSC();
    947         u64NanoTsBefore = RTTimeSystemNanoTS();
     1068        /*
     1069         * Read the TSC and current time, noting which CPU we're on.
     1070         */
     1071        uFlags = ASMIntDisableFlags();
     1072        uTscStart   = ASMReadTSC();
     1073        nsStart     = RTTimeSystemNanoTS();
     1074        idCpuStart  = RTMpCpuId();
    9481075        ASMSetFlags(uFlags);
    9491076
     1077        /*
     1078         * Delay for a while.
     1079         */
    9501080        if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
    9511081        {
     
    9541084             * Shorter interval produces more variance in the frequency (esp. Windows).
    9551085             */
    956             RTThreadSleep(200);
    957             u64NanoTsAfter = RTTimeSystemNanoTS();
    958             while (RTTimeSystemNanoTS() == u64NanoTsAfter)
     1086            uint64_t msElapsed = 0;
     1087            uint64_t msDelay =   ( ((fRough ? 16 : 200) * RT_NS_1MS + nsTimerIncr - 1) / nsTimerIncr * nsTimerIncr - RT_NS_100US )
     1088                               / RT_NS_1MS;
     1089            do
     1090            {
     1091                RTThreadSleep((RTMSINTERVAL)(msDelay - msElapsed));
     1092                nsStop    = RTTimeSystemNanoTS();
     1093                msElapsed = (nsStop - nsStart) / RT_NS_1MS;
     1094            } while (msElapsed < msDelay);
     1095
     1096            while (RTTimeSystemNanoTS() == nsStop)
    9591097                ASMNopPause();
    960             u64NanoTsAfter = RTTimeSystemNanoTS();
    9611098        }
    9621099        else
    9631100        {
    964             /* Busy-wait keeping the frequency up and measure. */
    965             for (;;)
     1101            /*
     1102             * Busy-wait keeping the frequency up.
     1103             */
     1104            do
    9661105            {
    967                 u64NanoTsAfter = RTTimeSystemNanoTS();
    968                 if (u64NanoTsAfter < RT_NS_100MS + u64NanoTsBefore)
    969                     ASMNopPause();
    970                 else
    971                     break;
     1106                ASMNopPause();
     1107                nsStop = RTTimeSystemNanoTS();
     1108            } while (nsStop - nsStart < RT_NS_100MS);
     1109        }
     1110
     1111        /*
     1112         * Read the TSC and time again.
     1113         */
     1114        uFlags = ASMIntDisableFlags();
     1115        uTscStop    = ASMReadTSC();
     1116        nsStop      = RTTimeSystemNanoTS();
     1117        idCpuStop   = RTMpCpuId();
     1118        ASMSetFlags(uFlags);
     1119
     1120        /*
     1121         * If the CPU changes things get a bit complicated and what we
     1122         * can get away with depends on the GIP mode / TSC reliablity.
     1123         */
     1124        if (idCpuStop != idCpuStart)
     1125        {
     1126            bool fDoXCall = false;
     1127
     1128            /*
     1129             * Synchronous TSC mode: we're probably fine as it's unlikely
     1130             * that we were rescheduled because of TSC throttling or power
     1131             * management reasons, so just go ahead.
     1132             */
     1133            if (pGip->u32Mode == SUPGIPMODE_SYNC_TSC)
     1134            {
     1135                /* Probably ok, maybe we should retry once?. */
     1136                Assert(pGip->enmUseTscDelta == SUPGIPUSETSCDELTA_NOT_APPLICABLE);
    9721137            }
    973         }
    974 
    975         uFlags      = ASMIntDisableFlags();
    976         idApicAfter = ASMGetApicId();
    977         u64TscAfter = ASMReadTSC();
    978         ASMSetFlags(uFlags);
    979 
    980         if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
    981         {
    982             int rc;
    983             bool fAppliedBefore;
    984             bool fAppliedAfter;
    985             rc = supdrvTscDeltaApply(pGip, &u64TscBefore, idApicBefore, &fAppliedBefore);   AssertRCReturn(rc, rc);
    986             rc = supdrvTscDeltaApply(pGip, &u64TscAfter,  idApicAfter,  &fAppliedAfter);    AssertRCReturn(rc, rc);
    987 
    988             if (   !fAppliedBefore
    989                 || !fAppliedAfter)
     1138            /*
     1139             * If we're just doing the rough measurement, do the cross call and
     1140             * get on with things (we don't have deltas!).
     1141             */
     1142            else if (fRough)
     1143                fDoXCall = true;
     1144            /*
     1145             * Invariant TSC mode: It doesn't matter if we have delta available
     1146             * for both CPUs.  That is not something we can assume at this point.
     1147             *
     1148             * Note! We cannot necessarily trust enmUseTscDelta here because it's
     1149             *       downgraded after each delta calculation and the delta
     1150             *       calculations may not be complete yet.
     1151             */
     1152            else if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
    9901153            {
    991 #ifdef SUPDRV_USE_TSC_DELTA_THREAD
     1154                if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
     1155                {
     1156                    uint32_t iStartCpuSet   = RTMpCpuIdToSetIndex(idCpuStart);
     1157                    uint32_t iStopCpuSet    = RTMpCpuIdToSetIndex(idCpuStop);
     1158                    uint16_t iStartGipCpu   = iStartCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
     1159                                            ? pGip->aiCpuFromCpuSetIdx[iStartCpuSet] : UINT16_MAX;
     1160                    uint16_t iStopGipCpu    = iStopCpuSet  < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx)
     1161                                            ? pGip->aiCpuFromCpuSetIdx[iStopCpuSet]  : UINT16_MAX;
     1162                    int64_t  iStartTscDelta = iStartGipCpu < pGip->cCpus ? pGip->aCPUs[iStartGipCpu].i64TSCDelta : INT64_MAX;
     1163                    int64_t  iStopTscDelta  = iStopGipCpu  < pGip->cCpus ? pGip->aCPUs[iStopGipCpu].i64TSCDelta  : INT64_MAX;
     1164                    if (RT_LIKELY(iStartTscDelta != INT64_MAX && iStopGipCpu != INT64_MAX))
     1165                    {
     1166                        if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)
     1167                        {
     1168                            uTscStart -= iStartTscDelta;
     1169                            uTscStop  -= iStopTscDelta;
     1170                        }
     1171                    }
     1172                    /*
     1173                     * Invalid CPU indexes are not caused by online/offline races, so
     1174                     * we have to trigger driver load failure if that happens as GIP
     1175                     * and IPRT assumptions are busted on this system.
     1176                     */
     1177                    else if (iStopGipCpu >= pGip->cCpus || iStartGipCpu >= pGip->cCpus)
     1178                    {
     1179                        SUPR0Printf("vboxdrv: Unexpected CPU index in supdrvGipInitMeasureTscFreq.\n");
     1180                        SUPR0Printf("vboxdrv: start: %u, %u, %#llx  stop: %u, %u, %#llx\n",
     1181                                    iStartCpuSet, iStartGipCpu, iStartTscDelta, iStopCpuSet, iStopGipCpu, iStopTscDelta);
     1182                        return VERR_INVALID_CPU_INDEX;
     1183                    }
     1184                    /*
     1185                     * No valid deltas.  We retry, if we're on our last retry
     1186                     * we do the cross call instead just to get a result.  The
     1187                     * frequency will be refined in a few seconds anyways.
     1188                     */
     1189                    else if (cTriesLeft > 0)
     1190                        continue;
     1191                    else
     1192                        fDoXCall = true;
     1193                }
     1194            }
     1195            /*
     1196             * Asynchronous TSC mode: This is bad as the reason we usually
     1197             * use this mode is to deal with variable TSC frequencies and
     1198             * deltas.  So, we need to get the TSC from the same CPU as
     1199             * started it, we also need to keep that CPU busy.  So, retry
     1200             * and fall back to the cross call on the last attempt.
     1201             */
     1202            else
     1203            {
     1204                Assert(pGip->u32Mode == SUPGIPMODE_ASYNC_TSC);
     1205                if (cTriesLeft > 0)
     1206                    continue;
     1207                fDoXCall = true;
     1208            }
     1209
     1210            if (fDoXCall)
     1211            {
    9921212                /*
    993                  * The TSC-delta measurements are kicked-off asynchronously as each host CPU is initialized.
    994                  * Therefore, if we failed to have a delta for the CPU(s) we were scheduled on (idApicBefore
    995                  * and idApicAfter) then wait until we have TSC-delta measurements for all online CPUs and
    996                  * proceed. This should be triggered just once if we're rather unlucky.
     1213                 * Try read the TSC and timestamp on the start CPU.
    9971214                 */
    998                 rc = supdrvTscDeltaThreadWaitForOnlineCpus(pDevExt);
    999                 if (rc == VERR_TIMEOUT)
    1000                 {
    1001                     SUPR0Printf("vboxdrv: supdrvGipInitMeasureTscFreq: timedout waiting for TSC-delta measurements.\n");
    1002                     return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED;
    1003                 }
    1004 #else
    1005                 SUPR0Printf("vboxdrv: supdrvGipInitMeasureTscFreq: idApicBefore=%u idApicAfter=%u cTriesLeft=%u\n",
    1006                             idApicBefore, idApicAfter, cTriesLeft);
    1007 #endif
    1008                 continue;
     1215                int rc = RTMpOnSpecific(idCpuStart, supdrvGipInitReadTscAndNanoTsOnCpu, &uTscStop, &nsStop);
     1216                if (RT_FAILURE(rc) && (!fRough || cTriesLeft > 0))
     1217                    continue;
    10091218            }
    10101219        }
    10111220
    10121221        /*
    1013          * Update GIP.
     1222         * Calculate the TSC frequency and update it (shared with the refinement timer).
    10141223         */
    1015         pGip->u64CpuHz = ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTsBefore);
    1016         if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
    1017             pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz;
     1224        supdrvGipInitSetCpuFreq(pGip, nsStop - nsStart, uTscStop - uTscStart);
    10181225        return VINF_SUCCESS;
    10191226    }
    10201227
     1228    Assert(!fRough);
    10211229    return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED;
    10221230}
     
    11011309    u64NanoTS = RTTimeSystemNanoTS() - pGip->u32UpdateIntervalNS;
    11021310    i = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu);
    1103     supdrvGipInitCpu(pDevExt, pGip, &pGip->aCPUs[i], u64NanoTS);
     1311
     1312    supdrvGipInitCpu(pGip, &pGip->aCPUs[i], u64NanoTS, pGip->u64CpuHz);
     1313
    11041314    idApic = ASMGetApicId();
    11051315    ASMAtomicWriteU16(&pGip->aCPUs[i].idApic,  idApic);
     
    14591669 * Initializes per-CPU GIP information.
    14601670 *
    1461  * @param   pDevExt     Pointer to the device instance data.
    14621671 * @param   pGip        Pointer to the GIP.
    14631672 * @param   pCpu        Pointer to which GIP CPU to initalize.
    14641673 * @param   u64NanoTS   The current nanosecond timestamp.
    1465  */
    1466 static void supdrvGipInitCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS)
    1467 {
    1468     /* !!! Warning !!! The GIP may not be linked to the device instance data at this point!
    1469        which is why we have 2 separate parameters. Don't dereference pDevExt->pGip here. */
     1674 * @param   uCpuHz      The CPU frequency to set, 0 if the caller doesn't know.
     1675 */
     1676static void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz)
     1677{
    14701678    pCpu->u32TransactionId   = 2;
    14711679    pCpu->u64NanoTS          = u64NanoTS;
     
    14791687    ASMAtomicWriteU16(&pCpu->idApic,    UINT16_MAX);
    14801688
    1481     /*
    1482      * We don't know the following values until we've executed updates.
    1483      * So, we'll just pretend it's a 4 GHz CPU and adjust the history it on
    1484      * the 2nd timer callout.
    1485      */
    1486     pCpu->u64CpuHz          = _4G + 1; /* tstGIP-2 depends on this. */
    1487     pCpu->u32UpdateIntervalTSC
    1488         = pCpu->au32TSCHistory[0]
     1689    /*
     1690     * The first time we're called, we don't have a CPU frequency handy,
     1691     * so pretend it's a 4 GHz CPU.  On CPUs that are online, we'll get
     1692     * called again and at that point we have a more plausible CPU frequency
     1693     * value handy.  The frequency history will also be adjusted again on
     1694     * the 2nd timer callout (maybe we can skip that now?).
     1695     */
     1696    if (!uCpuHz)
     1697    {
     1698        pCpu->u64CpuHz             = _4G - 1;
     1699        pCpu->u32UpdateIntervalTSC = (uint32_t)((_4G - 1) / pGip->u32UpdateHz);
     1700    }
     1701    else
     1702    {
     1703        pCpu->u64CpuHz             = uCpuHz;
     1704        pCpu->u32UpdateIntervalTSC = (uint32_t)(uCpuHz / pGip->u32UpdateHz);
     1705    }
     1706    pCpu->au32TSCHistory[0]
    14891707        = pCpu->au32TSCHistory[1]
    14901708        = pCpu->au32TSCHistory[2]
     
    14941712        = pCpu->au32TSCHistory[6]
    14951713        = pCpu->au32TSCHistory[7]
    1496         = (uint32_t)(_4G / pGip->u32UpdateHz);
     1714        = pCpu->u32UpdateIntervalTSC;
    14971715}
    14981716
     
    15511769        pGip->aiCpuFromCpuSetIdx[i] = UINT16_MAX;
    15521770    for (i = 0; i < cCpus; i++)
    1553         supdrvGipInitCpu(pDevExt, pGip, &pGip->aCPUs[i], u64NanoTS);
     1771        supdrvGipInitCpu(pGip, &pGip->aCPUs[i], u64NanoTS, 0 /*uCpuHz*/);
    15541772
    15551773    /*
     
    16311849    supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), RT_NS_1SEC / u32Interval /*=Hz*/, u32Interval, cCpus);
    16321850
     1851    /*
     1852     * Important sanity check...
     1853     */
    16331854    if (RT_UNLIKELY(   pGip->enmUseTscDelta == SUPGIPUSETSCDELTA_ZERO_CLAIMED
    16341855                    && pGip->u32Mode == SUPGIPMODE_ASYNC_TSC
     
    16401861    }
    16411862
    1642     RTCpuSetEmpty(&pDevExt->TscDeltaCpuSet);
    1643     RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet);
     1863    /*
     1864     * Do the TSC frequency measurements.
     1865     *
     1866     * If we're in invariant TSC mode, just to a quick preliminary measurement
     1867     * that the TSC-delta measurement code can use to yield cross calls.
     1868     *
     1869     * If we're in any of the other two modes, neither which require MP init,
     1870     * notifications or deltas for the job, do the full measurement now so
     1871     * that supdrvGipInitOnCpu can populate the TSC interval and history
     1872     * array with more reasonable values.
     1873     */
     1874    if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     1875    {
     1876        rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, true /*fRough*/); /* cannot fail */
     1877        supdrvGipInitStartTimerForRefiningInvariantTscFreq(pDevExt, pGip);
     1878    }
     1879    else
     1880        rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, false /*fRough*/);
     1881    if (RT_SUCCESS(rc))
     1882    {
     1883        /*
     1884         * Start TSC-delta measurement thread before we start getting MP
     1885         * events that will try kick it into action (includes the
     1886         * RTMpOnAll/supdrvGipInitOnCpu call below).
     1887         */
     1888        RTCpuSetEmpty(&pDevExt->TscDeltaCpuSet);
     1889        RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet);
    16441890#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    1645     if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
    1646     {
    1647         /* Initialize TSC-delta measurement thread before executing any Mp event callbacks. */
    1648         rc = supdrvTscDeltaThreadInit(pDevExt);
    1649     }
     1891        if (   pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED
     1892            && pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
     1893            rc = supdrvTscDeltaThreadInit(pDevExt);
    16501894#endif
    1651     if (RT_SUCCESS(rc))
    1652     {
    1653         rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt);
    16541895        if (RT_SUCCESS(rc))
    16551896        {
    1656             rc = RTMpOnAll(supdrvGipInitOnCpu, pDevExt, pGip);
     1897            rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt);
    16571898            if (RT_SUCCESS(rc))
    16581899            {
    1659 #ifndef SUPDRV_USE_TSC_DELTA_THREAD
    1660                 uint16_t iCpu;
    1661                 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
    1662                 {
    1663                     /*
    1664                      * Measure the TSC deltas now that we have MP notifications.
    1665                      */
    1666                     int cTries = 5;
    1667                     do
    1668                     {
    1669                         rc = supdrvMeasureInitialTscDeltas(pDevExt);
    1670                         if (   rc != VERR_TRY_AGAIN
    1671                             && rc != VERR_CPU_OFFLINE)
    1672                             break;
    1673                     } while (--cTries > 0);
    1674                     for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
    1675                         Log(("supdrvTscDeltaInit: cpu[%u] delta %lld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta));
    1676                 }
    1677                 else
    1678                 {
    1679                     for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
    1680                         AssertMsg(!pGip->aCPUs[iCpu].i64TSCDelta, ("iCpu=%u %lld mode=%d\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta, pGip->u32Mode));
    1681                 }
    1682 #endif
     1900                /*
     1901                 * Do GIP initialization on all online CPUs.  Wake up the
     1902                 * TSC-delta thread afterwards.
     1903                 */
     1904                rc = RTMpOnAll(supdrvGipInitOnCpu, pDevExt, pGip);
    16831905                if (RT_SUCCESS(rc))
    16841906                {
    1685                     rc = supdrvGipInitMeasureTscFreq(pDevExt);
     1907#ifdef SUPDRV_USE_TSC_DELTA_THREAD
     1908                    RTThreadUserSignal(pDevExt->hTscDeltaThread);
     1909#else
     1910                    uint16_t iCpu;
     1911                    if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
     1912                    {
     1913                        /*
     1914                         * Measure the TSC deltas now that we have MP notifications.
     1915                         */
     1916                        int cTries = 5;
     1917                        do
     1918                        {
     1919                            rc = supdrvMeasureInitialTscDeltas(pDevExt);
     1920                            if (   rc != VERR_TRY_AGAIN
     1921                                && rc != VERR_CPU_OFFLINE)
     1922                                break;
     1923                        } while (--cTries > 0);
     1924                        for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
     1925                            Log(("supdrvTscDeltaInit: cpu[%u] delta %lld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta));
     1926                    }
     1927                    else
     1928                    {
     1929                        for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
     1930                            AssertMsg(!pGip->aCPUs[iCpu].i64TSCDelta, ("iCpu=%u %lld mode=%d\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta, pGip->u32Mode));
     1931                    }
    16861932                    if (RT_SUCCESS(rc))
     1933#endif
    16871934                    {
    16881935                        /*
     
    17121959
    17131960                            g_pSUPGlobalInfoPage = pGip;
    1714                             if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)
    1715                                 supdrvGipInitAsyncRefineTscFreq(pDevExt);
    17161961                            return VINF_SUCCESS;
    17171962                        }
     
    17201965                        Assert(!pDevExt->pGipTimer);
    17211966                    }
    1722                     else
    1723                         OSDBGPRINT(("supdrvGipCreate: supdrvGipInitMeasureTscFreq failed. rc=%Rrc\n", rc));
    17241967                }
    17251968                else
    1726                     OSDBGPRINT(("supdrvGipCreate: supdrvMeasureInitialTscDeltas failed. rc=%Rrc\n", rc));
     1969                    OSDBGPRINT(("supdrvGipCreate: RTMpOnAll failed. rc=%Rrc\n", rc));
    17271970            }
    17281971            else
    1729                 OSDBGPRINT(("supdrvGipCreate: RTMpOnAll failed. rc=%Rrc\n", rc));
     1972                OSDBGPRINT(("supdrvGipCreate: failed to register MP event notfication. rc=%Rrc\n", rc));
    17301973        }
    17311974        else
    1732             OSDBGPRINT(("supdrvGipCreate: failed to register MP event notfication. rc=%Rrc\n", rc));
     1975            OSDBGPRINT(("supdrvGipCreate: supdrvTscDeltaInit failed. rc=%Rrc\n", rc));
    17331976    }
    17341977    else
    1735         OSDBGPRINT(("supdrvGipCreate: supdrvTscDeltaInit failed. rc=%Rrc\n", rc));
    1736 
    1737     supdrvGipDestroy(pDevExt); /* Releases timer frequency increase too. */
     1978        OSDBGPRINT(("supdrvGipCreate: supdrvMeasureInitialTscDeltas failed. rc=%Rrc\n", rc));
     1979
     1980    /* Releases timer frequency increase too. */
     1981    supdrvGipDestroy(pDevExt);
    17381982    return rc;
    17391983}
     
    17872031
    17882032    /*
    1789      * Destroy the TSC-refinement one-shot timer.
    1790      */
    1791     if (pDevExt->pTscRefineTimer)
    1792     {
    1793         RTTimerDestroy(pDevExt->pTscRefineTimer);
    1794         pDevExt->pTscRefineTimer = NULL;
     2033     * Destroy the TSC-refinement timer.
     2034     */
     2035    if (pDevExt->pInvarTscRefineTimer)
     2036    {
     2037        RTTimerDestroy(pDevExt->pInvarTscRefineTimer);
     2038        pDevExt->pInvarTscRefineTimer = NULL;
    17952039    }
    17962040
     
    22462490#endif
    22472491
     2492/** For padding variables to keep them away from other cache lines.  Better too
     2493 * large than too small!
     2494 * @remarks Current AMD64 and x86 CPUs seems to use 64 bytes.  There are claims
     2495 *          that NetBurst had 128 byte cache lines while the 486 thru Pentium
     2496 *          III had 32 bytes cache lines. */
     2497#define GIP_TSC_DELTA_CACHE_LINE_SIZE           128
     2498
    22482499
    22492500/**
     
    22622513typedef struct SUPDRVTSCDELTAMETHOD2
    22632514{
    2264     /** Padding to make sure the iCurSeqNo is in its own cache line.
    2265      * ASSUMES cacheline sizes <= 128 bytes. */
    2266     uint32_t                    au32CacheLinePaddingBefore[128 / sizeof(uint32_t)];
     2515    /** Padding to make sure the iCurSeqNo is in its own cache line. */
     2516    uint64_t                    au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 1];
    22672517    /** The current sequence number of this worker. */
    22682518    uint32_t volatile           iCurSeqNo;
    2269     /** Padding to make sure the iCurSeqNo is in its own cache line.
    2270      * ASSUMES cacheline sizes <= 128 bytes. */
    2271     uint32_t                    au32CacheLinePaddingAfter[128 / sizeof(uint32_t) - 1];
     2519    /** Padding to make sure the iCurSeqNo is in its own cache line. */
     2520    uint32_t                    au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint32_t) - 1];
    22722521    /** Result table. */
    22732522    SUPDRVTSCDELTAMETHOD2ENTRY  aResults[96];
     
    22782527
    22792528/**
     2529 * The TSC delta synchronization struct, version 2.
     2530 *
     2531 * The syncrhonization variable is completely isolated in its own cache line
     2532 * (provided our max cache line size estimate is correct).
     2533 */
     2534typedef struct SUPTSCDELTASYNC2
     2535{
     2536    /** Padding to make sure the uVar1 is in its own cache line. */
     2537    uint64_t                    au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
     2538    /** The synchronization variable, holds values GIP_TSC_DELTA_SYNC_*. */
     2539    volatile uint32_t           uVar1;
     2540    /** Unused. */
     2541    volatile uint32_t           uVar2;
     2542
     2543    /** Start RDTSC value.  This does not need to be in its own cache line, it's
     2544     * just put here to save stack space. */
     2545    uint64_t                    uTscStart;
     2546    /** Max number of ticks we can allow to elapse in the RTMpOn callback.
     2547     * This is estimated from the CPU frequency...  */
     2548    uint64_t                    cMaxTicks;
     2549
     2550    /** Padding to make sure the uVar1 is in its own cache line. */
     2551    uint64_t                    au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 2];
     2552} SUPTSCDELTASYNC2;
     2553AssertCompileSize(SUPTSCDELTASYNC2, GIP_TSC_DELTA_CACHE_LINE_SIZE * 2 + sizeof(uint64_t));
     2554typedef SUPTSCDELTASYNC2 *PSUPTSCDELTASYNC2;
     2555
     2556
     2557/**
    22802558 * Argument package/state passed by supdrvMeasureTscDeltaOne to the RTMpOn
    22812559 * callback worker.
     
    22832561typedef struct SUPDRVGIPTSCDELTARGS
    22842562{
     2563    /** The device extension.   */
    22852564    PSUPDRVDEVEXT           pDevExt;
     2565    /** Pointer to the GIP CPU array entry for the worker. */
    22862566    PSUPGIPCPU              pWorker;
     2567    /** Pointer to the GIP CPU array entry for the master. */
    22872568    PSUPGIPCPU              pMaster;
    2288     RTCPUID                 idMaster;
     2569    /** Pointer to the master's synchronization struct (on stack). */
     2570    PSUPTSCDELTASYNC2       pSyncMaster;
     2571    /** Pointer to the worker's synchronization struct (on stack). */
     2572    PSUPTSCDELTASYNC2       pSyncWorker;
    22892573
    22902574#if 0
     
    27703054#endif /* GIP_TSC_DELTA_METHOD_2 */
    27713055
     3056/** Prestart wait. */
     3057#define GIP_TSC_DELTA_SYNC2_PRESTART_WAIT    UINT32_C(0xffe)
     3058
     3059/** Start measurement of TSC delta. */
     3060#define GIP_TSC_DELTA_SYNC2_START            UINT32_C(1)
     3061/** Worker thread is ready for reading the TSC. */
     3062#define GIP_TSC_DELTA_SYNC2_WORKER_READY     UINT32_C(2)
     3063/** Worker thread is done updating TSC delta info. */
     3064#define GIP_TSC_DELTA_SYNC2_WORKER_DONE      UINT32_C(3)
     3065/** When IPRT is isn't concurrent safe: Master is ready and will wait for worker
     3066 *  with a timeout. */
     3067#define GIP_TSC_DELTA_SYNC2_PRESTART_MASTER  UINT32_C(4)
     3068
    27723069
    27733070/**
     
    27923089    PSUPGIPCPU              pGipCpuWorker    = pArgs->pWorker;
    27933090    PSUPGIPCPU              pGipCpuMaster    = pArgs->pMaster;
    2794     RTCPUID                 idMaster         = pArgs->idMaster;
     3091    bool const              fIsMaster        = idCpu == pGipCpuMaster->idCpu;
    27953092    uint32_t                iTry;
     3093#if 0
     3094    PSUPTSCDELTASYNC2       pOtherSync;
     3095    SUPTSCDELTASYNC2        MySync;
     3096#endif
    27963097
    27973098    /* A bit of paranoia first. */
     
    27993100        return;
    28003101
    2801     /* If the CPU isn't part of the measurement, return immediately. */
    2802     if (   idCpu != idMaster
     3102    /*
     3103     * If the CPU isn't part of the measurement, return immediately.
     3104     */
     3105    if (   !fIsMaster
    28033106        && idCpu != pGipCpuWorker->idCpu)
    28043107        return;
     3108
     3109#if 0
     3110    /*
     3111     * Set up my synchronization stuff and wait for the other party to show up.
     3112     * We don't wait forever since the other party may have gone fishing after
     3113     * we checked it out in supdrvMeasureTscDeltaOne, and then there is of course
     3114     * windows and it's BSOD if we waste too much time here.
     3115     */
     3116    if (fIsMaster)
     3117    {
     3118        MySync.uVar1 = GIP_TSC_DELTA_SYNC2_PRESTART_WAIT;
     3119        ASMSerializeInstruction(); ASMCompilerBarrier();
     3120        ASMAtomicWritePtr(&pArgs->pSyncMaster, &MySync);
     3121    }
     3122    else
     3123    {
     3124        MySync.uVar1 = GIP_TSC_DELTA_SYNC2_PRESTART_WAIT;
     3125        ASMSerializeInstruction(); ASMCompilerBarrier();
     3126        ASMAtomicWritePtr(&pArgs->pSyncWorker, &MySync);
     3127    }
     3128
     3129    MySync.uTscStart = ASMReadTSC();
     3130    MySync.cMaxTicks = u64CpuHz
     3131
     3132    while ((pOtherSync = ASMAtomicReadPtr((void * volatile *)(fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster))) != NULL)
     3133    {
     3134        uint32_t cInner = 10240;
     3135        while (   cInner-- > 0
     3136               && ASMAtomicUoReadU32(MySync.uVar1) == GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)
     3137            ASMNopPause();
     3138
     3139    }
     3140#endif
     3141
    28053142
    28063143    /* If the IPRT API isn't concurrent safe, the master and worker wait for each other
     
    28173154        ASMSerializeInstruction();
    28183155        uTscStart = ASMReadTSC();
    2819         if (idCpu == idMaster)
     3156        if (fIsMaster)
    28203157        {
    28213158            ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_PRESTART_MASTER);
     
    28623199         */
    28633200#ifdef GIP_TSC_DELTA_METHOD_1
    2864         supdrvTscDeltaMethod1Loop(pArgs, pSync, idCpu == idMaster, iTry);
     3201        supdrvTscDeltaMethod1Loop(pArgs, pSync, fIsMaster, iTry);
    28653202#elif defined(GIP_TSC_DELTA_METHOD_2)
    2866         supdrvTscDeltaMethod2Loop(pArgs, pSync, idCpu == idMaster, iTry);
     3203        supdrvTscDeltaMethod2Loop(pArgs, pSync, fIsMaster, iTry);
    28673204#else
    28683205# error "huh??"
     
    28743211        if (pGipCpuWorker->i64TSCDelta != INT64_MAX)
    28753212        {
    2876             if (idCpu == idMaster)
     3213            if (fIsMaster)
    28773214            {
    28783215                RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet);
     
    30033340        SUPDRVGIPTSCDELTARGS Args;
    30043341        RT_ZERO(Args);
    3005         Args.pWorker  = pGipCpuWorker;
    3006         Args.pMaster  = pGipCpuMaster;
    3007         Args.idMaster = idMaster;
    3008         Args.pDevExt  = pDevExt;
     3342        Args.pWorker     = pGipCpuWorker;
     3343        Args.pMaster     = pGipCpuMaster;
     3344        Args.pDevExt     = pDevExt;
     3345        Args.pSyncMaster = NULL;
     3346        Args.pSyncWorker = NULL;
    30093347#ifdef GIP_TSC_DELTA_METHOD_1
    30103348        rc = supdrvTscDeltaMethod1Init(&Args);
     
    36624000            return VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY;
    36634001
    3664         rc = RTThreadSleep(RT_MIN(cMsWaitThread - cMsElapsed, RT_MIN(iWaitLoop + 1, 10)));
     4002        rc = RTThreadSleep(RT_MIN((RTMSINTERVAL)(cMsWaitThread - cMsElapsed), RT_MIN(iWaitLoop + 1, 10)));
    36654003        if (rc == VERR_INTERRUPTED)
    36664004            return rc;
  • trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h

    r54327 r54352  
    712712    /** @} */
    713713
     714    /** @name Invariant TSC frequency refinement.
     715     * @{ */
     716    /** Nanosecond timestamp at the start of the TSC frequency refinement phase. */
     717    uint64_t                        nsStartInvarTscRefine;
     718    /** TSC reading at the start of the TSC frequency refinement phase. */
     719    uint64_t                        uTscStartInvarTscRefine;
     720    /** The CPU id of the CPU that u64TscAnchor was measured on. */
     721    RTCPUID                         idCpuInvarTscRefine;
     722    /** Pointer to the timer used to refine the TSC frequency. */
     723    PRTTIMER                        pInvarTscRefineTimer;
     724    /** @} */
     725
    714726    /** @name TSC-delta measurement.
    715727     *  @{ */
    716     /** TSC reading during start of TSC frequency refinement phase. */
    717     uint64_t                        u64TscAnchor;
    718     /** Timestamp (in nanosec) during start of TSC frequency refinement phase. */
    719     uint64_t                        u64NanoTSAnchor;
    720     /** Pointer to the timer used to refine the TSC frequency. */
    721     PRTTIMER                        pTscRefineTimer;
    722728    /** Pointer to the TSC delta sync. struct. */
    723729    void                           *pvTscDeltaSync;
  • trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp

    r54252 r54352  
    154154                uint32_t volatile *pu32TransactionId = NULL;
    155155                for (unsigned iCpu = 0; iCpu < g_pSUPGlobalInfoPage->cCpus; iCpu++)
    156                     if (    g_pSUPGlobalInfoPage->aCPUs[iCpu].u64CpuHz > 0
    157                         &&  g_pSUPGlobalInfoPage->aCPUs[iCpu].u64CpuHz != _4G + 1)
     156                    if (g_pSUPGlobalInfoPage->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_ONLINE)
    158157                    {
    159158                        char szCpuHzDeviation[32];
  • trunk/src/VBox/VMM/VMMR3/TM.cpp

    r54308 r54352  
    266266            SUPGetGIPModeName(pGip), pGip->u32UpdateHz,
    267267            pGip->u32UpdateIntervalNS));
    268     LogRel(("TM: GIP - u64CpuHz=%#RX64 (%'RU64)\n", pGip->u64CpuHz, pGip->u64CpuHz));
     268    LogRel(("TM: GIP - u64CpuHz=%'RU64 (%#RX64)  SUPGetCpuHzFromGip => %'RU64\n",
     269            pGip->u64CpuHz, pGip->u64CpuHz, SUPGetCpuHzFromGip(pGip)));
    269270
    270271    /*
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