Changeset 54252 in vbox
- Timestamp:
- Feb 17, 2015 7:24:45 PM (10 years ago)
- svn:sync-xref-src-repo-rev:
- 98319
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified trunk/include/VBox/sup.h ¶
r54224 r54252 284 284 285 285 286 /** 287 * The rules concerning the applicability of SUPGIPCPU::i64TscDelta. 288 */ 289 typedef enum SUPGIPUSETSCDELTA 290 { 291 /** Value for SUPGIPMODE_ASYNC_TSC. */ 292 SUPGIPUSETSCDELTA_NOT_APPLICABLE = 0, 293 /** The OS specific part of SUPDrv (or the user) claims the TSC is as 294 * good as zero. */ 295 SUPGIPUSETSCDELTA_ZERO_CLAIMED, 296 /** The differences in RDTSC output between the CPUs/cores/threads should 297 * be considered zero for all practical purposes. */ 298 SUPGIPUSETSCDELTA_PRACTICALLY_ZERO, 299 /** The differences in RDTSC output between the CPUs/cores/threads are a few 300 * hundred ticks or less. (Probably not worth calling ASMGetApicId two times 301 * just to apply deltas.) */ 302 SUPGIPUSETSCDELTA_ROUGHLY_ZERO, 303 /** Significant differences in RDTSC output between the CPUs/cores/threads, 304 * deltas must be applied. */ 305 SUPGIPUSETSCDELTA_NOT_ZERO, 306 /** End of valid values (exclusive). */ 307 SUPGIPUSETSCDELTA_END, 308 /** Make sure the type is 32-bit sized. */ 309 SUPGIPUSETSCDELTA_32BIT_HACK = 0x7fffffff 310 } SUPGIPUSETSCDELTA; 311 312 313 /** @name SUPGIPGETCPU_XXX - methods that aCPUs can be indexed. 314 * @{ 315 */ 316 /** Use ASMGetApicId (or equivalent) and translate the result via 317 * aiCpuFromApicId. */ 318 #define SUPGIPGETCPU_APIC_ID RT_BIT_32(0) 319 /** Use RDTSCP and translate the first RTCPUSET_MAX_CPUS of ECX via 320 * aiCpuFromCpuSetIdx. 321 * 322 * Linux stores the RTMpCpuId() value in ECX[11:0] and NUMA node number in 323 * ECX[12:31]. Solaris only stores RTMpCpuId() in ECX. On both systems 324 * RTMpCpuId() == RTMpCpuIdToSetIndex(RTMpCpuId()). RTCPUSET_MAX_CPUS is 325 * currently 64, 256 or 1024 in size, which lower than 326 * 4096, so there shouldn't be any range issues. */ 327 #define SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS RT_BIT_32(1) 328 /** Subtract the max IDT size from IDTR.LIMIT, extract the 329 * first RTCPUSET_MAX_CPUS and translate it via aiCpuFromCpuSetIdx. 330 * 331 * Darwin stores the RTMpCpuId() (== RTMpCpuIdToSetIndex(RTMpCpuId())) 332 * value in the IDT limit. The masking is a precaution against what linux 333 * does with RDTSCP. */ 334 #define SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS RT_BIT_32(2) 335 /* Linux also offers information via selector 0x78, but we'll settle for 336 RDTSCP for now. */ 337 /** @} */ 338 286 339 287 340 /** … … 329 382 /** The max CPU ID (RTMpGetMaxCpuId). */ 330 383 RTCPUID idCpuMax; 331 /** Whether the host OS has already normalized the hardware TSC deltas across 332 * CPUs. */ 333 bool fOsTscDeltasInSync; 334 /** Whether the TSC deltas are small enough to not bother applying. */ 335 bool fTscDeltasRoughlyInSync; 336 uint8_t au8Padding0[2]; 384 /** The applicability of SUPGIPCPU::i64TscDelta. */ 385 SUPGIPUSETSCDELTA enmUseTscDelta; 386 /** Mask of SUPGIPGETCPU_XXX values that indicates different ways that aCPU 387 * can be accessed from ring-3 and raw-mode context. */ 388 uint32_t fGetGipCpu; 337 389 338 390 /** Padding / reserved space for future data. */ 339 uint32_t au32Padding1[2 6];391 uint32_t au32Padding1[25]; 340 392 341 393 /** Table indexed by the CPU APIC ID to get the CPU table index. */ … … 370 422 * Upper 16 bits is the major version. Major version is only changed with 371 423 * incompatible changes in the GIP. */ 372 #define SUPGLOBALINFOPAGE_VERSION 0x000 50000424 #define SUPGLOBALINFOPAGE_VERSION 0x00060000 373 425 374 426 /** … … 436 488 437 489 /** Whether the application of TSC-deltas is required. */ 438 #define GIP_ARE_TSC_DELTAS_APPLICABLE(a_pGip) \ 439 ((a_pGip)->u32Mode == SUPGIPMODE_INVARIANT_TSC && !((a_pGip)->fOsTscDeltasInSync)) 490 #define GIP_ARE_TSC_DELTAS_APPLICABLE(a_pGip) ((a_pGip)->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 440 491 441 492 … … 1559 1610 DECLINLINE(uint64_t) SUPReadTsc(void) 1560 1611 { 1561 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(g_pSUPGlobalInfoPage) 1562 && !g_pSUPGlobalInfoPage->fTscDeltasRoughlyInSync) 1612 if (g_pSUPGlobalInfoPage->enmUseTscDelta > SUPGIPUSETSCDELTA_ROUGHLY_ZERO) 1563 1613 return SUPReadTscWithDelta(); 1564 1614 return ASMReadTSC(); -
TabularUnified trunk/include/VBox/sup.mac ¶
r54214 r54252 5 5 6 6 ; 7 ; Copyright (C) 2006-201 4Oracle Corporation7 ; Copyright (C) 2006-2015 Oracle Corporation 8 8 ; 9 9 ; This file is part of VirtualBox Open Source Edition (OSE), as … … 48 48 endstruc 49 49 50 %define SUPGIPUSETSCDELTA_NOT_APPLICABLE 0 51 %define SUPGIPUSETSCDELTA_ZERO_CLAIMED 1 52 %define SUPGIPUSETSCDELTA_PRACTICALLY_ZERO 2 53 %define SUPGIPUSETSCDELTA_ROUGHLY_ZERO 3 54 %define SUPGIPUSETSCDELTA_NOT_ZERO 4 55 56 %define SUPGIPGETCPU_APIC_ID 1 57 %define SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS 2 58 %define SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS 4 59 60 50 61 %define SUPGLOBALINFOPAGE_MAGIC 0x19590106 51 62 struc SUPGLOBALINFOPAGE … … 67 78 .u16Padding0 resw 1 68 79 .idCpuMax resd 1 69 .fOsTscDeltasInSync resb 1 70 .fTscDeltasRoughlyInSync resb 1 71 .au8Padding0 resb 2 72 .au32Padding1 resd 26 80 .enmUseTscDelta resd 1 81 .fGetGipCpu resd 1 82 .au32Padding1 resd 25 73 83 .aiCpuFromApicId resw 256 74 84 .aiCpuFromCpuSetIdx resw 256 … … 126 136 endstruc 127 137 128 ;;129 ; Macro to apply per-CPU TSC delta to the TSC value read in through rdtsc.130 ;131 ; @param %1 The pSupGipCpu pointer132 ; @remarks edx:eax contains the 64-bit TSC value to apply the delta to.133 %macro SUPTscDeltaApply 1134 ; Check if we have a valid TSC-delta, i.e. != INT64_MAX.135 cmp dword [%1 + SUPGIPCPU.i64TSCDelta], 0xffffffff136 jne %%valid_delta137 cmp dword [%1 + SUPGIPCPU.i64TSCDelta + 4], 0x7fffffff138 je %%done139 %%valid_delta:140 ; Subtract the delta from edx:eax141 sub eax, dword [%1 + SUPGIPCPU.i64TSCDelta]142 sbb edx, dword [%1 + SUPGIPCPU.i64TSCDelta + 4]143 %%done:144 %endmacro145 146 138 %endif 147 139 -
TabularUnified trunk/src/VBox/HostDrivers/Support/SUPDrv.c ¶
r54224 r54252 124 124 /** The TSC-refinement interval in seconds. */ 125 125 #define GIP_TSC_REFINE_INTERVAL 5 126 /** The TSC-delta threshold (in ticks) for whether it's worth applying them or 127 * not for performance reasons, see @bugref{6710} comment #124. */ 128 #define GIP_TSC_DELTA_APPLY_THRESHOLD 384 126 /** The TSC-delta threshold for the SUPGIPUSETSCDELTA_PRACTICALLY_ZERO rating */ 127 #define GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 24 128 /** The TSC-delta threshold for the SUPGIPUSETSCDELTA_ROUGHLY_ZERO rating */ 129 #define GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO 384 129 130 130 131 AssertCompile(GIP_TSC_DELTA_PRIMER_LOOPS < GIP_TSC_DELTA_READ_TIME_LOOPS); … … 163 164 static int supdrvIOCtl_LoggerSettings(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPLOGGERSETTINGS pReq); 164 165 static int supdrvIOCtl_MsrProber(PSUPDRVDEVEXT pDevExt, PSUPMSRPROBER pReq); 165 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUP TSCDELTAMEASURE pReq);166 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCDELTAMEASURE pReq); 166 167 static int supdrvIOCtl_TscRead(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCREAD pReq); 167 168 static int supdrvGipCreate(PSUPDRVDEVEXT pDevExt); 168 169 static void supdrvGipDestroy(PSUPDRVDEVEXT pDevExt); 169 static DECLCALLBACK(void) supdrvGipSync Timer(PRTTIMER pTimer, void *pvUser, uint64_t iTick);170 static DECLCALLBACK(void) supdrvGipSyncAndInvariantTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 170 171 static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 171 172 static DECLCALLBACK(void) supdrvGipMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser); … … 2252 2253 REQ_CHECK_SIZES(SUP_IOCTL_TSC_DELTA_MEASURE); 2253 2254 2254 pReqHdr->rc = supdrvIOCtl_TscDeltaMeasure(pDevExt, p Req);2255 pReqHdr->rc = supdrvIOCtl_TscDeltaMeasure(pDevExt, pSession, pReq); 2255 2256 return 0; 2256 2257 } … … 4031 4032 4032 4033 /** 4034 * State structure for supdrvGipDetectGetGipCpuCallback. 4035 */ 4036 typedef struct SUPDRVGIPDETECTGETCPU 4037 { 4038 /** Bitmap of APIC IDs that has been seen (initialized to zero). 4039 * Used to detect duplicate APIC IDs (paranoia). */ 4040 uint8_t volatile bmApicId[256 / 8]; 4041 /** Mask of supported GIP CPU getter methods (SUPGIPGETCPU_XXX) (all bits set 4042 * initially). The callback clears the methods not detected. */ 4043 uint32_t volatile fSupported; 4044 /** The first callback detecting any kind of range issues (initializsed to 4045 * NIL_RTCPUID). */ 4046 RTCPUID volatile idCpuProblem; 4047 } SUPDRVGIPDETECTGETCPU; 4048 /** Pointer to state structure for supdrvGipDetectGetGipCpuCallback. */ 4049 typedef SUPDRVGIPDETECTGETCPU *PSUPDRVGIPDETECTGETCPU; 4050 4051 4052 /** 4053 * Checks for alternative ways of getting the CPU ID. 4054 * 4055 * This also checks the APIC ID, CPU ID and CPU set index values against the 4056 * GIP tables. 4057 * 4058 * @param idCpu The CPU ID. Unused - we have to use the APIC ID. 4059 * @param pvUser1 Pointer to the state structure. 4060 * @param pvUser2 Pointer to the GIP. 4061 */ 4062 static DECLCALLBACK(void) supdrvGipDetectGetGipCpuCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2) 4063 { 4064 PSUPDRVGIPDETECTGETCPU pState = (PSUPDRVGIPDETECTGETCPU)pvUser1; 4065 PSUPGLOBALINFOPAGE pGip = (PSUPGLOBALINFOPAGE)pvUser2; 4066 uint32_t fSupported = 0; 4067 uint16_t idApic; 4068 int iCpuSet; 4069 4070 AssertMsg(idCpu == RTMpCpuId(), ("idCpu=%#x RTMpCpuId()=%#x\n", idCpu, RTMpCpuId())); /* paranoia^3 */ 4071 4072 /* 4073 * Check that the CPU ID and CPU set index are interchangable. 4074 */ 4075 iCpuSet = RTMpCpuIdToSetIndex(idCpu); 4076 if ((RTCPUID)iCpuSet == idCpu) 4077 { 4078 AssertCompile(RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS)); 4079 if ( iCpuSet >= 0 4080 && iCpuSet < RTCPUSET_MAX_CPUS 4081 && RT_IS_POWER_OF_TWO(RTCPUSET_MAX_CPUS)) 4082 { 4083 /* 4084 * Check whether the IDTR.LIMIT contains a CPU number. 4085 */ 4086 #ifdef RT_ARCH_X86 4087 uint16_t const cbIdt = sizeof(X86DESC64SYSTEM); 4088 #else 4089 uint16_t const cbIdt = sizeof(X86DESCGATE); 4090 #endif 4091 RTIDTR Idtr; 4092 ASMGetIDTR(&Idtr); 4093 if (Idtr.cbIdt >= cbIdt) 4094 { 4095 uint32_t uTmp = Idtr.cbIdt - cbIdt; 4096 uTmp &= RTCPUSET_MAX_CPUS - 1; 4097 if (uTmp == idCpu) 4098 { 4099 RTIDTR Idtr2; 4100 ASMGetIDTR(&Idtr2); 4101 if (Idtr2.cbIdt == Idtr.cbIdt) 4102 fSupported |= SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS; 4103 } 4104 } 4105 4106 /* 4107 * Check whether RDTSCP is an option. 4108 */ 4109 if (ASMHasCpuId()) 4110 { 4111 if ( ASMIsValidExtRange(ASMCpuId_EAX(UINT32_C(0x80000000))) 4112 && (ASMCpuId_EDX(UINT32_C(0x80000001)) & X86_CPUID_EXT_FEATURE_EDX_RDTSCP) ) 4113 { 4114 uint32_t uAux; 4115 ASMReadTscWithAux(&uAux); 4116 if ((uAux & (RTCPUSET_MAX_CPUS - 1)) == idCpu) 4117 { 4118 ASMNopPause(); 4119 ASMReadTscWithAux(&uAux); 4120 if ((uAux & (RTCPUSET_MAX_CPUS - 1)) == idCpu) 4121 fSupported |= SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS; 4122 } 4123 } 4124 } 4125 } 4126 } 4127 4128 /* 4129 * Check that the APIC ID is unique. 4130 */ 4131 idApic = ASMGetApicId(); 4132 if (RT_LIKELY( idApic < RT_ELEMENTS(pGip->aiCpuFromApicId) 4133 && !ASMAtomicBitTestAndSet(pState->bmApicId, idApic))) 4134 fSupported |= SUPGIPGETCPU_APIC_ID; 4135 else 4136 { 4137 AssertCompile(sizeof(pState->bmApicId) * 8 == RT_ELEMENTS(pGip->aiCpuFromApicId)); 4138 ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID); 4139 LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - duplicate APIC ID.\n", 4140 idCpu, iCpuSet, idApic)); 4141 } 4142 4143 /* 4144 * Check that the iCpuSet is within the expected range. 4145 */ 4146 if (RT_UNLIKELY( iCpuSet < 0 4147 || iCpuSet >= RTCPUSET_MAX_CPUS 4148 || iCpuSet >= RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) 4149 { 4150 ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID); 4151 LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - CPU set index is out of range.\n", 4152 idCpu, iCpuSet, idApic)); 4153 } 4154 else 4155 { 4156 RTCPUID idCpu2 = RTMpCpuIdFromSetIndex(iCpuSet); 4157 if (RT_UNLIKELY(idCpu2 != idCpu)) 4158 { 4159 ASMAtomicCmpXchgU32(&pState->idCpuProblem, idCpu, NIL_RTCPUID); 4160 LogRel(("supdrvGipDetectGetGipCpuCallback: idCpu=%#x iCpuSet=%d idApic=%#x - CPU id/index roundtrip problem: %#x\n", 4161 idCpu, iCpuSet, idApic, idCpu2)); 4162 } 4163 } 4164 4165 /* 4166 * Update the supported feature mask before we return. 4167 */ 4168 ASMAtomicAndU32(&pState->fSupported, fSupported); 4169 4170 NOREF(pvUser2); 4171 } 4172 4173 4174 /** 4033 4175 * Increase the timer freqency on hosts where this is possible (NT). 4034 4176 * … … 4138 4280 uint64_t u64NanoTS; 4139 4281 4282 /* 4283 * GIP starts/resumes updating again. On windows we bump the 4284 * host timer frequency to make sure we don't get stuck in guest 4285 * mode and to get better timer (and possibly clock) accuracy. 4286 */ 4140 4287 LogFlow(("SUPR0GipMap: Resumes GIP updating\n")); 4141 4288 4142 4289 supdrvGipRequestHigherTimerFrequencyFromSystem(pDevExt); 4143 4290 4291 /* 4292 * document me 4293 */ 4144 4294 if (pGipR0->aCPUs[0].u32TransactionId != 2 /* not the first time */) 4145 4295 { … … 4152 4302 } 4153 4303 4304 /* 4305 * document me 4306 */ 4154 4307 u64NanoTS = RTTimeSystemNanoTS() - pGipR0->u32UpdateIntervalNS; 4155 4308 if ( pGipR0->u32Mode == SUPGIPMODE_INVARIANT_TSC … … 4160 4313 RTMpOnAll(supdrvGipReInitCpuCallback, pGipR0, &u64NanoTS); 4161 4314 4315 /* 4316 * Detect alternative ways to figure the CPU ID in ring-3 and 4317 * raw-mode context. Check the sanity of the APIC IDs, CPU IDs, 4318 * and CPU set indexes while we're at it. 4319 */ 4320 if (RT_SUCCESS(rc)) 4321 { 4322 SUPDRVGIPDETECTGETCPU DetectState; 4323 RT_ZERO(DetectState.bmApicId); 4324 DetectState.fSupported = UINT32_MAX; 4325 DetectState.idCpuProblem = NIL_RTCPUID; 4326 rc = RTMpOnAll(supdrvGipDetectGetGipCpuCallback, &DetectState, pGipR0); 4327 if (DetectState.idCpuProblem == NIL_RTCPUID) 4328 { 4329 if ( DetectState.fSupported != UINT32_MAX 4330 && DetectState.fSupported != 0) 4331 { 4332 if (pGipR0->fGetGipCpu != DetectState.fSupported) 4333 { 4334 pGipR0->fGetGipCpu = DetectState.fSupported; 4335 LogRel(("SUPR0GipMap: fGetGipCpu=%#x\n", DetectState.fSupported)); 4336 } 4337 } 4338 else 4339 { 4340 LogRel(("SUPR0GipMap: No supported ways of getting the APIC ID or CPU number in ring-3! (%#x)\n", 4341 DetectState.fSupported)); 4342 rc = VERR_UNSUPPORTED_CPU; 4343 } 4344 } 4345 else 4346 { 4347 LogRel(("SUPR0GipMap: APIC ID, CPU ID or CPU set index problem detected on CPU #%u (%#x)!\n", 4348 DetectState.idCpuProblem, DetectState.idCpuProblem)); 4349 rc = VERR_INVALID_CPU_ID; 4350 } 4351 } 4352 4353 /* 4354 * Start the GIP timer if all is well.. 4355 */ 4356 if (RT_SUCCESS(rc)) 4357 { 4162 4358 #ifndef DO_NOT_START_GIP 4163 rc = RTTimerStart(pDevExt->pGipTimer, 0 /* fire ASAP */); AssertRC(rc);4359 rc = RTTimerStart(pDevExt->pGipTimer, 0 /* fire ASAP */); AssertRC(rc); 4164 4360 #endif 4165 rc = VINF_SUCCESS; 4361 rc = VINF_SUCCESS; 4362 } 4363 4364 /* 4365 * Bail out on error. 4366 */ 4367 if (RT_FAILURE(rc)) 4368 { 4369 LogRel(("SUPR0GipMap: failed rc=%Rrc\n", rc)); 4370 pDevExt->cGipUsers = 0; 4371 pSession->fGipReferenced = 0; 4372 if (pSession->GipMapObjR3 != NIL_RTR0MEMOBJ) 4373 { 4374 int rc2 = RTR0MemObjFree(pSession->GipMapObjR3, false); AssertRC(rc2); 4375 if (RT_SUCCESS(rc2)) 4376 pSession->GipMapObjR3 = NIL_RTR0MEMOBJ; 4377 } 4378 HCPhys = NIL_RTHCPHYS; 4379 pGipR3 = NIL_RTR3PTR; 4380 } 4166 4381 } 4167 4382 } … … 5781 5996 } 5782 5997 5783 5784 5998 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 5999 5785 6000 /** 5786 6001 * Switches the TSC-delta measurement thread into the butchered state. … … 6035 6250 static int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt) 6036 6251 { 6037 Assert( GIP_ARE_TSC_DELTAS_APPLICABLE(pDevExt->pGip));6252 Assert(pDevExt->pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 6038 6253 6039 6254 int rc = RTSpinlockCreate(&pDevExt->hTscDeltaSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_UNSAFE, "VBoxTscSpnLck"); … … 6136 6351 return VERR_TIMEOUT; 6137 6352 } 6353 6138 6354 #endif /* SUPDRV_USE_TSC_DELTA_THREAD */ 6139 6140 6355 6141 6356 /** … … 6164 6379 AssertPtr(puTsc); 6165 6380 AssertPtr(pGip); 6166 Assert( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));6381 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 6167 6382 6168 6383 /* … … 6284 6499 ASMSetFlags(uFlags); 6285 6500 6286 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6501 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 6287 6502 { 6288 6503 int rc; … … 6362 6577 u64NanoTS = RTTimeSystemNanoTS(); 6363 6578 ASMSetFlags(uFlags); 6364 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6579 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 6365 6580 supdrvTscDeltaApply(pGip, &u64Tsc, idApic, &fDeltaApplied); 6366 6581 u64DeltaNanoTS = u64NanoTS - pDevExt->u64NanoTSAnchor; … … 6381 6596 else 6382 6597 { 6383 #if 16384 6598 RTUINT128U CpuHz, Tmp, Divisor; 6385 6599 CpuHz.s.Lo = CpuHz.s.Hi = 0; … … 6387 6601 RTUInt128Div(&CpuHz, &Tmp, RTUInt128AssignU64(&Divisor, u64DeltaNanoTS)); 6388 6602 pGip->u64CpuHz = CpuHz.s.Lo; 6389 #else6390 /** @todo remove later */6391 /* Try not to lose precision, the larger the interval the more likely we overflow. */6392 if ( u64DeltaTsc < UINT64_MAX / RT_NS_100MS6393 && u64DeltaNanoTS / 10 < UINT32_MAX)6394 pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_100MS, (uint32_t)(u64DeltaNanoTS / 10));6395 else if ( u64DeltaTsc < UINT64_MAX / RT_NS_10MS6396 && u64DeltaNanoTS / 100 < UINT32_MAX)6397 pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_10MS, (uint32_t)(u64DeltaNanoTS / 100));6398 else if ( u64DeltaTsc < UINT64_MAX / RT_NS_1MS6399 && u64DeltaNanoTS / 1000 < UINT32_MAX)6400 pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_1MS, (uint32_t)(u64DeltaNanoTS / 1000));6401 else /* Screw it. */6402 pGip->u64CpuHz = u64DeltaTsc / (u64DeltaNanoTS / RT_NS_1SEC_64);6403 #endif6404 6603 } 6405 6604 … … 6428 6627 Assert(pDevExt->pGip); 6429 6628 6629 /* 6630 * <Insert missing comment [it's not "Validate.", I think...]> 6631 */ 6430 6632 pGip = pDevExt->pGip; 6431 6633 u64NanoTS = RTTimeSystemNanoTS(); … … 6437 6639 pDevExt->u64NanoTSAnchor = RTTimeSystemNanoTS(); 6438 6640 ASMSetFlags(uFlags); 6439 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6641 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 6440 6642 supdrvTscDeltaApply(pGip, &pDevExt->u64TscAnchor, idApic, &fDeltaApplied); 6441 6643 6442 6644 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 6645 /* 6646 * <Explain yourself> 6647 */ 6648 /** @todo r=bird: This is (and was) bogus on systems where we don't need to 6649 * apply any delta (not used on windows doesn't stick without comments). 6650 * What is the logic you want here exactly? */ 6443 6651 if ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC 6444 6652 && !fDeltaApplied) … … 6541 6749 supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), RT_NS_1SEC / u32Interval /*=Hz*/, u32Interval, cCpus); 6542 6750 6543 if (RT_UNLIKELY( pGip-> fOsTscDeltasInSync6751 if (RT_UNLIKELY( pGip->enmUseTscDelta == SUPGIPUSETSCDELTA_ZERO_CLAIMED 6544 6752 && pGip->u32Mode == SUPGIPMODE_ASYNC_TSC 6545 6753 && !supdrvOSGetForcedAsyncTscMode(pDevExt))) … … 6551 6759 6552 6760 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 6553 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6761 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 6554 6762 { 6555 6763 /* Initialize TSC-delta measurement thread before executing any Mp event callbacks. */ … … 6567 6775 uint16_t iCpu; 6568 6776 #ifndef SUPDRV_USE_TSC_DELTA_THREAD 6569 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6777 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 6570 6778 { 6571 6779 /* … … 6608 6816 } 6609 6817 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 6610 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, supdrvGipSyncTimer, pDevExt); 6818 rc = RTTimerCreateEx(&pDevExt->pGipTimer, u32Interval, 0 /* fFlags */, 6819 supdrvGipSyncAndInvariantTimer, pDevExt); 6611 6820 if (RT_SUCCESS(rc)) 6612 6821 { … … 6722 6931 6723 6932 /** 6724 * Timer callback function sync GIP mode. 6933 * Timer callback function for the sync and invariant GIP modes. 6934 * 6725 6935 * @param pTimer The timer. 6726 6936 * @param pvUser Opaque pointer to the device extension. 6727 6937 * @param iTick The timer tick. 6728 6938 */ 6729 static DECLCALLBACK(void) supdrvGipSync Timer(PRTTIMER pTimer, void *pvUser, uint64_t iTick)6939 static DECLCALLBACK(void) supdrvGipSyncAndInvariantTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick) 6730 6940 { 6731 6941 RTCCUINTREG uFlags; … … 6739 6949 u64NanoTS = RTTimeSystemNanoTS(); 6740 6950 6741 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))6951 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 6742 6952 { 6743 6953 /* … … 6747 6957 * rescheduling the tick to be delivered on the right CPU or missing the tick entirely. 6748 6958 * 6749 * The likely hood of this happening is really low. On Windows, Linux timers 6750 * fire on the CPU they were registered/started on. Darwin, Solaris need verification. 6959 * The likely hood of this happening is really low. On Windows, Linux, and Solaris 6960 * timers fire on the CPU they were registered/started on. Darwin timers doesn't 6961 * necessarily (they are high priority threads waiting). 6751 6962 */ 6752 6963 Assert(!ASMIntAreEnabled()); … … 6884 7095 * update the state and it'll get serviced when the thread's listening interval times out. 6885 7096 */ 6886 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))7097 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 6887 7098 { 6888 7099 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); … … 6943 7154 6944 7155 /* Reset the TSC delta, we will recalculate it lazily. */ 6945 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))7156 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 6946 7157 ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX); 6947 7158 … … 7172 7383 7173 7384 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) == GIP_TSC_DELTA_SYNC_START) 7174 ;7385 { /* nothing */ } 7175 7386 7176 7387 do … … 7183 7394 7184 7395 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) != GIP_TSC_DELTA_SYNC_WORKER_DONE) 7185 ;7396 { /* nothing */ } 7186 7397 7187 7398 if (i > GIP_TSC_DELTA_PRIMER_LOOPS + GIP_TSC_DELTA_READ_TIME_LOOPS) … … 7209 7420 ASMAtomicReadU64(&pGipCpuMaster->u64TSCSample); /* Warm the cache line. */ 7210 7421 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) != GIP_TSC_DELTA_SYNC_START) 7211 ;7422 { /* nothing */ } 7212 7423 Assert(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD); 7213 7424 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_WORKER_READY); … … 7307 7518 pGipCpuWorker = &pGip->aCPUs[idxWorker]; 7308 7519 7309 Assert( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));7520 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 7310 7521 7311 7522 if (pGipCpuWorker->idCpu == idMaster) … … 7316 7527 7317 7528 /* Set the master TSC as the initiator. */ 7318 while ( ASMAtomicCmpXchgU32(&pDevExt->idTscDeltaInitiator, idMaster, NIL_RTCPUID) == false)7529 while (!ASMAtomicCmpXchgU32(&pDevExt->idTscDeltaInitiator, idMaster, NIL_RTCPUID)) 7319 7530 { 7320 7531 /* … … 7333 7544 if (RT_SUCCESS(rc)) 7334 7545 { 7335 if (RT_UNLIKELY(pGipCpuWorker->i64TSCDelta == INT64_MAX)) 7546 if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX)) 7547 { 7548 /* 7549 * Work the TSC delta applicability rating. It starts 7550 * optimistic in supdrvGipInit, we downgrade it here. 7551 */ 7552 SUPGIPUSETSCDELTA enmRating; 7553 if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO 7554 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO) 7555 enmRating = SUPGIPUSETSCDELTA_NOT_ZERO; 7556 else if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 7557 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO) 7558 enmRating = SUPGIPUSETSCDELTA_ROUGHLY_ZERO; 7559 else 7560 enmRating = SUPGIPUSETSCDELTA_PRACTICALLY_ZERO; 7561 if (pGip->enmUseTscDelta < enmRating) 7562 { 7563 AssertCompile(sizeof(pGip->enmUseTscDelta) == sizeof(uint32_t)); 7564 ASMAtomicWriteU32((uint32_t volatile *)&pGip->enmUseTscDelta, enmRating); 7565 } 7566 } 7567 else 7336 7568 rc = VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED; 7337 else if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_APPLY_THRESHOLD7338 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_APPLY_THRESHOLD)7339 {7340 pGip->fTscDeltasRoughlyInSync = false;7341 }7342 7569 } 7343 7570 } … … 7373 7600 uint32_t cOnlineCpus = pGip->cOnlineCpus; 7374 7601 7375 Assert( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip));7602 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 7376 7603 7377 7604 /* … … 7621 7848 pCpu->u64TSC = ASMReadTSC(); 7622 7849 pCpu->u64TSCSample = GIP_TSC_DELTA_RSVD; 7623 pCpu->i64TSCDelta = GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)? INT64_MAX : 0;7850 pCpu->i64TSCDelta = pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED ? INT64_MAX : 0; 7624 7851 7625 7852 ASMAtomicWriteSize(&pCpu->enmState, SUPGIPCPUSTATE_INVALID); … … 7674 7901 memset(pGip, 0, cbGip); 7675 7902 7676 /*7677 * Record whether the host OS has already normalized inter-CPU deltas for the hardware TSC.7678 * We only bother with TSC-deltas on invariant CPUs for now.7679 */7680 pGip->fOsTscDeltasInSync = supdrvIsInvariantTsc() && supdrvOSAreTscDeltasInSync();7681 7682 pGip->fTscDeltasRoughlyInSync = true;7683 7903 pGip->u32Magic = SUPGLOBALINFOPAGE_MAGIC; 7684 7904 pGip->u32Version = SUPGLOBALINFOPAGE_VERSION; 7685 7905 pGip->u32Mode = supdrvGipDetermineTscMode(pDevExt); 7906 if ( pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC 7907 /*|| pGip->u32Mode == SUPGIPMODE_SYNC_TSC */) 7908 pGip->enmUseTscDelta = supdrvIsInvariantTsc() && supdrvOSAreTscDeltasInSync() /* Allow OS override (windows). */ 7909 ? SUPGIPUSETSCDELTA_ZERO_CLAIMED : SUPGIPUSETSCDELTA_PRACTICALLY_ZERO /* downgrade later */; 7910 else 7911 pGip->enmUseTscDelta = SUPGIPUSETSCDELTA_NOT_APPLICABLE; 7686 7912 pGip->cCpus = (uint16_t)cCpus; 7687 7913 pGip->cPages = (uint16_t)(cbGip / PAGE_SIZE); 7688 7914 pGip->u32UpdateHz = uUpdateHz; 7689 7915 pGip->u32UpdateIntervalNS = uUpdateIntervalNS; 7916 pGip->fGetGipCpu = SUPGIPGETCPU_APIC_ID; 7690 7917 RTCpuSetEmpty(&pGip->OnlineCpuSet); 7691 7918 RTCpuSetEmpty(&pGip->PresentCpuSet); … … 7699 7926 for (i = 0; i < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx); i++) 7700 7927 pGip->aiCpuFromCpuSetIdx[i] = UINT16_MAX; 7701 7702 7928 for (i = 0; i < cCpus; i++) 7703 7929 supdrvGipInitCpu(pDevExt, pGip, &pGip->aCPUs[i], u64NanoTS); … … 8066 8292 * 8067 8293 * @returns VBox status code. 8068 * @param pDevExt Pointer to the device instance data. 8069 * @param pReq Pointer to the TSC-delta measurement request. 8070 */ 8071 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPTSCDELTAMEASURE pReq) 8294 * @param pDevExt Pointer to the device instance data. 8295 * @param pSession The support driver session. 8296 * @param pReq Pointer to the TSC-delta measurement request. 8297 */ 8298 static int supdrvIOCtl_TscDeltaMeasure(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPTSCDELTAMEASURE pReq) 8072 8299 { 8073 8300 PSUPGLOBALINFOPAGE pGip; 8074 8301 RTCPUID idCpuWorker; 8075 int rc = VERR_CPU_NOT_FOUND;8302 int rc; 8076 8303 int16_t cTries; 8077 8304 RTMSINTERVAL cMsWaitRetry; … … 8081 8308 * Validate. 8082 8309 */ 8083 AssertReturn(pDevExt, VERR_INVALID_PARAMETER); 8084 AssertReturn(pReq, VERR_INVALID_PARAMETER); 8085 AssertReturn(pDevExt->pGip, VERR_INVALID_PARAMETER); 8310 AssertPtr(pDevExt); AssertPtr(pSession); AssertPtr(pReq); /* paranoia^2 */ 8311 if (pSession->GipMapObjR3 == NIL_RTR0MEMOBJ) 8312 return VERR_WRONG_ORDER; 8313 pGip = pDevExt->pGip; 8314 AssertReturn(pGip, VERR_INTERNAL_ERROR_2); 8315 8086 8316 idCpuWorker = pReq->u.In.idCpu; 8087 8317 if (idCpuWorker == NIL_RTCPUID) 8088 8318 return VERR_INVALID_CPU_ID; 8089 8090 8319 cTries = RT_MAX(pReq->u.In.cRetries + 1, 10); 8091 8320 cMsWaitRetry = RT_MAX(pReq->u.In.cMsWaitRetry, 5); 8321 8322 /* 8323 * The request is a noop if the TSC delta isn't being used. 8324 */ 8092 8325 pGip = pDevExt->pGip; 8093 8094 if (!GIP_ARE_TSC_DELTAS_APPLICABLE(pGip)) 8326 if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ZERO_CLAIMED) 8095 8327 return VINF_SUCCESS; 8096 8328 8329 rc = VERR_CPU_NOT_FOUND; 8097 8330 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 8098 8331 { … … 8174 8407 * upset if the GIP is some different mode. 8175 8408 */ 8176 if ( GIP_ARE_TSC_DELTAS_APPLICABLE(pGip))8409 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 8177 8410 { 8178 8411 uint32_t cTries = 0; -
TabularUnified trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h ¶
r54224 r54252 215 215 * - Fix SUPTSCREAD padding (#if 0 -> #if 1). 216 216 */ 217 #define SUPDRV_IOC_VERSION 0x001 e0000217 #define SUPDRV_IOC_VERSION 0x001f0000 218 218 219 219 /** SUP_IOCTL_COOKIE. */ … … 1485 1485 * Measure the TSC-delta between the specified CPU and the master TSC. 1486 1486 * 1487 * To call this I/O control, the client must first have mapped the GIP. 1488 * 1487 1489 * @{ 1488 1490 */ … … 1511 1513 /** Whether to do the measurement asynchronously (if possible). */ 1512 1514 bool fAsync; 1513 /** Padding for future. */1514 uint64_t auPadding[3];1515 1515 } In; 1516 1516 } u; 1517 1517 } SUPTSCDELTAMEASURE, *PSUPTSCDELTAMEASURE; 1518 1518 AssertCompileMemberAlignment(SUPTSCDELTAMEASURE, u, 8); 1519 AssertCompileSize(SUPTSCDELTAMEASURE, 6*4 + 4+1+1+1+1); 1519 1520 /** @} */ 1520 1521 … … 1546 1547 /** The APIC Id of the CPU where the TSC was read. */ 1547 1548 uint16_t idApic; 1548 /** Padding for future. */ 1549 #if 0 /* Not correct for 32-bit gcc. */ 1550 uint16_t auPadding[3 + 3*4]; 1551 #else 1552 uint64_t auPadding[3]; 1553 #endif 1549 /** Explicit alignment padding. */ 1550 uint16_t auPadding[3]; 1554 1551 } Out; 1555 1552 } u; 1556 1553 } SUPTSCREAD, *PSUPTSCREAD; 1557 1554 AssertCompileMemberAlignment(SUPTSCREAD, u, 8); 1558 #if 0 /* Not correct for 32-bit gcc. */ 1559 AssertCompileSize(SUPTSCREAD, 6*4 + 5*8); 1555 AssertCompileSize(SUPTSCREAD, 6*4 + 2*8); 1556 /** @} */ 1557 1558 #pragma pack() /* paranoia */ 1559 1560 1560 #endif 1561 /** @} */ 1562 1563 #pragma pack() /* paranoia */ 1564 1565 #endif 1566 1561 -
TabularUnified trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp ¶
r54214 r54252 251 251 RTPrintf("tstGIP-2: offline: %lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta); 252 252 253 RTPrintf(" fTscDeltasRoughlyInSync: %RTbool\n", g_pSUPGlobalInfoPage->fTscDeltasRoughlyInSync);254 RTPrintf("CPUID.Invariant-TSC : %RTbool\n", tstIsInvariantTsc());253 RTPrintf("tstGIP-2: enmUseTscDelta=%d fGetGipCpu=%#x\n", 254 g_pSUPGlobalInfoPage->enmUseTscDelta, g_pSUPGlobalInfoPage->fGetGipCpu); 255 255 if ( uCpuHzRef 256 256 && cCpuHzOverallDevCnt) 257 257 { 258 258 uint32_t uPct = (uint32_t)(uCpuHzOverallDeviation * 100000 / cCpuHzOverallDevCnt / uCpuHzRef + 5); 259 RTPrintf("tstGIP-2: Average CpuHz deviation: %d.%02d%%\n", 260 uPct / 1000, (uPct % 1000) / 10); 261 259 262 uint32_t uMaxPct = (uint32_t)(RT_ABS(iCpuHzMaxDeviation) * 100000 / uCpuHzRef + 5); 260 RTPrintf(" Average CpuHz deviation: %d.%02d%%\n", uPct / 1000, (uPct % 1000) / 10);261 RTPrintf("Maximum CpuHz deviation: %d.%02d%% (%RI64 ticks)\n",uMaxPct / 1000, (uMaxPct % 1000) / 10, iCpuHzMaxDeviation);263 RTPrintf("tstGIP-2: Maximum CpuHz deviation: %d.%02d%% (%RI64 ticks)\n", 264 uMaxPct / 1000, (uMaxPct % 1000) / 10, iCpuHzMaxDeviation); 262 265 } 263 266 } -
TabularUnified trunk/src/VBox/Runtime/common/time/timesup.cpp ¶
r54224 r54252 168 168 if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2) 169 169 iWorker = pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC 170 ? !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync171 ? RTTIMENANO_WORKER_LFENCE_INVAR_ WITH_DELTA : RTTIMENANO_WORKER_LFENCE_INVAR_NO_DELTA170 ? pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO 171 ? RTTIMENANO_WORKER_LFENCE_INVAR_NO_DELTA : RTTIMENANO_WORKER_LFENCE_INVAR_WITH_DELTA 172 172 : pGip->u32Mode == SUPGIPMODE_SYNC_TSC 173 ? false /** @todo !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync */174 ? RTTIMENANO_WORKER_LFENCE_SYNC_ WITH_DELTA : RTTIMENANO_WORKER_LFENCE_SYNC_NO_DELTA173 ? pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO 174 ? RTTIMENANO_WORKER_LFENCE_SYNC_NO_DELTA : RTTIMENANO_WORKER_LFENCE_SYNC_WITH_DELTA 175 175 : RTTIMENANO_WORKER_LFENCE_ASYNC; 176 176 else 177 177 iWorker = pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC 178 ? !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync179 ? RTTIMENANO_WORKER_LEGACY_INVAR_ WITH_DELTA : RTTIMENANO_WORKER_LEGACY_INVAR_NO_DELTA178 ? pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO 179 ? RTTIMENANO_WORKER_LEGACY_INVAR_NO_DELTA : RTTIMENANO_WORKER_LEGACY_INVAR_WITH_DELTA 180 180 : pGip->u32Mode == SUPGIPMODE_SYNC_TSC 181 ? false /** @todo !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync */182 ? RTTIMENANO_WORKER_LEGACY_SYNC_ WITH_DELTA : RTTIMENANO_WORKER_LEGACY_SYNC_NO_DELTA181 ? pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO 182 ? RTTIMENANO_WORKER_LEGACY_SYNC_NO_DELTA : RTTIMENANO_WORKER_LEGACY_SYNC_WITH_DELTA 183 183 : RTTIMENANO_WORKER_LEGACY_ASYNC; 184 184 } -
TabularUnified trunk/src/VBox/Runtime/testcase/tstRTTime.cpp ¶
r48935 r54252 98 98 else 99 99 { 100 RTTestValue(hTest, "Total time delta", u64OSElapsedTS - u64RTElapsedTS, RTTESTUNIT_NS); 100 if (u64OSElapsedTS >= u64RTElapsedTS) 101 RTTestValue(hTest, "Total time delta", u64OSElapsedTS - u64RTElapsedTS, RTTESTUNIT_NS); 102 else 103 RTTestValue(hTest, "Total time delta", u64RTElapsedTS - u64OSElapsedTS, RTTESTUNIT_NS); 101 104 RTTestPrintf(hTest, RTTESTLVL_INFO, "total time difference: u64OSElapsedTS=%#llx u64RTElapsedTS=%#llx delta=%lld\n", 102 105 u64OSElapsedTS, u64RTElapsedTS, u64OSElapsedTS - u64RTElapsedTS); -
TabularUnified trunk/src/VBox/VMM/VMMR3/TM.cpp ¶
r54219 r54252 168 168 *******************************************************************************/ 169 169 static bool tmR3HasFixedTSC(PVM pVM); 170 static bool tmR3ReallyNeedDeltas(PSUPGLOBALINFOPAGE pGip);171 170 static const char * tmR3GetTSCModeName(PVM pVM); 172 171 static uint64_t tmR3CalibrateTSC(PVM pVM); … … 231 230 * as well and save costly world switches. 232 231 */ 233 pVM->tm.s.pvGIPR3 = (void *)g_pSUPGlobalInfoPage; 232 PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; 233 pVM->tm.s.pvGIPR3 = (void *)pGip; 234 234 AssertMsgReturn(pVM->tm.s.pvGIPR3, ("GIP support is now required!\n"), VERR_TM_GIP_REQUIRED); 235 AssertMsgReturn((g_pSUPGlobalInfoPage->u32Version >> 16) == (SUPGLOBALINFOPAGE_VERSION >> 16), 236 ("Unsupported GIP version!\n"), VERR_TM_GIP_VERSION); 235 AssertMsgReturn((pGip->u32Version >> 16) == (SUPGLOBALINFOPAGE_VERSION >> 16), 236 ("Unsupported GIP version %#x! (expected=%#x)\n", pGip->u32Version, SUPGLOBALINFOPAGE_VERSION), 237 VERR_TM_GIP_VERSION); 237 238 238 239 RTHCPHYS HCPhysGIP; … … 242 243 RTGCPTR GCPtr; 243 244 #ifdef SUP_WITH_LOTS_OF_CPUS 244 rc = MMR3HyperMapHCPhys(pVM, pVM->tm.s.pvGIPR3, NIL_RTR0PTR, HCPhysGIP, (size_t) g_pSUPGlobalInfoPage->cPages * PAGE_SIZE,245 rc = MMR3HyperMapHCPhys(pVM, pVM->tm.s.pvGIPR3, NIL_RTR0PTR, HCPhysGIP, (size_t)pGip->cPages * PAGE_SIZE, 245 246 "GIP", &GCPtr); 246 247 #else … … 257 258 258 259 /* Check assumptions made in TMAllVirtual.cpp about the GIP update interval. */ 259 if ( g_pSUPGlobalInfoPage->u32Magic == SUPGLOBALINFOPAGE_MAGIC260 && g_pSUPGlobalInfoPage->u32UpdateIntervalNS >= 250000000 /* 0.25s */)260 if ( pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC 261 && pGip->u32UpdateIntervalNS >= 250000000 /* 0.25s */) 261 262 return VMSetError(pVM, VERR_TM_GIP_UPDATE_INTERVAL_TOO_BIG, RT_SRC_POS, 262 263 N_("The GIP update interval is too big. u32UpdateIntervalNS=%RU32 (u32UpdateHz=%RU32)"), 263 g_pSUPGlobalInfoPage->u32UpdateIntervalNS, g_pSUPGlobalInfoPage->u32UpdateHz);264 LogRel(("TM: GIP - u32Mode=%d (%s) u32UpdateHz=%u u32UpdateIntervalNS=%u\n", g_pSUPGlobalInfoPage->u32Mode,265 SUPGetGIPModeName( g_pSUPGlobalInfoPage), g_pSUPGlobalInfoPage->u32UpdateHz,266 g_pSUPGlobalInfoPage->u32UpdateIntervalNS));267 LogRel(("TM: GIP - u64CpuHz=%#RX64 (%'RU64)\n", g_pSUPGlobalInfoPage->u64CpuHz, g_pSUPGlobalInfoPage->u64CpuHz));264 pGip->u32UpdateIntervalNS, pGip->u32UpdateHz); 265 LogRel(("TM: GIP - u32Mode=%d (%s) u32UpdateHz=%u u32UpdateIntervalNS=%u\n", pGip->u32Mode, 266 SUPGetGIPModeName(pGip), pGip->u32UpdateHz, 267 pGip->u32UpdateIntervalNS)); 268 LogRel(("TM: GIP - u64CpuHz=%#RX64 (%'RU64)\n", pGip->u64CpuHz, pGip->u64CpuHz)); 268 269 269 270 /* … … 275 276 if (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_SSE2) 276 277 { 277 if ( g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC)278 pVM->tm.s.pfnVirtualGetRawR3 = tmR3ReallyNeedDeltas(g_pSUPGlobalInfoPage)279 ? RTTimeNanoTSLFenceInvariant WithDelta : RTTimeNanoTSLFenceInvariantNoDelta;280 else if ( g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)281 pVM->tm.s.pfnVirtualGetRawR3 = false /** @todo tmR3ReallyNeedDeltas(g_pSUPGlobalInfoPage) */282 ? RTTimeNanoTSLFenceSync WithDelta : RTTimeNanoTSLFenceSyncNoDelta;278 if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 279 pVM->tm.s.pfnVirtualGetRawR3 = pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO 280 ? RTTimeNanoTSLFenceInvariantNoDelta : RTTimeNanoTSLFenceInvariantWithDelta; 281 else if (pGip->u32Mode == SUPGIPMODE_SYNC_TSC) 282 pVM->tm.s.pfnVirtualGetRawR3 = pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO 283 ? RTTimeNanoTSLFenceSyncNoDelta : RTTimeNanoTSLFenceSyncWithDelta; 283 284 else 284 285 pVM->tm.s.pfnVirtualGetRawR3 = RTTimeNanoTSLFenceAsync; … … 286 287 else 287 288 { 288 if ( g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_INVARIANT_TSC)289 pVM->tm.s.pfnVirtualGetRawR3 = tmR3ReallyNeedDeltas(g_pSUPGlobalInfoPage)290 ? RTTimeNanoTSLegacyInvariant WithDelta : RTTimeNanoTSLegacyInvariantNoDelta;291 else if ( g_pSUPGlobalInfoPage->u32Mode == SUPGIPMODE_SYNC_TSC)292 pVM->tm.s.pfnVirtualGetRawR3 = false /** @todo tmR3ReallyNeedDeltas(g_pSUPGlobalInfoPage) */293 ? RTTimeNanoTSLegacySync WithDelta : RTTimeNanoTSLegacySyncNoDelta;289 if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 290 pVM->tm.s.pfnVirtualGetRawR3 = pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO 291 ? RTTimeNanoTSLegacyInvariantNoDelta : RTTimeNanoTSLegacyInvariantWithDelta; 292 else if (pGip->u32Mode == SUPGIPMODE_SYNC_TSC) 293 pVM->tm.s.pfnVirtualGetRawR3 = pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO 294 ? RTTimeNanoTSLegacySyncNoDelta : RTTimeNanoTSLegacySyncWithDelta; 294 295 else 295 296 pVM->tm.s.pfnVirtualGetRawR3 = RTTimeNanoTSLegacyAsync; … … 619 620 * Dump the GIPCPU TSC-deltas, iterate using the Apic Id to get master at the beginning in most cases. 620 621 */ 621 LogRel(("TM: GIP - fTscDeltasRoughlyInSync=%RTbool\n", g_pSUPGlobalInfoPage->fTscDeltasRoughlyInSync));622 unsigned cGipCpus = RT_ELEMENTS(g_pSUPGlobalInfoPage->aiCpuFromApicId);623 for (u nsigned i = 0; i < cGipCpus; i++)624 { 625 uint16_t iCpu = g_pSUPGlobalInfoPage->aiCpuFromApicId[i];622 LogRel(("TM: GIP - enmUseTscDelta=%d fGetGipCpu=%#x cCpus=%#x\n", 623 pGip->enmUseTscDelta, pGip->fGetGipCpu, pGip->cCpus)); 624 for (uint32_t i = 0; i < RT_ELEMENTS(pGip->aiCpuFromApicId); i++) 625 { 626 uint16_t iCpu = pGip->aiCpuFromApicId[i]; 626 627 #if 1 627 628 if (iCpu != UINT16_MAX) 628 LogRel(("TM: GIP - CPU[%d]: idApic=%d i64TSCDelta=%RI64\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].idCpu,629 g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic, g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta));629 LogRel(("TM: GIP - CPU[%d]: idApic=%d i64TSCDelta=%RI64\n", pGip->aCPUs[iCpu].idCpu, 630 pGip->aCPUs[iCpu].idApic, pGip->aCPUs[iCpu].i64TSCDelta)); 630 631 #else 631 632 /* Dump 2 entries per line, saves vertical space in release log but more dumps bytes due to formatting. */ … … 633 634 for (unsigned k = i + 1; k < cGipCpus; k++) 634 635 { 635 iCpu2 = g_pSUPGlobalInfoPage->aiCpuFromApicId[k];636 iCpu2 = pGip->aiCpuFromApicId[k]; 636 637 if (iCpu2 != UINT16_MAX) 637 638 { … … 644 645 { 645 646 LogRel(("TM: GIP - CPU[%d]: idApic=%d i64TSCDelta=%-4lld CPU[%d]: idApic=%d i64TSCDelta=%lld\n", 646 g_pSUPGlobalInfoPage->aCPUs[iCpu].idCpu, g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic,647 g_pSUPGlobalInfoPage->aCPUs[iCpu].i64TSCDelta, g_pSUPGlobalInfoPage->aCPUs[iCpu2].idCpu,648 g_pSUPGlobalInfoPage->aCPUs[iCpu2].idApic, g_pSUPGlobalInfoPage->aCPUs[iCpu2].i64TSCDelta));647 pGip->aCPUs[iCpu].idCpu, pGip->aCPUs[iCpu].idApic, 648 pGip->aCPUs[iCpu].i64TSCDelta, pGip->aCPUs[iCpu2].idCpu, 649 pGip->aCPUs[iCpu2].idApic, pGip->aCPUs[iCpu2].i64TSCDelta)); 649 650 } 650 651 else if (iCpu != UINT16_MAX) 651 LogRel(("TM: GIP - CPU[%d]: idApic=%d i64TSCDelta=%lld\n", g_pSUPGlobalInfoPage->aCPUs[iCpu].idCpu,652 g_pSUPGlobalInfoPage->aCPUs[iCpu].idApic));652 LogRel(("TM: GIP - CPU[%d]: idApic=%d i64TSCDelta=%lld\n", pGip->aCPUs[iCpu].idCpu, 653 pGip->aCPUs[iCpu].idApic)); 653 654 #endif 654 655 } … … 941 942 } 942 943 return false; 943 }944 945 946 /**947 * Checks if we really need to apply the delta values when calculating time.948 *949 * Getting the delta for a CPU is _very_ expensive, it more than doubles the950 * execution time for RTTimeNanoTS.951 *952 * @returns true if deltas needs to be applied, false if not.953 * @param pGip The GIP.954 *955 * @remarks If you change this, make sure to also change956 * rtTimeNanoTsInternalReallyNeedDeltas().957 */958 static bool tmR3ReallyNeedDeltas(PSUPGLOBALINFOPAGE pGip)959 {960 return !pGip->fOsTscDeltasInSync && !pGip->fTscDeltasRoughlyInSync;961 #if 0962 if (!pGip->fOsTscDeltasInSync)963 {964 uint32_t i = pGip->cCpus;965 while (i-- > 0)966 if ( pGip->aCPUs[i].enmState == SUPGIPCPUSTATE_ONLINE967 && ( pGip->aCPUs[i].i64TSCDelta > 384968 || pGip->aCPUs[i].i64TSCDelta < -384) )969 return true;970 }971 return false;972 #endif973 944 } 974 945
Note:
See TracChangeset
for help on using the changeset viewer.