VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTR0Timer.cpp@ 98032

Last change on this file since 98032 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.7 KB
Line 
1/* $Id: tstRTR0Timer.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT R0 Testcase - Timers.
4 */
5
6/*
7 * Copyright (C) 2009-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/timer.h>
42
43#include <iprt/asm.h>
44#include <iprt/asm-amd64-x86.h>
45#include <iprt/cpuset.h>
46#include <iprt/err.h>
47#include <iprt/mem.h>
48#include <iprt/mp.h>
49#include <iprt/param.h>
50#include <iprt/string.h>
51#include <iprt/thread.h>
52#include <iprt/time.h>
53#include <VBox/sup.h>
54#include "tstRTR0Timer.h"
55#include "tstRTR0Common.h"
56
57
58/*********************************************************************************************************************************
59* Structures and Typedefs *
60*********************************************************************************************************************************/
61typedef struct
62{
63 /** Array of nano second timestamp of the first few shots. */
64 uint64_t volatile aShotNsTSes[10];
65 /** The number of shots. */
66 uint32_t volatile cShots;
67 /** The shot at which action is to be taken. */
68 uint32_t iActionShot;
69 /** The RC of whatever operation performed in the handler. */
70 int volatile rc;
71 /** Set if it's a periodic test. */
72 bool fPeriodic;
73 /** Test specific stuff. */
74 union
75 {
76 /** tstRTR0TimerCallbackU32ChangeInterval parameters. */
77 struct
78 {
79 /** The interval change step. */
80 uint32_t cNsChangeStep;
81 /** The current timer interval. */
82 uint32_t cNsCurInterval;
83 /** The minimum interval. */
84 uint32_t cNsMinInterval;
85 /** The maximum interval. */
86 uint32_t cNsMaxInterval;
87 /** Direction flag; false = decrement, true = increment. */
88 bool fDirection;
89 /** The number of steps between each change. */
90 uint8_t cStepsBetween;
91 } ChgInt;
92 /** tstRTR0TimerCallbackSpecific parameters. */
93 struct
94 {
95 /** The expected CPU. */
96 RTCPUID idCpu;
97 /** Set if this failed. */
98 bool fFailed;
99 } Specific;
100 } u;
101} TSTRTR0TIMERS1;
102typedef TSTRTR0TIMERS1 *PTSTRTR0TIMERS1;
103
104
105/**
106 * Per cpu state for an omni timer test.
107 */
108typedef struct TSTRTR0TIMEROMNI1
109{
110 /** When we started receiving timer callbacks on this CPU. */
111 uint64_t u64Start;
112 /** When we received the last tick on this timer. */
113 uint64_t u64Last;
114 /** The number of ticks received on this CPU. */
115 uint32_t volatile cTicks;
116 uint32_t u32Padding;
117} TSTRTR0TIMEROMNI1;
118typedef TSTRTR0TIMEROMNI1 *PTSTRTR0TIMEROMNI1;
119
120
121/*********************************************************************************************************************************
122* Global Variables *
123*********************************************************************************************************************************/
124/**
125 * Latency data.
126 */
127static struct TSTRTR0TIMEROMNILATENCY
128{
129 /** The number of samples. */
130 volatile uint32_t cSamples;
131 uint32_t auPadding[3];
132 struct
133 {
134 uint64_t uTsc;
135 uint64_t uNanoTs;
136 } aSamples[4096];
137} g_aOmniLatency[16];
138
139
140
141
142/**
143 * Callback for the omni timer latency test, adds a sample to g_aOmniLatency.
144 *
145 * @param pTimer The timer.
146 * @param iTick The current tick.
147 * @param pvUser The user argument.
148 */
149static DECLCALLBACK(void) tstRTR0TimerCallbackLatencyOmni(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
150{
151 RTCPUID idCpu = RTMpCpuId();
152 uint32_t iCpu = RTMpCpuIdToSetIndex(idCpu);
153 NOREF(pTimer); NOREF(pvUser); NOREF(iTick);
154
155 //RTR0TESTR0_CHECK_MSG(iCpu < RT_ELEMENTS(g_aOmniLatency), ("iCpu=%d idCpu=%u\n", iCpu, idCpu));
156 if (iCpu < RT_ELEMENTS(g_aOmniLatency))
157 {
158 uint32_t iSample = g_aOmniLatency[iCpu].cSamples;
159 if (iSample < RT_ELEMENTS(g_aOmniLatency[iCpu].aSamples))
160 {
161 g_aOmniLatency[iCpu].aSamples[iSample].uTsc = ASMReadTSC();
162 g_aOmniLatency[iCpu].aSamples[iSample].uNanoTs = RTTimeSystemNanoTS();
163 g_aOmniLatency[iCpu].cSamples = iSample + 1;
164 }
165 }
166}
167
168
169/**
170 * Callback which increments a 32-bit counter.
171 *
172 * @param pTimer The timer.
173 * @param iTick The current tick.
174 * @param pvUser The user argument.
175 */
176static DECLCALLBACK(void) tstRTR0TimerCallbackOmni(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
177{
178 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)pvUser;
179 RTCPUID idCpu = RTMpCpuId();
180 uint32_t iCpu = RTMpCpuIdToSetIndex(idCpu);
181 NOREF(pTimer);
182
183 RTR0TESTR0_CHECK_MSG(iCpu < RTCPUSET_MAX_CPUS, ("iCpu=%d idCpu=%u\n", iCpu, idCpu));
184 if (iCpu < RTCPUSET_MAX_CPUS)
185 {
186 uint32_t iCountedTick = ASMAtomicIncU32(&paStates[iCpu].cTicks);
187 RTR0TESTR0_CHECK_MSG(iCountedTick == iTick,
188 ("iCountedTick=%u iTick=%u iCpu=%d idCpu=%u\n", iCountedTick, iTick, iCpu, idCpu));
189 paStates[iCpu].u64Last = RTTimeSystemNanoTS();
190 if (!paStates[iCpu].u64Start)
191 {
192 paStates[iCpu].u64Start = paStates[iCpu].u64Last;
193 RTR0TESTR0_CHECK_MSG(iCountedTick == 1, ("iCountedTick=%u iCpu=%d idCpu=%u\n", iCountedTick, iCpu, idCpu));
194 }
195 }
196}
197
198
199/**
200 * Callback for one-shot resolution detection.
201 *
202 * @param pTimer The timer.
203 * @param iTick The current tick.
204 * @param pvUser Points to variable with the start TS, update to time
205 * elapsed till this call.
206 */
207static DECLCALLBACK(void) tstRTR0TimerCallbackOneShotElapsed(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
208{
209 RT_NOREF(pTimer, iTick);
210 uint64_t *puNanoTS = (uint64_t *)pvUser;
211 *puNanoTS = RTTimeSystemNanoTS() - *puNanoTS;
212}
213
214
215/**
216 * Callback which increments a 32-bit counter.
217 *
218 * @param pTimer The timer.
219 * @param iTick The current tick.
220 * @param pvUser The user argument.
221 */
222static DECLCALLBACK(void) tstRTR0TimerCallbackSpecific(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
223{
224 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
225 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
226 NOREF(pTimer);
227
228 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
229 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
230
231 RTCPUID idCpu = RTMpCpuId();
232 if (pState->u.Specific.idCpu != idCpu)
233 pState->u.Specific.fFailed = true;
234 RTR0TESTR0_CHECK_MSG(pState->u.Specific.idCpu == idCpu, ("idCpu=%u, expected %u\n", idCpu, pState->u.Specific.idCpu));
235
236 if (pState->fPeriodic)
237 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
238 else
239 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
240}
241
242
243/**
244 * Callback which changes the interval at each invocation.
245 *
246 * The changes are governed by TSTRTR0TIMERS1::ChangeInterval. The callback
247 * calls RTTimerStop at iActionShot.
248 *
249 * @param pTimer The timer.
250 * @param iTick The current tick.
251 * @param pvUser The user argument.
252 */
253static DECLCALLBACK(void) tstRTR0TimerCallbackChangeInterval(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
254{
255 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
256 uint32_t iShot = ASMAtomicIncU32(&pState->cShots) - 1;
257
258 if (iShot < RT_ELEMENTS(pState->aShotNsTSes))
259 pState->aShotNsTSes[iShot] = RTTimeSystemNanoTS();
260 if (pState->fPeriodic)
261 RTR0TESTR0_CHECK_MSG(iShot + 1 == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
262 else
263 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
264
265 if (!(iShot % pState->u.ChgInt.cStepsBetween))
266 {
267 if (pState->u.ChgInt.fDirection)
268 {
269 pState->u.ChgInt.cNsCurInterval += pState->u.ChgInt.cNsChangeStep;
270 if ( pState->u.ChgInt.cNsCurInterval > pState->u.ChgInt.cNsMaxInterval
271 || pState->u.ChgInt.cNsCurInterval < pState->u.ChgInt.cNsMinInterval
272 || !pState->u.ChgInt.cNsCurInterval)
273 {
274 pState->u.ChgInt.cNsCurInterval = pState->u.ChgInt.cNsMaxInterval;
275 pState->u.ChgInt.fDirection = false;
276 }
277 }
278 else
279 {
280 pState->u.ChgInt.cNsCurInterval -= pState->u.ChgInt.cNsChangeStep;
281 if ( pState->u.ChgInt.cNsCurInterval < pState->u.ChgInt.cNsMinInterval
282 || pState->u.ChgInt.cNsCurInterval > pState->u.ChgInt.cNsMaxInterval
283 || pState->u.ChgInt.cNsCurInterval)
284 {
285 pState->u.ChgInt.cNsCurInterval = pState->u.ChgInt.cNsMinInterval;
286 pState->u.ChgInt.fDirection = true;
287 }
288 }
289
290 RTR0TESTR0_CHECK_RC(RTTimerChangeInterval(pTimer, pState->u.ChgInt.cNsCurInterval), VINF_SUCCESS);
291 }
292
293 if (iShot == pState->iActionShot)
294 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStop(pTimer), VINF_SUCCESS);
295}
296
297
298/**
299 * Callback which increments destroy the timer when it fires.
300 *
301 * @param pTimer The timer.
302 * @param iTick The current tick.
303 * @param pvUser The user argument.
304 */
305static DECLCALLBACK(void) tstRTR0TimerCallbackDestroyOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
306{
307 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
308 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
309
310 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
311 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
312 if (pState->fPeriodic)
313 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
314 else
315 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
316
317 if (iShot == pState->iActionShot + 1)
318 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerDestroy(pTimer), VINF_SUCCESS);
319}
320
321
322/**
323 * Callback which increments restarts a timer once.
324 *
325 * @param pTimer The timer.
326 * @param iTick The current tick.
327 * @param pvUser The user argument.
328 */
329static DECLCALLBACK(void) tstRTR0TimerCallbackRestartOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
330{
331 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
332 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
333
334 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
335 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
336 if (pState->fPeriodic)
337 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
338 else
339 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
340
341 if (iShot == pState->iActionShot + 1)
342 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStart(pTimer, 10000000 /* 10ms */), VINF_SUCCESS);
343}
344
345
346/**
347 * Callback which increments a 32-bit counter.
348 *
349 * @param pTimer The timer.
350 * @param iTick The current tick.
351 * @param pvUser The user argument.
352 */
353static DECLCALLBACK(void) tstRTR0TimerCallbackU32Counter(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
354{
355 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
356 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
357 NOREF(pTimer);
358
359 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
360 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
361 if (pState->fPeriodic)
362 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
363 else
364 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
365}
366
367
368#ifdef SOME_UNUSED_FUNCTION
369/**
370 * Checks that the interval between two timer shots are within the specified
371 * range.
372 *
373 * @returns 0 if ok, 1 if bad.
374 * @param iShot The shot number (for bitching).
375 * @param uPrevTS The time stamp of the previous shot (ns).
376 * @param uThisTS The timer stamp of this shot (ns).
377 * @param uMin The minimum interval (ns).
378 * @param uMax The maximum interval (ns).
379 */
380static int tstRTR0TimerCheckShotInterval(uint32_t iShot, uint64_t uPrevTS, uint64_t uThisTS, uint32_t uMin, uint32_t uMax)
381{
382 uint64_t uDelta = uThisTS - uPrevTS;
383 RTR0TESTR0_CHECK_MSG_RET(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin), 1);
384 RTR0TESTR0_CHECK_MSG_RET(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax), 1);
385 return 0;
386}
387#endif
388
389
390/**
391 * Checks that the interval between timer shots are within a certain range.
392 *
393 * @returns Number of violations (i.e. 0 is ok).
394 * @param pState The state.
395 * @param uStartNsTS The start time stamp (ns).
396 * @param uMin The minimum interval (ns).
397 * @param uMax The maximum interval (ns).
398 */
399static int tstRTR0TimerCheckShotIntervals(PTSTRTR0TIMERS1 pState, uint64_t uStartNsTS, uint32_t uMin, uint32_t uMax)
400{
401 uint64_t uMaxDelta = 0;
402 uint64_t uMinDelta = UINT64_MAX;
403 uint32_t cBadShots = 0;
404 uint32_t cShots = pState->cShots;
405 uint64_t uPrevTS = uStartNsTS;
406 for (uint32_t iShot = 0; iShot < cShots; iShot++)
407 {
408 uint64_t uThisTS = pState->aShotNsTSes[iShot];
409 uint64_t uDelta = uThisTS - uPrevTS;
410 if (uDelta > uMaxDelta)
411 uMaxDelta = uDelta;
412 if (uDelta < uMinDelta)
413 uMinDelta = uDelta;
414 cBadShots += !(uDelta >= uMin && uDelta <= uMax);
415
416 RTR0TESTR0_CHECK_MSG(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin));
417 RTR0TESTR0_CHECK_MSG(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax));
418
419 uPrevTS = uThisTS;
420 }
421
422 RTR0TestR0Info("uMaxDelta=%llu uMinDelta=%llu\n", uMaxDelta, uMinDelta);
423 return cBadShots;
424}
425
426
427/**
428 * Service request callback function.
429 *
430 * @returns VBox status code.
431 * @param pSession The caller's session.
432 * @param u64Arg 64-bit integer argument.
433 * @param pReqHdr The request header. Input / Output. Optional.
434 */
435DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
436 uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
437{
438 RTR0TESTR0_SRV_REQ_PROLOG_RET(pReqHdr);
439 NOREF(pSession);
440
441 /*
442 * Common parameter and state variables.
443 */
444 uint32_t const cNsSysHz = RTTimerGetSystemGranularity();
445 uint32_t const cNsMaxHighResHz = 10000; /** @todo need API for this */
446 TSTRTR0TIMERS1 State;
447 if ( cNsSysHz < UINT32_C(1000)
448 || cNsSysHz > UINT32_C(1000000000)
449 || cNsMaxHighResHz < UINT32_C(1)
450 || cNsMaxHighResHz > UINT32_C(1000000000))
451 {
452 RTR0TESTR0_CHECK_MSG(cNsSysHz > UINT32_C(1000) && cNsSysHz < UINT32_C(1000000000), ("%u", cNsSysHz));
453 RTR0TESTR0_CHECK_MSG(cNsMaxHighResHz > UINT32_C(1) && cNsMaxHighResHz < UINT32_C(1000000000), ("%u", cNsMaxHighResHz));
454 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
455 return VINF_SUCCESS;
456 }
457
458 /*
459 * The big switch.
460 */
461 switch (uOperation)
462 {
463 RTR0TESTR0_IMPLEMENT_SANITY_CASES();
464 RTR0TESTR0_IMPLEMENT_DEFAULT_CASE(uOperation);
465
466 case TSTRTR0TIMER_ONE_SHOT_BASIC:
467 case TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES:
468 {
469 /* Create a one-shot timer and take one shot. */
470 PRTTIMER pTimer;
471 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
472 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State);
473 if (rc == VERR_NOT_SUPPORTED)
474 {
475 RTR0TestR0Info("one-shot timer are not supported, skipping\n");
476 RTR0TESTR0_SKIP();
477 break;
478 }
479 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
480
481 do /* break loop */
482 {
483 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
484 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
485 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
486 RTThreadSleep(5);
487 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
488
489 /* check that it is restartable. */
490 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
491 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
492 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
493 RTThreadSleep(5);
494 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
495
496 /* check that it respects the timeout value and can be cancelled. */
497 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
498 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
499 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
500 RTThreadSleep(1);
501 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
502
503 /* Check some double starts and stops (shall not assert). */
504 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
505 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
506 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
507 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
508 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VERR_TIMER_SUSPENDED);
509 RTThreadSleep(1);
510 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
511 } while (0);
512 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
513 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
514 break;
515 }
516
517 case TSTRTR0TIMER_ONE_SHOT_RESTART:
518 case TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES:
519 {
520#if !defined(RT_OS_SOLARIS) /* Not expected to work on all hosts. */
521 /* Create a one-shot timer and restart it in the callback handler. */
522 PRTTIMER pTimer;
523 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
524 for (uint32_t iTest = 0; iTest < 2; iTest++)
525 {
526 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State);
527 if (rc == VERR_NOT_SUPPORTED)
528 {
529 RTR0TestR0Info("one-shot timer are not supported, skipping\n");
530 RTR0TESTR0_SKIP();
531 break;
532 }
533 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
534
535 RT_ZERO(State);
536 State.iActionShot = 0;
537 ASMAtomicWriteU32(&State.cShots, State.cShots);
538 do /* break loop */
539 {
540 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
541 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; i++)
542 RTThreadSleep(5);
543 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 2, ("cShots=%u\n", State.cShots));
544 } while (0);
545 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
546 }
547#else
548 RTR0TestR0Info("restarting from callback not supported on this platform\n");
549 RTR0TESTR0_SKIP();
550#endif
551 break;
552 }
553
554 case TSTRTR0TIMER_ONE_SHOT_DESTROY:
555 case TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES:
556 {
557#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_WINDOWS) /* Not expected to work on all hosts. */
558 /* Create a one-shot timer and destroy it in the callback handler. */
559 PRTTIMER pTimer;
560 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
561 for (uint32_t iTest = 0; iTest < 2; iTest++)
562 {
563 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State);
564 if (rc == VERR_NOT_SUPPORTED)
565 {
566 RTR0TestR0Info("one-shot timer are not supported, skipping\n");
567 RTR0TESTR0_SKIP();
568 break;
569 }
570 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
571
572 RT_ZERO(State);
573 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
574 State.iActionShot = 0;
575 ASMAtomicWriteU32(&State.cShots, State.cShots);
576 do /* break loop */
577 {
578 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
579 for (uint32_t i = 0; i < 1000 && (ASMAtomicUoReadU32(&State.cShots) < 1 || State.rc == VERR_IPE_UNINITIALIZED_STATUS); i++)
580 RTThreadSleep(5);
581 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
582 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
583 } while (0);
584 if (RT_FAILURE(State.rc))
585 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
586 }
587#else
588 RTR0TestR0Info("destroying from callback not supported on this platform\n");
589 RTR0TESTR0_SKIP();
590#endif
591 break;
592 }
593
594 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC:
595 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC_HIRES:
596 {
597 PRTTIMER pTimer = NULL;
598 RTCPUSET OnlineSet;
599 RTMpGetOnlineSet(&OnlineSet);
600 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
601 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
602 {
603 RT_ZERO(State);
604 State.iActionShot = 0;
605 State.rc = VINF_SUCCESS;
606 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
607 ASMAtomicWriteU32(&State.cShots, State.cShots);
608
609 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
610 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
611 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackSpecific, &State);
612 if (rc == VERR_NOT_SUPPORTED)
613 {
614 RTR0TestR0Info("one-shot specific timer are not supported, skipping\n");
615 RTR0TESTR0_SKIP();
616 break;
617 }
618 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
619
620 for (uint32_t i = 0; i < 5 && !RTR0TestR0HaveErrors(); i++)
621 {
622 ASMAtomicWriteU32(&State.cShots, 0);
623 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
624 uint64_t cNsElapsed = RTTimeSystemNanoTS();
625 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; j++)
626 RTThreadSleep(5);
627 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
628 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1,
629 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
630 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed ));
631 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
632 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
633 }
634
635 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
636 pTimer = NULL;
637 if (RTR0TestR0HaveErrors())
638 break;
639
640 RTMpGetOnlineSet(&OnlineSet);
641 }
642 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
643 break;
644 }
645
646 case TSTRTR0TIMER_ONE_SHOT_RESOLUTION:
647 case TSTRTR0TIMER_ONE_SHOT_RESOLUTION_HIRES:
648 {
649 /* Just create a timer and do a number of RTTimerStart with a small
650 interval and see how quickly it gets called. */
651 PRTTIMER pTimer;
652 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
653 uint64_t volatile cNsElapsed = 0;
654 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackOneShotElapsed, (void *)&cNsElapsed),
655 VINF_SUCCESS);
656
657 uint32_t cTotal = 0;
658 uint32_t cNsTotal = 0;
659 uint32_t cNsMin = UINT32_MAX;
660 uint32_t cNsMax = 0;
661 for (uint32_t i = 0; i < 200; i++)
662 {
663 cNsElapsed = RTTimeSystemNanoTS();
664 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, RT_NS_1US), VINF_SUCCESS);
665 RTThreadSleep(10);
666 cTotal += 1;
667 cNsTotal += cNsElapsed;
668 if (cNsMin > cNsElapsed)
669 cNsMin = cNsElapsed;
670 if (cNsMax < cNsElapsed)
671 cNsMax = cNsElapsed;
672 }
673 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
674 pTimer = NULL;
675 RTR0TestR0Info("nsMin=%u nsAvg=%u nsMax=%u cTotal=%u\n", cNsMin, cNsTotal / cTotal, cNsMax, cTotal);
676 break;
677 }
678
679 case TSTRTR0TIMER_PERIODIC_BASIC:
680 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES:
681 {
682 /* Create a periodic timer running at 10 HZ. */
683 uint32_t const u10HzAsNs = RT_NS_1SEC / 10;
684 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2;
685 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2;
686 PRTTIMER pTimer;
687 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
688 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, u10HzAsNs, fFlags, tstRTR0TimerCallbackU32Counter, &State),
689 VINF_SUCCESS);
690
691 for (uint32_t iTest = 0; iTest < 2; iTest++)
692 {
693 RT_ZERO(State);
694 State.fPeriodic = true;
695 ASMAtomicWriteU32(&State.cShots, State.cShots);
696
697 uint64_t uStartNsTS = RTTimeSystemNanoTS();
698 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
699 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
700 RTThreadSleep(10);
701 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
702 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 10, ("cShots=%u\n", State.cShots));
703 if (tstRTR0TimerCheckShotIntervals(&State, uStartNsTS, u10HzAsNsMin, u10HzAsNsMax))
704 break;
705 RTThreadSleep(1); /** @todo RTTimerStop doesn't currently make sure the timer callback not is running
706 * before returning on windows, linux (low res) and possible other plaforms. */
707 }
708 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
709 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
710 break;
711 }
712
713 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS:
714 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES:
715 {
716 /* create, start, stop & destroy high res timers a number of times. */
717 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
718 for (uint32_t i = 0; i < 40; i++)
719 {
720 PRTTIMER pTimer;
721 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackU32Counter, &State),
722 VINF_SUCCESS);
723 for (uint32_t j = 0; j < 10; j++)
724 {
725 RT_ZERO(State);
726 State.fPeriodic = true;
727 ASMAtomicWriteU32(&State.cShots, State.cShots); /* ordered, necessary? */
728
729 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
730 for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
731 RTThreadSleep(1);
732 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
733 RTThreadSleep(1); /** @todo RTTimerStop doesn't currently make sure the timer callback not is running
734 * before returning on windows, linux (low res) and possible other plaforms. */
735 }
736 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
737 }
738 break;
739 }
740
741 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL:
742 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES:
743 {
744 /* Initialize the test parameters, using the u64Arg value for selecting variations. */
745 RT_ZERO(State);
746 State.cShots = 0;
747 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
748 State.iActionShot = 42;
749 State.fPeriodic = true;
750 State.u.ChgInt.fDirection = !!(u64Arg & 1);
751 if (uOperation == TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES)
752 {
753 State.u.ChgInt.cNsMaxInterval = RT_MAX(cNsMaxHighResHz * 10, 20000000); /* 10x / 20 ms */
754 State.u.ChgInt.cNsMinInterval = RT_MAX(cNsMaxHighResHz, 10000); /* min / 10 us */
755 }
756 else
757 {
758 State.u.ChgInt.cNsMaxInterval = cNsSysHz * 4;
759 State.u.ChgInt.cNsMinInterval = cNsSysHz;
760 }
761 State.u.ChgInt.cNsChangeStep = (State.u.ChgInt.cNsMaxInterval - State.u.ChgInt.cNsMinInterval) / 10;
762 State.u.ChgInt.cNsCurInterval = State.u.ChgInt.fDirection
763 ? State.u.ChgInt.cNsMaxInterval : State.u.ChgInt.cNsMinInterval;
764 State.u.ChgInt.cStepsBetween = u64Arg & 4 ? 1 : 3;
765 RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMinInterval > 1000, ("%u\n", State.u.ChgInt.cNsMinInterval));
766 RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMaxInterval > State.u.ChgInt.cNsMinInterval, ("max=%u min=%u\n", State.u.ChgInt.cNsMaxInterval, State.u.ChgInt.cNsMinInterval));
767 ASMAtomicWriteU32(&State.cShots, State.cShots);
768
769 /* create the timer and check if RTTimerChangeInterval is supported. */
770 PRTTIMER pTimer;
771 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
772 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackChangeInterval, &State),
773 VINF_SUCCESS);
774 int rc = RTTimerChangeInterval(pTimer, State.u.ChgInt.cNsMinInterval);
775 if (rc == VERR_NOT_SUPPORTED)
776 {
777 RTR0TestR0Info("RTTimerChangeInterval not supported, skipped");
778 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
779 RTR0TESTR0_SKIP();
780 break;
781 }
782
783 /* do the test. */
784 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u64Arg & 2 ? State.u.ChgInt.cNsCurInterval : 0), VINF_SUCCESS);
785 for (uint32_t k = 0;
786 k < 1000
787 && ASMAtomicReadU32(&State.cShots) <= State.iActionShot
788 && State.rc == VERR_IPE_UNINITIALIZED_STATUS;
789 k++)
790 RTThreadSleep(10);
791
792 rc = RTTimerStop(pTimer);
793 RTR0TESTR0_CHECK_MSG_BREAK(rc == VERR_TIMER_SUSPENDED || rc == VINF_SUCCESS, ("rc = %Rrc (RTTimerStop)\n", rc));
794 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
795 break;
796 }
797
798 case TSTRTR0TIMER_PERIODIC_SPECIFIC:
799 case TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES:
800 {
801 PRTTIMER pTimer = NULL;
802 RTCPUSET OnlineSet;
803 RTMpGetOnlineSet(&OnlineSet);
804 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
805 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
806 {
807 RT_ZERO(State);
808 State.iActionShot = 0;
809 State.rc = VINF_SUCCESS;
810 State.fPeriodic = true;
811 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
812 ASMAtomicWriteU32(&State.cShots, State.cShots);
813
814 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
815 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
816 int rc = RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackSpecific, &State);
817 if (rc == VERR_NOT_SUPPORTED)
818 {
819 RTR0TestR0Info("specific timer are not supported, skipping\n");
820 RTR0TESTR0_SKIP();
821 break;
822 }
823 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
824
825 for (uint32_t i = 0; i < 3 && !RTR0TestR0HaveErrors(); i++)
826 {
827 ASMAtomicWriteU32(&State.cShots, 0);
828 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
829 uint64_t cNsElapsed = RTTimeSystemNanoTS();
830 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 8; j++)
831 RTThreadSleep(5);
832 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
833 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
834 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) > 5,
835 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
836 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed));
837 RTThreadSleep(1); /** @todo RTTimerStop doesn't currently make sure the timer callback not is running
838 * before returning on windows, linux (low res) and possible other plaforms. */
839 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
840 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
841 }
842
843 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
844 pTimer = NULL;
845 if (RTR0TestR0HaveErrors())
846 break;
847
848 RTMpGetOnlineSet(&OnlineSet);
849 }
850 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
851 break;
852 }
853
854 case TSTRTR0TIMER_PERIODIC_OMNI:
855 case TSTRTR0TIMER_PERIODIC_OMNI_HIRES:
856 {
857 /* Create a periodic timer running at max host frequency, but no more than 1000 Hz. */
858 uint32_t cNsInterval = cNsSysHz;
859 while (cNsInterval < UINT32_C(1000000))
860 cNsInterval *= 2;
861 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)RTMemAllocZ(sizeof(paStates[0]) * RTCPUSET_MAX_CPUS);
862 RTR0TESTR0_CHECK_MSG_BREAK(paStates, ("%d\n", RTCPUSET_MAX_CPUS));
863
864 PRTTIMER pTimer;
865 uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
866 | RTTIMER_FLAGS_CPU_ALL;
867 int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates);
868 if (rc == VERR_NOT_SUPPORTED)
869 {
870 RTR0TESTR0_SKIP_BREAK();
871 }
872 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
873
874 for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
875 {
876 /* reset the state */
877 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
878 {
879 paStates[iCpu].u64Start = 0;
880 paStates[iCpu].u64Last = 0;
881 ASMAtomicWriteU32(&paStates[iCpu].cTicks, 0);
882 }
883
884 /* run it for 5 seconds. */
885 RTCPUSET OnlineSet;
886 uint64_t uStartNsTS = RTTimeSystemNanoTS();
887 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
888 RTMpGetOnlineSet(&OnlineSet);
889
890 for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT64_C(5000000000); i++)
891 RTThreadSleep(2);
892
893 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
894 uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
895
896 /* Do a min/max on the start and stop times and calculate the test period. */
897 uint64_t u64MinStart = UINT64_MAX;
898 uint64_t u64MaxStop = 0;
899 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
900 {
901 if (paStates[iCpu].u64Start)
902 {
903 if (paStates[iCpu].u64Start < u64MinStart)
904 u64MinStart = paStates[iCpu].u64Start;
905 if (paStates[iCpu].u64Last > u64MaxStop)
906 u64MaxStop = paStates[iCpu].u64Last;
907 }
908 }
909 RTR0TESTR0_CHECK_MSG(u64MinStart < u64MaxStop, ("%llu, %llu", u64MinStart, u64MaxStop));
910 uint64_t cNsElapsed = u64MaxStop - u64MinStart;
911 RTR0TESTR0_CHECK_MSG(cNsElapsed <= cNsElapsedX + 100000, ("%llu, %llu", cNsElapsed, cNsElapsedX)); /* the fudge factor is time drift */
912 uint32_t cAvgTicks = cNsElapsed / cNsInterval + 1;
913
914 /* Check tick counts. ASSUMES no cpu on- or offlining.
915 This only catches really bad stuff. */
916 uint32_t cMargin = TSTRTR0TIMER_IS_HIRES(uOperation) ? 10 : 5; /* Allow a wider deviation for the non hires timers. */
917 uint32_t cMinTicks = cAvgTicks - cAvgTicks / cMargin;
918 uint32_t cMaxTicks = cAvgTicks + cAvgTicks / cMargin + 1;
919 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
920 if (paStates[iCpu].cTicks)
921 {
922 RTR0TESTR0_CHECK_MSG(RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
923 RTR0TESTR0_CHECK_MSG(paStates[iCpu].cTicks <= cMaxTicks && paStates[iCpu].cTicks >= cMinTicks,
924 ("min=%u, ticks=%u, avg=%u max=%u, iCpu=%u, iCpuCurr=%u, interval=%'u, elapsed=%'llu/%'llu\n",
925 cMinTicks, paStates[iCpu].cTicks, cAvgTicks, cMaxTicks, iCpu,
926 RTMpCpuIdToSetIndex(RTMpCpuId()),
927 cNsInterval, cNsElapsed, cNsElapsedX));
928 }
929 else
930 RTR0TESTR0_CHECK_MSG(!RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
931 }
932
933 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
934 RTMemFree(paStates);
935 break;
936 }
937
938
939 case TSTRTR0TIMER_LATENCY_OMNI:
940 case TSTRTR0TIMER_LATENCY_OMNI_HIRES:
941 {
942 /*
943 * Create a periodic timer running at max host frequency, but no more than 1000 Hz.
944 * Unless it's a high resolution timer, which we try at double the rate.
945 * Windows seems to limit the highres stuff to around 500-600 us interval.
946 */
947 PRTTIMER pTimer;
948 uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
949 | RTTIMER_FLAGS_CPU_ALL;
950 uint32_t const cNsMinInterval = TSTRTR0TIMER_IS_HIRES(uOperation) ? cNsMaxHighResHz : RT_NS_1MS;
951 uint32_t cNsInterval = TSTRTR0TIMER_IS_HIRES(uOperation) ? cNsSysHz / 2 : cNsSysHz;
952 while (cNsInterval < cNsMinInterval)
953 cNsInterval *= 2;
954 int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackLatencyOmni, NULL);
955 if (rc == VERR_NOT_SUPPORTED)
956 {
957 RTR0TESTR0_SKIP_BREAK();
958 }
959 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
960
961 /*
962 * Reset the state and run the test for 4 seconds.
963 */
964 RT_ZERO(g_aOmniLatency);
965
966 RTCPUSET OnlineSet;
967 uint64_t uStartNsTS = RTTimeSystemNanoTS();
968 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
969 RTMpGetOnlineSet(&OnlineSet);
970
971 for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT64_C(4000000000); i++)
972 RTThreadSleep(2);
973
974 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
975
976 /*
977 * Process the result.
978 */
979 int32_t cNsLow = cNsInterval / 4 * 3; /* 75% */
980 int32_t cNsHigh = cNsInterval / 4 * 5; /* 125% */
981 uint32_t cTotal = 0;
982 uint32_t cLow = 0;
983 uint32_t cHigh = 0;
984 for (uint32_t iCpu = 0; iCpu < RT_ELEMENTS(g_aOmniLatency); iCpu++)
985 {
986 uint32_t cSamples = g_aOmniLatency[iCpu].cSamples;
987 if (cSamples > 1)
988 {
989 cTotal += cSamples - 1;
990 for (uint32_t iSample = 1; iSample < cSamples; iSample++)
991 {
992 int64_t cNsDelta = g_aOmniLatency[iCpu].aSamples[iSample].uNanoTs
993 - g_aOmniLatency[iCpu].aSamples[iSample - 1].uNanoTs;
994 if (cNsDelta < cNsLow)
995 cLow++;
996 else if (cNsDelta > cNsHigh)
997 cHigh++;
998 }
999 }
1000 }
1001 RTR0TestR0Info("125%%: %u; 75%%: %u; total: %u", cHigh, cLow, cTotal);
1002 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
1003#if 1
1004 RTR0TestR0Info("cNsSysHz=%u cNsInterval=%RU32 cNsLow=%d cNsHigh=%d", cNsSysHz, cNsInterval, cNsLow, cNsHigh);
1005 if (TSTRTR0TIMER_IS_HIRES(uOperation))
1006 RTR0TestR0Info("RTTimerCanDoHighResolution -> %d", RTTimerCanDoHighResolution());
1007 for (uint32_t iSample = 1; iSample < 6; iSample++)
1008 RTR0TestR0Info("%RU64/%#RU64",
1009 g_aOmniLatency[0].aSamples[iSample].uNanoTs - g_aOmniLatency[0].aSamples[iSample - 1].uNanoTs,
1010 g_aOmniLatency[0].aSamples[iSample].uTsc - g_aOmniLatency[0].aSamples[iSample - 1].uTsc);
1011#endif
1012 break;
1013 }
1014
1015 }
1016
1017 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
1018 /* The error indicator is the '!' in the message buffer. */
1019 return VINF_SUCCESS;
1020}
1021
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette