Changeset 32572 in vbox for trunk/src/VBox/VMM
- Timestamp:
- Sep 16, 2010 4:18:12 PM (14 years ago)
- Location:
- trunk/src/VBox/VMM
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/TMAll.cpp
r32489 r32572 2374 2374 /* Fudge factor. */ 2375 2375 /** @todo make this configurable. */ 2376 #if 0 /* what's wrong with this expression? I end up with uHz = 0 after this multiplication... */ 2376 2377 uHz *= 110 + pVCpu->idCpu == pVM->tm.s.idTimerCpu; 2378 #else 2379 if (pVCpu->idCpu == pVM->tm.s.idTimerCpu) 2380 uHz *= 111; 2381 else 2382 uHz *= 110; 2383 #endif 2377 2384 uHz /= 100; 2378 2385 2386 //LogAlways(("TMCalcHostTimerFrequency->%u\n", uHz)); 2379 2387 return uHz; 2380 2388 } -
trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp
r32489 r32572 57 57 #include <iprt/memobj.h> 58 58 #include <iprt/mp.h> 59 #include <iprt/cpuset.h> 60 #include <iprt/spinlock.h> 61 #include <iprt/timer.h> 62 63 64 /******************************************************************************* 65 * Defined Constants And Macros * 66 *******************************************************************************/ 67 #ifdef DOXYGEN_RUNNING 68 /** Define this to enable the periodic preemption timer. */ 69 # define GVMM_SCHED_WITH_PPT 70 #endif 59 71 60 72 … … 97 109 # define GVMM_MAX_HANDLES 128 98 110 #endif 111 112 /** 113 * Per host CPU GVMM data. 114 */ 115 typedef struct GVMMHOSTCPU 116 { 117 /** Magic number (GVMMHOSTCPU_MAGIC). */ 118 uint32_t volatile u32Magic; 119 /** The CPU ID. */ 120 RTCPUID idCpu; 121 /** The CPU set index. */ 122 uint32_t idxCpuSet; 123 124 #ifdef GVMM_SCHED_WITH_PPT 125 /** Periodic preemption timer data. */ 126 struct 127 { 128 /** The handle to the periodic preemption timer. */ 129 PRTTIMER pTimer; 130 /** Spinlock protecting the data below. */ 131 RTSPINLOCK hSpinlock; 132 /** The smalles Hz that we need to care about. (static) */ 133 uint32_t uMinHz; 134 /** The number of ticks between each historization. */ 135 uint32_t cTicksHistoriziationInterval; 136 /** The current historization tick (counting up to 137 * cTicksHistoriziationInterval and then resetting). */ 138 uint32_t iTickHistorization; 139 /** The current timer interval. This is set to 0 when inactive. */ 140 uint32_t cNsInterval; 141 /** The current timer frequency. This is set to 0 when inactive. */ 142 uint32_t uTimerHz; 143 /** The current max frequency reported by the EMTs. 144 * This gets historicize and reset by the timer callback. This is 145 * read without holding the spinlock, so needs atomic updating. */ 146 uint32_t volatile uDesiredHz; 147 /** Whether the timer was started or not. */ 148 bool volatile fStarted; 149 /** Set if we're starting timer. */ 150 bool volatile fStarting; 151 /** The index of the next history entry (mod it). */ 152 uint32_t iHzHistory; 153 /** Hitoricized uDesiredHz values. The array wraps around, new entries 154 * are added at iHzHistory. This is updated approximately every 155 * GVMMHOSTCPU_PPT_HIST_INTERVAL_NS by the timer callback. */ 156 uint32_t aHzHistory[32]; 157 /** Statistics counter for recording the number of interval changes. */ 158 uint64_t cChanges; 159 /** Statistics counter for recording the number of timer starts. */ 160 uint64_t cStarts; 161 } Ppt; 162 #endif /* GVMM_SCHED_WITH_PPT */ 163 164 } GVMMHOSTCPU; 165 /** Pointer to the per host CPU GVMM data. */ 166 typedef GVMMHOSTCPU *PGVMMHOSTCPU; 167 /** The GVMMHOSTCPU::u32Magic value (Petra, Tanya & Rachel Haden). */ 168 #define GVMMHOSTCPU_MAGIC UINT32_C(0x19711011) 169 /** The interval on history entry should cover (approximately) give in 170 * nanoseconds. */ 171 #define GVMMHOSTCPU_PPT_HIST_INTERVAL_NS UINT32_C(20000000) 172 99 173 100 174 /** … … 148 222 */ 149 223 uint32_t nsEarlyWakeUp2; 224 225 /** The number of entries in the host CPU array (aHostCpus). */ 226 uint32_t cHostCpus; 227 /** Per host CPU data (variable length). */ 228 GVMMHOSTCPU aHostCpus[1]; 150 229 } GVMM; 151 230 /** Pointer to the GVMM instance data. */ … … 198 277 static int gvmmR0ByVM(PVM pVM, PGVM *ppGVM, PGVMM *ppGVMM, bool fTakeUsedLock); 199 278 static int gvmmR0ByVMAndEMT(PVM pVM, VMCPUID idCpu, PGVM *ppGVM, PGVMM *ppGVMM); 279 #ifdef GVMM_SCHED_WITH_PPT 280 static DECLCALLBACK(void) gvmmR0SchedPeriodicPreemptionTimerCallback(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 281 #endif 200 282 201 283 … … 214 296 * Allocate and initialize the instance data. 215 297 */ 216 PGVMM pGVMM = (PGVMM)RTMemAllocZ(sizeof(*pGVMM)); 298 uint32_t cHostCpus = RTMpGetArraySize(); 299 AssertMsgReturn(cHostCpus > 0 && cHostCpus < _64K, ("%d", (int)cHostCpus), VERR_INTERNAL_ERROR_2); 300 301 PGVMM pGVMM = (PGVMM)RTMemAllocZ(RT_UOFFSETOF(GVMM, aHostCpus[cHostCpus])); 217 302 if (!pGVMM) 218 303 return VERR_NO_MEMORY; … … 250 335 pGVMM->nsEarlyWakeUp2 = 50000 /* ns (0.050 ms) */; 251 336 252 g_pGVMM = pGVMM; 253 LogFlow(("GVMMR0Init: pGVMM=%p\n", pGVMM)); 254 return VINF_SUCCESS; 255 } 256 337 /* The host CPU data. */ 338 pGVMM->cHostCpus = cHostCpus; 339 uint32_t iCpu = cHostCpus; 340 RTCPUSET PossibleSet; 341 RTMpGetSet(&PossibleSet); 342 while (iCpu-- > 0) 343 { 344 pGVMM->aHostCpus[iCpu].idxCpuSet = iCpu; 345 #ifdef GVMM_SCHED_WITH_PPT 346 pGVMM->aHostCpus[iCpu].Ppt.pTimer = NULL; 347 pGVMM->aHostCpus[iCpu].Ppt.hSpinlock = NIL_RTSPINLOCK; 348 pGVMM->aHostCpus[iCpu].Ppt.uMinHz = 5; /** @todo Add some API which figures this one out. (not *that* important) */ 349 pGVMM->aHostCpus[iCpu].Ppt.cTicksHistoriziationInterval = 1; 350 //pGVMM->aHostCpus[iCpu].Ppt.iTickHistorization = 0; 351 //pGVMM->aHostCpus[iCpu].Ppt.cNsInterval = 0; 352 //pGVMM->aHostCpus[iCpu].Ppt.uTimerHz = 0; 353 //pGVMM->aHostCpus[iCpu].Ppt.uDesiredHz = 0; 354 //pGVMM->aHostCpus[iCpu].Ppt.fStarted = false; 355 //pGVMM->aHostCpus[iCpu].Ppt.fStarting = false; 356 //pGVMM->aHostCpus[iCpu].Ppt.iHzHistory = 0; 357 //pGVMM->aHostCpus[iCpu].Ppt.aHzHistory = {0}; 358 #endif 359 360 if (RTCpuSetIsMember(&PossibleSet, iCpu)) 361 { 362 pGVMM->aHostCpus[iCpu].idCpu = RTMpCpuIdFromSetIndex(iCpu); 363 pGVMM->aHostCpus[iCpu].u32Magic = GVMMHOSTCPU_MAGIC; 364 365 #ifdef GVMM_SCHED_WITH_PPT 366 rc = RTTimerCreateEx(&pGVMM->aHostCpus[iCpu].Ppt.pTimer, 367 50*1000*1000 /* whatever */, 368 RTTIMER_FLAGS_CPU(iCpu) | RTTIMER_FLAGS_HIGH_RES, 369 gvmmR0SchedPeriodicPreemptionTimerCallback, 370 &pGVMM->aHostCpus[iCpu]); 371 if (RT_SUCCESS(rc)) 372 rc = RTSpinlockCreate(&pGVMM->aHostCpus[iCpu].Ppt.hSpinlock); 373 if (RT_FAILURE(rc)) 374 { 375 while (iCpu < cHostCpus) 376 { 377 RTTimerDestroy(pGVMM->aHostCpus[iCpu].Ppt.pTimer); 378 RTSpinlockDestroy(pGVMM->aHostCpus[iCpu].Ppt.hSpinlock); 379 pGVMM->aHostCpus[iCpu].Ppt.hSpinlock = NIL_RTSPINLOCK; 380 iCpu++; 381 } 382 break; 383 } 384 #endif 385 } 386 else 387 { 388 pGVMM->aHostCpus[iCpu].idCpu = NIL_RTCPUID; 389 pGVMM->aHostCpus[iCpu].u32Magic = 0; 390 } 391 } 392 if (RT_SUCCESS(rc)) 393 { 394 g_pGVMM = pGVMM; 395 LogFlow(("GVMMR0Init: pGVMM=%p cHostCpus=%u\n", pGVMM, cHostCpus)); 396 return VINF_SUCCESS; 397 } 398 399 /* bail out. */ 400 RTSemFastMutexDestroy(pGVMM->UsedLock); 401 pGVMM->UsedLock = NIL_RTSEMFASTMUTEX; 402 } 257 403 RTSemFastMutexDestroy(pGVMM->CreateDestroyLock); 404 pGVMM->CreateDestroyLock = NIL_RTSEMFASTMUTEX; 258 405 } 259 406 … … 282 429 } 283 430 284 pGVMM->u32Magic++; 285 431 /* 432 * First of all, stop all active timers. 433 */ 434 uint32_t cActiveTimers = 0; 435 uint32_t iCpu = pGVMM->cHostCpus; 436 while (iCpu-- > 0) 437 { 438 ASMAtomicWriteU32(&pGVMM->aHostCpus[iCpu].u32Magic, ~GVMMHOSTCPU_MAGIC); 439 #ifdef GVMM_SCHED_WITH_PPT 440 if ( pGVMM->aHostCpus[iCpu].Ppt.pTimer != NULL 441 && RT_SUCCESS(RTTimerStop(pGVMM->aHostCpus[iCpu].Ppt.pTimer))) 442 cActiveTimers++; 443 #endif 444 } 445 if (cActiveTimers) 446 RTThreadSleep(1); /* fudge */ 447 448 /* 449 * Invalidate the and free resources. 450 */ 451 pGVMM->u32Magic = ~GVMM_MAGIC; 286 452 RTSemFastMutexDestroy(pGVMM->UsedLock); 287 453 pGVMM->UsedLock = NIL_RTSEMFASTMUTEX; … … 295 461 pGVMM->iUsedHead = 0; 296 462 } 463 464 #ifdef GVMM_SCHED_WITH_PPT 465 iCpu = pGVMM->cHostCpus; 466 while (iCpu-- > 0) 467 { 468 RTTimerDestroy(pGVMM->aHostCpus[iCpu].Ppt.pTimer); 469 pGVMM->aHostCpus[iCpu].Ppt.pTimer = NULL; 470 RTSpinlockDestroy(pGVMM->aHostCpus[iCpu].Ppt.hSpinlock); 471 pGVMM->aHostCpus[iCpu].Ppt.hSpinlock = NIL_RTSPINLOCK; 472 } 473 #endif 297 474 298 475 RTMemFree(pGVMM); … … 1886 2063 1887 2064 2065 #ifdef GVMM_SCHED_WITH_PPT 2066 /** 2067 * Timer callback for the periodic preemption timer. 2068 * 2069 * @param pTimer The timer handle. 2070 * @param pvUser Pointer to the per cpu structure. 2071 * @param iTick The current tick. 2072 */ 2073 static DECLCALLBACK(void) gvmmR0SchedPeriodicPreemptionTimerCallback(PRTTIMER pTimer, void *pvUser, uint64_t iTick) 2074 { 2075 PGVMMHOSTCPU pCpu = (PGVMMHOSTCPU)pvUser; 2076 2077 /* 2078 * Termination check 2079 */ 2080 if (pCpu->u32Magic != GVMMHOSTCPU_MAGIC) 2081 return; 2082 2083 /* 2084 * Do the house keeping. 2085 */ 2086 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 2087 RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2088 2089 if (++pCpu->Ppt.iTickHistorization >= pCpu->Ppt.cTicksHistoriziationInterval) 2090 { 2091 /* 2092 * Historicize the max frequency. 2093 */ 2094 uint32_t iHzHistory = ++pCpu->Ppt.iHzHistory % RT_ELEMENTS(pCpu->Ppt.aHzHistory); 2095 pCpu->Ppt.aHzHistory[iHzHistory] = pCpu->Ppt.uDesiredHz; 2096 pCpu->Ppt.iTickHistorization = 0; 2097 pCpu->Ppt.uDesiredHz = 0; 2098 2099 /* 2100 * Check if the current timer frequency. 2101 */ 2102 uint32_t uHistMaxHz = 0; 2103 for (uint32_t i = 0; i < RT_ELEMENTS(pCpu->Ppt.aHzHistory); i++) 2104 if (pCpu->Ppt.aHzHistory[i] > uHistMaxHz) 2105 uHistMaxHz = pCpu->Ppt.aHzHistory[i]; 2106 if (uHistMaxHz == pCpu->Ppt.uTimerHz) 2107 RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2108 else if (uHistMaxHz) 2109 { 2110 /* 2111 * Reprogram it. 2112 */ 2113 pCpu->Ppt.cChanges++; 2114 pCpu->Ppt.iTickHistorization = 0; 2115 pCpu->Ppt.uTimerHz = uHistMaxHz; 2116 uint32_t const cNsInterval = UINT32_C(1000000000) / uHistMaxHz; 2117 pCpu->Ppt.cNsInterval = cNsInterval; 2118 if (cNsInterval < GVMMHOSTCPU_PPT_HIST_INTERVAL_NS) 2119 pCpu->Ppt.cTicksHistoriziationInterval = ( GVMMHOSTCPU_PPT_HIST_INTERVAL_NS 2120 + GVMMHOSTCPU_PPT_HIST_INTERVAL_NS / 2 - 1) 2121 / cNsInterval; 2122 else 2123 pCpu->Ppt.cTicksHistoriziationInterval = 1; 2124 RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2125 2126 /*SUPR0Printf("Cpu%u: change to %u Hz / %u ns\n", pCpu->idxCpuSet, uHistMaxHz, cNsInterval);*/ 2127 RTTimerChangeInterval(pTimer, cNsInterval); 2128 } 2129 else 2130 { 2131 /* 2132 * Stop it. 2133 */ 2134 pCpu->Ppt.fStarted = false; 2135 pCpu->Ppt.uTimerHz = 0; 2136 pCpu->Ppt.cNsInterval = 0; 2137 RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2138 2139 /*SUPR0Printf("Cpu%u: stopping (%u Hz)\n", pCpu->idxCpuSet, uHistMaxHz);*/ 2140 RTTimerStop(pTimer); 2141 } 2142 } 2143 else 2144 RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2145 } 2146 #endif /* GVMM_SCHED_WITH_PPT */ 2147 1888 2148 1889 2149 /** … … 1891 2151 * 1892 2152 * The caller must have disabled preemption! 2153 * The caller must check that the host can do high resolution timers. 1893 2154 * 1894 2155 * @param pVM The VM handle. … … 1898 2159 GVMMR0DECL(void) GVMMR0SchedUpdatePeriodicPreemptionTimer(PVM pVM, RTCPUID idHostCpu, uint32_t uHz) 1899 2160 { 1900 2161 #ifdef GVMM_SCHED_WITH_PPT 2162 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD)); 2163 Assert(RTTimerCanDoHighResolution()); 2164 2165 /* 2166 * Resolve the per CPU data. 2167 */ 2168 uint32_t iCpu = RTMpCpuIdToSetIndex(idHostCpu); 2169 PGVMM pGVMM = g_pGVMM; 2170 if ( !VALID_PTR(pGVMM) 2171 || pGVMM->u32Magic != GVMM_MAGIC) 2172 return; 2173 AssertMsgReturnVoid(iCpu < pGVMM->cHostCpus, ("iCpu=%d cHostCpus=%d\n", iCpu, pGVMM->cHostCpus)); 2174 PGVMMHOSTCPU pCpu = &pGVMM->aHostCpus[iCpu]; 2175 AssertMsgReturnVoid( pCpu->u32Magic == GVMMHOSTCPU_MAGIC 2176 && pCpu->idCpu == idHostCpu, 2177 ("u32Magic=%#x idCpu=% idHostCpu=%d\n", pCpu->u32Magic, pCpu->idCpu, idHostCpu)); 2178 2179 /* 2180 * Check whether we need to do anything about the timer. 2181 * We have to be a little bit careful since we might be race the timer 2182 * callback here. 2183 */ 2184 if (uHz > 20000) 2185 uHz = 20000; 2186 if (RT_UNLIKELY( uHz > ASMAtomicReadU32(&pCpu->Ppt.uDesiredHz) 2187 && uHz >= pCpu->Ppt.uMinHz 2188 && !pCpu->Ppt.fStarting /* solaris paranoia */)) 2189 { 2190 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER; 2191 RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2192 2193 pCpu->Ppt.uDesiredHz = uHz; 2194 uint32_t cNsInterval = 0; 2195 if (!pCpu->Ppt.fStarted) 2196 { 2197 pCpu->Ppt.cStarts++; 2198 pCpu->Ppt.fStarted = true; 2199 pCpu->Ppt.fStarting = true; 2200 pCpu->Ppt.iTickHistorization = 0; 2201 pCpu->Ppt.uTimerHz = uHz; 2202 pCpu->Ppt.cNsInterval = cNsInterval = UINT32_C(1000000000) / uHz; 2203 if (cNsInterval < GVMMHOSTCPU_PPT_HIST_INTERVAL_NS) 2204 pCpu->Ppt.cTicksHistoriziationInterval = ( GVMMHOSTCPU_PPT_HIST_INTERVAL_NS 2205 + GVMMHOSTCPU_PPT_HIST_INTERVAL_NS / 2 - 1) 2206 / cNsInterval; 2207 else 2208 pCpu->Ppt.cTicksHistoriziationInterval = 1; 2209 } 2210 2211 RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2212 2213 if (cNsInterval) 2214 { 2215 RTTimerChangeInterval(pCpu->Ppt.pTimer, cNsInterval); 2216 int rc = RTTimerStart(pCpu->Ppt.pTimer, cNsInterval); 2217 AssertRC(rc); 2218 2219 RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2220 if (RT_FAILURE(rc)) 2221 pCpu->Ppt.fStarted = false; 2222 pCpu->Ppt.fStarting = false; 2223 RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp); 2224 } 2225 } 2226 #endif /* GVMM_SCHED_WITH_PPT */ 1901 2227 } 1902 2228
Note:
See TracChangeset
for help on using the changeset viewer.