VirtualBox

Changeset 54387 in vbox for trunk/src/VBox/HostDrivers


Ignore:
Timestamp:
Feb 23, 2015 4:31:58 PM (10 years ago)
Author:
vboxsync
Message:

SUPDrvGip.cpp: Start the TSC measurement by testing for zero delta. We do alternate TSC reads on the two CPUs and check that the TSC value is ever increasing.

File:
1 edited

Legend:

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

    r54379 r54387  
    25672567/** Go! */
    25682568#define GIP_TSC_DELTA_SYNC2_GO               UINT32_C(0x1002)
     2569/** Used by the verfication test. */
     2570#define GIP_TSC_DELTA_SYNC2_GO_GO            UINT32_C(0x1003)
    25692571
    25702572/** We reached the time limit. */
     
    25862588    /** Pointer to the GIP CPU array entry for the master. */
    25872589    PSUPGIPCPU                  pMaster;
    2588     /** Pointer to the master's synchronization struct (on stack). */
    2589     PSUPTSCDELTASYNC2 volatile  pSyncMaster;
    2590     /** Pointer to the worker's synchronization struct (on stack). */
    2591     PSUPTSCDELTASYNC2 volatile  pSyncWorker;
    25922590    /** The maximum number of ticks to spend in supdrvMeasureTscDeltaCallback.
    25932591     * (This is what we need a rough TSC frequency for.)  */
     
    26142612    } M2;
    26152613#endif
     2614
     2615
     2616    /** Padding to make sure the master variables live in its own cache lines. */
     2617    uint64_t                    au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
     2618    /** Pointer to the master's synchronization struct (on stack). */
     2619    PSUPTSCDELTASYNC2 volatile  pSyncMaster;
     2620    /** Verification test TSC values for the master. */
     2621    uint64_t volatile           auVerifyMasterTscs[32];
     2622    /** The verifier verdict, VINF_SUCCESS if ok, VERR_OUT_OF_RANGE if not,
     2623     * VERR_TRY_AGAIN on timeout. */
     2624    int32_t                     rcVerify;
     2625    /** The maximum difference between TSC read during delta verification. */
     2626    int64_t                     cMaxVerifyTscTicks;
     2627    /** The minimum difference between two TSC reads during verification. */
     2628    int64_t                     cMinVerifyTscTicks;
     2629    /** The bad TSC diff, worker relative to master (= worker - master).
     2630     * Negative value means the worker is behind the master.  */
     2631    int64_t                     iVerifyBadTscDiff;
     2632
     2633    /** Padding to make sure the uVar1 is in its own cache line. */
     2634    uint64_t                    au64CacheLinePaddingBetween[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
     2635    /** Pointer to the worker's synchronization struct (on stack). */
     2636    PSUPTSCDELTASYNC2 volatile  pSyncWorker;
     2637    /** Verification test TSC values for the worker. */
     2638    uint64_t volatile           auVerifyWorkerTscs[32];
     2639
     2640    /** Padding to make sure the above is in its own cache line. */
     2641    uint64_t                    au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
    26162642} SUPDRVGIPTSCDELTARGS;
    26172643typedef SUPDRVGIPTSCDELTARGS *PSUPDRVGIPTSCDELTARGS;
     
    26262652 * @{
    26272653 */
    2628 #if defined(DEBUG_bird) && defined(RT_OS_WINDOWS)
     2654#if defined(DEBUG_bird) /* || defined(VBOX_STRICT) */
    26292655# define TSCDELTA_DBG_VARS()            uint32_t iDbgCounter
    26302656# define TSCDELTA_DBG_START_LOOP()      do { iDbgCounter = 0; } while (0)
    2631 # define TSCDELTA_DBG_CHECK_LOOP()      do { if (++iDbgCounter == 0) RT_BREAKPOINT(); } while (0)
     2657# define TSCDELTA_DBG_CHECK_LOOP() \
     2658    do { iDbgCounter++; if ((iDbgCounter & UINT32_C(0x01ffffff)) == 0) RT_BREAKPOINT(); } while (0)
    26322659#else
    26332660# define TSCDELTA_DBG_VARS()            ((void)0)
     
    32943321
    32953322
    3296 static int supdrvMeasureTscDeltaCallbackAbortSyncSetup(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync,
    3297                                                        bool fIsMaster, bool fTimeout)
     3323static int supdrvTscDeltaVerify(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync,
     3324                                PSUPTSCDELTASYNC2 pOtherSync, bool fIsMaster, int64_t iWorkerTscDelta)
     3325{
     3326    PSUPGIPCPU pGipCpuWorker = pArgs->pWorker;
     3327    PSUPGIPCPU pGipCpuMaster = pArgs->pMaster;
     3328    uint32_t   i;
     3329    TSCDELTA_DBG_VARS();
     3330
     3331    for (;;)
     3332    {
     3333        RTCCUINTREG uFlags;
     3334        AssertCompile((RT_ELEMENTS(pArgs->auVerifyMasterTscs) & 1) == 0);
     3335        AssertCompile(RT_ELEMENTS(pArgs->auVerifyWorkerTscs) == RT_ELEMENTS(pArgs->auVerifyMasterTscs));
     3336
     3337        if (fIsMaster)
     3338        {
     3339            uint64_t uTscWorker;
     3340            TSCDELTA_MASTER_SYNC_BEFORE(pMySync, pOtherSync);
     3341
     3342            /*
     3343             * Collect TSC, master goes first.
     3344             */
     3345            for (i = 0; i < RT_ELEMENTS(pArgs->auVerifyMasterTscs); i += 2)
     3346            {
     3347                /* Read, kick & wait #1. */
     3348                uint64_t register uTsc = ASMReadTSC();
     3349                ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO_GO);
     3350                ASMSerializeInstruction();
     3351                pArgs->auVerifyMasterTscs[i] = uTsc;
     3352                TSCDELTA_DBG_START_LOOP();
     3353                while (ASMAtomicReadU32(&pMySync->uSyncVar) == GIP_TSC_DELTA_SYNC2_GO)
     3354                {
     3355                    TSCDELTA_DBG_CHECK_LOOP();
     3356                    ASMNopPause();
     3357                }
     3358
     3359                /* Read, kick & wait #2. */
     3360                uTsc = ASMReadTSC();
     3361                ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO);
     3362                ASMSerializeInstruction();
     3363                pArgs->auVerifyMasterTscs[i + 1] = uTsc;
     3364                TSCDELTA_DBG_START_LOOP();
     3365                while (ASMAtomicReadU32(&pMySync->uSyncVar) == GIP_TSC_DELTA_SYNC2_GO_GO)
     3366                {
     3367                    TSCDELTA_DBG_CHECK_LOOP();
     3368                    ASMNopPause();
     3369                }
     3370            }
     3371
     3372            TSCDELTA_MASTER_SYNC_AFTER(pMySync, pOtherSync);
     3373
     3374            /*
     3375             * Process the data.
     3376             */
     3377            pArgs->cMaxVerifyTscTicks = INT64_MIN;
     3378            pArgs->cMinVerifyTscTicks = INT64_MAX;
     3379            pArgs->iVerifyBadTscDiff  = 0;
     3380            ASMAtomicWriteS32(&pArgs->rcVerify, VINF_SUCCESS);
     3381            uTscWorker = 0;
     3382            for (i = 0; i < RT_ELEMENTS(pArgs->auVerifyMasterTscs); i++)
     3383            {
     3384                /* Master vs previous worker entry. */
     3385                uint64_t uTscMaster = pArgs->auVerifyMasterTscs[i] - pGipCpuMaster->i64TSCDelta;
     3386                int64_t  iDiff;
     3387                if (i > 0)
     3388                {
     3389                    iDiff = uTscMaster - uTscWorker;
     3390                    if (iDiff > pArgs->cMaxVerifyTscTicks)
     3391                        pArgs->cMaxVerifyTscTicks = iDiff;
     3392                    if (iDiff < pArgs->cMinVerifyTscTicks)
     3393                        pArgs->cMinVerifyTscTicks = iDiff;
     3394                    if (iDiff < 0)
     3395                    {
     3396                        pArgs->iVerifyBadTscDiff = -iDiff;
     3397                        ASMAtomicWriteS32(&pArgs->rcVerify, VERR_OUT_OF_RANGE);
     3398                        break;
     3399                    }
     3400                }
     3401
     3402                /* Worker vs master. */
     3403                uTscWorker = pArgs->auVerifyWorkerTscs[i] - iWorkerTscDelta;
     3404                iDiff = uTscWorker - uTscMaster;
     3405                if (iDiff > pArgs->cMaxVerifyTscTicks)
     3406                    pArgs->cMaxVerifyTscTicks = iDiff;
     3407                if (iDiff < pArgs->cMinVerifyTscTicks)
     3408                    pArgs->cMinVerifyTscTicks = iDiff;
     3409                if (iDiff < 0)
     3410                {
     3411                    pArgs->iVerifyBadTscDiff = iDiff;
     3412                    ASMAtomicWriteS32(&pArgs->rcVerify, VERR_OUT_OF_RANGE);
     3413                    break;
     3414                }
     3415            }
     3416
     3417            /* Done. */
     3418            TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pMySync, pOtherSync);
     3419        }
     3420        else
     3421        {
     3422            /*
     3423             * The worker, master leads.
     3424             */
     3425            TSCDELTA_OTHER_SYNC_BEFORE(pMySync, pOtherSync);
     3426
     3427            for (i = 0; i < RT_ELEMENTS(pArgs->auVerifyWorkerTscs); i += 2)
     3428            {
     3429                uint64_t register uTsc;
     3430
     3431                /* Wait, Read and Kick #1. */
     3432                TSCDELTA_DBG_START_LOOP();
     3433                while (ASMAtomicReadU32(&pMySync->uSyncVar) == GIP_TSC_DELTA_SYNC2_GO)
     3434                {
     3435                    TSCDELTA_DBG_CHECK_LOOP();
     3436                    ASMNopPause();
     3437                }
     3438                uTsc = ASMReadTSC();
     3439                ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO_GO);
     3440                ASMSerializeInstruction();
     3441                pArgs->auVerifyWorkerTscs[i] = uTsc;
     3442
     3443                /* Wait, Read and Kick #2. */
     3444                TSCDELTA_DBG_START_LOOP();
     3445                while (ASMAtomicReadU32(&pMySync->uSyncVar) == GIP_TSC_DELTA_SYNC2_GO_GO)
     3446                {
     3447                    TSCDELTA_DBG_CHECK_LOOP();
     3448                    ASMNopPause();
     3449                }
     3450                uTsc = ASMReadTSC();
     3451                ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_GO);
     3452                ASMSerializeInstruction();
     3453                pArgs->auVerifyWorkerTscs[i + 1] = uTsc;
     3454            }
     3455
     3456            TSCDELTA_OTHER_SYNC_AFTER(pMySync, pOtherSync);
     3457        }
     3458        return pArgs->rcVerify;
     3459    }
     3460
     3461    /*
     3462     * Timed out, please retry.
     3463     */
     3464    ASMAtomicWriteS32(&pArgs->rcVerify, VERR_TRY_AGAIN);
     3465    return VERR_TIMEOUT;
     3466}
     3467
     3468
     3469
     3470/**
     3471 * Handles the special abort procedure during synchronization setup in
     3472 * supdrvMeasureTscDeltaCallbackUnwrapped().
     3473 *
     3474 * @returns 0 (dummy, ignored)
     3475 * @param   pArgs               Pointer to argument/state data.
     3476 * @param   pMySync             Pointer to my sync structure.
     3477 * @param   fIsMaster           Set if we're the master, clear if worker.
     3478 * @param   fTimeout            Set if it's a timeout.
     3479 */
     3480DECL_NO_INLINE(static, int)
     3481supdrvMeasureTscDeltaCallbackAbortSyncSetup(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync, bool fIsMaster, bool fTimeout)
    32983482{
    32993483    PSUPTSCDELTASYNC2 volatile *ppMySync    = fIsMaster ? &pArgs->pSyncMaster : &pArgs->pSyncWorker;
     
    33533537    SUPTSCDELTASYNC2            MySync;
    33543538    PSUPTSCDELTASYNC2           pOtherSync;
     3539    int                         rc;
    33553540    TSCDELTA_DBG_VARS();
    33563541
     
    34223607            return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
    34233608
    3424     /*
    3425      * Retry loop.
    3426      */
    3427     Assert(pGipCpuWorker->i64TSCDelta == INT64_MAX);
    3428     for (iTry = 0; iTry < 12; iTry++)
    3429     {
    3430         if (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_READY)
    3431             break;
    3432 
    3433         /*
    3434          * Do the measurements.
    3435          */
     3609/** @todo Add a resumable state to pArgs so we don't waste time if we time
     3610 *        out or something.  Timeouts are legit, any of the two CPUs may get
     3611 *        interrupted. */
     3612
     3613    /*
     3614     * Start by seeing if we have a zero delta between the two CPUs.
     3615     * This should normally be the case.
     3616     */
     3617    rc = supdrvTscDeltaVerify(pArgs, &MySync, pOtherSync, fIsMaster, GIP_TSC_DELTA_INITIAL_MASTER_VALUE);
     3618    if (RT_SUCCESS(rc))
     3619    {
     3620        if (fIsMaster)
     3621        {
     3622            ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, GIP_TSC_DELTA_INITIAL_MASTER_VALUE);
     3623            RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet);
     3624            RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet);
     3625        }
     3626        else
     3627        {
     3628            RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
     3629            RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
     3630        }
     3631    }
     3632    /*
     3633     * If the verification didn't time out, do regular delta measurements.
     3634     * We retry this until we get a reasonable value.
     3635     */
     3636    else if (rc != VERR_TIMEOUT)
     3637    {
     3638        Assert(pGipCpuWorker->i64TSCDelta == INT64_MAX);
     3639        for (iTry = 0; iTry < 12; iTry++)
     3640        {
     3641            if (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_READY)
     3642                break;
     3643
     3644            /*
     3645             * Do the measurements.
     3646             */
    34363647#ifdef GIP_TSC_DELTA_METHOD_1
    3437         supdrvTscDeltaMethod1Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry);
     3648            supdrvTscDeltaMethod1Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry);
    34383649#elif defined(GIP_TSC_DELTA_METHOD_2)
    3439         supdrvTscDeltaMethod2Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry);
     3650            supdrvTscDeltaMethod2Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry);
    34403651#else
    34413652# error "huh??"
    34423653#endif
    3443         if (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_READY)
    3444             break;
    3445 
    3446         /*
    3447          * Success? If so, stop trying.
    3448          */
    3449         if (pGipCpuWorker->i64TSCDelta != INT64_MAX)
    3450         {
    3451             if (fIsMaster)
     3654            if (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_READY)
     3655                break;
     3656
     3657            /*
     3658             * Success? If so, stop trying.
     3659             */
     3660            if (pGipCpuWorker->i64TSCDelta != INT64_MAX)
    34523661            {
    3453                 RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet);
    3454                 RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet);
     3662                if (fIsMaster)
     3663                {
     3664                    RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet);
     3665                    RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet);
     3666                }
     3667                else
     3668                {
     3669                    RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
     3670                    RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
     3671                }
     3672                break;
    34553673            }
    3456             else
    3457             {
    3458                 RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
    3459                 RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
    3460             }
    3461             break;
    34623674        }
    34633675    }
     
    36273839                if (RT_SUCCESS(rc))
    36283840                {
     3841#if 0
     3842                    SUPR0Printf("rcVerify=%d iVerifyBadTscDiff=%lld cMinVerifyTscTicks=%lld cMaxVerifyTscTicks=%lld\n",
     3843                                pArgs->rcVerify, pArgs->iVerifyBadTscDiff, pArgs->cMinVerifyTscTicks, pArgs->cMaxVerifyTscTicks);
     3844#endif
    36293845                    if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX))
    36303846                    {
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