Changeset 54321 in vbox
- Timestamp:
- Feb 20, 2015 4:25:43 AM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/HostDrivers/Support/SUPDrv.c
r54318 r54321 7116 7116 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 7117 7117 { 7118 RTCpuSetAdd (&pDevExt->TscDeltaCpuSet, iCpuSet);7118 RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, iCpuSet); 7119 7119 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 7120 7120 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); … … 7178 7178 ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX); 7179 7179 /* Remove this CPU from the set of CPUs that we have obtained the TSC deltas. */ 7180 RTCpuSetDel (&pDevExt->TscDeltaObtainedCpuSet, iCpuSet);7180 RTCpuSetDelByIndex(&pDevExt->TscDeltaObtainedCpuSet, iCpuSet); 7181 7181 } 7182 7182 … … 7244 7244 7245 7245 for (i = 0; i < RTCPUSET_MAX_CPUS; i++) 7246 { 7247 RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i); 7248 if ( RTCpuSetIsMember(&OnlineCpus, idCurCpu) 7249 && idCurCpu != idGipMaster) 7246 if (RTCpuSetIsMemberByIndex(&OnlineCpus, i)) 7250 7247 { 7251 idNewGipMaster = idCurCpu; 7252 break; 7248 RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i); 7249 if (idCurCpu != idGipMaster) 7250 { 7251 idNewGipMaster = idCurCpu; 7252 break; 7253 } 7253 7254 } 7254 }7255 7255 7256 7256 Log(("supdrvGipMpEvent: Gip master %#lx -> %#lx\n", (long)idGipMaster, (long)idNewGipMaster)); … … 7262 7262 7263 7263 7264 /* 7265 * Select TSC delta measurement algorithm. 7266 */ 7267 #if 1 7268 # define GIP_TSC_DELTA_METHOD_1 7269 #else 7270 # define GIP_TSC_DELTA_METHOD_2 7271 #endif 7272 7273 7274 #ifdef GIP_TSC_DELTA_METHOD_2 7275 7276 /** 7277 * TSC delta measurment algorithm \#2 result entry. 7278 */ 7279 typedef struct SUPDRVTSCDELTAMETHOD2ENTRY 7280 { 7281 uint32_t iSeqMine; 7282 uint32_t iSeqOther; 7283 uint64_t uTsc; 7284 } SUPDRVTSCDELTAMETHOD2ENTRY; 7285 7286 /** 7287 * TSC delta measurment algorithm \#2 Data. 7288 */ 7289 typedef struct SUPDRVTSCDELTAMETHOD2 7290 { 7291 /** Padding to make sure the iCurSeqNo is in its own cache line. 7292 * ASSUMES cacheline sizes <= 128 bytes. */ 7293 uint32_t au32CacheLinePaddingBefore[128 / sizeof(uint32_t)]; 7294 /** The current sequence number of this worker. */ 7295 uint32_t volatile iCurSeqNo; 7296 /** Padding to make sure the iCurSeqNo is in its own cache line. 7297 * ASSUMES cacheline sizes <= 128 bytes. */ 7298 uint32_t au32CacheLinePaddingAfter[128 / sizeof(uint32_t) - 1]; 7299 /** Result table. */ 7300 SUPDRVTSCDELTAMETHOD2ENTRY aResults[96]; 7301 } SUPDRVTSCDELTAMETHOD2; 7302 /** Pointer to the data for TSC delta mesurment algorithm \#2 .*/ 7303 typedef SUPDRVTSCDELTAMETHOD2 *PSUPDRVTSCDELTAMETHOD2; 7304 7305 #endif /* GIP_TSC_DELTA_METHOD_2 */ 7306 7307 /** 7308 * Argument package/state passed by supdrvMeasureTscDeltaOne to the RTMpOn 7309 * callback worker. 7310 */ 7311 typedef struct SUPDRVGIPTSCDELTARGS 7312 { 7313 PSUPDRVDEVEXT pDevExt; 7314 PSUPGIPCPU pWorker; 7315 PSUPGIPCPU pMaster; 7316 RTCPUID idMaster; 7317 #ifdef GIP_TSC_DELTA_METHOD_2 7318 PSUPDRVTSCDELTAMETHOD2 pMasterData; 7319 PSUPDRVTSCDELTAMETHOD2 pWorkerData; 7320 uint32_t cHits; 7321 /*uint32_t cOffByOne;*/ 7322 uint32_t iAttempt; /**< 1-base outer loop counter. */ 7323 bool fLagMaster; 7324 bool fLagWorker; 7325 #endif 7326 } SUPDRVGIPTSCDELTARGS; 7327 typedef SUPDRVGIPTSCDELTARGS *PSUPDRVGIPTSCDELTARGS; 7328 7329 7330 #ifdef GIP_TSC_DELTA_METHOD_2 7331 /* 7332 * TSC delta measurement algorithm \#2 configuration and code - Experimental!! 7333 */ 7334 # undef GIP_TSC_DELTA_LOOPS 7335 # undef GIP_TSC_DELTA_READ_TIME_LOOPS 7336 # undef GIP_TSC_DELTA_PRIMER_LOOPS 7337 # define GIP_TSC_DELTA_LOOPS 17 7338 # define GIP_TSC_DELTA_PRIMER_LOOPS 1 7339 # define GIP_TSC_DELTA_READ_TIME_LOOPS GIP_TSC_DELTA_PRIMER_LOOPS /* no read-time-loops necessary */ 7340 7341 7342 static int supdrvTscDeltaMethod2Init(PSUPDRVGIPTSCDELTARGS pArgs) 7343 { 7344 uint32_t const fFlags = /*RTMEMALLOCEX_FLAGS_ANY_CTX |*/ RTMEMALLOCEX_FLAGS_ZEROED; 7345 int rc = RTMemAllocEx(sizeof(*pArgs->pMasterData), 0, fFlags, (void **)&pArgs->pWorkerData); 7346 if (RT_SUCCESS(rc)) 7347 rc = RTMemAllocEx(sizeof(*pArgs->pMasterData), 0, fFlags, (void **)&pArgs->pMasterData); 7348 return rc; 7349 } 7350 7351 7352 static void supdrvTscDeltaMethod2Term(PSUPDRVGIPTSCDELTARGS pArgs) 7353 { 7354 RTMemFreeEx(pArgs->pMasterData, sizeof(*pArgs->pMasterData)); 7355 RTMemFreeEx(pArgs->pWorkerData, sizeof(*pArgs->pWorkerData)); 7356 /*SUPR0Printf("cHits=%d cOffByOne=%d m=%d w=%d\n", pArgs->cHits, pArgs->cOffByOne, pArgs->pMaster->idApic, pArgs->pWorker->idApic);*/ 7357 } 7358 7359 7360 static void supdrvTscDeltaMethod2Looped(PSUPDRVGIPTSCDELTARGS pArgs, RTCPUID idCpu, unsigned iLoop) 7361 { 7362 if (pArgs->idMaster == idCpu) 7363 { 7364 if (iLoop < GIP_TSC_DELTA_PRIMER_LOOPS) 7365 { 7366 if (iLoop == 0) 7367 pArgs->iAttempt++; 7368 7369 /* Lag during the priming to be nice to everyone.. */ 7370 pArgs->fLagMaster = true; 7371 pArgs->fLagWorker = true; 7372 } 7373 else if (iLoop < (GIP_TSC_DELTA_LOOPS - GIP_TSC_DELTA_PRIMER_LOOPS) / 4) 7374 { 7375 /* 25 % of the body without lagging. */ 7376 pArgs->fLagMaster = false; 7377 pArgs->fLagWorker = false; 7378 } 7379 else if (iLoop < (GIP_TSC_DELTA_LOOPS - GIP_TSC_DELTA_PRIMER_LOOPS) / 4 * 2) 7380 { 7381 /* 25 % of the body with both lagging. */ 7382 pArgs->fLagMaster = true; 7383 pArgs->fLagWorker = true; 7384 } 7385 else 7386 { 7387 /* 50% of the body with alternating lag. */ 7388 pArgs->fLagMaster = (iLoop & 1) == 0; 7389 pArgs->fLagWorker = (iLoop & 1) == 1; 7390 } 7391 } 7392 } 7393 7394 7395 /** 7396 * The core function of the 2nd TSC delta mesurment algorithm. 7397 * 7398 * The idea here is that we have the two CPUs execute the exact same code 7399 * collecting a largish set of TSC samples. The code has one data dependency on 7400 * the other CPU which intention it is to synchronize the execution as well as 7401 * help cross references the two sets of TSC samples (the sequence numbers). 7402 * 7403 * The @a fLag parameter is used to modify the execution a tiny bit on one or 7404 * both of the CPUs. When @a fLag differs between the CPUs, it is thought that 7405 * it will help with making the CPUs enter lock step execution occationally. 7406 * 7407 */ 7408 static void supdrvTscDeltaMethod2CollectData(PSUPDRVTSCDELTAMETHOD2 pMyData, uint32_t volatile *piOtherSeqNo, bool fLag) 7409 { 7410 SUPDRVTSCDELTAMETHOD2ENTRY *pEntry = &pMyData->aResults[0]; 7411 uint32_t cLeft = RT_ELEMENTS(pMyData->aResults); 7412 7413 ASMAtomicWriteU32(&pMyData->iCurSeqNo, 0); 7414 ASMSerializeInstruction(); 7415 while (cLeft-- > 0) 7416 { 7417 uint64_t uTsc; 7418 uint32_t iSeqMine = ASMAtomicIncU32(&pMyData->iCurSeqNo); 7419 uint32_t iSeqOther = ASMAtomicReadU32(piOtherSeqNo); 7420 ASMCompilerBarrier(); 7421 ASMSerializeInstruction(); /* Way better result than with ASMMemoryFenceSSE2() in this position! */ 7422 uTsc = ASMReadTSC(); 7423 ASMAtomicIncU32(&pMyData->iCurSeqNo); 7424 ASMCompilerBarrier(); 7425 ASMSerializeInstruction(); 7426 pEntry->iSeqMine = iSeqMine; 7427 pEntry->iSeqOther = iSeqOther; 7428 pEntry->uTsc = uTsc; 7429 pEntry++; 7430 ASMSerializeInstruction(); 7431 if (fLag) 7432 ASMNopPause(); 7433 } 7434 } 7435 7436 7437 static void supdrvTscDeltaMethod2ProcessDataSet(PSUPDRVGIPTSCDELTARGS pArgs, PSUPDRVTSCDELTAMETHOD2 pMyData, 7438 bool fIsMaster, uint32_t cResults, 7439 PSUPDRVTSCDELTAMETHOD2 pOtherData, int64_t iMasterTscDelta, 7440 int64_t volatile *piWorkerTscDelta) 7441 { 7442 uint32_t cHits = 0; 7443 #if 0 7444 uint32_t cOffByOne = 0; 7445 #endif 7446 uint32_t idxResult = 0; 7447 int64_t iBestDelta = *piWorkerTscDelta; 7448 7449 if (cResults > RT_ELEMENTS(pMyData->aResults)) 7450 cResults = RT_ELEMENTS(pMyData->aResults); 7451 7452 for (idxResult = 0; idxResult < cResults; idxResult++) 7453 { 7454 uint32_t idxOther = pMyData->aResults[idxResult].iSeqOther; 7455 if (idxOther & 1) 7456 { 7457 idxOther >>= 1; 7458 if (idxOther < RT_ELEMENTS(pOtherData->aResults)) 7459 { 7460 if (pOtherData->aResults[idxOther].iSeqOther == pMyData->aResults[idxResult].iSeqMine) 7461 { 7462 int64_t iDelta; 7463 if (fIsMaster) 7464 iDelta = pOtherData->aResults[idxOther].uTsc 7465 - (pMyData->aResults[idxResult].uTsc - iMasterTscDelta); 7466 else 7467 iDelta = (pOtherData->aResults[idxResult].uTsc - iMasterTscDelta) 7468 - pMyData->aResults[idxOther].uTsc; 7469 if ( iDelta >= GIP_TSC_DELTA_INITIAL_MASTER_VALUE 7470 ? iDelta < iBestDelta 7471 : iDelta > iBestDelta || iBestDelta == INT64_MAX) 7472 iBestDelta = iDelta; 7473 cHits++; 7474 } 7475 } 7476 } 7477 #if 0 /* Can be used to detect battles between threads on the same core. Decided to change the master instead. */ 7478 else 7479 { 7480 idxOther >>= 1; 7481 if ( idxOther < RT_ELEMENTS(pOtherData->aResults) 7482 && pOtherData->aResults[idxOther].iSeqOther == pMyData->aResults[idxResult].iSeqMine) 7483 cOffByOne++; 7484 } 7485 #endif 7486 } 7487 7488 if (cHits > 0) 7489 *piWorkerTscDelta = iBestDelta; 7490 pArgs->cHits += cHits; 7491 #if 0 7492 pArgs->cOffByOne += cOffByOne; 7493 #endif 7494 } 7495 7496 7497 static void supdrvTscDeltaMethod2ProcessDataOnMaster(PSUPDRVGIPTSCDELTARGS pArgs, bool fFinalLoop) 7498 { 7499 supdrvTscDeltaMethod2ProcessDataSet(pArgs, 7500 pArgs->pMasterData, 7501 true /*fIsMaster*/, 7502 RT_ELEMENTS(pArgs->pMasterData->aResults), 7503 pArgs->pWorkerData, 7504 pArgs->pMaster->i64TSCDelta, 7505 &pArgs->pWorker->i64TSCDelta); 7506 7507 supdrvTscDeltaMethod2ProcessDataSet(pArgs, 7508 pArgs->pWorkerData, 7509 false /*fIsMaster*/, 7510 ASMAtomicReadU32(&pArgs->pWorkerData->iCurSeqNo) >> 1, 7511 pArgs->pMasterData, 7512 pArgs->pMaster->i64TSCDelta, 7513 &pArgs->pWorker->i64TSCDelta); 7514 } 7515 7516 #endif /* GIP_TSC_DELTA_METHOD_2 */ 7517 7518 7264 7519 /** 7265 7520 * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs … … 7267 7522 * 7268 7523 * @param idCpu The CPU we are current scheduled on. 7269 * @param pvUser1 Opaque pointer to the device instance data.7270 * @param pvUser2 Pointer to the SUPGIPCPU entry of the worker CPU.7524 * @param pvUser1 Pointer to a parameter package (SUPDRVGIPTSCDELTARGS). 7525 * @param pvUser2 Unused. 7271 7526 * 7272 7527 * @remarks Measuring TSC deltas between the CPUs is tricky because we need to … … 7297 7552 static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2) 7298 7553 { 7299 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser1; 7554 PSUPDRVGIPTSCDELTARGS pArgs = (PSUPDRVGIPTSCDELTARGS)pvUser1; 7555 PSUPDRVDEVEXT pDevExt = pArgs->pDevExt; 7300 7556 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 7301 PSUPGIPCPU pGipCpuWorker = (PSUPGIPCPU)pvUser2; 7302 uint32_t idWorker = pGipCpuWorker->idCpu; 7303 RTCPUID idMaster = ASMAtomicUoReadU32(&pDevExt->idTscDeltaInitiator); 7304 unsigned idxMaster = supdrvGipFindCpuIndexForCpuId(pGip, idMaster); 7305 PSUPGIPCPU pGipCpuMaster = &pGip->aCPUs[idxMaster]; 7557 PSUPGIPCPU pGipCpuWorker = pArgs->pWorker; 7558 PSUPGIPCPU pGipCpuMaster = pArgs->pMaster; 7559 RTCPUID idMaster = pArgs->idMaster; 7306 7560 int cTriesLeft; 7307 7561 7562 /* A bit of paranoia first. */ 7563 if (!pGipCpuMaster || !pGipCpuWorker) 7564 return; 7565 7566 /* If the CPU isn't part of the measurement, return immediately. */ 7308 7567 if ( idCpu != idMaster 7309 && idCpu != idWorker)7568 && idCpu != pGipCpuWorker->idCpu) 7310 7569 return; 7311 7570 … … 7369 7628 for (i = 0; i < GIP_TSC_DELTA_LOOPS; i++) 7370 7629 { 7630 #ifdef GIP_TSC_DELTA_METHOD_2 7631 supdrvTscDeltaMethod2Looped(pArgs, idCpu, i); 7632 #endif 7371 7633 if (idCpu == idMaster) 7372 7634 { … … 7375 7637 */ 7376 7638 RTCCUINTREG uFlags; 7377 Assert(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD); 7639 AssertMsg(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD, 7640 ("%#llx idMaster=%#x idWorker=%#x (idGipMaster=%#x)\n", 7641 pGipCpuMaster->u64TSCSample, idMaster, pGipCpuWorker->idCpu, pDevExt->idGipMaster)); 7378 7642 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_START); 7379 7643 … … 7385 7649 { /* nothing */ } 7386 7650 7651 #ifdef GIP_TSC_DELTA_METHOD_1 7387 7652 do 7388 7653 { … … 7391 7656 } while (pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD); 7392 7657 7658 #elif defined(GIP_TSC_DELTA_METHOD_2) 7659 supdrvTscDeltaMethod2CollectData(pArgs->pMasterData, &pArgs->pWorkerData->iCurSeqNo, pArgs->fLagMaster); 7660 #else 7661 # error "tsc delta method not selected" 7662 #endif 7663 7664 /* Sync up with worker. */ 7393 7665 ASMSetFlags(uFlags); 7394 7666 … … 7396 7668 { /* nothing */ } 7397 7669 7670 /* Process the data. */ 7398 7671 if (i > GIP_TSC_DELTA_PRIMER_LOOPS + GIP_TSC_DELTA_READ_TIME_LOOPS) 7399 7672 { 7673 #ifdef GIP_TSC_DELTA_METHOD_1 7400 7674 if (pGipCpuWorker->u64TSCSample != GIP_TSC_DELTA_RSVD) 7401 7675 { 7402 7676 int64_t iDelta = pGipCpuWorker->u64TSCSample 7403 7677 - (pGipCpuMaster->u64TSCSample - pGipCpuMaster->i64TSCDelta); 7404 if ( iDelta >= 07678 if ( iDelta >= GIP_TSC_DELTA_INITIAL_MASTER_VALUE 7405 7679 ? iDelta < pGipCpuWorker->i64TSCDelta 7406 7680 : iDelta > pGipCpuWorker->i64TSCDelta || pGipCpuWorker->i64TSCDelta == INT64_MAX) 7407 7681 pGipCpuWorker->i64TSCDelta = iDelta; 7408 7682 } 7683 #elif defined(GIP_TSC_DELTA_METHOD_2) 7684 if (i > GIP_TSC_DELTA_PRIMER_LOOPS) 7685 supdrvTscDeltaMethod2ProcessDataOnMaster(pArgs, i == GIP_TSC_DELTA_LOOPS - 1); 7686 #else 7687 # error "tsc delta method not selected" 7688 #endif 7409 7689 } 7410 7690 7691 /* Reset our TSC sample and tell the worker to move on. */ 7411 7692 ASMAtomicWriteU64(&pGipCpuMaster->u64TSCSample, GIP_TSC_DELTA_RSVD); 7412 7693 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP); … … 7427 7708 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_WORKER_READY); 7428 7709 7710 #ifdef GIP_TSC_DELTA_METHOD_1 7429 7711 /* 7430 7712 * Keep reading the TSC until we notice that the master has read his. Reading … … 7460 7742 } 7461 7743 7744 #elif defined(GIP_TSC_DELTA_METHOD_2) 7745 supdrvTscDeltaMethod2CollectData(pArgs->pWorkerData, &pArgs->pMasterData->iCurSeqNo, pArgs->fLagWorker); 7746 #else 7747 # error "tsc delta method not selected" 7748 #endif 7749 7750 /* Tell master we're done collecting our data. */ 7462 7751 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_WORKER_DONE); 7752 7753 /* Wait for the master to process the data. */ 7463 7754 while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) == GIP_TSC_DELTA_SYNC_WORKER_DONE) 7464 7755 ASMNopPause(); … … 7466 7757 } 7467 7758 7759 /* 7760 * We must reset the worker TSC sample value in case it gets picked as a 7761 * GIP master later on (it's trashed above, naturally). 7762 */ 7763 if (idCpu == idMaster) 7764 ASMAtomicWriteU64(&pGipCpuWorker->u64TSCSample, GIP_TSC_DELTA_RSVD); 7765 7766 /* 7767 * Success? If so, stop trying. 7768 */ 7468 7769 if (pGipCpuWorker->i64TSCDelta != INT64_MAX) 7469 7770 { 7470 7771 if (idCpu == idMaster) 7471 7772 { 7472 RTCpuSetDel (&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet);7473 RTCpuSetAdd (&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet);7773 RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet); 7774 RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet); 7474 7775 } 7475 7776 else 7476 7777 { 7477 RTCpuSetDel (&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);7478 RTCpuSetAdd (&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);7778 RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet); 7779 RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet); 7479 7780 } 7480 7781 break; … … 7521 7822 static int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker) 7522 7823 { 7523 int rc; 7524 PSUPGLOBALINFOPAGE pGip; 7525 PSUPGIPCPU pGipCpuWorker; 7526 RTCPUID idMaster; 7527 7528 AssertReturn(pDevExt, VERR_INVALID_PARAMETER); 7529 AssertReturn(pDevExt->pGip, VERR_INVALID_PARAMETER); 7530 7531 pGip = pDevExt->pGip; 7532 idMaster = pDevExt->idGipMaster; 7533 pGipCpuWorker = &pGip->aCPUs[idxWorker]; 7534 7824 int rc; 7825 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 7826 RTCPUID idMaster = pDevExt->idGipMaster; 7827 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[idxWorker]; 7828 PSUPGIPCPU pGipCpuMaster; 7829 uint32_t iGipCpuMaster; 7830 7831 /* Validate input a bit. */ 7832 AssertReturn(pGip, VERR_INVALID_PARAMETER); 7535 7833 Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED); 7536 7834 … … 7545 7843 } 7546 7844 7547 /* Set the master TSC as the initiator. */ 7845 /* 7846 * If the CPU has hyper-threading and the APIC IDs of the master and worker are adjacent, 7847 * try pick a different master. (This fudge only works with multi core systems.) 7848 * ASSUMES related threads have adjacent APIC IDs. ASSUMES two threads per core. 7849 */ 7850 iGipCpuMaster = supdrvGipFindCpuIndexForCpuId(pGip, idMaster); 7851 AssertReturn(iGipCpuMaster < pGip->cCpus, VERR_INVALID_CPU_ID); 7852 pGipCpuMaster = &pGip->aCPUs[iGipCpuMaster]; 7853 if ( (pGipCpuMaster->idApic & ~1) == (pGipCpuWorker->idApic & ~1) 7854 && ASMHasCpuId() 7855 && ASMIsValidStdRange(ASMCpuId_EAX(0)) 7856 && (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_HTT) 7857 && pGip->cOnlineCpus > 2) 7858 { 7859 uint32_t i; 7860 for (i = 0; i < pGip->cCpus; i++) 7861 if ( i != iGipCpuMaster 7862 && i != idxWorker 7863 && pGip->aCPUs[i].enmState == SUPGIPCPUSTATE_ONLINE 7864 && pGip->aCPUs[i].i64TSCDelta != INT64_MAX 7865 && pGip->aCPUs[i].idCpu != NIL_RTCPUID 7866 && pGip->aCPUs[i].idCpu != idMaster /* paranoia starts here... */ 7867 && pGip->aCPUs[i].idCpu != pGipCpuWorker->idCpu 7868 && pGip->aCPUs[i].idApic != pGipCpuWorker->idApic 7869 && pGip->aCPUs[i].idApic != pGipCpuMaster->idApic) 7870 { 7871 iGipCpuMaster = i; 7872 pGipCpuMaster = &pGip->aCPUs[i]; 7873 idMaster = pGipCpuMaster->idCpu; 7874 break; 7875 } 7876 } 7877 7878 /* 7879 * Set the master TSC as the initiator. This serializes delta measurments. 7880 */ 7548 7881 while (!ASMAtomicCmpXchgU32(&pDevExt->idTscDeltaInitiator, idMaster, NIL_RTCPUID)) 7549 7882 { … … 7552 7885 * being executed and that can take a good while to be done. 7553 7886 */ 7554 RTThreadSleep(1); 7555 } 7556 7557 if (RTCpuSetIsMember(&pGip->OnlineCpuSet, pGipCpuWorker->idCpu)) 7558 { 7559 /* Fire TSC-read workers on all CPUs but only synchronize between master and one worker to ease memory contention. */ 7560 ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX); 7561 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP); 7562 rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, pDevExt, pGipCpuWorker); 7887 RTThreadSleep(1); /** @todo r=bird: This won't work with preemption disabled, not on real OSes anyway. */ 7888 } 7889 7890 if (RTCpuSetIsMemberByIndex(&pGip->OnlineCpuSet, pGipCpuWorker->iCpuSet)) 7891 { 7892 /* 7893 * Initialize data package for the RTMpOnAll callback. 7894 */ 7895 SUPDRVGIPTSCDELTARGS Args; 7896 RT_ZERO(Args); 7897 Args.pWorker = pGipCpuWorker; 7898 Args.pMaster = pGipCpuMaster; 7899 Args.idMaster = idMaster; 7900 Args.pDevExt = pDevExt; 7901 #ifdef GIP_TSC_DELTA_METHOD_1 7902 rc = VINF_SUCCESS; 7903 #elif defined(GIP_TSC_DELTA_METHOD_2) 7904 rc = supdrvTscDeltaMethod2Init(&Args); 7905 #else 7906 # error "huh?" 7907 #endif 7563 7908 if (RT_SUCCESS(rc)) 7564 7909 { 7565 if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX)) 7910 /* 7911 * Fire TSC-read workers on all CPUs but only synchronize between master 7912 * and one worker to ease memory contention. 7913 */ 7914 ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX); 7915 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP); 7916 7917 rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, &Args, NULL); 7918 if (RT_SUCCESS(rc)) 7566 7919 { 7567 /* 7568 * Work the TSC delta applicability rating. It starts 7569 * optimistic in supdrvGipInit, we downgrade it here. 7570 */ 7571 SUPGIPUSETSCDELTA enmRating; 7572 if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO 7573 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO) 7574 enmRating = SUPGIPUSETSCDELTA_NOT_ZERO; 7575 else if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 7576 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO) 7577 enmRating = SUPGIPUSETSCDELTA_ROUGHLY_ZERO; 7920 if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX)) 7921 { 7922 /* 7923 * Work the TSC delta applicability rating. It starts 7924 * optimistic in supdrvGipInit, we downgrade it here. 7925 */ 7926 SUPGIPUSETSCDELTA enmRating; 7927 if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO 7928 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO) 7929 enmRating = SUPGIPUSETSCDELTA_NOT_ZERO; 7930 else if ( pGipCpuWorker->i64TSCDelta > GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 7931 || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO) 7932 enmRating = SUPGIPUSETSCDELTA_ROUGHLY_ZERO; 7933 else 7934 enmRating = SUPGIPUSETSCDELTA_PRACTICALLY_ZERO; 7935 if (pGip->enmUseTscDelta < enmRating) 7936 { 7937 AssertCompile(sizeof(pGip->enmUseTscDelta) == sizeof(uint32_t)); 7938 ASMAtomicWriteU32((uint32_t volatile *)&pGip->enmUseTscDelta, enmRating); 7939 } 7940 } 7578 7941 else 7579 enmRating = SUPGIPUSETSCDELTA_PRACTICALLY_ZERO; 7580 if (pGip->enmUseTscDelta < enmRating) 7581 { 7582 AssertCompile(sizeof(pGip->enmUseTscDelta) == sizeof(uint32_t)); 7583 ASMAtomicWriteU32((uint32_t volatile *)&pGip->enmUseTscDelta, enmRating); 7584 } 7942 rc = VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED; 7585 7943 } 7586 else 7587 rc = VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED; 7588 } 7944 } 7945 7946 #ifdef GIP_TSC_DELTA_METHOD_2 7947 supdrvTscDeltaMethod2Term(&Args); 7948 #endif 7589 7949 } 7590 7950 else … … 7612 7972 PSUPGIPCPU pGipCpuMaster; 7613 7973 unsigned iCpu; 7974 unsigned iOddEven; 7614 7975 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 7615 7976 uint32_t idxMaster = UINT32_MAX; … … 7634 7995 { 7635 7996 PSUPGIPCPU pGipCpu = &pGip->aCPUs[idxCpu]; 7636 if (RTCpuSetIsMember (&pGip->OnlineCpuSet, pGipCpu->idCpu))7997 if (RTCpuSetIsMemberByIndex(&pGip->OnlineCpuSet, pGipCpu->iCpuSet)) 7637 7998 { 7638 7999 idxMaster = idxCpu; … … 7656 8017 7657 8018 /* 7658 * Loop thru the GIP CPU array and get deltas for each CPU (except the master). 7659 */ 7660 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 7661 { 7662 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu]; 7663 if ( iCpu != idxMaster 7664 && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet)) 7665 { 7666 rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu); 7667 if (RT_FAILURE(rc)) 8019 * Loop thru the GIP CPU array and get deltas for each CPU (except the 8020 * master). We do the CPUs with the even numbered APIC IDs first so that 8021 * we've got alternative master CPUs to pick from on hyper-threaded systems. 8022 */ 8023 for (iOddEven = 0; iOddEven < 2; iOddEven++) 8024 { 8025 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 8026 { 8027 PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu]; 8028 if ( iCpu != idxMaster 8029 && (iOddEven > 0 || (pGipCpuWorker->idApic & 1) == 0) 8030 && RTCpuSetIsMemberByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet)) 7668 8031 { 7669 SUPR0Printf("supdrvMeasureTscDeltaOne failed. rc=%d CPU[%u].idCpu=%u Master[%u].idCpu=%u\n", rc, iCpu, 7670 pGipCpuWorker->idCpu, idxMaster, pDevExt->idGipMaster, pGipCpuMaster->idCpu); 7671 break; 7672 } 7673 7674 if (ASMAtomicReadU32(&pDevExt->cMpOnOffEvents) != cMpOnOffEvents) 7675 { 7676 SUPR0Printf("One or more CPUs transitioned between online & offline states. I'm confused, retry...\n"); 7677 rc = VERR_TRY_AGAIN; 7678 break; 8032 rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu); 8033 if (RT_FAILURE(rc)) 8034 { 8035 SUPR0Printf("supdrvMeasureTscDeltaOne failed. rc=%d CPU[%u].idCpu=%u Master[%u].idCpu=%u\n", rc, iCpu, 8036 pGipCpuWorker->idCpu, idxMaster, pDevExt->idGipMaster, pGipCpuMaster->idCpu); 8037 break; 8038 } 8039 8040 if (ASMAtomicReadU32(&pDevExt->cMpOnOffEvents) != cMpOnOffEvents) 8041 { 8042 SUPR0Printf("One or more CPUs transitioned between online & offline states. I'm confused, retry...\n"); 8043 rc = VERR_TRY_AGAIN; 8044 break; 8045 } 7679 8046 } 7680 8047 } … … 8381 8748 * thread. Check if anyone uses/needs fAsync before implementing this. */ 8382 8749 RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock); 8383 RTCpuSetAdd (&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);8750 RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet); 8384 8751 if ( pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening 8385 8752 || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
Note:
See TracChangeset
for help on using the changeset viewer.