Changeset 53269 in vbox for trunk/src/VBox/HostDrivers/Support/SUPDrv.c
- Timestamp:
- Nov 7, 2014 5:41:01 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrv.c
r53230 r53269 205 205 * or offline. */ 206 206 static volatile uint32_t g_cMpOnOffEvents; 207 /** TSC reading during start of TSC frequency refinement phase. */ 208 uint64_t g_u64TSCAnchor; 209 /** Timestamp (in nanosec) during start of TSC frequency refinement phase. */ 210 uint64_t g_u64NanoTSAnchor; 207 211 208 212 /** … … 5921 5925 5922 5926 5923 #if 0 5924 /** 5925 * Measures the nominal TSC frequency. 5927 /** 5928 * Measures the TSC frequency of the system. 5926 5929 * 5927 5930 * Uses a busy-wait method for the async. case as it is intended to help push 5928 5931 * the CPU frequency up, while for the invariant cases using a sleeping method. 5929 5932 * 5933 * The TSC frequency can vary on systems that are not reported as invariant. 5934 * However, on such systems the object of this function is to find out what the 5935 * nominal, maximum TSC frequency under normal CPU operation. 5936 * 5930 5937 * @returns VBox status code. 5931 5938 * @param pGip Pointer to the GIP. … … 5933 5940 * @remarks Must be called only after measuring the TSC deltas. 5934 5941 */ 5935 static int supdrvGipMeasure NominalTscFreq(PSUPGLOBALINFOPAGE pGip)5942 static int supdrvGipMeasureTscFreq(PSUPGLOBALINFOPAGE pGip) 5936 5943 { 5937 5944 int cTriesLeft = 4; … … 5944 5951 { 5945 5952 RTCCUINTREG uFlags; 5946 uint64_t u64NanoTs ;5953 uint64_t u64NanoTsBefore; 5947 5954 uint64_t u64NanoTsAfter; 5948 5955 uint64_t u64TscBefore; … … 5955 5962 * Especially important on Windows where the granularity is terrible. 5956 5963 */ 5957 u64NanoTs = RTTimeSystemNanoTS();5958 while (RTTimeSystemNanoTS() == u64NanoTs )5964 u64NanoTsBefore = RTTimeSystemNanoTS(); 5965 while (RTTimeSystemNanoTS() == u64NanoTsBefore) 5959 5966 ASMNopPause(); 5960 5967 5961 uFlags = ASMIntDisableFlags();5962 idApicBefore = ASMGetApicId();5963 u64TscBefore = ASMReadTSC();5964 u64NanoTs 5968 uFlags = ASMIntDisableFlags(); 5969 idApicBefore = ASMGetApicId(); 5970 u64TscBefore = ASMReadTSC(); 5971 u64NanoTsBefore = RTTimeSystemNanoTS(); 5965 5972 ASMSetFlags(uFlags); 5966 5973 … … 5971 5978 * Shorter interval produces more variance in the frequency (esp. Windows). 5972 5979 */ 5973 RTThreadSleep(200); /* Sleeping shorter produces a tad more variance in the frequency than I'd like. */5980 RTThreadSleep(200); 5974 5981 u64NanoTsAfter = RTTimeSystemNanoTS(); 5975 5982 while (RTTimeSystemNanoTS() == u64NanoTsAfter) … … 5979 5986 else 5980 5987 { 5981 /* Busy wait, ramps up the CPU frequency on async systems. */5988 /* Busy-wait keeping the frequency up and measure. */ 5982 5989 for (;;) 5983 5990 { 5984 5991 u64NanoTsAfter = RTTimeSystemNanoTS(); 5985 if (u64NanoTsAfter < RT_NS_100MS + u64NanoTs )5992 if (u64NanoTsAfter < RT_NS_100MS + u64NanoTsBefore) 5986 5993 ASMNopPause(); 5987 5994 else … … 5991 5998 5992 5999 uFlags = ASMIntDisableFlags(); 6000 idApicAfter = ASMGetApicId(); 5993 6001 u64TscAfter = ASMReadTSC(); 5994 idApicAfter = ASMGetApicId();5995 6002 ASMSetFlags(uFlags); 5996 6003 … … 5998 6005 if (supdrvIsInvariantTsc()) 5999 6006 { 6000 PSUPGIPCPU pGipCpuBefore; 6001 PSUPGIPCPU pGipCpuAfter; 6002 6003 uint16_t iCpuBefore = pGip->aiCpuFromApicId[idApicBefore]; 6004 uint16_t iCpuAfter = pGip->aiCpuFromApicId[idApicAfter]; 6005 AssertMsgReturn(iCpuBefore < pGip->cCpus, ("iCpuBefore=%u cCpus=%u\n", iCpuBefore, pGip->cCpus), VERR_INVALID_CPU_INDEX); 6006 AssertMsgReturn(iCpuAfter < pGip->cCpus, ("iCpuAfter=%u cCpus=%u\n", iCpuAfter, pGip->cCpus), VERR_INVALID_CPU_INDEX); 6007 pGipCpuBefore = &pGip->aCPUs[iCpuBefore]; 6008 pGipCpuAfter = &pGip->aCPUs[iCpuAfter]; 6009 6010 if ( pGipCpuBefore->i64TSCDelta != INT64_MAX 6011 && pGipCpuAfter->i64TSCDelta != INT64_MAX) 6012 { 6013 u64TscBefore -= pGipCpuBefore->i64TSCDelta; 6014 u64TscAfter -= pGipCpuAfter->i64TSCDelta; 6015 6016 SUPR0Printf("vboxdrv: TSC frequency is %lu Hz - invariant, kernel timer granularity is %lu Ns\n", 6017 ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTs), 6018 RTTimerGetSystemGranularity()); 6019 return VINF_SUCCESS; 6020 } 6021 else 6022 { 6023 SUPR0Printf("vboxdrv: supdrvGipMeasureNominalTscFreq: iCpuBefore=%u iCpuAfter=%u cTriesLeft=%u\n", iCpuBefore, 6024 iCpuAfter, cTriesLeft); 6025 } 6026 } 6027 else 6028 { 6029 SUPR0Printf("vboxdrv: TSC frequency is %lu Hz - maybe variant, kernel timer granularity is %lu Ns\n", 6030 ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTs), 6031 RTTimerGetSystemGranularity()); 6032 return VINF_SUCCESS; 6033 } 6007 int rc; 6008 bool fAppliedBefore; 6009 bool fAppliedAfter; 6010 rc = SUPTscDeltaApply(pGip, &u64TscBefore, idApicBefore, &fAppliedBefore); AssertRCReturn(rc, rc); 6011 rc = SUPTscDeltaApply(pGip, &u64TscAfter, idApicAfter, &fAppliedAfter); AssertRCReturn(rc, rc); 6012 6013 if ( !fAppliedBefore 6014 || !fAppliedAfter) 6015 { 6016 SUPR0Printf("vboxdrv: supdrvGipMeasureTscFreq: idApicBefore=%u idApicAfter=%u cTriesLeft=%u\n", 6017 idApicBefore, idApicAfter, cTriesLeft); 6018 continue; 6019 } 6020 } 6021 6022 /* 6023 * Update GIP. 6024 */ 6025 pGip->u64CpuHz = ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTsBefore); 6026 return VINF_SUCCESS; 6034 6027 } 6035 6028 6036 6029 return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED; 6037 6030 } 6038 #endif6039 6031 6040 6032 … … 6128 6120 #endif 6129 6121 6130 #if 0 6131 /** @todo refactor later and use the nominal TSC rate for invariant case as 6132 * the real and constant TSC rate. */ 6133 supdrvGipMeasureNominalTscFreq(pGip); 6134 #endif 6135 6136 /* 6137 * Create the timer. 6138 * If CPU_ALL isn't supported we'll have to fall back to synchronous mode. 6139 */ 6140 if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC) 6141 { 6142 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, RTTIMER_FLAGS_CPU_ALL, supdrvGipAsyncTimer, pDevExt); 6143 if (rc == VERR_NOT_SUPPORTED) 6144 { 6145 OSDBGPRINT(("supdrvGipCreate: omni timer not supported, falling back to synchronous mode\n")); 6146 pGip->u32Mode = SUPGIPMODE_SYNC_TSC; 6147 } 6148 } 6149 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 6150 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, supdrvGipSyncTimer, pDevExt); 6122 rc = supdrvGipMeasureTscFreq(pGip); 6151 6123 if (RT_SUCCESS(rc)) 6152 6124 { 6125 if (supdrvIsInvariantTsc()) 6126 { 6127 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 6128 pGip->aCPUs[iCpu].u64CpuHz = pGip->u64CpuHz; 6129 } 6130 6153 6131 /* 6154 * We're good. 6132 * Create the timer. 6133 * If CPU_ALL isn't supported we'll have to fall back to synchronous mode. 6155 6134 */ 6156 Log(("supdrvGipCreate: %u ns interval.\n", u32Interval)); 6157 g_pSUPGlobalInfoPage = pGip; 6158 return VINF_SUCCESS; 6159 } 6160 else 6161 { 6162 OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %u ns interval. rc=%Rrc\n", u32Interval, rc)); 6163 Assert(!pDevExt->pGipTimer); 6135 if (pGip->u32Mode == SUPGIPMODE_ASYNC_TSC) 6136 { 6137 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, RTTIMER_FLAGS_CPU_ALL, supdrvGipAsyncTimer, pDevExt); 6138 if (rc == VERR_NOT_SUPPORTED) 6139 { 6140 OSDBGPRINT(("supdrvGipCreate: omni timer not supported, falling back to synchronous mode\n")); 6141 pGip->u32Mode = SUPGIPMODE_SYNC_TSC; 6142 } 6143 } 6144 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 6145 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, supdrvGipSyncTimer, pDevExt); 6146 if (RT_SUCCESS(rc)) 6147 { 6148 /* 6149 * We're good. 6150 */ 6151 Log(("supdrvGipCreate: %u ns interval.\n", u32Interval)); 6152 g_pSUPGlobalInfoPage = pGip; 6153 return VINF_SUCCESS; 6154 } 6155 else 6156 { 6157 OSDBGPRINT(("supdrvGipCreate: failed create GIP timer at %u ns interval. rc=%Rrc\n", u32Interval, rc)); 6158 Assert(!pDevExt->pGipTimer); 6159 } 6164 6160 } 6165 6161 } … … 6281 6277 6282 6278 ASMSetFlags(fOldFlags); 6279 6280 if (supdrvIsInvariantTsc()) 6281 { 6282 /* 6283 * Refine the TSC frequency measurement over a longer interval. Ideally, we want to keep the 6284 * interval as small as possible while gaining the most consistent and accurate frequency 6285 * (compared to what the host OS might have measured). 6286 * 6287 * In theory, we gain more accuracy with longer intervals, but we want VMs to startup with the 6288 * same TSC frequency whenever possible so we need to keep the interval short. 6289 */ 6290 uint8_t idApic; 6291 uint64_t u64NanoTS; 6292 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 6293 const int cSeconds = 3; 6294 if (RT_UNLIKELY(iTick == 3)) /* Helps with more consistent values across multiple runs (esp. Windows). */ 6295 { 6296 u64NanoTS = RTTimeSystemNanoTS(); 6297 while (RTTimeSystemNanoTS() == u64NanoTS) 6298 ASMNopPause(); 6299 fOldFlags = ASMIntDisableFlags(); 6300 idApic = ASMGetApicId(); 6301 g_u64TSCAnchor = ASMReadTSC(); 6302 g_u64NanoTSAnchor = RTTimeSystemNanoTS(); 6303 ASMSetFlags(fOldFlags); 6304 SUPTscDeltaApply(pGip, &g_u64TSCAnchor, idApic, NULL /* pfDeltaApplied */); 6305 ++g_u64TSCAnchor; 6306 } 6307 else if (g_u64TSCAnchor) 6308 { 6309 uint64_t u64DeltaNanoTS; 6310 u64NanoTS = RTTimeSystemNanoTS(); 6311 while (RTTimeSystemNanoTS() == u64NanoTS) 6312 ASMNopPause(); 6313 fOldFlags = ASMIntDisableFlags(); 6314 idApic = ASMGetApicId(); 6315 u64TSC = ASMReadTSC(); 6316 u64NanoTS = RTTimeSystemNanoTS(); 6317 ASMSetFlags(fOldFlags); 6318 SUPTscDeltaApply(pGip, &u64TSC, idApic, NULL /* pfDeltaApplied */); 6319 u64DeltaNanoTS = u64NanoTS - g_u64NanoTSAnchor; 6320 if (u64DeltaNanoTS >= cSeconds * RT_NS_1SEC_64) 6321 { 6322 uint16_t iCpu; 6323 if (u64DeltaNanoTS < UINT32_MAX) 6324 pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64TSC - g_u64TSCAnchor, RT_NS_1SEC, u64DeltaNanoTS); 6325 else 6326 pGip->u64CpuHz = (u64TSC - g_u64TSCAnchor) / (u64DeltaNanoTS / RT_NS_1SEC); 6327 6328 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 6329 pGip->aCPUs[iCpu].u64CpuHz = pGip->u64CpuHz; 6330 g_u64TSCAnchor = 0; 6331 } 6332 } 6333 } 6283 6334 } 6284 6335 … … 7069 7120 * @param pDevExt Pointer to the device instance data. 7070 7121 */ 7071 static SUPGIPMODE supdrvGipDetermin TscMode(PSUPDRVDEVEXT pDevExt)7122 static SUPGIPMODE supdrvGipDetermineTscMode(PSUPDRVDEVEXT pDevExt) 7072 7123 { 7073 7124 #if 0 … … 7191 7242 pGip->u32Magic = SUPGLOBALINFOPAGE_MAGIC; 7192 7243 pGip->u32Version = SUPGLOBALINFOPAGE_VERSION; 7193 pGip->u32Mode = supdrvGipDetermin TscMode(pDevExt);7244 pGip->u32Mode = supdrvGipDetermineTscMode(pDevExt); 7194 7245 pGip->cCpus = (uint16_t)cCpus; 7195 7246 pGip->cPages = (uint16_t)(cbGip / PAGE_SIZE); … … 7384 7435 ASMAtomicWriteU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack); 7385 7436 7437 if (supdrvIsInvariantTsc()) 7438 return; 7439 7386 7440 /* 7387 7441 * CpuHz. 7388 7442 */ 7389 u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, RT_NS_1SEC _64);7443 u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, RT_NS_1SEC); 7390 7444 u64CpuHz /= pGip->u32UpdateIntervalNS; 7391 7445 ASMAtomicWriteU64(&pGipCpu->u64CpuHz, u64CpuHz);
Note:
See TracChangeset
for help on using the changeset viewer.