Changeset 54355 in vbox
- Timestamp:
- Feb 22, 2015 2:36:45 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp
r54354 r54355 768 768 */ 769 769 770 /** 771 * Used by supdrvInitRefineInvariantTscFreqTimer and supdrvGipInitMeasureTscFreq 772 * to update the TSC frequency related GIP variables. 773 * 774 * @param pGip The GIP. 775 * @param nsElapsed The number of nano seconds elapsed. 776 * @param cElapsedTscTicks The corresponding number of TSC ticks. 777 */ 770 778 static void supdrvGipInitSetCpuFreq(PSUPGLOBALINFOPAGE pGip, uint64_t nsElapsed, uint64_t cElapsedTscTicks) 771 779 { … … 805 813 * @param iTick The timer tick. 806 814 */ 807 static DECLCALLBACK(void) supdrvInitRefineInvariantTsc Timer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)815 static DECLCALLBACK(void) supdrvInitRefineInvariantTscFreqTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick) 808 816 { 809 817 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser; … … 937 945 * @param pDevExt Pointer to the device instance data. 938 946 * @param pGip Pointer to the GIP. 939 *940 * @remarks We cannot use this941 947 */ 942 948 static void supdrvGipInitStartTimerForRefiningInvariantTscFreq(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip) … … 983 989 rc = RTTimerCreateEx(&pDevExt->pInvarTscRefineTimer, 0 /* one-shot */, 984 990 RTTIMER_FLAGS_CPU(RTMpCpuIdToSetIndex(pDevExt->idCpuInvarTscRefine)), 985 supdrvInitRefineInvariantTsc Timer, pDevExt);991 supdrvInitRefineInvariantTscFreqTimer, pDevExt); 986 992 if (RT_SUCCESS(rc)) 987 993 { … … 995 1001 { 996 1002 rc = RTTimerCreateEx(&pDevExt->pInvarTscRefineTimer, 0 /* one-shot */, RTTIMER_FLAGS_CPU_ANY, 997 supdrvInitRefineInvariantTsc Timer, pDevExt);1003 supdrvInitRefineInvariantTscFreqTimer, pDevExt); 998 1004 if (RT_SUCCESS(rc)) 999 1005 { … … 1152 1158 else if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 1153 1159 { 1160 /** @todo This section of code is never reached atm, consider dropping it later on... */ 1154 1161 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 1155 1162 { … … 2130 2137 ASMAtomicWriteU64(&pGipCpu->u64TSC, u64TSC); 2131 2138 2132 /* We don't need to keep realculating the frequency when it's invariant. */ 2133 if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 2134 return; 2135 2136 if (u64TSCDelta >> 32) 2137 { 2138 u64TSCDelta = pGipCpu->u32UpdateIntervalTSC; 2139 pGipCpu->cErrors++; 2140 } 2141 2142 /* 2143 * On the 2nd and 3rd callout, reset the history with the current TSC 2144 * interval since the values entered by supdrvGipInit are totally off. 2145 * The interval on the 1st callout completely unreliable, the 2nd is a bit 2146 * better, while the 3rd should be most reliable. 2147 */ 2148 u32TransactionId = pGipCpu->u32TransactionId; 2149 if (RT_UNLIKELY( ( u32TransactionId == 5 2150 || u32TransactionId == 7) 2151 && ( iTick == 2 2152 || iTick == 3) )) 2153 { 2154 unsigned i; 2155 for (i = 0; i < RT_ELEMENTS(pGipCpu->au32TSCHistory); i++) 2156 ASMAtomicUoWriteU32(&pGipCpu->au32TSCHistory[i], (uint32_t)u64TSCDelta); 2157 } 2158 2159 /* 2160 * Validate the NanoTS deltas between timer fires with an arbitrary threshold of 0.5%. 2161 * Wait until we have at least one full history since the above history reset. The 2162 * assumption is that the majority of the previous history values will be tolerable. 2163 * See @bugref{6710} comment #67. 2164 */ 2165 if ( u32TransactionId > 23 /* 7 + (8 * 2) */ 2166 && pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 2167 { 2168 uint32_t uNanoTsThreshold = pGip->u32UpdateIntervalNS / 200; 2169 if ( pGipCpu->u32PrevUpdateIntervalNS > pGip->u32UpdateIntervalNS + uNanoTsThreshold 2170 || pGipCpu->u32PrevUpdateIntervalNS < pGip->u32UpdateIntervalNS - uNanoTsThreshold) 2139 /* 2140 * We don't need to keep realculating the frequency when it's invariant, so 2141 * the remainder of this function is only for the sync and async TSC modes. 2142 */ 2143 if (pGip->u32Mode != SUPGIPMODE_INVARIANT_TSC) 2144 { 2145 if (u64TSCDelta >> 32) 2146 { 2147 u64TSCDelta = pGipCpu->u32UpdateIntervalTSC; 2148 pGipCpu->cErrors++; 2149 } 2150 2151 /* 2152 * On the 2nd and 3rd callout, reset the history with the current TSC 2153 * interval since the values entered by supdrvGipInit are totally off. 2154 * The interval on the 1st callout completely unreliable, the 2nd is a bit 2155 * better, while the 3rd should be most reliable. 2156 */ 2157 /** @todo Could we drop this now that we initializes the history 2158 * with nominal TSC frequency values? */ 2159 u32TransactionId = pGipCpu->u32TransactionId; 2160 if (RT_UNLIKELY( ( u32TransactionId == 5 2161 || u32TransactionId == 7) 2162 && ( iTick == 2 2163 || iTick == 3) )) 2164 { 2165 unsigned i; 2166 for (i = 0; i < RT_ELEMENTS(pGipCpu->au32TSCHistory); i++) 2167 ASMAtomicUoWriteU32(&pGipCpu->au32TSCHistory[i], (uint32_t)u64TSCDelta); 2168 } 2169 2170 /* 2171 * Validate the NanoTS deltas between timer fires with an arbitrary threshold of 0.5%. 2172 * Wait until we have at least one full history since the above history reset. The 2173 * assumption is that the majority of the previous history values will be tolerable. 2174 * See @bugref{6710} comment #67. 2175 */ 2176 /** @todo Could we drop the fuding there now that we initializes the history 2177 * with nominal TSC frequency values? */ 2178 if ( u32TransactionId > 23 /* 7 + (8 * 2) */ 2179 && pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 2180 { 2181 uint32_t uNanoTsThreshold = pGip->u32UpdateIntervalNS / 200; 2182 if ( pGipCpu->u32PrevUpdateIntervalNS > pGip->u32UpdateIntervalNS + uNanoTsThreshold 2183 || pGipCpu->u32PrevUpdateIntervalNS < pGip->u32UpdateIntervalNS - uNanoTsThreshold) 2184 { 2185 uint32_t u32; 2186 u32 = pGipCpu->au32TSCHistory[0]; 2187 u32 += pGipCpu->au32TSCHistory[1]; 2188 u32 += pGipCpu->au32TSCHistory[2]; 2189 u32 += pGipCpu->au32TSCHistory[3]; 2190 u32 >>= 2; 2191 u64TSCDelta = pGipCpu->au32TSCHistory[4]; 2192 u64TSCDelta += pGipCpu->au32TSCHistory[5]; 2193 u64TSCDelta += pGipCpu->au32TSCHistory[6]; 2194 u64TSCDelta += pGipCpu->au32TSCHistory[7]; 2195 u64TSCDelta >>= 2; 2196 u64TSCDelta += u32; 2197 u64TSCDelta >>= 1; 2198 } 2199 } 2200 2201 /* 2202 * TSC History. 2203 */ 2204 Assert(RT_ELEMENTS(pGipCpu->au32TSCHistory) == 8); 2205 iTSCHistoryHead = (pGipCpu->iTSCHistoryHead + 1) & 7; 2206 ASMAtomicWriteU32(&pGipCpu->iTSCHistoryHead, iTSCHistoryHead); 2207 ASMAtomicWriteU32(&pGipCpu->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta); 2208 2209 /* 2210 * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ. 2211 * 2212 * On Windows, we have an occasional (but recurring) sour value that messed up 2213 * the history but taking only 1 interval reduces the precision overall. 2214 */ 2215 if ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC 2216 || pGip->u32UpdateHz >= 1000) 2171 2217 { 2172 2218 uint32_t u32; … … 2176 2222 u32 += pGipCpu->au32TSCHistory[3]; 2177 2223 u32 >>= 2; 2178 u64TSCDelta = pGipCpu->au32TSCHistory[4]; 2179 u64TSCDelta += pGipCpu->au32TSCHistory[5]; 2180 u64TSCDelta += pGipCpu->au32TSCHistory[6]; 2181 u64TSCDelta += pGipCpu->au32TSCHistory[7]; 2182 u64TSCDelta >>= 2; 2183 u64TSCDelta += u32; 2184 u64TSCDelta >>= 1; 2185 } 2186 } 2187 2188 /* 2189 * TSC History. 2190 */ 2191 Assert(RT_ELEMENTS(pGipCpu->au32TSCHistory) == 8); 2192 iTSCHistoryHead = (pGipCpu->iTSCHistoryHead + 1) & 7; 2193 ASMAtomicWriteU32(&pGipCpu->iTSCHistoryHead, iTSCHistoryHead); 2194 ASMAtomicWriteU32(&pGipCpu->au32TSCHistory[iTSCHistoryHead], (uint32_t)u64TSCDelta); 2195 2196 /* 2197 * UpdateIntervalTSC = average of last 8,2,1 intervals depending on update HZ. 2198 * 2199 * On Windows, we have an occasional (but recurring) sour value that messed up 2200 * the history but taking only 1 interval reduces the precision overall. 2201 * However, this problem existed before the invariant mode was introduced. 2202 */ 2203 if ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC 2204 || pGip->u32UpdateHz >= 1000) 2205 { 2206 uint32_t u32; 2207 u32 = pGipCpu->au32TSCHistory[0]; 2208 u32 += pGipCpu->au32TSCHistory[1]; 2209 u32 += pGipCpu->au32TSCHistory[2]; 2210 u32 += pGipCpu->au32TSCHistory[3]; 2211 u32 >>= 2; 2212 u32UpdateIntervalTSC = pGipCpu->au32TSCHistory[4]; 2213 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[5]; 2214 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[6]; 2215 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[7]; 2216 u32UpdateIntervalTSC >>= 2; 2217 u32UpdateIntervalTSC += u32; 2218 u32UpdateIntervalTSC >>= 1; 2219 2220 /* Value chosen for a 2GHz Athlon64 running linux 2.6.10/11. */ 2221 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14; 2222 } 2223 else if (pGip->u32UpdateHz >= 90) 2224 { 2225 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta; 2226 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[(iTSCHistoryHead - 1) & 7]; 2227 u32UpdateIntervalTSC >>= 1; 2228 2229 /* value chosen on a 2GHz thinkpad running windows */ 2230 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7; 2231 } 2232 else 2233 { 2234 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta; 2235 2236 /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */ 2237 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6; 2238 } 2239 ASMAtomicWriteU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack); 2240 2241 /* 2242 * CpuHz. 2243 */ 2244 u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, RT_NS_1SEC); 2245 u64CpuHz /= pGip->u32UpdateIntervalNS; 2246 ASMAtomicWriteU64(&pGipCpu->u64CpuHz, u64CpuHz); 2224 u32UpdateIntervalTSC = pGipCpu->au32TSCHistory[4]; 2225 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[5]; 2226 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[6]; 2227 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[7]; 2228 u32UpdateIntervalTSC >>= 2; 2229 u32UpdateIntervalTSC += u32; 2230 u32UpdateIntervalTSC >>= 1; 2231 2232 /* Value chosen for a 2GHz Athlon64 running linux 2.6.10/11. */ 2233 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 14; 2234 } 2235 else if (pGip->u32UpdateHz >= 90) 2236 { 2237 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta; 2238 u32UpdateIntervalTSC += pGipCpu->au32TSCHistory[(iTSCHistoryHead - 1) & 7]; 2239 u32UpdateIntervalTSC >>= 1; 2240 2241 /* value chosen on a 2GHz thinkpad running windows */ 2242 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 7; 2243 } 2244 else 2245 { 2246 u32UpdateIntervalTSC = (uint32_t)u64TSCDelta; 2247 2248 /* This value hasn't be checked yet.. waiting for OS/2 and 33Hz timers.. :-) */ 2249 u32UpdateIntervalTSCSlack = u32UpdateIntervalTSC >> 6; 2250 } 2251 ASMAtomicWriteU32(&pGipCpu->u32UpdateIntervalTSC, u32UpdateIntervalTSC + u32UpdateIntervalTSCSlack); 2252 2253 /* 2254 * CpuHz. 2255 */ 2256 u64CpuHz = ASMMult2xU32RetU64(u32UpdateIntervalTSC, RT_NS_1SEC); 2257 u64CpuHz /= pGip->u32UpdateIntervalNS; 2258 ASMAtomicWriteU64(&pGipCpu->u64CpuHz, u64CpuHz); 2259 } 2247 2260 } 2248 2261
Note:
See TracChangeset
for help on using the changeset viewer.