Changeset 54352 in vbox
- Timestamp:
- Feb 22, 2015 1:32:45 AM (10 years ago)
- Location:
- trunk
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/sup.h
r54339 r54352 496 496 * Gets the TSC frequency of the calling CPU. 497 497 * 498 * @returns TSC frequency, UINT64_MAX on failure .498 * @returns TSC frequency, UINT64_MAX on failure (asserted). 499 499 * @param pGip The GIP pointer. 500 500 */ … … 502 502 { 503 503 if (RT_LIKELY( pGip 504 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC 505 && pGip->u64CpuHz)) 504 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) 506 505 { 507 506 switch (pGip->u32Mode) … … 523 522 * Gets the TSC frequency of the specified CPU. 524 523 * 525 * @returns TSC frequency, UINT64_MAX on failure .524 * @returns TSC frequency, UINT64_MAX on failure (asserted). 526 525 * @param pGip The GIP pointer. 527 526 * @param iCpuSet The CPU set index of the CPU in question. … … 530 529 { 531 530 if (RT_LIKELY( pGip 532 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC 533 && pGip->u64CpuHz)) 531 && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) 534 532 { 535 533 switch (pGip->u32Mode) … … 554 552 555 553 554 #if 0 /* Not used anywhere. Unsure where this would be useful. */ 556 555 /** 557 556 * Checks if the provided TSC frequency is close enough to the computed TSC … … 580 579 return false; 581 580 } 581 #endif 582 582 583 583 #if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) -
trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp
r54345 r54352 89 89 /** The number of loops until we keep computing the minumum read time. */ 90 90 #define GIP_TSC_DELTA_READ_TIME_LOOPS 24 91 92 /** @name Master / worker synchronization values. 93 * @{ */ 91 94 /** Stop measurement of TSC delta. */ 92 #define GIP_TSC_DELTA_SYNC_STOP 095 #define GIP_TSC_DELTA_SYNC_STOP UINT32_C(0) 93 96 /** Start measurement of TSC delta. */ 94 #define GIP_TSC_DELTA_SYNC_START 197 #define GIP_TSC_DELTA_SYNC_START UINT32_C(1) 95 98 /** Worker thread is ready for reading the TSC. */ 96 #define GIP_TSC_DELTA_SYNC_WORKER_READY 299 #define GIP_TSC_DELTA_SYNC_WORKER_READY UINT32_C(2) 97 100 /** Worker thread is done updating TSC delta info. */ 98 #define GIP_TSC_DELTA_SYNC_WORKER_DONE 3101 #define GIP_TSC_DELTA_SYNC_WORKER_DONE UINT32_C(3) 99 102 /** When IPRT is isn't concurrent safe: Master is ready and will wait for worker 100 103 * with a timeout. */ 101 #define GIP_TSC_DELTA_SYNC_PRESTART_MASTER 4 104 #define GIP_TSC_DELTA_SYNC_PRESTART_MASTER UINT32_C(4) 105 /** @} */ 106 102 107 /** When IPRT is isn't concurrent safe: Worker is ready after waiting for 103 108 * master with a timeout. */ 104 109 #define GIP_TSC_DELTA_SYNC_PRESTART_WORKER 5 105 110 /** The TSC-refinement interval in seconds. */ 106 #define GIP_TSC_REFINE_ INTERVAL5111 #define GIP_TSC_REFINE_PREIOD_IN_SECS 5 107 112 /** The TSC-delta threshold for the SUPGIPUSETSCDELTA_PRACTICALLY_ZERO rating */ 108 113 #define GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO 32 … … 136 141 static DECLCALLBACK(void) supdrvGipSyncAndInvariantTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 137 142 static DECLCALLBACK(void) supdrvGipAsyncTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick); 138 static void supdrvGipInitCpu(PSUP DRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS);143 static void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz); 139 144 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 140 145 static int supdrvTscDeltaThreadInit(PSUPDRVDEVEXT pDevExt); … … 763 768 */ 764 769 770 static void supdrvGipInitSetCpuFreq(PSUPGLOBALINFOPAGE pGip, uint64_t nsElapsed, uint64_t cElapsedTscTicks) 771 { 772 /* 773 * Calculate the frequency. 774 */ 775 uint64_t uCpuHz; 776 if ( cElapsedTscTicks < UINT64_MAX / RT_NS_1SEC 777 && nsElapsed < UINT32_MAX) 778 uCpuHz = ASMMultU64ByU32DivByU32(cElapsedTscTicks, RT_NS_1SEC, (uint32_t)nsElapsed); 779 else 780 { 781 RTUINT128U CpuHz, Tmp, Divisor; 782 CpuHz.s.Lo = CpuHz.s.Hi = 0; 783 RTUInt128MulU64ByU64(&Tmp, cElapsedTscTicks, RT_NS_1SEC_64); 784 RTUInt128Div(&CpuHz, &Tmp, RTUInt128AssignU64(&Divisor, nsElapsed)); 785 uCpuHz = CpuHz.s.Lo; 786 } 787 788 /* 789 * Update the GIP. 790 */ 791 ASMAtomicWriteU64(&pGip->u64CpuHz, uCpuHz); 792 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 793 ASMAtomicWriteU64(&pGip->aCPUs[0].u64CpuHz, uCpuHz); 794 } 795 765 796 766 797 /** 767 798 * Timer callback function for TSC frequency refinement in invariant GIP mode. 799 * 800 * This is started during driver init and fires once 801 * GIP_TSC_REFINE_PREIOD_IN_SECS seconds later. 768 802 * 769 803 * @param pTimer The timer. … … 771 805 * @param iTick The timer tick. 772 806 */ 773 static DECLCALLBACK(void) supdrvInitAsyncRefineTscTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick) 774 { 775 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser; 776 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 777 bool fDeltaApplied = false; 778 uint8_t idApic; 779 uint64_t u64DeltaNanoTS; 780 uint64_t u64DeltaTsc; 781 uint64_t u64NanoTS; 782 uint64_t u64Tsc; 783 RTCCUINTREG uFlags; 807 static DECLCALLBACK(void) supdrvInitRefineInvariantTscTimer(PRTTIMER pTimer, void *pvUser, uint64_t iTick) 808 { 809 PSUPDRVDEVEXT pDevExt = (PSUPDRVDEVEXT)pvUser; 810 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 811 RTCPUID idCpu; 812 uint64_t cNsElapsed; 813 uint64_t cTscTicksElapsed; 814 uint64_t nsNow; 815 uint64_t uTsc; 816 RTCCUINTREG uFlags; 784 817 785 818 /* Paranoia. */ 786 Assert(pGip); 787 Assert(pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC); 788 789 #if !defined(RT_OS_OS2) /* PORTME: Disable if timers are called from clock interrupt handler or with interrupts disabled. */ 819 AssertReturnVoid(pGip); 820 AssertReturnVoid(pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC); 821 822 /* 823 * Try get close to the next clock tick as usual. 824 * 825 * PORTME: If timers are called from the clock interrupt handler, or 826 * an interrupt handler with higher priority than the clock 827 * interrupt, or spinning for ages in timer handlers is frowned 828 * upon, this look must be disabled! 829 * 830 * Darwin, FreeBSD, Linux, Solaris, Windows 8.1+: 831 * High RTTimeSystemNanoTS resolution should prevent any noticable 832 * spinning her. 833 * 834 * Windows 8.0 and earlier: 835 * We're running in a DPC here, so we may trigger the DPC watchdog? 836 * 837 * OS/2: 838 * Timer callbacks are done in the clock interrupt, so skip it. 839 */ 840 #if !defined(RT_OS_OS2) 841 nsNow = RTTimeSystemNanoTS(); 842 while (RTTimeSystemNanoTS() == nsNow) 843 ASMNopPause(); 844 #endif 845 846 uFlags = ASMIntDisableFlags(); 847 uTsc = ASMReadTSC(); 848 nsNow = RTTimeSystemNanoTS(); 849 idCpu = RTMpCpuId(); 850 ASMSetFlags(uFlags); 851 852 cNsElapsed = nsNow - pDevExt->nsStartInvarTscRefine; 853 cTscTicksElapsed = uTsc - pDevExt->uTscStartInvarTscRefine; 854 855 /* 856 * If the above measurement was taken on a different CPU than the one we 857 * started the rprocess on, cTscTicksElapsed will need to be adjusted with 858 * the TSC deltas of both the CPUs. 859 * 860 * We ASSUME that the delta calculation process takes less time than the 861 * TSC frequency refinement timer. If it doesn't, we'll complain and 862 * drop the frequency refinement. 863 * 864 * Note! We cannot entirely trust enmUseTscDelta here because it's 865 * downgraded after each delta calculation. 866 */ 867 if ( idCpu != pDevExt->idCpuInvarTscRefine 868 && pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 869 { 870 uint32_t iStartCpuSet = RTMpCpuIdToSetIndex(pDevExt->idCpuInvarTscRefine); 871 uint32_t iStopCpuSet = RTMpCpuIdToSetIndex(idCpu); 872 uint16_t iStartGipCpu = iStartCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx) 873 ? pGip->aiCpuFromCpuSetIdx[iStartCpuSet] : UINT16_MAX; 874 uint16_t iStopGipCpu = iStopCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx) 875 ? pGip->aiCpuFromCpuSetIdx[iStopCpuSet] : UINT16_MAX; 876 int64_t iStartTscDelta = iStartGipCpu < pGip->cCpus ? pGip->aCPUs[iStartGipCpu].i64TSCDelta : INT64_MAX; 877 int64_t iStopTscDelta = iStopGipCpu < pGip->cCpus ? pGip->aCPUs[iStopGipCpu].i64TSCDelta : INT64_MAX; 878 if (RT_LIKELY(iStartTscDelta != INT64_MAX && iStopGipCpu != INT64_MAX)) 879 { 880 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 881 { 882 /* cTscTicksElapsed = (uTsc - iStopTscDelta) - (pDevExt->uTscStartInvarTscRefine - iStartTscDelta); */ 883 cTscTicksElapsed += iStartTscDelta - iStopTscDelta; 884 } 885 } 886 /* 887 * Allow 5 times the refinement period to elapse before we give up on the TSC delta 888 * calculations. 889 */ 890 else if (cNsElapsed <= GIP_TSC_REFINE_PREIOD_IN_SECS * 5 * RT_NS_1SEC_64) 891 { 892 int rc = RTTimerStart(pTimer, RT_NS_1SEC); 893 AssertRC(rc); 894 return; 895 } 896 else 897 { 898 SUPR0Printf("vboxdrv: Failed to refine invariant TSC frequency because deltas are unavailable after %u (%u) seconds\n", 899 (uint32_t)(cNsElapsed / RT_NS_1SEC), GIP_TSC_REFINE_PREIOD_IN_SECS); 900 SUPR0Printf("vboxdrv: start: %u, %u, %#llx stop: %u, %u, %#llx\n", 901 iStartCpuSet, iStartGipCpu, iStartTscDelta, iStopCpuSet, iStopGipCpu, iStopTscDelta); 902 return; 903 } 904 } 905 906 /* 907 * Calculate and update the CPU frequency variables in GIP. 908 * 909 * If there is a GIP user already and we've already refined the frequency 910 * a couple of times, don't update it as we want a stable frequency value 911 * for all VMs. 912 */ 913 if ( pDevExt->cGipUsers == 0 914 || cNsElapsed < RT_NS_1SEC * 2) 915 { 916 supdrvGipInitSetCpuFreq(pGip, cNsElapsed, cTscTicksElapsed); 917 918 /* 919 * Reschedule the timer if we haven't yet reached the defined refinement period. 920 */ 921 if (cNsElapsed < GIP_TSC_REFINE_PREIOD_IN_SECS * RT_NS_1SEC_64) 922 { 923 int rc = RTTimerStart(pTimer, RT_NS_1SEC); 924 AssertRC(rc); 925 } 926 } 927 } 928 929 930 /** 931 * Start the TSC-frequency refinment timer for the invariant TSC GIP mode. 932 * 933 * We cannot use this in the synchronous and asynchronous tsc GIP modes because 934 * the CPU may change the TSC frequence between now and when the timer fires 935 * (supdrvInitAsyncRefineTscTimer). 936 * 937 * @param pDevExt Pointer to the device instance data. 938 * @param pGip Pointer to the GIP. 939 * 940 * @remarks We cannot use this 941 */ 942 static void supdrvGipInitStartTimerForRefiningInvariantTscFreq(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip) 943 { 944 uint64_t u64NanoTS; 945 RTCCUINTREG uFlags; 946 int rc; 947 948 /* 949 * Record the TSC and NanoTS as the starting anchor point for refinement 950 * of the TSC. We try get as close to a clock tick as possible on systems 951 * which does not provide high resolution time. 952 */ 790 953 u64NanoTS = RTTimeSystemNanoTS(); 791 954 while (RTTimeSystemNanoTS() == u64NanoTS) 792 955 ASMNopPause(); 793 #endif 794 uFlags 795 idApic = ASMGetApicId();796 u64Tsc = ASMReadTSC();797 u64NanoTS = RTTimeSystemNanoTS();956 957 uFlags = ASMIntDisableFlags(); 958 pDevExt->uTscStartInvarTscRefine = ASMReadTSC(); 959 pDevExt->nsStartInvarTscRefine = RTTimeSystemNanoTS(); 960 pDevExt->idCpuInvarTscRefine = RTMpCpuId(); 798 961 ASMSetFlags(uFlags); 799 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 800 supdrvTscDeltaApply(pGip, &u64Tsc, idApic, &fDeltaApplied); 801 u64DeltaNanoTS = u64NanoTS - pDevExt->u64NanoTSAnchor; 802 u64DeltaTsc = u64Tsc - pDevExt->u64TscAnchor; 803 804 if (RT_UNLIKELY( pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO 805 && !fDeltaApplied)) 806 { 807 Log(("vboxdrv: failed to refine TSC frequency as TSC-deltas unavailable after %d seconds!\n", 808 GIP_TSC_REFINE_INTERVAL)); 809 return; 810 } 811 812 /* Calculate the TSC frequency. */ 813 if ( u64DeltaTsc < UINT64_MAX / RT_NS_1SEC 814 && u64DeltaNanoTS < UINT32_MAX) 815 pGip->u64CpuHz = ASMMultU64ByU32DivByU32(u64DeltaTsc, RT_NS_1SEC, (uint32_t)u64DeltaNanoTS); 816 else 817 { 818 RTUINT128U CpuHz, Tmp, Divisor; 819 CpuHz.s.Lo = CpuHz.s.Hi = 0; 820 RTUInt128MulU64ByU64(&Tmp, u64DeltaTsc, RT_NS_1SEC_64); 821 RTUInt128Div(&CpuHz, &Tmp, RTUInt128AssignU64(&Divisor, u64DeltaNanoTS)); 822 pGip->u64CpuHz = CpuHz.s.Lo; 823 } 824 825 /* Update rest of GIP. */ 826 Assert(pGip->u32Mode != SUPGIPMODE_ASYNC_TSC); /* See SUPGetCpuHzFromGIP().*/ 827 pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz; 828 } 829 830 831 /** 832 * Starts the TSC-frequency refinement phase asynchronously. 833 * 834 * @param pDevExt Pointer to the device instance data. 835 */ 836 static void supdrvGipInitAsyncRefineTscFreq(PSUPDRVDEVEXT pDevExt) 837 { 838 uint64_t u64NanoTS; 839 RTCCUINTREG uFlags; 840 uint8_t idApic; 841 int rc; 842 PSUPGLOBALINFOPAGE pGip; 843 844 /* Validate. */ 845 Assert(pDevExt); 846 Assert(pDevExt->pGip); 847 pGip = pDevExt->pGip; 848 849 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 850 /* 851 * If the TSC-delta thread is created, wait until it's done calculating 852 * the TSC-deltas on the relevant online CPUs before we start the TSC refinement. 853 */ 854 if ( pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED 855 && ASMAtomicReadS32(&pDevExt->rcTscDelta) == VERR_NOT_AVAILABLE) 856 { 857 rc = supdrvTscDeltaThreadWaitForOnlineCpus(pDevExt); 858 if (rc == VERR_TIMEOUT) 859 { 860 SUPR0Printf("vboxdrv: Skipping refinement of TSC frequency as TSC-delta measurement timed out!\n"); 962 963 /* 964 * Create a timer that runs on the same CPU so we won't have a depencency 965 * on the TSC-delta and can run in parallel to it. On systems that does not 966 * implement CPU specific timers we'll apply deltas in the timer callback, 967 * just like we do for CPUs going offline. 968 * 969 * The longer the refinement interval the better the accuracy, at least in 970 * theory. If it's too long though, ring-3 may already be starting its 971 * first VMs before we're done. On most systems we will be loading the 972 * support driver during boot and VMs won't be started for a while yet, 973 * it is really only a problem during development (especiall with 974 * on-demand driver starting on windows). 975 * 976 * To avoid wasting time doing a long supdrvGipInitMeasureTscFreq call 977 * to calculate the frequencey during driver loading, the timer is set 978 * to fire after 200 ms the first time. It will then reschedule itself 979 * to fire every second until GIP_TSC_REFINE_PREIOD_IN_SECS has been 980 * reached or it notices that there is a user land client with GIP 981 * mapped (we want a stable frequency for all VMs). 982 */ 983 rc = RTTimerCreateEx(&pDevExt->pInvarTscRefineTimer, 0 /* one-shot */, 984 RTTIMER_FLAGS_CPU(RTMpCpuIdToSetIndex(pDevExt->idCpuInvarTscRefine)), 985 supdrvInitRefineInvariantTscTimer, pDevExt); 986 if (RT_SUCCESS(rc)) 987 { 988 rc = RTTimerStart(pDevExt->pInvarTscRefineTimer, 2*RT_NS_100MS); 989 if (RT_SUCCESS(rc)) 861 990 return; 862 } 863 } 864 #endif 865 866 /* 867 * Record the TSC and NanoTS as the starting anchor point for refinement of the 868 * TSC. We deliberately avoid using SUPReadTSC() here as we want to keep the 869 * reading of the TSC and the NanoTS as close as possible. 870 */ 871 u64NanoTS = RTTimeSystemNanoTS(); 872 while (RTTimeSystemNanoTS() == u64NanoTS) 873 ASMNopPause(); 874 uFlags = ASMIntDisableFlags(); 875 idApic = ASMGetApicId(); 876 pDevExt->u64TscAnchor = ASMReadTSC(); 877 pDevExt->u64NanoTSAnchor = RTTimeSystemNanoTS(); 991 RTTimerDestroy(pDevExt->pInvarTscRefineTimer); 992 } 993 994 if (rc == VERR_CPU_OFFLINE || rc == VERR_NOT_SUPPORTED) 995 { 996 rc = RTTimerCreateEx(&pDevExt->pInvarTscRefineTimer, 0 /* one-shot */, RTTIMER_FLAGS_CPU_ANY, 997 supdrvInitRefineInvariantTscTimer, pDevExt); 998 if (RT_SUCCESS(rc)) 999 { 1000 rc = RTTimerStart(pDevExt->pInvarTscRefineTimer, 2*RT_NS_100MS); 1001 if (RT_SUCCESS(rc)) 1002 return; 1003 RTTimerDestroy(pDevExt->pInvarTscRefineTimer); 1004 } 1005 } 1006 1007 pDevExt->pInvarTscRefineTimer = NULL; 1008 OSDBGPRINT(("vboxdrv: Failed to create or start TSC frequency refinement timer: rc=%Rrc\n", rc)); 1009 } 1010 1011 1012 /** 1013 * @callback_method_impl{PFNRTMPWORKER, 1014 * RTMpOnSpecific callback for reading TSC and time on the CPU we started 1015 * the measurements on.} 1016 */ 1017 DECLCALLBACK(void) supdrvGipInitReadTscAndNanoTsOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2) 1018 { 1019 RTCCUINTREG uFlags = ASMIntDisableFlags(); 1020 uint64_t *puTscStop = (uint64_t *)pvUser1; 1021 uint64_t *pnsStop = (uint64_t *)pvUser2; 1022 1023 *puTscStop = ASMReadTSC(); 1024 *pnsStop = RTTimeSystemNanoTS(); 1025 878 1026 ASMSetFlags(uFlags); 879 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO)880 supdrvTscDeltaApply(pGip, &pDevExt->u64TscAnchor, idApic, NULL /* pfDeltaApplied */);881 882 rc = RTTimerCreateEx(&pDevExt->pTscRefineTimer, 0 /* one-shot */, RTTIMER_FLAGS_CPU_ANY,883 supdrvInitAsyncRefineTscTimer, pDevExt);884 if (RT_SUCCESS(rc))885 {886 /*887 * Refine the TSC frequency measurement over a long interval. Ideally, we want to keep the888 * interval as small as possible while gaining the most consistent and accurate frequency889 * (compared to what the host OS might have measured).890 *891 * In theory, we gain more accuracy with longer intervals, but we want VMs to startup with the892 * same TSC frequency whenever possible so we need to keep the interval short.893 */894 rc = RTTimerStart(pDevExt->pTscRefineTimer, GIP_TSC_REFINE_INTERVAL * RT_NS_1SEC_64);895 AssertRC(rc);896 }897 else898 OSDBGPRINT(("RTTimerCreateEx failed to create one-shot timer. rc=%Rrc\n", rc));899 1027 } 900 1028 … … 902 1030 /** 903 1031 * Measures the TSC frequency of the system. 904 *905 * Uses a busy-wait method for the async. case as it is intended to help push906 * the CPU frequency up, while for the invariant cases using a sleeping method.907 1032 * 908 1033 * The TSC frequency can vary on systems which are not reported as invariant. … … 911 1036 * 912 1037 * @returns VBox status code. 913 * @param pDevExt Pointer to the device instance. 914 * 915 * @remarks Must be called only -after- measuring the TSC deltas. 916 */ 917 static int supdrvGipInitMeasureTscFreq(PSUPDRVDEVEXT pDevExt) 918 { 919 int cTriesLeft = 4; 920 PSUPGLOBALINFOPAGE pGip = pDevExt->pGip; 921 922 /* Assert order. */ 923 AssertReturn(pGip, VERR_INVALID_PARAMETER); 924 AssertReturn(pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC, VERR_WRONG_ORDER); 925 1038 * @param pDevExt Pointer to the device instance. 1039 * @param pGip Pointer to the GIP. 1040 * @param fRough Set if we're doing the rough calculation that the 1041 * TSC measuring code needs, where accuracy isn't all 1042 * that important (too high is better than to low). 1043 * When clear we try for best accuracy that we can 1044 * achieve in reasonably short time. 1045 */ 1046 static int supdrvGipInitMeasureTscFreq(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, bool fRough) 1047 { 1048 uint32_t nsTimerIncr = RTTimerGetSystemGranularity(); 1049 int cTriesLeft = fRough ? 4 : 2; 926 1050 while (cTriesLeft-- > 0) 927 1051 { 928 1052 RTCCUINTREG uFlags; 929 uint64_t u64NanoTsBefore;930 uint64_t u64NanoTsAfter;931 uint64_t u 64TscBefore;932 uint64_t u 64TscAfter;933 uint8_t idApicBefore;934 uint8_t idApicAfter;1053 uint64_t nsStart; 1054 uint64_t nsStop; 1055 uint64_t uTscStart; 1056 uint64_t uTscStop; 1057 RTCPUID idCpuStart; 1058 RTCPUID idCpuStop; 935 1059 936 1060 /* 937 * Synchronize with the host OS clock tick before reading the TSC.938 * Especially important on older Windows version where the granularity is terrible.1061 * Synchronize with the host OS clock tick on systems without high 1062 * resolution time API (older Windows version for example). 939 1063 */ 940 u64NanoTsBefore= RTTimeSystemNanoTS();941 while (RTTimeSystemNanoTS() == u64NanoTsBefore)1064 nsStart = RTTimeSystemNanoTS(); 1065 while (RTTimeSystemNanoTS() == nsStart) 942 1066 ASMNopPause(); 943 1067 944 uFlags = ASMIntDisableFlags(); 945 idApicBefore = ASMGetApicId(); 946 u64TscBefore = ASMReadTSC(); 947 u64NanoTsBefore = RTTimeSystemNanoTS(); 1068 /* 1069 * Read the TSC and current time, noting which CPU we're on. 1070 */ 1071 uFlags = ASMIntDisableFlags(); 1072 uTscStart = ASMReadTSC(); 1073 nsStart = RTTimeSystemNanoTS(); 1074 idCpuStart = RTMpCpuId(); 948 1075 ASMSetFlags(uFlags); 949 1076 1077 /* 1078 * Delay for a while. 1079 */ 950 1080 if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 951 1081 { … … 954 1084 * Shorter interval produces more variance in the frequency (esp. Windows). 955 1085 */ 956 RTThreadSleep(200); 957 u64NanoTsAfter = RTTimeSystemNanoTS(); 958 while (RTTimeSystemNanoTS() == u64NanoTsAfter) 1086 uint64_t msElapsed = 0; 1087 uint64_t msDelay = ( ((fRough ? 16 : 200) * RT_NS_1MS + nsTimerIncr - 1) / nsTimerIncr * nsTimerIncr - RT_NS_100US ) 1088 / RT_NS_1MS; 1089 do 1090 { 1091 RTThreadSleep((RTMSINTERVAL)(msDelay - msElapsed)); 1092 nsStop = RTTimeSystemNanoTS(); 1093 msElapsed = (nsStop - nsStart) / RT_NS_1MS; 1094 } while (msElapsed < msDelay); 1095 1096 while (RTTimeSystemNanoTS() == nsStop) 959 1097 ASMNopPause(); 960 u64NanoTsAfter = RTTimeSystemNanoTS();961 1098 } 962 1099 else 963 1100 { 964 /* Busy-wait keeping the frequency up and measure. */ 965 for (;;) 1101 /* 1102 * Busy-wait keeping the frequency up. 1103 */ 1104 do 966 1105 { 967 u64NanoTsAfter = RTTimeSystemNanoTS(); 968 if (u64NanoTsAfter < RT_NS_100MS + u64NanoTsBefore) 969 ASMNopPause(); 970 else 971 break; 1106 ASMNopPause(); 1107 nsStop = RTTimeSystemNanoTS(); 1108 } while (nsStop - nsStart < RT_NS_100MS); 1109 } 1110 1111 /* 1112 * Read the TSC and time again. 1113 */ 1114 uFlags = ASMIntDisableFlags(); 1115 uTscStop = ASMReadTSC(); 1116 nsStop = RTTimeSystemNanoTS(); 1117 idCpuStop = RTMpCpuId(); 1118 ASMSetFlags(uFlags); 1119 1120 /* 1121 * If the CPU changes things get a bit complicated and what we 1122 * can get away with depends on the GIP mode / TSC reliablity. 1123 */ 1124 if (idCpuStop != idCpuStart) 1125 { 1126 bool fDoXCall = false; 1127 1128 /* 1129 * Synchronous TSC mode: we're probably fine as it's unlikely 1130 * that we were rescheduled because of TSC throttling or power 1131 * management reasons, so just go ahead. 1132 */ 1133 if (pGip->u32Mode == SUPGIPMODE_SYNC_TSC) 1134 { 1135 /* Probably ok, maybe we should retry once?. */ 1136 Assert(pGip->enmUseTscDelta == SUPGIPUSETSCDELTA_NOT_APPLICABLE); 972 1137 } 973 } 974 975 uFlags = ASMIntDisableFlags(); 976 idApicAfter = ASMGetApicId(); 977 u64TscAfter = ASMReadTSC(); 978 ASMSetFlags(uFlags); 979 980 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 981 { 982 int rc; 983 bool fAppliedBefore; 984 bool fAppliedAfter; 985 rc = supdrvTscDeltaApply(pGip, &u64TscBefore, idApicBefore, &fAppliedBefore); AssertRCReturn(rc, rc); 986 rc = supdrvTscDeltaApply(pGip, &u64TscAfter, idApicAfter, &fAppliedAfter); AssertRCReturn(rc, rc); 987 988 if ( !fAppliedBefore 989 || !fAppliedAfter) 1138 /* 1139 * If we're just doing the rough measurement, do the cross call and 1140 * get on with things (we don't have deltas!). 1141 */ 1142 else if (fRough) 1143 fDoXCall = true; 1144 /* 1145 * Invariant TSC mode: It doesn't matter if we have delta available 1146 * for both CPUs. That is not something we can assume at this point. 1147 * 1148 * Note! We cannot necessarily trust enmUseTscDelta here because it's 1149 * downgraded after each delta calculation and the delta 1150 * calculations may not be complete yet. 1151 */ 1152 else if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 990 1153 { 991 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 1154 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 1155 { 1156 uint32_t iStartCpuSet = RTMpCpuIdToSetIndex(idCpuStart); 1157 uint32_t iStopCpuSet = RTMpCpuIdToSetIndex(idCpuStop); 1158 uint16_t iStartGipCpu = iStartCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx) 1159 ? pGip->aiCpuFromCpuSetIdx[iStartCpuSet] : UINT16_MAX; 1160 uint16_t iStopGipCpu = iStopCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx) 1161 ? pGip->aiCpuFromCpuSetIdx[iStopCpuSet] : UINT16_MAX; 1162 int64_t iStartTscDelta = iStartGipCpu < pGip->cCpus ? pGip->aCPUs[iStartGipCpu].i64TSCDelta : INT64_MAX; 1163 int64_t iStopTscDelta = iStopGipCpu < pGip->cCpus ? pGip->aCPUs[iStopGipCpu].i64TSCDelta : INT64_MAX; 1164 if (RT_LIKELY(iStartTscDelta != INT64_MAX && iStopGipCpu != INT64_MAX)) 1165 { 1166 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_PRACTICALLY_ZERO) 1167 { 1168 uTscStart -= iStartTscDelta; 1169 uTscStop -= iStopTscDelta; 1170 } 1171 } 1172 /* 1173 * Invalid CPU indexes are not caused by online/offline races, so 1174 * we have to trigger driver load failure if that happens as GIP 1175 * and IPRT assumptions are busted on this system. 1176 */ 1177 else if (iStopGipCpu >= pGip->cCpus || iStartGipCpu >= pGip->cCpus) 1178 { 1179 SUPR0Printf("vboxdrv: Unexpected CPU index in supdrvGipInitMeasureTscFreq.\n"); 1180 SUPR0Printf("vboxdrv: start: %u, %u, %#llx stop: %u, %u, %#llx\n", 1181 iStartCpuSet, iStartGipCpu, iStartTscDelta, iStopCpuSet, iStopGipCpu, iStopTscDelta); 1182 return VERR_INVALID_CPU_INDEX; 1183 } 1184 /* 1185 * No valid deltas. We retry, if we're on our last retry 1186 * we do the cross call instead just to get a result. The 1187 * frequency will be refined in a few seconds anyways. 1188 */ 1189 else if (cTriesLeft > 0) 1190 continue; 1191 else 1192 fDoXCall = true; 1193 } 1194 } 1195 /* 1196 * Asynchronous TSC mode: This is bad as the reason we usually 1197 * use this mode is to deal with variable TSC frequencies and 1198 * deltas. So, we need to get the TSC from the same CPU as 1199 * started it, we also need to keep that CPU busy. So, retry 1200 * and fall back to the cross call on the last attempt. 1201 */ 1202 else 1203 { 1204 Assert(pGip->u32Mode == SUPGIPMODE_ASYNC_TSC); 1205 if (cTriesLeft > 0) 1206 continue; 1207 fDoXCall = true; 1208 } 1209 1210 if (fDoXCall) 1211 { 992 1212 /* 993 * The TSC-delta measurements are kicked-off asynchronously as each host CPU is initialized. 994 * Therefore, if we failed to have a delta for the CPU(s) we were scheduled on (idApicBefore 995 * and idApicAfter) then wait until we have TSC-delta measurements for all online CPUs and 996 * proceed. This should be triggered just once if we're rather unlucky. 1213 * Try read the TSC and timestamp on the start CPU. 997 1214 */ 998 rc = supdrvTscDeltaThreadWaitForOnlineCpus(pDevExt); 999 if (rc == VERR_TIMEOUT) 1000 { 1001 SUPR0Printf("vboxdrv: supdrvGipInitMeasureTscFreq: timedout waiting for TSC-delta measurements.\n"); 1002 return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED; 1003 } 1004 #else 1005 SUPR0Printf("vboxdrv: supdrvGipInitMeasureTscFreq: idApicBefore=%u idApicAfter=%u cTriesLeft=%u\n", 1006 idApicBefore, idApicAfter, cTriesLeft); 1007 #endif 1008 continue; 1215 int rc = RTMpOnSpecific(idCpuStart, supdrvGipInitReadTscAndNanoTsOnCpu, &uTscStop, &nsStop); 1216 if (RT_FAILURE(rc) && (!fRough || cTriesLeft > 0)) 1217 continue; 1009 1218 } 1010 1219 } 1011 1220 1012 1221 /* 1013 * Update GIP.1222 * Calculate the TSC frequency and update it (shared with the refinement timer). 1014 1223 */ 1015 pGip->u64CpuHz = ((u64TscAfter - u64TscBefore) * RT_NS_1SEC_64) / (u64NanoTsAfter - u64NanoTsBefore); 1016 if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC) 1017 pGip->aCPUs[0].u64CpuHz = pGip->u64CpuHz; 1224 supdrvGipInitSetCpuFreq(pGip, nsStop - nsStart, uTscStop - uTscStart); 1018 1225 return VINF_SUCCESS; 1019 1226 } 1020 1227 1228 Assert(!fRough); 1021 1229 return VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED; 1022 1230 } … … 1101 1309 u64NanoTS = RTTimeSystemNanoTS() - pGip->u32UpdateIntervalNS; 1102 1310 i = supdrvGipFindOrAllocCpuIndexForCpuId(pGip, idCpu); 1103 supdrvGipInitCpu(pDevExt, pGip, &pGip->aCPUs[i], u64NanoTS); 1311 1312 supdrvGipInitCpu(pGip, &pGip->aCPUs[i], u64NanoTS, pGip->u64CpuHz); 1313 1104 1314 idApic = ASMGetApicId(); 1105 1315 ASMAtomicWriteU16(&pGip->aCPUs[i].idApic, idApic); … … 1459 1669 * Initializes per-CPU GIP information. 1460 1670 * 1461 * @param pDevExt Pointer to the device instance data.1462 1671 * @param pGip Pointer to the GIP. 1463 1672 * @param pCpu Pointer to which GIP CPU to initalize. 1464 1673 * @param u64NanoTS The current nanosecond timestamp. 1465 */ 1466 static void supdrvGipInitCpu(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS) 1467 { 1468 /* !!! Warning !!! The GIP may not be linked to the device instance data at this point! 1469 which is why we have 2 separate parameters. Don't dereference pDevExt->pGip here. */ 1674 * @param uCpuHz The CPU frequency to set, 0 if the caller doesn't know. 1675 */ 1676 static void supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS, uint64_t uCpuHz) 1677 { 1470 1678 pCpu->u32TransactionId = 2; 1471 1679 pCpu->u64NanoTS = u64NanoTS; … … 1479 1687 ASMAtomicWriteU16(&pCpu->idApic, UINT16_MAX); 1480 1688 1481 /* 1482 * We don't know the following values until we've executed updates. 1483 * So, we'll just pretend it's a 4 GHz CPU and adjust the history it on 1484 * the 2nd timer callout. 1485 */ 1486 pCpu->u64CpuHz = _4G + 1; /* tstGIP-2 depends on this. */ 1487 pCpu->u32UpdateIntervalTSC 1488 = pCpu->au32TSCHistory[0] 1689 /* 1690 * The first time we're called, we don't have a CPU frequency handy, 1691 * so pretend it's a 4 GHz CPU. On CPUs that are online, we'll get 1692 * called again and at that point we have a more plausible CPU frequency 1693 * value handy. The frequency history will also be adjusted again on 1694 * the 2nd timer callout (maybe we can skip that now?). 1695 */ 1696 if (!uCpuHz) 1697 { 1698 pCpu->u64CpuHz = _4G - 1; 1699 pCpu->u32UpdateIntervalTSC = (uint32_t)((_4G - 1) / pGip->u32UpdateHz); 1700 } 1701 else 1702 { 1703 pCpu->u64CpuHz = uCpuHz; 1704 pCpu->u32UpdateIntervalTSC = (uint32_t)(uCpuHz / pGip->u32UpdateHz); 1705 } 1706 pCpu->au32TSCHistory[0] 1489 1707 = pCpu->au32TSCHistory[1] 1490 1708 = pCpu->au32TSCHistory[2] … … 1494 1712 = pCpu->au32TSCHistory[6] 1495 1713 = pCpu->au32TSCHistory[7] 1496 = (uint32_t)(_4G / pGip->u32UpdateHz);1714 = pCpu->u32UpdateIntervalTSC; 1497 1715 } 1498 1716 … … 1551 1769 pGip->aiCpuFromCpuSetIdx[i] = UINT16_MAX; 1552 1770 for (i = 0; i < cCpus; i++) 1553 supdrvGipInitCpu(p DevExt, pGip, &pGip->aCPUs[i], u64NanoTS);1771 supdrvGipInitCpu(pGip, &pGip->aCPUs[i], u64NanoTS, 0 /*uCpuHz*/); 1554 1772 1555 1773 /* … … 1631 1849 supdrvGipInit(pDevExt, pGip, HCPhysGip, RTTimeSystemNanoTS(), RT_NS_1SEC / u32Interval /*=Hz*/, u32Interval, cCpus); 1632 1850 1851 /* 1852 * Important sanity check... 1853 */ 1633 1854 if (RT_UNLIKELY( pGip->enmUseTscDelta == SUPGIPUSETSCDELTA_ZERO_CLAIMED 1634 1855 && pGip->u32Mode == SUPGIPMODE_ASYNC_TSC … … 1640 1861 } 1641 1862 1642 RTCpuSetEmpty(&pDevExt->TscDeltaCpuSet); 1643 RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet); 1863 /* 1864 * Do the TSC frequency measurements. 1865 * 1866 * If we're in invariant TSC mode, just to a quick preliminary measurement 1867 * that the TSC-delta measurement code can use to yield cross calls. 1868 * 1869 * If we're in any of the other two modes, neither which require MP init, 1870 * notifications or deltas for the job, do the full measurement now so 1871 * that supdrvGipInitOnCpu can populate the TSC interval and history 1872 * array with more reasonable values. 1873 */ 1874 if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 1875 { 1876 rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, true /*fRough*/); /* cannot fail */ 1877 supdrvGipInitStartTimerForRefiningInvariantTscFreq(pDevExt, pGip); 1878 } 1879 else 1880 rc = supdrvGipInitMeasureTscFreq(pDevExt, pGip, false /*fRough*/); 1881 if (RT_SUCCESS(rc)) 1882 { 1883 /* 1884 * Start TSC-delta measurement thread before we start getting MP 1885 * events that will try kick it into action (includes the 1886 * RTMpOnAll/supdrvGipInitOnCpu call below). 1887 */ 1888 RTCpuSetEmpty(&pDevExt->TscDeltaCpuSet); 1889 RTCpuSetEmpty(&pDevExt->TscDeltaObtainedCpuSet); 1644 1890 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 1645 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 1646 { 1647 /* Initialize TSC-delta measurement thread before executing any Mp event callbacks. */ 1648 rc = supdrvTscDeltaThreadInit(pDevExt); 1649 } 1891 if ( pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED 1892 && pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC) 1893 rc = supdrvTscDeltaThreadInit(pDevExt); 1650 1894 #endif 1651 if (RT_SUCCESS(rc))1652 {1653 rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt);1654 1895 if (RT_SUCCESS(rc)) 1655 1896 { 1656 rc = RTMp OnAll(supdrvGipInitOnCpu, pDevExt, pGip);1897 rc = RTMpNotificationRegister(supdrvGipMpEvent, pDevExt); 1657 1898 if (RT_SUCCESS(rc)) 1658 1899 { 1659 #ifndef SUPDRV_USE_TSC_DELTA_THREAD 1660 uint16_t iCpu; 1661 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 1662 { 1663 /* 1664 * Measure the TSC deltas now that we have MP notifications. 1665 */ 1666 int cTries = 5; 1667 do 1668 { 1669 rc = supdrvMeasureInitialTscDeltas(pDevExt); 1670 if ( rc != VERR_TRY_AGAIN 1671 && rc != VERR_CPU_OFFLINE) 1672 break; 1673 } while (--cTries > 0); 1674 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 1675 Log(("supdrvTscDeltaInit: cpu[%u] delta %lld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta)); 1676 } 1677 else 1678 { 1679 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 1680 AssertMsg(!pGip->aCPUs[iCpu].i64TSCDelta, ("iCpu=%u %lld mode=%d\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta, pGip->u32Mode)); 1681 } 1682 #endif 1900 /* 1901 * Do GIP initialization on all online CPUs. Wake up the 1902 * TSC-delta thread afterwards. 1903 */ 1904 rc = RTMpOnAll(supdrvGipInitOnCpu, pDevExt, pGip); 1683 1905 if (RT_SUCCESS(rc)) 1684 1906 { 1685 rc = supdrvGipInitMeasureTscFreq(pDevExt); 1907 #ifdef SUPDRV_USE_TSC_DELTA_THREAD 1908 RTThreadUserSignal(pDevExt->hTscDeltaThread); 1909 #else 1910 uint16_t iCpu; 1911 if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED) 1912 { 1913 /* 1914 * Measure the TSC deltas now that we have MP notifications. 1915 */ 1916 int cTries = 5; 1917 do 1918 { 1919 rc = supdrvMeasureInitialTscDeltas(pDevExt); 1920 if ( rc != VERR_TRY_AGAIN 1921 && rc != VERR_CPU_OFFLINE) 1922 break; 1923 } while (--cTries > 0); 1924 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 1925 Log(("supdrvTscDeltaInit: cpu[%u] delta %lld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta)); 1926 } 1927 else 1928 { 1929 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++) 1930 AssertMsg(!pGip->aCPUs[iCpu].i64TSCDelta, ("iCpu=%u %lld mode=%d\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta, pGip->u32Mode)); 1931 } 1686 1932 if (RT_SUCCESS(rc)) 1933 #endif 1687 1934 { 1688 1935 /* … … 1712 1959 1713 1960 g_pSUPGlobalInfoPage = pGip; 1714 if (pGip->u32Mode == SUPGIPMODE_INVARIANT_TSC)1715 supdrvGipInitAsyncRefineTscFreq(pDevExt);1716 1961 return VINF_SUCCESS; 1717 1962 } … … 1720 1965 Assert(!pDevExt->pGipTimer); 1721 1966 } 1722 else1723 OSDBGPRINT(("supdrvGipCreate: supdrvGipInitMeasureTscFreq failed. rc=%Rrc\n", rc));1724 1967 } 1725 1968 else 1726 OSDBGPRINT(("supdrvGipCreate: supdrvMeasureInitialTscDeltasfailed. rc=%Rrc\n", rc));1969 OSDBGPRINT(("supdrvGipCreate: RTMpOnAll failed. rc=%Rrc\n", rc)); 1727 1970 } 1728 1971 else 1729 OSDBGPRINT(("supdrvGipCreate: RTMpOnAll failed. rc=%Rrc\n", rc));1972 OSDBGPRINT(("supdrvGipCreate: failed to register MP event notfication. rc=%Rrc\n", rc)); 1730 1973 } 1731 1974 else 1732 OSDBGPRINT(("supdrvGipCreate: failed to register MP event notfication. rc=%Rrc\n", rc));1975 OSDBGPRINT(("supdrvGipCreate: supdrvTscDeltaInit failed. rc=%Rrc\n", rc)); 1733 1976 } 1734 1977 else 1735 OSDBGPRINT(("supdrvGipCreate: supdrvTscDeltaInit failed. rc=%Rrc\n", rc)); 1736 1737 supdrvGipDestroy(pDevExt); /* Releases timer frequency increase too. */ 1978 OSDBGPRINT(("supdrvGipCreate: supdrvMeasureInitialTscDeltas failed. rc=%Rrc\n", rc)); 1979 1980 /* Releases timer frequency increase too. */ 1981 supdrvGipDestroy(pDevExt); 1738 1982 return rc; 1739 1983 } … … 1787 2031 1788 2032 /* 1789 * Destroy the TSC-refinement one-shottimer.1790 */ 1791 if (pDevExt->p TscRefineTimer)1792 { 1793 RTTimerDestroy(pDevExt->p TscRefineTimer);1794 pDevExt->p TscRefineTimer = NULL;2033 * Destroy the TSC-refinement timer. 2034 */ 2035 if (pDevExt->pInvarTscRefineTimer) 2036 { 2037 RTTimerDestroy(pDevExt->pInvarTscRefineTimer); 2038 pDevExt->pInvarTscRefineTimer = NULL; 1795 2039 } 1796 2040 … … 2246 2490 #endif 2247 2491 2492 /** For padding variables to keep them away from other cache lines. Better too 2493 * large than too small! 2494 * @remarks Current AMD64 and x86 CPUs seems to use 64 bytes. There are claims 2495 * that NetBurst had 128 byte cache lines while the 486 thru Pentium 2496 * III had 32 bytes cache lines. */ 2497 #define GIP_TSC_DELTA_CACHE_LINE_SIZE 128 2498 2248 2499 2249 2500 /** … … 2262 2513 typedef struct SUPDRVTSCDELTAMETHOD2 2263 2514 { 2264 /** Padding to make sure the iCurSeqNo is in its own cache line. 2265 * ASSUMES cacheline sizes <= 128 bytes. */ 2266 uint32_t au32CacheLinePaddingBefore[128 / sizeof(uint32_t)]; 2515 /** Padding to make sure the iCurSeqNo is in its own cache line. */ 2516 uint64_t au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 1]; 2267 2517 /** The current sequence number of this worker. */ 2268 2518 uint32_t volatile iCurSeqNo; 2269 /** Padding to make sure the iCurSeqNo is in its own cache line. 2270 * ASSUMES cacheline sizes <= 128 bytes. */ 2271 uint32_t au32CacheLinePaddingAfter[128 / sizeof(uint32_t) - 1]; 2519 /** Padding to make sure the iCurSeqNo is in its own cache line. */ 2520 uint32_t au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint32_t) - 1]; 2272 2521 /** Result table. */ 2273 2522 SUPDRVTSCDELTAMETHOD2ENTRY aResults[96]; … … 2278 2527 2279 2528 /** 2529 * The TSC delta synchronization struct, version 2. 2530 * 2531 * The syncrhonization variable is completely isolated in its own cache line 2532 * (provided our max cache line size estimate is correct). 2533 */ 2534 typedef struct SUPTSCDELTASYNC2 2535 { 2536 /** Padding to make sure the uVar1 is in its own cache line. */ 2537 uint64_t au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)]; 2538 /** The synchronization variable, holds values GIP_TSC_DELTA_SYNC_*. */ 2539 volatile uint32_t uVar1; 2540 /** Unused. */ 2541 volatile uint32_t uVar2; 2542 2543 /** Start RDTSC value. This does not need to be in its own cache line, it's 2544 * just put here to save stack space. */ 2545 uint64_t uTscStart; 2546 /** Max number of ticks we can allow to elapse in the RTMpOn callback. 2547 * This is estimated from the CPU frequency... */ 2548 uint64_t cMaxTicks; 2549 2550 /** Padding to make sure the uVar1 is in its own cache line. */ 2551 uint64_t au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 2]; 2552 } SUPTSCDELTASYNC2; 2553 AssertCompileSize(SUPTSCDELTASYNC2, GIP_TSC_DELTA_CACHE_LINE_SIZE * 2 + sizeof(uint64_t)); 2554 typedef SUPTSCDELTASYNC2 *PSUPTSCDELTASYNC2; 2555 2556 2557 /** 2280 2558 * Argument package/state passed by supdrvMeasureTscDeltaOne to the RTMpOn 2281 2559 * callback worker. … … 2283 2561 typedef struct SUPDRVGIPTSCDELTARGS 2284 2562 { 2563 /** The device extension. */ 2285 2564 PSUPDRVDEVEXT pDevExt; 2565 /** Pointer to the GIP CPU array entry for the worker. */ 2286 2566 PSUPGIPCPU pWorker; 2567 /** Pointer to the GIP CPU array entry for the master. */ 2287 2568 PSUPGIPCPU pMaster; 2288 RTCPUID idMaster; 2569 /** Pointer to the master's synchronization struct (on stack). */ 2570 PSUPTSCDELTASYNC2 pSyncMaster; 2571 /** Pointer to the worker's synchronization struct (on stack). */ 2572 PSUPTSCDELTASYNC2 pSyncWorker; 2289 2573 2290 2574 #if 0 … … 2770 3054 #endif /* GIP_TSC_DELTA_METHOD_2 */ 2771 3055 3056 /** Prestart wait. */ 3057 #define GIP_TSC_DELTA_SYNC2_PRESTART_WAIT UINT32_C(0xffe) 3058 3059 /** Start measurement of TSC delta. */ 3060 #define GIP_TSC_DELTA_SYNC2_START UINT32_C(1) 3061 /** Worker thread is ready for reading the TSC. */ 3062 #define GIP_TSC_DELTA_SYNC2_WORKER_READY UINT32_C(2) 3063 /** Worker thread is done updating TSC delta info. */ 3064 #define GIP_TSC_DELTA_SYNC2_WORKER_DONE UINT32_C(3) 3065 /** When IPRT is isn't concurrent safe: Master is ready and will wait for worker 3066 * with a timeout. */ 3067 #define GIP_TSC_DELTA_SYNC2_PRESTART_MASTER UINT32_C(4) 3068 2772 3069 2773 3070 /** … … 2792 3089 PSUPGIPCPU pGipCpuWorker = pArgs->pWorker; 2793 3090 PSUPGIPCPU pGipCpuMaster = pArgs->pMaster; 2794 RTCPUID idMaster = pArgs->idMaster;3091 bool const fIsMaster = idCpu == pGipCpuMaster->idCpu; 2795 3092 uint32_t iTry; 3093 #if 0 3094 PSUPTSCDELTASYNC2 pOtherSync; 3095 SUPTSCDELTASYNC2 MySync; 3096 #endif 2796 3097 2797 3098 /* A bit of paranoia first. */ … … 2799 3100 return; 2800 3101 2801 /* If the CPU isn't part of the measurement, return immediately. */ 2802 if ( idCpu != idMaster 3102 /* 3103 * If the CPU isn't part of the measurement, return immediately. 3104 */ 3105 if ( !fIsMaster 2803 3106 && idCpu != pGipCpuWorker->idCpu) 2804 3107 return; 3108 3109 #if 0 3110 /* 3111 * Set up my synchronization stuff and wait for the other party to show up. 3112 * We don't wait forever since the other party may have gone fishing after 3113 * we checked it out in supdrvMeasureTscDeltaOne, and then there is of course 3114 * windows and it's BSOD if we waste too much time here. 3115 */ 3116 if (fIsMaster) 3117 { 3118 MySync.uVar1 = GIP_TSC_DELTA_SYNC2_PRESTART_WAIT; 3119 ASMSerializeInstruction(); ASMCompilerBarrier(); 3120 ASMAtomicWritePtr(&pArgs->pSyncMaster, &MySync); 3121 } 3122 else 3123 { 3124 MySync.uVar1 = GIP_TSC_DELTA_SYNC2_PRESTART_WAIT; 3125 ASMSerializeInstruction(); ASMCompilerBarrier(); 3126 ASMAtomicWritePtr(&pArgs->pSyncWorker, &MySync); 3127 } 3128 3129 MySync.uTscStart = ASMReadTSC(); 3130 MySync.cMaxTicks = u64CpuHz 3131 3132 while ((pOtherSync = ASMAtomicReadPtr((void * volatile *)(fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster))) != NULL) 3133 { 3134 uint32_t cInner = 10240; 3135 while ( cInner-- > 0 3136 && ASMAtomicUoReadU32(MySync.uVar1) == GIP_TSC_DELTA_SYNC2_PRESTART_WAIT) 3137 ASMNopPause(); 3138 3139 } 3140 #endif 3141 2805 3142 2806 3143 /* If the IPRT API isn't concurrent safe, the master and worker wait for each other … … 2817 3154 ASMSerializeInstruction(); 2818 3155 uTscStart = ASMReadTSC(); 2819 if ( idCpu == idMaster)3156 if (fIsMaster) 2820 3157 { 2821 3158 ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_PRESTART_MASTER); … … 2862 3199 */ 2863 3200 #ifdef GIP_TSC_DELTA_METHOD_1 2864 supdrvTscDeltaMethod1Loop(pArgs, pSync, idCpu == idMaster, iTry);3201 supdrvTscDeltaMethod1Loop(pArgs, pSync, fIsMaster, iTry); 2865 3202 #elif defined(GIP_TSC_DELTA_METHOD_2) 2866 supdrvTscDeltaMethod2Loop(pArgs, pSync, idCpu == idMaster, iTry);3203 supdrvTscDeltaMethod2Loop(pArgs, pSync, fIsMaster, iTry); 2867 3204 #else 2868 3205 # error "huh??" … … 2874 3211 if (pGipCpuWorker->i64TSCDelta != INT64_MAX) 2875 3212 { 2876 if ( idCpu == idMaster)3213 if (fIsMaster) 2877 3214 { 2878 3215 RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet); … … 3003 3340 SUPDRVGIPTSCDELTARGS Args; 3004 3341 RT_ZERO(Args); 3005 Args.pWorker = pGipCpuWorker; 3006 Args.pMaster = pGipCpuMaster; 3007 Args.idMaster = idMaster; 3008 Args.pDevExt = pDevExt; 3342 Args.pWorker = pGipCpuWorker; 3343 Args.pMaster = pGipCpuMaster; 3344 Args.pDevExt = pDevExt; 3345 Args.pSyncMaster = NULL; 3346 Args.pSyncWorker = NULL; 3009 3347 #ifdef GIP_TSC_DELTA_METHOD_1 3010 3348 rc = supdrvTscDeltaMethod1Init(&Args); … … 3662 4000 return VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY; 3663 4001 3664 rc = RTThreadSleep(RT_MIN( cMsWaitThread - cMsElapsed, RT_MIN(iWaitLoop + 1, 10)));4002 rc = RTThreadSleep(RT_MIN((RTMSINTERVAL)(cMsWaitThread - cMsElapsed), RT_MIN(iWaitLoop + 1, 10))); 3665 4003 if (rc == VERR_INTERRUPTED) 3666 4004 return rc; -
trunk/src/VBox/HostDrivers/Support/SUPDrvInternal.h
r54327 r54352 712 712 /** @} */ 713 713 714 /** @name Invariant TSC frequency refinement. 715 * @{ */ 716 /** Nanosecond timestamp at the start of the TSC frequency refinement phase. */ 717 uint64_t nsStartInvarTscRefine; 718 /** TSC reading at the start of the TSC frequency refinement phase. */ 719 uint64_t uTscStartInvarTscRefine; 720 /** The CPU id of the CPU that u64TscAnchor was measured on. */ 721 RTCPUID idCpuInvarTscRefine; 722 /** Pointer to the timer used to refine the TSC frequency. */ 723 PRTTIMER pInvarTscRefineTimer; 724 /** @} */ 725 714 726 /** @name TSC-delta measurement. 715 727 * @{ */ 716 /** TSC reading during start of TSC frequency refinement phase. */717 uint64_t u64TscAnchor;718 /** Timestamp (in nanosec) during start of TSC frequency refinement phase. */719 uint64_t u64NanoTSAnchor;720 /** Pointer to the timer used to refine the TSC frequency. */721 PRTTIMER pTscRefineTimer;722 728 /** Pointer to the TSC delta sync. struct. */ 723 729 void *pvTscDeltaSync; -
trunk/src/VBox/HostDrivers/Support/testcase/tstGIP-2.cpp
r54252 r54352 154 154 uint32_t volatile *pu32TransactionId = NULL; 155 155 for (unsigned iCpu = 0; iCpu < g_pSUPGlobalInfoPage->cCpus; iCpu++) 156 if ( g_pSUPGlobalInfoPage->aCPUs[iCpu].u64CpuHz > 0 157 && g_pSUPGlobalInfoPage->aCPUs[iCpu].u64CpuHz != _4G + 1) 156 if (g_pSUPGlobalInfoPage->aCPUs[iCpu].enmState == SUPGIPCPUSTATE_ONLINE) 158 157 { 159 158 char szCpuHzDeviation[32]; -
trunk/src/VBox/VMM/VMMR3/TM.cpp
r54308 r54352 266 266 SUPGetGIPModeName(pGip), pGip->u32UpdateHz, 267 267 pGip->u32UpdateIntervalNS)); 268 LogRel(("TM: GIP - u64CpuHz=%#RX64 (%'RU64)\n", pGip->u64CpuHz, pGip->u64CpuHz)); 268 LogRel(("TM: GIP - u64CpuHz=%'RU64 (%#RX64) SUPGetCpuHzFromGip => %'RU64\n", 269 pGip->u64CpuHz, pGip->u64CpuHz, SUPGetCpuHzFromGip(pGip))); 269 270 270 271 /*
Note:
See TracChangeset
for help on using the changeset viewer.