Changeset 54395 in vbox for trunk/src/VBox/HostDrivers/Support
- Timestamp:
- Feb 23, 2015 5:34:01 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp
r54392 r54395 109 109 #define GIP_TSC_DELTA_SYNC_PRESTART_WORKER 5 110 110 /** The TSC-refinement interval in seconds. */ 111 #define GIP_TSC_REFINE_P REIOD_IN_SECS 5111 #define GIP_TSC_REFINE_PERIOD_IN_SECS 5 112 112 /** The TSC-delta threshold for the SUPGIPUSETSCDELTA_PRACTICALLY_ZERO rating */ 113 113 #define GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 32 … … 142 142 static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 143 143 static void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz); 144 static int supdrvMeasureInitialTscDeltas(PSUPDRVDEVEXT pDevExt); 145 static int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker); 144 146 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 145 147 static int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt); 146 148 static void supdrvTscDeltaTerm(PSUPDRVDEVEXT pDevExt); 147 static int supdrvTscDeltaThreadWaitForOnlineCpus(PSUPDRVDEVEXT pDevExt);149 static void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt); 148 150 #endif 149 151 … … 197 199 * @note Don't you dare change the delta calculation. If you really do, make 198 200 * sure you update all places where it's used (IPRT, SUPLibAll.cpp, 199 * SUPDrv.c, supdrvGipMpEvent , and more).201 * SUPDrv.c, supdrvGipMpEvent(), and more). 200 202 */ 201 203 DECLINLINE(int) supdrvTscDeltaApply(PSUPGLOBALINFOPAGE pGip, uint64_t *puTsc, uint16_t idApic, bool *pfDeltaApplied) … … 769 771 770 772 /** 771 * Used by supdrvInitRefineInvariantTscFreqTimer and supdrvGipInitMeasureTscFreq 772 * to update the TSC frequency related GIP variables. 773 * Used by supdrvInitRefineInvariantTscFreqTimer() and 774 * supdrvGipInitMeasureTscFreq() to update the TSC frequency related GIP 775 * variables. 773 776 * 774 777 * @param pGip The GIP. … … 807 810 * 808 811 * This is started during driver init and fires once 809 * GIP_TSC_REFINE_P REIOD_IN_SECS seconds later.812 * GIP_TSC_REFINE_PERIOD_IN_SECS seconds later. 810 813 * 811 814 * @param pTimer The timer. … … 834 837 * an interrupt handler with higher priority than the clock 835 838 * interrupt, or spinning for ages in timer handlers is frowned 836 * upon, this lookmust be disabled!839 * upon, this code must be disabled! 837 840 * 838 841 * Darwin, FreeBSD, Linux, Solaris, Windows 8.1+: … … 863 866 /* 864 867 * If the above measurement was taken on a different CPU than the one we 865 * started the rprocess on, cTscTicksElapsed will need to be adjusted with868 * started the process on, cTscTicksElapsed will need to be adjusted with 866 869 * the TSC deltas of both the CPUs. 867 870 * … … 896 899 * calculations. 897 900 */ 898 else if (cNsElapsed <= GIP_TSC_REFINE_P REIOD_IN_SECS * 5 * RT_NS_1SEC_64)901 else if (cNsElapsed <= GIP_TSC_REFINE_PERIOD_IN_SECS * 5 * RT_NS_1SEC_64) 899 902 { 900 903 int rc = RTTimerStart(pTimer, RT_NS_1SEC); … … 905 908 { 906 909 SUPR0Printf("vboxdrv: Failed to refine invariant TSC frequency because deltas are unavailable after %u (%u) seconds\n", 907 (uint32_t)(cNsElapsed / RT_NS_1SEC), GIP_TSC_REFINE_P REIOD_IN_SECS);910 (uint32_t)(cNsElapsed / RT_NS_1SEC), GIP_TSC_REFINE_PERIOD_IN_SECS); 908 911 SUPR0Printf("vboxdrv: start: %u, %u, %#llx stop: %u, %u, %#llx\n", 909 912 iStartCpuSet, iStartGipCpu, iStartTscDelta, iStopCpuSet, iStopGipCpu, iStopTscDelta); … … 927 930 * Reschedule the timer if we haven't yet reached the defined refinement period. 928 931 */ 929 if (cNsElapsed < GIP_TSC_REFINE_P REIOD_IN_SECS * RT_NS_1SEC_64)932 if (cNsElapsed < GIP_TSC_REFINE_PERIOD_IN_SECS * RT_NS_1SEC_64) 930 933 { 931 934 int rc = RTTimerStart(pTimer, RT_NS_1SEC); … … 980 983 * first VMs before we're done. On most systems we will be loading the 981 984 * support driver during boot and VMs won't be started for a while yet, 982 * it is really only a problem during development (especiall with985 * it is really only a problem during development (especially with 983 986 * on-demand driver starting on windows). 984 987 * 985 * To avoid wasting time doing a long supdrvGipInitMeasureTscFreq call986 * to calculate the frequenc ey during driver loading, the timer is set988 * To avoid wasting time doing a long supdrvGipInitMeasureTscFreq() call 989 * to calculate the frequency during driver loading, the timer is set 987 990 * to fire after 200 ms the first time. It will then reschedule itself 988 * to fire every second until GIP_TSC_REFINE_P REIOD_IN_SECS has been991 * to fire every second until GIP_TSC_REFINE_PERIOD_IN_SECS has been 989 992 * reached or it notices that there is a user land client with GIP 990 993 * mapped (we want a stable frequency for all VMs). … … 1292 1295 1293 1296 AssertPtrReturnVoid(pGip); 1297 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD)); 1294 1298 AssertRelease(idCpu == RTMpCpuId()); 1295 1299 Assert(pGip->cPossibleCpus == RTMpGetCount()); … … 1333 1337 ASMAtomicWriteU16(&pGip->aiCpuFromCpuSetIdx[iCpuSet], i); 1334 1338 1339 /* Add this CPU to this set of CPUs we need to calculate the TSC-delta for. */ 1340 RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, RTMpCpuIdToSetIndex(idCpu)); 1341 1335 1342 /* Update the Mp online/offline counter. */ 1336 1343 ASMAtomicIncU32(&pDevExt->cMpOnOffEvents); 1337 1344 1338 /* Add this CPU to the set of CPUs for which we need to calculate their TSC-deltas. */ 1339 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 1340 { 1341 RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, iCpuSet); 1342 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 1343 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 1344 if ( pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening 1345 || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring) 1346 { 1347 pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure; 1348 } 1349 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 1350 #endif 1351 } 1352 1353 /* commit it */ 1345 /* Commit it. */ 1354 1346 ASMAtomicWriteSize(&pGip->aCPUs[i].enmState, SUPGIPCPUSTATE_ONLINE); 1355 1347 1356 1348 RTSpinlockRelease(pDevExt->hGipSpinlock); 1349 } 1350 1351 1352 /** 1353 * RTMpOnSpecific callback wrapper for supdrvGipMpEventOnlineOrInitOnCpu(). 1354 * 1355 * @param idCpu The CPU ID we are running on. 1356 * @param pvUser1 Opaque pointer to the device instance data. 1357 * @param pvUser2 Not used. 1358 */ 1359 static DECLCALLBACK(void) supdrvGipMpEventOnlineCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2) 1360 { 1361 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser1; 1362 NOREF(pvUser2); 1363 supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu); 1357 1364 } 1358 1365 … … 1396 1403 } 1397 1404 1398 /* commit it*/1405 /* Commit it. */ 1399 1406 ASMAtomicWriteSize(&pGip->aCPUs[i].enmState, SUPGIPCPUSTATE_OFFLINE); 1400 1407 … … 1412 1419 * @param idCpu The cpu it applies to. 1413 1420 * @param pvUser Pointer to the device extension. 1414 *1415 * @remarks This function -must- fire on the newly online'd CPU for the1416 * RTMPEVENT_ONLINE case and can fire on any CPU for the1417 * RTMPEVENT_OFFLINE case.1418 1421 */ 1419 1422 static DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser) … … 1422 1425 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 1423 1426 1424 AssertRelease(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));1425 1426 /*1427 * Update the GIP CPU data.1428 */1429 1427 if (pGip) 1430 1428 { 1429 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER; 1431 1430 switch (enmEvent) 1432 1431 { 1433 1432 case RTMPEVENT_ONLINE: 1434 AssertRelease(idCpu == RTMpCpuId()); 1435 supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu); 1433 { 1434 RTThreadPreemptDisable(&PreemptState); 1435 if (idCpu == RTMpCpuId()) 1436 { 1437 supdrvGipMpEventOnlineOrInitOnCpu(pDevExt, idCpu); 1438 RTThreadPreemptRestore(&PreemptState); 1439 } 1440 else 1441 { 1442 RTThreadPreemptRestore(&PreemptState); 1443 RTMpOnSpecific(idCpu, supdrvGipMpEventOnlineCallback, pDevExt, NULL /* pvUser2 */); 1444 } 1445 1446 /* 1447 * Recompute TSC-delta for the newly online'd CPU. 1448 */ 1449 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 1450 { 1451 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 1452 supdrvTscDeltaThreadStartMeasurement(pDevExt); 1453 #else 1454 uint32_t iCpu = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu); 1455 supdrvMeasureTscDeltaOne(pDevExt, iCpu); 1456 #endif 1457 } 1436 1458 break; 1459 } 1460 1437 1461 case RTMPEVENT_OFFLINE: 1438 1462 supdrvGipMpEventOffline(pDevExt, idCpu); … … 1689 1713 ASMAtomicWriteU16(&pCpu->idApic, UINT16_MAX); 1690 1714 1691 /* 1715 /* 1692 1716 * The first time we're called, we don't have a CPU frequency handy, 1693 1717 * so pretend it's a 4 GHz CPU. On CPUs that are online, we'll get … … 1873 1897 * If we're in any of the other two modes, neither which require MP init, 1874 1898 * notifications or deltas for the job, do the full measurement now so 1875 * that supdrvGipInitOnCpu can populate the TSC interval and history1899 * that supdrvGipInitOnCpu() can populate the TSC interval and history 1876 1900 * array with more reasonable values. 1877 1901 */ 1878 1902 if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 1879 1903 { 1880 rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, true /* fRough*/); /* cannot fail */1904 rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, true /* fRough */); /* cannot fail */ 1881 1905 supdrvGipInitStartTimerForRefiningInvariantTscFreq(pDevExt, pGip); 1882 1906 } 1883 1907 else 1884 rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, false /* fRough*/);1908 rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, false /* fRough */); 1885 1909 if (RT_SUCCESS(rc)) 1886 1910 { … … 1910 1934 { 1911 1935 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 1912 if (pDevExt->hTscDeltaThread != NIL_RTTHREAD) 1913 RTThreadUserSignal(pDevExt->hTscDeltaThread); 1936 supdrvTscDeltaThreadStartMeasurement(pDevExt); 1914 1937 #else 1915 1938 uint16_t iCpu; … … 2432 2455 2433 2456 ASMSetFlags(uFlags); 2434 2435 #ifdef SUPDRV_USE_TSC_DELTA_THREAD2436 if ( pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED2437 && !RTCpuSetIsEmpty(&pDevExt->TscDeltaCpuSet))2438 {2439 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);2440 if ( pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening2441 || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)2442 pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure;2443 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock);2444 /** @todo Do the actual poking using -- RTThreadUserSignal() */2445 }2446 #endif2447 2457 } 2448 2458 … … 2577 2587 2578 2588 /** 2579 * Argument package/state passed by supdrvMeasureTscDeltaOne to the RTMpOn2589 * Argument package/state passed by supdrvMeasureTscDeltaOne() to the RTMpOn 2580 2590 * callback worker. 2581 2591 */ … … 3157 3167 * The idea here is that we have the two CPUs execute the exact same code 3158 3168 * collecting a largish set of TSC samples. The code has one data dependency on 3159 * the other CPU w hich intention it is to synchronize the execution as well as3160 * help cross references the two sets of TSC samples (the sequence numbers).3169 * the other CPU with the intention to synchronize the execution as well 3170 * as help cross references the two sets of TSC samples (the sequence numbers). 3161 3171 * 3162 3172 * The @a fLag parameter is used to modify the execution a tiny bit on one or … … 3811 3821 */ 3812 3822 PSUPDRVGIPTSCDELTARGS pArgs = (PSUPDRVGIPTSCDELTARGS)RTMemAllocZ(sizeof(*pArgs)); 3813 if ( pArgs)3823 if (RT_LIKELY(pArgs)) 3814 3824 { 3815 3825 pArgs->pWorker = pGipCpuWorker; … … 4106 4116 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 4107 4117 pDevExt->cMsTscDeltaTimeout = 1; 4108 RTThreadSleep(1 0);4118 RTThreadSleep(1); 4109 4119 /* fall thru */ 4110 4120 } … … 4256 4266 4257 4267 /** 4258 * Waits for TSC-delta measurements to be completed for all online CPUs. 4259 * 4260 * @returns VBox status code. 4261 * @param pDevExt Pointer to the device instance data. 4262 */ 4263 static int supdrvTscDeltaThreadWaitForOnlineCpus(PSUPDRVDEVEXT pDevExt) 4264 { 4265 int cTriesLeft = 5; 4266 int cMsTotalWait; 4267 int cMsWaited = 0; 4268 int cMsWaitGranularity = 1; 4269 4270 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 4271 AssertReturn(pGip, VERR_INVALID_POINTER); 4272 4273 if (RT_UNLIKELY(pDevExt->hTscDeltaThread == NIL_RTTHREAD)) 4274 return VERR_THREAD_NOT_WAITABLE; 4275 4276 cMsTotalWait = RT_MIN(pGip->cPresentCpus + 10, 200); 4277 while (cTriesLeft-- > 0) 4278 { 4279 if (RTCpuSetIsEqual(&pDevExt->TscDeltaObtainedCpuSet, &pGip->OnlineCpuSet)) 4280 return VINF_SUCCESS; 4281 RTThreadSleep(cMsWaitGranularity); 4282 cMsWaited += cMsWaitGranularity; 4283 if (cMsWaited >= cMsTotalWait) 4284 break; 4285 } 4286 4287 return VERR_TIMEOUT; 4268 * Signals the TSC-delta thread to start measuring TSC-deltas. 4269 * 4270 * @param pDevExt Pointer to the device instance data. 4271 */ 4272 static void supdrvTscDeltaThreadStartMeasurement(PSUPDRVDEVEXT pDevExt) 4273 { 4274 if (RT_LIKELY(pDevExt->hTscDeltaThread != NIL_RTTHREAD)) 4275 { 4276 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 4277 if ( pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening 4278 || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring) 4279 { 4280 pDevExt->enmTscDeltaThreadState = kTscDeltaThreadState_WaitAndMeasure; 4281 } 4282 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); 4283 RTThreadUserSignal(pDevExt->hTscDeltaThread); 4284 } 4288 4285 } 4289 4286 … … 4457 4454 return VERR_INVALID_FLAGS; 4458 4455 4456 /* 4457 * The request is a noop if the TSC delta isn't being used. 4458 */ 4459 if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED) 4460 return VINF_SUCCESS; 4461 4459 4462 if (cTries == 0) 4460 4463 cTries = 12; … … 4466 4469 else if (cMsWaitRetry > 1000) 4467 4470 cMsWaitRetry = 1000; 4468 4469 /*4470 * The request is a noop if the TSC delta isn't being used.4471 */4472 if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED)4473 return VINF_SUCCESS;4474 4471 4475 4472 #ifdef SUPDRV_USE_TSC_DELTA_THREAD … … 4497 4494 rc = VINF_SUCCESS; 4498 4495 } 4499 else 4496 else if (pDevExt->enmTscDeltaThreadState != kTscDeltaThreadState_WaitAndMeasure) 4500 4497 rc = VERR_THREAD_IS_DEAD; 4501 4498 RTSpinlockRelease(pDevExt->hTscDeltaSpinlock); … … 4613 4610 4614 4611 return SUPR0TscDeltaMeasureBySetIndex(pSession, iCpuSet, fFlags, cMsWaitRetry, 4615 cTries == 0 ? 5 *RT_MS_1SEC : cMsWaitRetry * cTries /*cMsWaitThread*/,4612 cTries == 0 ? 5 * RT_MS_1SEC : cMsWaitRetry * cTries /*cMsWaitThread*/, 4616 4613 cTries); 4617 4614 } … … 4691 4688 rc = supdrvMeasureTscDeltaOne(pDevExt, iGipCpu); 4692 4689 Assert(pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX || RT_FAILURE_NP(rc)); 4693 /** @todo should probably delay on failure... dpc watchdogs 4690 /** @todo should probably delay on failure... dpc watchdogs */ 4694 4691 } 4695 4692 else
Note:
See TracChangeset
for help on using the changeset viewer.