Changeset 54387 in vbox for trunk/src/VBox/HostDrivers
- Timestamp:
- Feb 23, 2015 4:31:58 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp
r54379 r54387 2567 2567 /** Go! */ 2568 2568 #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) 2569 2571 2570 2572 /** We reached the time limit. */ … … 2586 2588 /** Pointer to the GIP CPU array entry for the master. */ 2587 2589 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;2592 2590 /** The maximum number of ticks to spend in supdrvMeasureTscDeltaCallback. 2593 2591 * (This is what we need a rough TSC frequency for.) */ … … 2614 2612 } M2; 2615 2613 #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)]; 2616 2642 } SUPDRVGIPTSCDELTARGS; 2617 2643 typedef SUPDRVGIPTSCDELTARGS *PSUPDRVGIPTSCDELTARGS; … … 2626 2652 * @{ 2627 2653 */ 2628 #if defined(DEBUG_bird) && defined(RT_OS_WINDOWS)2654 #if defined(DEBUG_bird) /* || defined(VBOX_STRICT) */ 2629 2655 # define TSCDELTA_DBG_VARS() uint32_t iDbgCounter 2630 2656 # 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) 2632 2659 #else 2633 2660 # define TSCDELTA_DBG_VARS() ((void)0) … … 3294 3321 3295 3322 3296 static int supdrvMeasureTscDeltaCallbackAbortSyncSetup(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync, 3297 bool fIsMaster, bool fTimeout) 3323 static 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 */ 3480 DECL_NO_INLINE(static, int) 3481 supdrvMeasureTscDeltaCallbackAbortSyncSetup(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync, bool fIsMaster, bool fTimeout) 3298 3482 { 3299 3483 PSUPTSCDELTASYNC2 volatile *ppMySync = fIsMaster ? &pArgs->pSyncMaster : &pArgs->pSyncWorker; … … 3353 3537 SUPTSCDELTASYNC2 MySync; 3354 3538 PSUPTSCDELTASYNC2 pOtherSync; 3539 int rc; 3355 3540 TSCDELTA_DBG_VARS(); 3356 3541 … … 3422 3607 return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/); 3423 3608 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 */ 3436 3647 #ifdef GIP_TSC_DELTA_METHOD_1 3437 supdrvTscDeltaMethod1Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry);3648 supdrvTscDeltaMethod1Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry); 3438 3649 #elif defined(GIP_TSC_DELTA_METHOD_2) 3439 supdrvTscDeltaMethod2Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry);3650 supdrvTscDeltaMethod2Loop(pArgs, &MySync, pOtherSync, fIsMaster, iTry); 3440 3651 #else 3441 3652 # error "huh??" 3442 3653 #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) 3452 3661 { 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; 3455 3673 } 3456 else3457 {3458 RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);3459 RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);3460 }3461 break;3462 3674 } 3463 3675 } … … 3627 3839 if (RT_SUCCESS(rc)) 3628 3840 { 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 3629 3845 if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX)) 3630 3846 {
Note:
See TracChangeset
for help on using the changeset viewer.