vbox的更動 2869 路徑 trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp
- 時間撮記:
- 2007-5-25 下午01:15:39 (18 年 以前)
- 檔案:
-
- 修改 1 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp
r2861 r2869 47 47 48 48 49 /** 50 * This is (mostly) the same as rtTimeNanoTSInternal() except 51 * for the two globals which live in TM. 52 * 53 * @returns Nanosecond timestamp. 54 * @param pVM The VM handle. 55 */ 56 static uint64_t tmVirtualGetRawNanoTS(PVM pVM) 57 { 58 uint64_t u64Delta; 59 uint32_t u32NanoTSFactor0; 60 uint64_t u64TSC; 61 uint64_t u64NanoTS; 62 uint32_t u32UpdateIntervalTSC; 63 64 /* 65 * Read the GIP data. 66 */ 67 for (;;) 68 { 69 uint32_t u32TransactionId; 70 PCSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; 71 #ifdef IN_RING3 72 if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC)) 73 return RTTimeSystemNanoTS(); 74 #endif 75 76 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 77 { 78 u32TransactionId = pGip->aCPUs[0].u32TransactionId; 79 #ifdef __L4__ 80 Assert((u32TransactionId & 1) == 0); 81 #endif 82 u32UpdateIntervalTSC = pGip->aCPUs[0].u32UpdateIntervalTSC; 83 u64NanoTS = pGip->aCPUs[0].u64NanoTS; 84 u64TSC = pGip->aCPUs[0].u64TSC; 85 u32NanoTSFactor0 = pGip->u32UpdateIntervalNS; 86 u64Delta = ASMReadTSC(); 87 if (RT_UNLIKELY( pGip->aCPUs[0].u32TransactionId != u32TransactionId 88 || (u32TransactionId & 1))) 89 continue; 90 } 91 else 92 { 93 /* SUPGIPMODE_ASYNC_TSC */ 94 PCSUPGIPCPU pGipCpu; 95 96 uint8_t u8ApicId = ASMGetApicId(); 97 if (RT_LIKELY(u8ApicId < RT_ELEMENTS(pGip->aCPUs))) 98 pGipCpu = &pGip->aCPUs[u8ApicId]; 99 else 100 { 101 AssertMsgFailed(("%x\n", u8ApicId)); 102 pGipCpu = &pGip->aCPUs[0]; 103 } 104 105 u32TransactionId = pGipCpu->u32TransactionId; 106 #ifdef __L4__ 107 Assert((u32TransactionId & 1) == 0); 108 #endif 109 u32UpdateIntervalTSC = pGipCpu->u32UpdateIntervalTSC; 110 u64NanoTS = pGipCpu->u64NanoTS; 111 u64TSC = pGipCpu->u64TSC; 112 u32NanoTSFactor0 = pGip->u32UpdateIntervalNS; 113 u64Delta = ASMReadTSC(); 114 if (RT_UNLIKELY(u8ApicId != ASMGetApicId())) 115 continue; 116 if (RT_UNLIKELY( pGipCpu->u32TransactionId != u32TransactionId 117 || (u32TransactionId & 1))) 118 continue; 119 } 120 break; 121 } 122 123 /* 124 * Calc NanoTS delta. 125 */ 126 u64Delta -= u64TSC; 127 if (u64Delta > u32UpdateIntervalTSC) 128 { 129 /* 130 * We've expired the interval, cap it. If we're here for the 2nd 131 * time without any GIP update inbetween, the checks against 132 * pVM->tm.s.u64VirtualRawPrev below will force 1ns stepping. 133 */ 134 u64Delta = u32UpdateIntervalTSC; 135 } 136 #if !defined(_MSC_VER) || defined(__AMD64__) /* GCC makes very pretty code from these two inline calls, while MSC cannot. */ 137 u64Delta = ASMMult2xU32RetU64((uint32_t)u64Delta, u32NanoTSFactor0); 138 u64Delta = ASMDivU64ByU32RetU32(u64Delta, u32UpdateIntervalTSC); 139 #else 140 __asm 141 { 142 mov eax, dword ptr [u64Delta] 143 mul dword ptr [u32NanoTSFactor0] 144 div dword ptr [u32UpdateIntervalTSC] 145 mov dword ptr [u64Delta], eax 146 xor edx, edx 147 mov dword ptr [u64Delta + 4], edx 148 } 149 #endif 150 151 /* 152 * Calculate the time and compare it with the previously returned value. 153 * 154 * Since this function is called *very* frequently when the VM is running 155 * and then mostly on EMT, we can restrict the valid range of the delta 156 * (-1s to 2*GipUpdates) and simplify/optimize the default path. 157 */ 158 u64NanoTS += u64Delta; 159 uint64_t u64PrevNanoTS = ASMAtomicReadU64(&pVM->tm.s.u64VirtualRawPrev); 160 uint64_t u64DeltaPrev = u64NanoTS - u64PrevNanoTS; 161 if (RT_LIKELY(u64DeltaPrev < 1000000000 /* 1s */)) 162 /* frequent - less than 1s since last call. */; 163 else if ( (int64_t)u64DeltaPrev < 0 164 && (int64_t)u64DeltaPrev + u32NanoTSFactor0 * 2 > 0) 165 { 166 /* occasional - u64NanoTS is in the 'past' relative to previous returns. */ 167 ASMAtomicIncU32(&pVM->tm.s.c1nsVirtualRawSteps); 168 u64NanoTS = u64PrevNanoTS + 1; 169 } 170 else if (u64PrevNanoTS) 171 { 172 /* Something has gone bust, if negative offset it's real bad.*/ 173 ASMAtomicIncU32(&pVM->tm.s.cVirtualRawBadRawPrev); 174 if ((int64_t)u64DeltaPrev < 0) 175 LogRel(("TM: u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64 u64Delta=%#RX64\n", 176 u64DeltaPrev, u64PrevNanoTS, u64NanoTS, u64Delta)); 177 else 178 Log(("TM: u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64 u64Delta=%#RX64 (debugging?)\n", 179 u64DeltaPrev, u64PrevNanoTS, u64NanoTS, u64Delta)); 180 #ifdef DEBUG_bird 181 AssertMsgFailed(("u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64 u64Delta=%#RX64\n", 182 u64DeltaPrev, u64PrevNanoTS, u64NanoTS, u64Delta)); 183 #endif 184 } 185 /* else: We're resuming (see TMVirtualResume). */ 186 if (RT_LIKELY(ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualRawPrev, u64NanoTS, u64PrevNanoTS))) 187 return u64NanoTS; 188 189 /* 190 * Attempt updating the previous value, provided we're still ahead of it. 191 * 192 * There is no point in recalculating u64NanoTS because we got preemted or if 193 * we raced somebody while the GIP was updated, since these are events 194 * that might occure at any point in the return path as well. 195 */ 196 for (int cTries = 100;;) 197 { 198 u64PrevNanoTS = ASMAtomicReadU64(&pVM->tm.s.u64VirtualRawPrev); 199 if (u64PrevNanoTS >= u64NanoTS) 200 break; 201 if (ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualRawPrev, u64NanoTS, u64PrevNanoTS)) 202 break; 203 AssertBreak(--cTries <= 0, ); 204 } 205 206 return u64NanoTS; 207 } 208 209 49 210 50 211 /** … … 60 221 * warp drive has been enabled. 61 222 */ 62 uint64_t u64 = RTTimeNanoTS();223 uint64_t u64 = tmVirtualGetRawNanoTS(pVM); 63 224 u64 -= pVM->tm.s.u64VirtualWarpDriveStart; 64 225 u64 *= pVM->tm.s.u32VirtualWarpDrivePercentage; … … 68 229 /* 69 230 * Now we apply the virtual time offset. 70 * (Which is the negate RTTimeNanoTS() value for when the virtual machine71 * started if it had been running continuously without any suspends.)231 * (Which is the negated tmVirtualGetRawNanoTS() value for when the virtual 232 * machine started if it had been running continuously without any suspends.) 72 233 */ 73 234 u64 -= pVM->tm.s.u64VirtualOffset; … … 85 246 { 86 247 if (RT_LIKELY(!pVM->tm.s.fVirtualWarpDrive)) 87 return RTTimeNanoTS() - pVM->tm.s.u64VirtualOffset;248 return tmVirtualGetRawNanoTS(pVM) - pVM->tm.s.u64VirtualOffset; 88 249 return tmVirtualGetRawNonNormal(pVM); 89 250 } … … 209 370 * - We might be on a different CPU which TSC isn't quite in sync with the 210 371 * other CPUs in the system. 211 * - RTTimeNanoTS() is returning sligtly different values in GC, R0 and R3 because212 * of the static variable it uses with the previous read time.213 372 * - Another thread is racing us and we might have been preemnted while inside 214 373 * this function. … … 350 509 { 351 510 STAM_COUNTER_INC(&pVM->tm.s.StatVirtualResume); 352 pVM->tm.s.u64VirtualWarpDriveStart = RTTimeNanoTS(); 511 pVM->tm.s.u64VirtualRawPrev = 0; 512 pVM->tm.s.u64VirtualWarpDriveStart = tmVirtualGetRawNanoTS(pVM); 353 513 pVM->tm.s.u64VirtualOffset = pVM->tm.s.u64VirtualWarpDriveStart - pVM->tm.s.u64Virtual; 354 514 pVM->tm.s.fVirtualTicking = true;
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器