Changeset 54278 in vbox
- Timestamp:
- Feb 18, 2015 7:42:01 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/time/timesupref.h
r54270 r54278 44 44 RTDECL(uint64_t) rtTimeNanoTSInternalRef(PRTTIMENANOTSDATA pData) 45 45 { 46 uint64_t u64Delta; 47 #if TMPL_MODE == TMPL_MODE_SYNC_INVAR_WITH_DELTA 48 int64_t i64TscDelta; 49 # ifdef IN_RING3 50 PSUPGIPCPU pGipCpuAttemptedTscRecalibration = NULL; 51 # endif 52 #endif 53 uint32_t u32NanoTSFactor0; 54 uint64_t u64TSC; 55 uint64_t u64NanoTS; 56 uint32_t u32UpdateIntervalTSC; 57 uint64_t u64PrevNanoTS; 46 #if TMPL_MODE == TMPL_MODE_SYNC_INVAR_WITH_DELTA && defined(IN_RING3) 47 PSUPGIPCPU pGipCpuAttemptedTscRecalibration = NULL; 48 #endif 58 49 AssertCompile(RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS)); 59 50 60 /*61 * Read the GIP data and the previous value.62 */63 51 for (;;) 64 52 { … … 147 135 * without triggering serializing twice. 148 136 */ 149 u 32NanoTSFactor0= pGip->u32UpdateIntervalNS;137 uint32_t u32NanoTSFactor0 = pGip->u32UpdateIntervalNS; 150 138 #if TMPL_MODE == TMPL_MODE_ASYNC 151 u 32UpdateIntervalTSC= pGipCpu->u32UpdateIntervalTSC;152 u 64NanoTS= pGipCpu->u64NanoTS;153 u 64TSC= pGipCpu->u64TSC;154 #else 155 u 32UpdateIntervalTSC= pGip->aCPUs[0].u32UpdateIntervalTSC;156 u 64NanoTS= pGip->aCPUs[0].u64NanoTS;157 u 64TSC= pGip->aCPUs[0].u64TSC;139 uint32_t u32UpdateIntervalTSC = pGipCpu->u32UpdateIntervalTSC; 140 uint64_t u64NanoTS = pGipCpu->u64NanoTS; 141 uint64_t u64TSC = pGipCpu->u64TSC; 142 #else 143 uint32_t u32UpdateIntervalTSC = pGip->aCPUs[0].u32UpdateIntervalTSC; 144 uint64_t u64NanoTS = pGip->aCPUs[0].u64NanoTS; 145 uint64_t u64TSC = pGip->aCPUs[0].u64TSC; 158 146 # if TMPL_MODE == TMPL_MODE_SYNC_INVAR_WITH_DELTA 159 i64TscDelta = pGipCpu->i64TSCDelta; 160 # endif 161 #endif 147 int64_t i64TscDelta = pGipCpu->i64TSCDelta; 148 # endif 149 #endif 150 uint64_t u64PrevNanoTS = ASMAtomicUoReadU64(pData->pu64Prev); 162 151 #if TMPL_GET_CPU_METHOD == SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS 163 u64PrevNanoTS = ASMAtomicUoReadU64(pData->pu64Prev);164 152 ASMCompilerBarrier(); 165 153 uint32_t uAux2; 166 u64Delta = ASMReadTscWithAux(&uAux2); /* serializing */ 167 #else 168 u64Delta = ASMReadTSC(); 169 u64PrevNanoTS = ASMAtomicUoReadU64(pData->pu64Prev); 154 uint64_t u64Delta = ASMReadTscWithAux(&uAux2); /* serializing */ 155 #else 156 uint64_t u64Delta = ASMReadTSC(); 170 157 ASMCompilerBarrier(); 171 158 # if TMPL_GET_CPU_METHOD != SUPGIPGETCPU_APIC_ID /* getting APIC will serialize */ \ … … 222 209 ASMSetFlags(uFlags); 223 210 #endif 224 break; 211 212 /* 213 * Calc NanoTS delta. 214 */ 215 u64Delta -= u64TSC; 216 if (RT_LIKELY(u64Delta <= u32UpdateIntervalTSC)) 217 { /* MSVC branch hint, probably pointless. */ } 218 else 219 { 220 /* 221 * We've expired the interval, cap it. If we're here for the 2nd 222 * time without any GIP update in-between, the checks against 223 * *pu64Prev below will force 1ns stepping. 224 */ 225 ASMAtomicIncU32(&pData->cExpired++); 226 u64Delta = u32UpdateIntervalTSC; 227 } 228 #if !defined(_MSC_VER) || !defined(RT_ARCH_X86) /* GCC makes very pretty code from these two inline calls, while MSC cannot. */ 229 u64Delta = ASMMult2xU32RetU64((uint32_t)u64Delta, u32NanoTSFactor0); 230 u64Delta = ASMDivU64ByU32RetU32(u64Delta, u32UpdateIntervalTSC); 231 #else 232 __asm 233 { 234 mov eax, dword ptr [u64Delta] 235 mul dword ptr [u32NanoTSFactor0] 236 div dword ptr [u32UpdateIntervalTSC] 237 mov dword ptr [u64Delta], eax 238 xor edx, edx 239 mov dword ptr [u64Delta + 4], edx 240 } 241 #endif 242 243 /* 244 * Calculate the time and compare it with the previously returned value. 245 */ 246 u64NanoTS += u64Delta; 247 uint64_t u64DeltaPrev = u64NanoTS - u64PrevNanoTS; 248 if (RT_LIKELY( u64DeltaPrev > 0 249 && u64DeltaPrev < UINT64_C(86000000000000) /* 24h */)) 250 { /* Frequent - less than 24h since last call. */ } 251 else if (RT_LIKELY( (int64_t)u64DeltaPrev <= 0 252 && (int64_t)u64DeltaPrev + u32NanoTSFactor0 * 2 >= 0)) 253 { 254 /* Occasional - u64NanoTS is in the recent 'past' relative the previous call. */ 255 ASMAtomicIncU32(&pData->c1nsSteps); 256 u64NanoTS = u64PrevNanoTS + 1; 257 } 258 else if (!u64PrevNanoTS) 259 /* We're resuming (see TMVirtualResume). */; 260 else 261 { 262 /* Something has gone bust, if negative offset it's real bad. */ 263 ASMAtomicIncU32(&pData->cBadPrev); 264 pData->pfnBad(pData, u64NanoTS, u64DeltaPrev, u64PrevNanoTS); 265 } 266 267 /* 268 * Attempt updating the previous value, provided we're still ahead of it. 269 * 270 * There is no point in recalculating u64NanoTS because we got preempted or if 271 * we raced somebody while the GIP was updated, since these are events 272 * that might occur at any point in the return path as well. 273 */ 274 if (RT_LIKELY(ASMAtomicCmpXchgU64(pData->pu64Prev, u64NanoTS, u64PrevNanoTS))) 275 return u64NanoTS; 276 277 ASMAtomicIncU32(&pData->cUpdateRaces); 278 for (int cTries = 25; cTries > 0; cTries--) 279 { 280 u64PrevNanoTS = ASMAtomicReadU64(pData->pu64Prev); 281 if (u64PrevNanoTS >= u64NanoTS) 282 break; 283 if (ASMAtomicCmpXchgU64(pData->pu64Prev, u64NanoTS, u64PrevNanoTS)) 284 break; 285 ASMNopPause(); 286 } 287 return u64NanoTS; 225 288 } 289 226 290 #if TMPL_MODE == TMPL_MODE_SYNC_INVAR_WITH_DELTA && defined(IN_RING3) 227 291 /* … … 284 348 return pData->pfnRediscover(pData); 285 349 } 286 287 /*288 * Calc NanoTS delta.289 */290 u64Delta -= u64TSC;291 if (RT_UNLIKELY(u64Delta > u32UpdateIntervalTSC))292 {293 /*294 * We've expired the interval, cap it. If we're here for the 2nd295 * time without any GIP update in-between, the checks against296 * *pu64Prev below will force 1ns stepping.297 */298 pData->cExpired++;299 u64Delta = u32UpdateIntervalTSC;300 }301 #if !defined(_MSC_VER) || defined(RT_ARCH_AMD64) /* GCC makes very pretty code from these two inline calls, while MSC cannot. */302 u64Delta = ASMMult2xU32RetU64((uint32_t)u64Delta, u32NanoTSFactor0);303 u64Delta = ASMDivU64ByU32RetU32(u64Delta, u32UpdateIntervalTSC);304 #else305 __asm306 {307 mov eax, dword ptr [u64Delta]308 mul dword ptr [u32NanoTSFactor0]309 div dword ptr [u32UpdateIntervalTSC]310 mov dword ptr [u64Delta], eax311 xor edx, edx312 mov dword ptr [u64Delta + 4], edx313 }314 #endif315 316 /*317 * Calculate the time and compare it with the previously returned value.318 */319 u64NanoTS += u64Delta;320 uint64_t u64DeltaPrev = u64NanoTS - u64PrevNanoTS;321 if (RT_LIKELY( u64DeltaPrev > 0322 && u64DeltaPrev < UINT64_C(86000000000000) /* 24h */))323 /* Frequent - less than 24h since last call. */;324 else if (RT_LIKELY( (int64_t)u64DeltaPrev <= 0325 && (int64_t)u64DeltaPrev + u32NanoTSFactor0 * 2 >= 0))326 {327 /* Occasional - u64NanoTS is in the recent 'past' relative the previous call. */328 ASMAtomicIncU32(&pData->c1nsSteps);329 u64NanoTS = u64PrevNanoTS + 1;330 }331 else if (!u64PrevNanoTS)332 /* We're resuming (see TMVirtualResume). */;333 else334 {335 /* Something has gone bust, if negative offset it's real bad. */336 ASMAtomicIncU32(&pData->cBadPrev);337 pData->pfnBad(pData, u64NanoTS, u64DeltaPrev, u64PrevNanoTS);338 }339 340 if (RT_UNLIKELY(!ASMAtomicCmpXchgU64(pData->pu64Prev, u64NanoTS, u64PrevNanoTS)))341 {342 /*343 * Attempt updating the previous value, provided we're still ahead of it.344 *345 * There is no point in recalculating u64NanoTS because we got preempted or if346 * we raced somebody while the GIP was updated, since these are events347 * that might occur at any point in the return path as well.348 */349 pData->cUpdateRaces++;350 for (int cTries = 25; cTries > 0; cTries--)351 {352 u64PrevNanoTS = ASMAtomicReadU64(pData->pu64Prev);353 if (u64PrevNanoTS >= u64NanoTS)354 break;355 if (ASMAtomicCmpXchgU64(pData->pu64Prev, u64NanoTS, u64PrevNanoTS))356 break;357 }358 }359 return u64NanoTS;360 350 } 361 351
Note:
See TracChangeset
for help on using the changeset viewer.