Changeset 92825 in vbox
- Timestamp:
- Dec 8, 2021 3:32:59 PM (3 years ago)
- Location:
- trunk/src/VBox/Runtime
- Files:
-
- 6 edited
-
r0drv/nt/initterm-r0drv-nt.cpp (modified) (2 diffs)
-
r0drv/nt/internal-r0drv-nt.h (modified) (3 diffs)
-
r0drv/nt/timer-r0drv-nt.cpp (modified) (14 diffs)
-
testcase/tstRTR0Timer.cpp (modified) (9 diffs)
-
testcase/tstRTR0Timer.h (modified) (2 diffs)
-
testcase/tstRTR0TimerDriver.cpp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/nt/initterm-r0drv-nt.cpp
r92183 r92825 49 49 /** ExSetTimerResolution, introduced in W2K. */ 50 50 PFNMYEXSETTIMERRESOLUTION g_pfnrtNtExSetTimerResolution; 51 /** ExAllocateTimer, introduced in Windows 8.1 */ 52 PFNEXALLOCATETIMER g_pfnrtExAllocateTimer; 53 /** ExDeleteTimer, introduced in Windows 8.1 */ 54 PFNEXDELETETIMER g_pfnrtExDeleteTimer; 55 /** ExSetTimer, introduced in Windows 8.1 */ 56 PFNEXSETTIMER g_pfnrtExSetTimer; 57 /** ExCancelTimer, introduced in Windows 8.1 */ 58 PFNEXCANCELTIMER g_pfnrtExCancelTimer; 51 59 /** KeFlushQueuedDpcs, introduced in XP. */ 52 60 PFNMYKEFLUSHQUEUEDDPCS g_pfnrtNtKeFlushQueuedDpcs; … … 303 311 GET_SYSTEM_ROUTINE(ExFreePoolWithTag); 304 312 GET_SYSTEM_ROUTINE_PRF(Nt,ExSetTimerResolution); 313 GET_SYSTEM_ROUTINE_TYPE(ExAllocateTimer, PFNEXALLOCATETIMER); 314 GET_SYSTEM_ROUTINE_TYPE(ExDeleteTimer, PFNEXDELETETIMER); 315 GET_SYSTEM_ROUTINE_TYPE(ExSetTimer, PFNEXSETTIMER); 316 GET_SYSTEM_ROUTINE_TYPE(ExCancelTimer, PFNEXCANCELTIMER); 305 317 GET_SYSTEM_ROUTINE_PRF(Nt,KeFlushQueuedDpcs); 306 318 GET_SYSTEM_ROUTINE(KeIpiGenericCall); -
trunk/src/VBox/Runtime/r0drv/nt/internal-r0drv-nt.h
r91449 r92825 36 36 RT_C_DECLS_BEGIN 37 37 38 /******************************************************************************* 39 * Structures and Typedefs *40 ******************************************************************************* /38 /********************************************************************************************************************************* 39 * Structures and Typedefs * 40 *********************************************************************************************************************************/ 41 41 typedef ULONG (__stdcall *PFNMYEXSETTIMERRESOLUTION)(ULONG, BOOLEAN); 42 42 typedef VOID (__stdcall *PFNMYKEFLUSHQUEUEDDPCS)(VOID); … … 54 54 SIZE_T, MEMORY_CACHING_TYPE, ULONG); 55 55 56 #ifndef EX_TIMER_HIGH_RESOLUTION /* Too old DDK, so add missing bits. */ 57 # define EX_TIMER_NO_WAKE RT_BIT_32(3) 58 # define EX_TIMER_HIGH_RESOLUTION RT_BIT_32(2) 59 # define EX_TIMER_NOTIFICATION RT_BIT_32(31) 60 typedef struct _EX_TIMER *PEX_TIMER; 61 typedef VOID (__stdcall *PEXT_CALLBACK)(PEX_TIMER, void *); 62 typedef PEX_TIMER (__stdcall *PFNEXALLOCATETIMER)(PEXT_CALLBACK pfnCallback, void *pvUser, ULONG fFlags); 56 63 57 /******************************************************************************* 58 * Global Variables * 59 *******************************************************************************/ 64 typedef VOID (__stdcall *PEXT_DELETE_CALLBACK)(void *); 65 typedef struct _EXT_DELETE_PARAMETERS 66 { 67 ULONG Version; 68 ULONG Reserved; 69 PEXT_DELETE_CALLBACK DeleteCallback; 70 void *DeleteContext; 71 } EXT_DELETE_PARAMETERS; 72 typedef EXT_DELETE_PARAMETERS *PEXT_DELETE_PARAMETERS; 73 DECLINLINE(void) ExInitializeDeleteTimerParameters(PEXT_DELETE_PARAMETERS pParams) 74 { 75 pParams->Version = 0; 76 pParams->Reserved = 0; 77 pParams->DeleteCallback = NULL; 78 pParams->DeleteContext = NULL; 79 } 80 typedef BOOLEAN (__stdcall *PFNEXDELETETIMER)(PEX_TIMER pTimer, BOOLEAN fCancel, BOOLEAN fWait, PEXT_DELETE_PARAMETERS pParams); 81 82 typedef struct _EXT_SET_PARAMETERS_V0 83 { 84 ULONG Version; 85 ULONG Reserved; 86 LONGLONG NoWakeTolerance; 87 } EXT_SET_PARAMETERS; 88 typedef EXT_SET_PARAMETERS *PEXT_SET_PARAMETERS; 89 DECLINLINE(void) ExInitializeSetTimerParameters(PEXT_SET_PARAMETERS pParams) 90 { 91 pParams->Version = 0; 92 pParams->Reserved = 0; 93 pParams->NoWakeTolerance = 0; 94 } 95 typedef BOOLEAN (__stdcall *PFNEXSETTIMER)(PEX_TIMER pTimer, LONGLONG DueTime, LONGLONG Period, PEXT_SET_PARAMETERS pParams); 96 97 typedef BOOLEAN (__stdcall *PFNEXCANCELTIMER)(PEX_TIMER pTimer, void *pvReserved); 98 99 #else 100 typedef decltype(ExAllocateTimer) *PFNEXALLOCATETIMER; 101 typedef decltype(ExDeleteTimer) *PFNEXDELETETIMER; 102 typedef decltype(ExSetTimer) *PFNEXSETTIMER; 103 typedef decltype(ExCancelTimer) *PFNEXCANCELTIMER; 104 #endif 105 106 107 /********************************************************************************************************************************* 108 * Global Variables * 109 *********************************************************************************************************************************/ 60 110 extern RTCPUSET g_rtMpNtCpuSet; 61 111 extern uint32_t g_cRtMpNtMaxGroups; … … 66 116 extern decltype(ExFreePoolWithTag) *g_pfnrtExFreePoolWithTag; 67 117 extern PFNMYEXSETTIMERRESOLUTION g_pfnrtNtExSetTimerResolution; 118 extern PFNEXALLOCATETIMER g_pfnrtExAllocateTimer; 119 extern PFNEXDELETETIMER g_pfnrtExDeleteTimer; 120 extern PFNEXSETTIMER g_pfnrtExSetTimer; 121 extern PFNEXCANCELTIMER g_pfnrtExCancelTimer; 68 122 extern PFNMYKEFLUSHQUEUEDDPCS g_pfnrtNtKeFlushQueuedDpcs; 69 123 extern PFNHALREQUESTIPI_W7PLUS g_pfnrtHalRequestIpiW7Plus; -
trunk/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp
r82968 r92825 43 43 #include "internal/magics.h" 44 44 45 46 /********************************************************************************************************************************* 47 * Defined Constants And Macros * 48 *********************************************************************************************************************************/ 45 49 /** This seems to provide better accuracy. */ 46 50 #define RTR0TIMER_NT_MANUAL_RE_ARM 1 51 52 #if !defined(IN_GUEST) || defined(DOXYGEN_RUNNING) 53 /** This using high resolution timers introduced with windows 8.1. */ 54 # define RTR0TIMER_NT_HIGH_RES 1 55 #endif 47 56 48 57 … … 99 108 uint64_t uNtStartTime; 100 109 #endif 101 /** The N ttimer object. */110 /** The NT timer object. */ 102 111 KTIMER NtTimer; 112 #ifdef RTR0TIMER_NT_HIGH_RES 113 /** High resolution timer. If not NULL, this must be used instead of NtTimer. */ 114 PEX_TIMER pHighResTimer; 115 #endif 103 116 /** The number of sub-timers. */ 104 117 RTCPUID cSubTimers; … … 145 158 * @param pTimer The timer. 146 159 * @param iTick The current timer tick. 147 * @param pMasterDpc The master DPC. 148 */ 149 DECLINLINE(void) rtTimerNtRearmInternval(PRTTIMER pTimer, uint64_t iTick, PKDPC pMasterDpc) 160 */ 161 DECLINLINE(void) rtTimerNtRearmInternval(PRTTIMER pTimer, uint64_t iTick) 150 162 { 151 163 #ifdef RTR0TIMER_NT_MANUAL_RE_ARM 152 164 Assert(pTimer->u64NanoInterval); 153 RT_NOREF1(pMasterDpc);154 165 155 166 uint64_t uNtNext = (iTick * pTimer->u64NanoInterval) / 100 - 10; /* 1us fudge */ … … 163 174 DueTime.QuadPart = -2500; /* 0.25ms */ 164 175 165 KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, &pTimer->aSubTimers[0].NtDpc); 176 # ifdef RTR0TIMER_NT_HIGH_RES 177 if (pTimer->pHighResTimer) 178 g_pfnrtExSetTimer(pTimer->pHighResTimer, DueTime.QuadPart, 0, NULL); 179 else 180 # endif 181 KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, &pTimer->aSubTimers[0].NtDpc); 166 182 #else 167 RT_NOREF 3(pTimer, iTick, pMasterDpc);168 #endif 169 } 170 171 172 /** 173 * Timer callback functionfor the non-omni timers.183 RT_NOREF(pTimer, iTick); 184 #endif 185 } 186 187 188 /** 189 * Common timer callback worker for the non-omni timers. 174 190 * 175 191 * @returns HRTIMER_NORESTART or HRTIMER_RESTART depending on whether it's a one-shot or interval timer. 192 * @param pTimer The timer. 193 */ 194 static void rtTimerNtSimpleCallbackWorker(PRTTIMER pTimer) 195 { 196 /* 197 * Check that we haven't been suspended before doing the callout. 198 */ 199 if ( !ASMAtomicUoReadBool(&pTimer->fSuspended) 200 && pTimer->u32Magic == RTTIMER_MAGIC) 201 { 202 ASMAtomicWriteHandle(&pTimer->aSubTimers[0].hActiveThread, RTThreadNativeSelf()); 203 204 if (!pTimer->u64NanoInterval) 205 ASMAtomicWriteBool(&pTimer->fSuspended, true); 206 uint64_t iTick = ++pTimer->aSubTimers[0].iTick; 207 if (pTimer->u64NanoInterval) 208 rtTimerNtRearmInternval(pTimer, iTick); 209 pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick); 210 211 ASMAtomicWriteHandle(&pTimer->aSubTimers[0].hActiveThread, NIL_RTNATIVETHREAD); 212 } 213 } 214 215 216 /** 217 * Timer callback function for the low-resolution non-omni timers. 218 * 176 219 * @param pDpc Pointer to the DPC. 177 220 * @param pvUser Pointer to our internal timer structure. … … 188 231 #endif 189 232 190 /* 191 * Check that we haven't been suspended before doing the callout. 192 */ 193 if ( !ASMAtomicUoReadBool(&pTimer->fSuspended) 194 && pTimer->u32Magic == RTTIMER_MAGIC) 195 { 196 ASMAtomicWriteHandle(&pTimer->aSubTimers[0].hActiveThread, RTThreadNativeSelf()); 197 198 if (!pTimer->u64NanoInterval) 199 ASMAtomicWriteBool(&pTimer->fSuspended, true); 200 uint64_t iTick = ++pTimer->aSubTimers[0].iTick; 201 if (pTimer->u64NanoInterval) 202 rtTimerNtRearmInternval(pTimer, iTick, &pTimer->aSubTimers[0].NtDpc); 203 pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick); 204 205 ASMAtomicWriteHandle(&pTimer->aSubTimers[0].hActiveThread, NIL_RTNATIVETHREAD); 206 } 207 208 NOREF(pDpc); NOREF(SystemArgument1); NOREF(SystemArgument2); 209 } 233 rtTimerNtSimpleCallbackWorker(pTimer); 234 235 RT_NOREF(pDpc, SystemArgument1, SystemArgument2); 236 } 237 238 239 #ifdef RTR0TIMER_NT_HIGH_RES 240 /** 241 * Timer callback function for the high-resolution non-omni timers. 242 * 243 * @param pExTimer The windows timer. 244 * @param pvUser Pointer to our internal timer structure. 245 */ 246 static void _stdcall rtTimerNtHighResSimpleCallback(PEX_TIMER pExTimer, void *pvUser) 247 { 248 PRTTIMER pTimer = (PRTTIMER)pvUser; 249 AssertPtr(pTimer); 250 Assert(pTimer->pHighResTimer == pExTimer); 251 # ifdef RT_STRICT 252 if (KeGetCurrentIrql() < DISPATCH_LEVEL) 253 RTAssertMsg2Weak("rtTimerNtHighResSimpleCallback: Irql=%d expected >=%d\n", KeGetCurrentIrql(), DISPATCH_LEVEL); 254 # endif 255 256 /* If we're not on the desired CPU, trigger the DPC. That will rearm the 257 timer and such. */ 258 if ( !pTimer->fSpecificCpu 259 || pTimer->idCpu == RTMpCpuId()) 260 rtTimerNtSimpleCallbackWorker(pTimer); 261 else 262 KeInsertQueueDpc(&pTimer->aSubTimers[0].NtDpc, 0, 0); 263 264 RT_NOREF(pExTimer); 265 } 266 #endif /* RTR0TIMER_NT_HIGH_RES */ 210 267 211 268 … … 254 311 255 312 /** 256 * The timer callback for an omni-timer.313 * Common timer callback worker for omni-timers. 257 314 * 258 315 * This is responsible for queueing the DPCs for the other CPUs and 259 316 * perform the callback on the CPU on which it is called. 260 317 * 261 * @param pDpc The DPC object. 262 * @param pvUser Pointer to the sub-timer. 263 * @param SystemArgument1 Some system stuff. 264 * @param SystemArgument2 Some system stuff. 265 */ 266 static void _stdcall rtTimerNtOmniMasterCallback(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2) 267 { 268 PRTTIMERNTSUBTIMER pSubTimer = (PRTTIMERNTSUBTIMER)pvUser; 269 PRTTIMER pTimer = pSubTimer->pParent; 270 int iCpuSelf = RTMpCpuIdToSetIndex(RTMpCpuId()); 271 272 AssertPtr(pTimer); 318 * @param pTimer The timer. 319 * @param pSubTimer The sub-timer of the calling CPU. 320 * @param iCpuSelf The set index of the CPU we're running on. 321 */ 322 static void rtTimerNtOmniMasterCallbackWorker(PRTTIMER pTimer, PRTTIMERNTSUBTIMER pSubTimer, int iCpuSelf) 323 { 273 324 #ifdef RT_STRICT 274 325 if (KeGetCurrentIrql() < DISPATCH_LEVEL) … … 301 352 302 353 uint64_t iTick = ++pSubTimer->iTick; 303 rtTimerNtRearmInternval(pTimer, iTick , &pTimer->aSubTimers[RTMpCpuIdToSetIndex(pTimer->idCpu)].NtDpc);354 rtTimerNtRearmInternval(pTimer, iTick); 304 355 pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick); 305 356 } … … 329 380 ASMAtomicWriteHandle(&pSubTimer->hActiveThread, NIL_RTNATIVETHREAD); 330 381 } 331 332 NOREF(pDpc); NOREF(SystemArgument1); NOREF(SystemArgument2); 333 } 334 382 } 383 384 385 /** 386 * The timer callback for an omni-timer, low-resolution. 387 * 388 * @param pDpc The DPC object. 389 * @param pvUser Pointer to the sub-timer. 390 * @param SystemArgument1 Some system stuff. 391 * @param SystemArgument2 Some system stuff. 392 */ 393 static void _stdcall rtTimerNtOmniMasterCallback(IN PKDPC pDpc, IN PVOID pvUser, IN PVOID SystemArgument1, IN PVOID SystemArgument2) 394 { 395 PRTTIMERNTSUBTIMER const pSubTimer = (PRTTIMERNTSUBTIMER)pvUser; 396 PRTTIMER const pTimer = pSubTimer->pParent; 397 int const iCpuSelf = RTMpCpuIdToSetIndex(RTMpCpuId()); 398 399 AssertPtr(pTimer); 400 #ifdef RT_STRICT 401 if (KeGetCurrentIrql() < DISPATCH_LEVEL) 402 RTAssertMsg2Weak("rtTimerNtOmniMasterCallback: Irql=%d expected >=%d\n", KeGetCurrentIrql(), DISPATCH_LEVEL); 403 if (pSubTimer - &pTimer->aSubTimers[0] != iCpuSelf) 404 RTAssertMsg2Weak("rtTimerNtOmniMasterCallback: iCpuSelf=%d pSubTimer=%p / %d\n", iCpuSelf, pSubTimer, pSubTimer - &pTimer->aSubTimers[0]); 405 #endif 406 407 rtTimerNtOmniMasterCallbackWorker(pTimer, pSubTimer, iCpuSelf); 408 409 RT_NOREF(pDpc, SystemArgument1, SystemArgument2); 410 } 411 412 413 #ifdef RTR0TIMER_NT_HIGH_RES 414 /** 415 * The timer callback for an high-resolution omni-timer. 416 * 417 * @param pExTimer The windows timer. 418 * @param pvUser Pointer to our internal timer structure. 419 */ 420 static void __stdcall rtTimerNtHighResOmniCallback(PEX_TIMER pExTimer, void *pvUser) 421 { 422 PRTTIMER const pTimer = (PRTTIMER)pvUser; 423 int const iCpuSelf = RTMpCpuIdToSetIndex(RTMpCpuId()); 424 PRTTIMERNTSUBTIMER const pSubTimer = &pTimer->aSubTimers[iCpuSelf]; 425 426 AssertPtr(pTimer); 427 Assert(pTimer->pHighResTimer == pExTimer); 428 # ifdef RT_STRICT 429 if (KeGetCurrentIrql() < DISPATCH_LEVEL) 430 RTAssertMsg2Weak("rtTimerNtHighResOmniCallback: Irql=%d expected >=%d\n", KeGetCurrentIrql(), DISPATCH_LEVEL); 431 # endif 432 433 rtTimerNtOmniMasterCallbackWorker(pTimer, pSubTimer, iCpuSelf); 434 435 RT_NOREF(pExTimer); 436 } 437 #endif /* RTR0TIMER_NT_HIGH_RES */ 335 438 336 439 … … 373 476 for (unsigned iCpu = 0; iCpu < cSubTimers; iCpu++) 374 477 pTimer->aSubTimers[iCpu].iTick = 0; 478 #ifdef RTR0TIMER_NT_MANUAL_RE_ARM 479 pTimer->uNtStartTime = rtTimerNtQueryInterruptTime() + u64First / 100; 480 #endif 375 481 ASMAtomicWriteS32(&pTimer->cOmniSuspendCountDown, 0); 376 482 ASMAtomicWriteBool(&pTimer->fSuspended, false); 483 484 #ifdef RTR0TIMER_NT_HIGH_RES 485 if (pTimer->pHighResTimer) 486 { 487 # ifdef RTR0TIMER_NT_MANUAL_RE_ARM 488 g_pfnrtExSetTimer(pTimer->pHighResTimer, DueTime.QuadPart, 0, NULL); 489 # else 490 g_pfnrtExSetTimer(pTimer->pHighResTimer, DueTime.QuadPart, RT_MIN(pTimer->u64NanoInterval / 100, MAXLONG), NULL); 491 # endif 492 } 493 else 494 #endif 495 { 377 496 #ifdef RTR0TIMER_NT_MANUAL_RE_ARM 378 pTimer->uNtStartTime = rtTimerNtQueryInterruptTime() + u64First / 100; 379 KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, pMasterDpc); 497 KeSetTimerEx(&pTimer->NtTimer, DueTime, 0, pMasterDpc); 380 498 #else 381 KeSetTimerEx(&pTimer->NtTimer, DueTime, ulInterval, pMasterDpc); 382 #endif 499 KeSetTimerEx(&pTimer->NtTimer, DueTime, ulInterval, pMasterDpc); 500 #endif 501 } 383 502 return VINF_SUCCESS; 384 503 } … … 399 518 ASMAtomicWriteBool(&pTimer->fSuspended, true); 400 519 401 KeCancelTimer(&pTimer->NtTimer); 520 #ifdef RTR0TIMER_NT_HIGH_RES 521 if (pTimer->pHighResTimer) 522 g_pfnrtExCancelTimer(pTimer->pHighResTimer, NULL); 523 else 524 #endif 525 KeCancelTimer(&pTimer->NtTimer); 402 526 403 527 for (RTCPUID iCpu = 0; iCpu < pTimer->cSubTimers; iCpu++) … … 456 580 if (!ASMAtomicUoReadBool(&pTimer->fSuspended)) 457 581 rtTimerNtStopWorker(pTimer); 582 583 #ifdef RTR0TIMER_NT_HIGH_RES 584 /* 585 * Destroy the high-resolution timer before flushing DPCs. 586 */ 587 if (pTimer->pHighResTimer) 588 { 589 g_pfnrtExDeleteTimer(pTimer->pHighResTimer, TRUE /*fCancel*/, TRUE /*fWait*/, NULL); 590 pTimer->pHighResTimer = NULL; 591 } 592 #endif 458 593 459 594 /* … … 499 634 /* 500 635 * Initialize it. 636 * 637 * Note! The difference between a SynchronizationTimer and a NotificationTimer 638 * (KeInitializeTimer) is, as far as I can gather, only that the former 639 * will wake up exactly one waiting thread and the latter will wake up 640 * everyone. Since we don't do any waiting on the NtTimer, that is not 641 * relevant to us. 501 642 */ 502 643 pTimer->u32Magic = RTTIMER_MAGIC; … … 510 651 pTimer->pvUser = pvUser; 511 652 pTimer->u64NanoInterval = u64NanoInterval; 512 if (g_pfnrtKeInitializeTimerEx) 513 g_pfnrtKeInitializeTimerEx(&pTimer->NtTimer, SynchronizationTimer); 653 654 int rc = VINF_SUCCESS; 655 #ifdef RTR0TIMER_NT_HIGH_RES 656 if ( (fFlags & RTTIMER_FLAGS_HIGH_RES) 657 && RTTimerCanDoHighResolution()) 658 { 659 pTimer->pHighResTimer = g_pfnrtExAllocateTimer(pTimer->fOmniTimer ? rtTimerNtHighResOmniCallback 660 : rtTimerNtHighResSimpleCallback, pTimer, 661 EX_TIMER_HIGH_RESOLUTION | EX_TIMER_NOTIFICATION); 662 if (!pTimer->pHighResTimer) 663 rc = VERR_OUT_OF_RESOURCES; 664 } 514 665 else 515 KeInitializeTimer(&pTimer->NtTimer); 516 int rc = VINF_SUCCESS; 517 if (pTimer->fOmniTimer) 518 { 519 /* 520 * Initialize the per-cpu "sub-timers", select the first online cpu 521 * to be the master. 522 * ASSUMES that no cpus will ever go offline. 523 */ 524 pTimer->idCpu = NIL_RTCPUID; 525 for (unsigned iCpu = 0; iCpu < cSubTimers && RT_SUCCESS(rc); iCpu++) 666 #endif 667 { 668 if (g_pfnrtKeInitializeTimerEx) /** @todo just call KeInitializeTimer. */ 669 g_pfnrtKeInitializeTimerEx(&pTimer->NtTimer, SynchronizationTimer); 670 else 671 KeInitializeTimer(&pTimer->NtTimer); 672 } 673 if (RT_SUCCESS(rc)) 674 { 675 if (pTimer->fOmniTimer) 526 676 { 527 pTimer->aSubTimers[iCpu].iTick = 0; 528 pTimer->aSubTimers[iCpu].pParent = pTimer; 529 530 if ( pTimer->idCpu == NIL_RTCPUID 531 && RTMpIsCpuOnline(RTMpCpuIdFromSetIndex(iCpu))) 677 /* 678 * Initialize the per-cpu "sub-timers", select the first online cpu to be 679 * the master. This ASSUMES that no cpus will ever go offline. 680 * 681 * Note! For the high-resolution scenario, all DPC callbacks are slaves as 682 * we have a dedicated timer callback, set above during allocation, 683 * and don't control which CPU it (rtTimerNtHighResOmniCallback) is 684 * called on. 685 */ 686 pTimer->idCpu = NIL_RTCPUID; 687 for (unsigned iCpu = 0; iCpu < cSubTimers && RT_SUCCESS(rc); iCpu++) 532 688 { 533 pTimer->idCpu = RTMpCpuIdFromSetIndex(iCpu); 534 KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniMasterCallback, &pTimer->aSubTimers[iCpu]); 689 pTimer->aSubTimers[iCpu].iTick = 0; 690 pTimer->aSubTimers[iCpu].pParent = pTimer; 691 692 if ( pTimer->idCpu == NIL_RTCPUID 693 && RTMpIsCpuOnline(RTMpCpuIdFromSetIndex(iCpu))) 694 { 695 pTimer->idCpu = RTMpCpuIdFromSetIndex(iCpu); 696 #ifdef RTR0TIMER_NT_HIGH_RES 697 if (pTimer->pHighResTimer) 698 KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniSlaveCallback, &pTimer->aSubTimers[iCpu]); 699 else 700 #endif 701 KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniMasterCallback, &pTimer->aSubTimers[iCpu]); 702 } 703 else 704 KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniSlaveCallback, &pTimer->aSubTimers[iCpu]); 705 if (g_pfnrtKeSetImportanceDpc) 706 g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[iCpu].NtDpc, HighImportance); 707 rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[iCpu].NtDpc, iCpu); 535 708 } 536 else 537 KeInitializeDpc(&pTimer->aSubTimers[iCpu].NtDpc, rtTimerNtOmniSlaveCallback, &pTimer->aSubTimers[iCpu]); 709 Assert(pTimer->idCpu != NIL_RTCPUID); 710 } 711 else 712 { 713 /* 714 * Initialize the first "sub-timer", target the DPC on a specific processor 715 * if requested to do so. 716 */ 717 pTimer->aSubTimers[0].iTick = 0; 718 pTimer->aSubTimers[0].pParent = pTimer; 719 720 KeInitializeDpc(&pTimer->aSubTimers[0].NtDpc, rtTimerNtSimpleCallback, pTimer); 538 721 if (g_pfnrtKeSetImportanceDpc) 539 g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[iCpu].NtDpc, HighImportance); 540 rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[iCpu].NtDpc, iCpu); 722 g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[0].NtDpc, HighImportance); 723 if (pTimer->fSpecificCpu) 724 rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, (int)pTimer->idCpu); 541 725 } 542 Assert(pTimer->idCpu != NIL_RTCPUID); 543 } 544 else 545 { 546 /* 547 * Initialize the first "sub-timer", target the DPC on a specific processor 548 * if requested to do so. 549 */ 550 pTimer->aSubTimers[0].iTick = 0; 551 pTimer->aSubTimers[0].pParent = pTimer; 552 553 KeInitializeDpc(&pTimer->aSubTimers[0].NtDpc, rtTimerNtSimpleCallback, pTimer); 554 if (g_pfnrtKeSetImportanceDpc) 555 g_pfnrtKeSetImportanceDpc(&pTimer->aSubTimers[0].NtDpc, HighImportance); 556 if (pTimer->fSpecificCpu) 557 rc = rtMpNtSetTargetProcessorDpc(&pTimer->aSubTimers[0].NtDpc, (int)pTimer->idCpu); 558 } 559 if (RT_SUCCESS(rc)) 560 { 561 *ppTimer = pTimer; 562 return VINF_SUCCESS; 726 if (RT_SUCCESS(rc)) 727 { 728 *ppTimer = pTimer; 729 return VINF_SUCCESS; 730 } 731 732 #ifdef RTR0TIMER_NT_HIGH_RES 733 if (pTimer->pHighResTimer) 734 { 735 g_pfnrtExDeleteTimer(pTimer->pHighResTimer, FALSE, FALSE, NULL); 736 pTimer->pHighResTimer = NULL; 737 } 738 #endif 563 739 } 564 740 … … 593 769 RTDECL(bool) RTTimerCanDoHighResolution(void) 594 770 { 771 #ifdef RTR0TIMER_NT_HIGH_RES 772 return g_pfnrtExAllocateTimer != NULL 773 && g_pfnrtExDeleteTimer != NULL 774 && g_pfnrtExSetTimer != NULL 775 && g_pfnrtExCancelTimer != NULL; 776 #else 595 777 return false; 596 } 597 778 #endif 779 } 780 -
trunk/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
r82968 r92825 128 128 129 129 130 131 130 132 /** 131 133 * Callback for the omni timer latency test, adds a sample to g_aOmniLatency. … … 141 143 NOREF(pTimer); NOREF(pvUser); NOREF(iTick); 142 144 143 RTR0TESTR0_CHECK_MSG(iCpu < RT_ELEMENTS(g_aOmniLatency), ("iCpu=%d idCpu=%u\n", iCpu, idCpu));145 //RTR0TESTR0_CHECK_MSG(iCpu < RT_ELEMENTS(g_aOmniLatency), ("iCpu=%d idCpu=%u\n", iCpu, idCpu)); 144 146 if (iCpu < RT_ELEMENTS(g_aOmniLatency)) 145 147 { … … 153 155 } 154 156 } 155 156 157 157 158 … … 183 184 } 184 185 } 186 } 187 188 189 /** 190 * Callback for one-shot resolution detection. 191 * 192 * @param pTimer The timer. 193 * @param iTick The current tick. 194 * @param pvUser Points to variable with the start TS, update to time 195 * elapsed till this call. 196 */ 197 static DECLCALLBACK(void) tstRTR0TimerCallbackOneShotElapsed(PRTTIMER pTimer, void *pvUser, uint64_t iTick) 198 { 199 RT_NOREF(pTimer, iTick); 200 uint64_t *puNanoTS = (uint64_t *)pvUser; 201 *puNanoTS = RTTimeSystemNanoTS() - *puNanoTS; 185 202 } 186 203 … … 617 634 } 618 635 636 case TSTRTR0TIMER_ONE_SHOT_RESOLUTION: 637 case TSTRTR0TIMER_ONE_SHOT_RESOLUTION_HIRES: 638 { 639 /* Just create a timer and do a number of RTTimerStart with a small 640 interval and see how quickly it gets called. */ 641 PRTTIMER pTimer; 642 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0; 643 uint64_t volatile cNsElapsed = 0; 644 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackOneShotElapsed, (void *)&cNsElapsed), 645 VINF_SUCCESS); 646 647 uint32_t cTotal = 0; 648 uint32_t cNsTotal = 0; 649 uint32_t cNsMin = UINT32_MAX; 650 uint32_t cNsMax = 0; 651 for (uint32_t i = 0; i < 200; i++) 652 { 653 cNsElapsed = RTTimeSystemNanoTS(); 654 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, RT_NS_1US), VINF_SUCCESS); 655 RTThreadSleep(10); 656 cTotal += 1; 657 cNsTotal += cNsElapsed; 658 if (cNsMin > cNsElapsed) 659 cNsMin = cNsElapsed; 660 if (cNsMax < cNsElapsed) 661 cNsMax = cNsElapsed; 662 } 663 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS); 664 pTimer = NULL; 665 RTR0TestR0Info("nsMin=%u nsAvg=%u nsMax=%u cTotal=%u\n", cNsMin, cNsTotal / cTotal, cNsMax, cTotal); 666 break; 667 } 668 619 669 case TSTRTR0TIMER_PERIODIC_BASIC: 620 670 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES: 621 671 { 622 672 /* Create a periodic timer running at 10 HZ. */ 623 uint32_t const u10HzAsNs = 100000000;673 uint32_t const u10HzAsNs = RT_NS_1SEC / 10; 624 674 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2; 625 675 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2; … … 876 926 } 877 927 928 878 929 case TSTRTR0TIMER_LATENCY_OMNI: 879 930 case TSTRTR0TIMER_LATENCY_OMNI_HIRES: … … 881 932 /* 882 933 * Create a periodic timer running at max host frequency, but no more than 1000 Hz. 934 * Unless it's a high resolution timer, which we try at double the rate. 935 * Windows seems to limit the highres stuff to around 500-600 us interval. 883 936 */ 884 937 PRTTIMER pTimer; 885 938 uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0) 886 939 | RTTIMER_FLAGS_CPU_ALL; 887 uint32_t cNsInterval = cNsSysHz; 888 while (cNsInterval < UINT32_C(1000000)) 940 uint32_t const cNsMinInterval = TSTRTR0TIMER_IS_HIRES(uOperation) ? cNsMaxHighResHz : RT_NS_1MS; 941 uint32_t cNsInterval = TSTRTR0TIMER_IS_HIRES(uOperation) ? cNsSysHz / 2 : cNsSysHz; 942 while (cNsInterval < cNsMinInterval) 889 943 cNsInterval *= 2; 890 944 int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackLatencyOmni, NULL); … … 926 980 for (uint32_t iSample = 1; iSample < cSamples; iSample++) 927 981 { 928 int64_t cNsDelta = g_aOmniLatency[iCpu].aSamples[iSample - 1].uNanoTs929 - g_aOmniLatency[iCpu].aSamples[iSample ].uNanoTs;982 int64_t cNsDelta = g_aOmniLatency[iCpu].aSamples[iSample].uNanoTs 983 - g_aOmniLatency[iCpu].aSamples[iSample - 1].uNanoTs; 930 984 if (cNsDelta < cNsLow) 931 985 cLow++; … … 937 991 RTR0TestR0Info("125%%: %u; 75%%: %u; total: %u", cHigh, cLow, cTotal); 938 992 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS); 993 #if 1 994 RTR0TestR0Info("cNsSysHz=%u cNsInterval=%RU32 cNsLow=%d cNsHigh=%d", cNsSysHz, cNsInterval, cNsLow, cNsHigh); 995 if (TSTRTR0TIMER_IS_HIRES(uOperation)) 996 RTR0TestR0Info("RTTimerCanDoHighResolution -> %d", RTTimerCanDoHighResolution()); 997 for (uint32_t iSample = 1; iSample < 6; iSample++) 998 RTR0TestR0Info("%RU64/%#RU64", 999 g_aOmniLatency[0].aSamples[iSample].uNanoTs - g_aOmniLatency[0].aSamples[iSample - 1].uNanoTs, 1000 g_aOmniLatency[0].aSamples[iSample].uTsc - g_aOmniLatency[0].aSamples[iSample - 1].uTsc); 1001 #endif 939 1002 break; 940 1003 } -
trunk/src/VBox/Runtime/testcase/tstRTR0Timer.h
r82968 r92825 62 62 TSTRTR0TIMER_LATENCY_OMNI, 63 63 TSTRTR0TIMER_LATENCY_OMNI_HIRES, 64 TSTRTR0TIMER_ONE_SHOT_RESOLUTION, 65 TSTRTR0TIMER_ONE_SHOT_RESOLUTION_HIRES, 64 66 TSTRTR0TIMER_END 65 67 } TSTRTR0TIMER; … … 77 79 || (uOperation) == TSTRTR0TIMER_PERIODIC_OMNI_HIRES \ 78 80 || (uOperation) == TSTRTR0TIMER_LATENCY_OMNI_HIRES \ 81 || (uOperation) == TSTRTR0TIMER_ONE_SHOT_RESOLUTION_HIRES \ 79 82 ) 80 83 -
trunk/src/VBox/Runtime/testcase/tstRTR0TimerDriver.cpp
r82968 r92825 80 80 if (RTTestErrorCount(g_hTest) == 0) 81 81 { 82 RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_RESOLUTION, "One shot resolution"); 82 83 # if 1 83 84 RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_RESTART, "Restart one shot from callback"); … … 101 102 if (RTTestErrorCount(g_hTest) == 0) 102 103 { 104 RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_RESOLUTION_HIRES, "One shot hires resolution"); 103 105 # if 1 104 106 RTR3TestR0SimpleTest(TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES, "Restart hires one shot from callback");
Note:
See TracChangeset
for help on using the changeset viewer.

