VirtualBox

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

Last change on this file since 47553 was 47553, checked in by vboxsync, 12 years ago

Fix R0 timer testcase on darwin and make it possible to skip R0 tests when the feature is not supported (for the timer testcase it is the RTTIMER_FLAGS_CPU_ALL flag which is not supported on darwin)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.9 KB
Line 
1/* $Id: tstRTR0Timer.cpp 47553 2013-08-06 10:03:55Z vboxsync $ */
2/** @file
3 * IPRT R0 Testcase - Timers.
4 */
5
6/*
7 * Copyright (C) 2009-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/timer.h>
32
33#include <iprt/asm.h>
34#include <iprt/cpuset.h>
35#include <iprt/err.h>
36#include <iprt/mem.h>
37#include <iprt/mp.h>
38#include <iprt/param.h>
39#include <iprt/string.h>
40#include <iprt/thread.h>
41#include <iprt/time.h>
42#include <VBox/sup.h>
43#include "tstRTR0Timer.h"
44#include "tstRTR0Common.h"
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50typedef struct
51{
52 /** Array of nano second timestamp of the first few shots. */
53 uint64_t volatile aShotNsTSes[10];
54 /** The number of shots. */
55 uint32_t volatile cShots;
56 /** The shot at which action is to be taken. */
57 uint32_t iActionShot;
58 /** The RC of whatever operation performed in the handler. */
59 int volatile rc;
60 /** Set if it's a periodic test. */
61 bool fPeriodic;
62 /** Test specific stuff. */
63 union
64 {
65 /** tstRTR0TimerCallbackU32ChangeInterval parameters. */
66 struct
67 {
68 /** The interval change step. */
69 uint32_t cNsChangeStep;
70 /** The current timer interval. */
71 uint32_t cNsCurInterval;
72 /** The minimum interval. */
73 uint32_t cNsMinInterval;
74 /** The maximum interval. */
75 uint32_t cNsMaxInterval;
76 /** Direction flag; false = decrement, true = increment. */
77 bool fDirection;
78 /** The number of steps between each change. */
79 uint8_t cStepsBetween;
80 } ChgInt;
81 /** tstRTR0TimerCallbackSpecific parameters. */
82 struct
83 {
84 /** The expected CPU. */
85 RTCPUID idCpu;
86 /** Set if this failed. */
87 bool fFailed;
88 } Specific;
89 } u;
90} TSTRTR0TIMERS1;
91typedef TSTRTR0TIMERS1 *PTSTRTR0TIMERS1;
92
93
94/**
95 * Per cpu state for an omni timer test.
96 */
97typedef struct TSTRTR0TIMEROMNI1
98{
99 /** When we started receiving timer callbacks on this CPU. */
100 uint64_t u64Start;
101 /** When we received the last tick on this timer. */
102 uint64_t u64Last;
103 /** The number of ticks received on this CPU. */
104 uint32_t volatile cTicks;
105 uint32_t u32Padding;
106} TSTRTR0TIMEROMNI1;
107typedef TSTRTR0TIMEROMNI1 *PTSTRTR0TIMEROMNI1;
108
109
110/**
111 * Callback which increments a 32-bit counter.
112 *
113 * @param pTimer The timer.
114 * @param iTick The current tick.
115 * @param pvUser The user argument.
116 */
117static DECLCALLBACK(void) tstRTR0TimerCallbackOmni(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
118{
119 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)pvUser;
120 RTCPUID idCpu = RTMpCpuId();
121 uint32_t iCpu = RTMpCpuIdToSetIndex(idCpu);
122 NOREF(pTimer);
123
124 RTR0TESTR0_CHECK_MSG(iCpu < RTCPUSET_MAX_CPUS, ("iCpu=%d idCpu=%u\n", iCpu, idCpu));
125 if (iCpu < RTCPUSET_MAX_CPUS)
126 {
127 uint32_t iCountedTick = ASMAtomicIncU32(&paStates[iCpu].cTicks);
128 RTR0TESTR0_CHECK_MSG(iCountedTick == iTick,
129 ("iCountedTick=%u iTick=%u iCpu=%d idCpu=%u\n", iCountedTick, iTick, iCpu, idCpu));
130 paStates[iCpu].u64Last = RTTimeSystemNanoTS();
131 if (!paStates[iCpu].u64Start)
132 {
133 paStates[iCpu].u64Start = paStates[iCpu].u64Last;
134 RTR0TESTR0_CHECK_MSG(iCountedTick == 1, ("iCountedTick=%u iCpu=%d idCpu=%u\n", iCountedTick, iCpu, idCpu));
135 }
136 }
137}
138
139
140/**
141 * Callback which increments a 32-bit counter.
142 *
143 * @param pTimer The timer.
144 * @param iTick The current tick.
145 * @param pvUser The user argument.
146 */
147static DECLCALLBACK(void) tstRTR0TimerCallbackSpecific(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
148{
149 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
150 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
151 NOREF(pTimer);
152
153 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
154 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
155
156 RTCPUID idCpu = RTMpCpuId();
157 if (pState->u.Specific.idCpu != idCpu)
158 pState->u.Specific.fFailed = true;
159 RTR0TESTR0_CHECK_MSG(pState->u.Specific.idCpu == idCpu, ("idCpu=%u, expected %u\n", idCpu, pState->u.Specific.idCpu));
160
161 if (pState->fPeriodic)
162 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
163 else
164 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
165}
166
167
168/**
169 * Callback which changes the interval at each invocation.
170 *
171 * The changes are governed by TSTRTR0TIMERS1::ChangeInterval. The callback
172 * calls RTTimerStop at iActionShot.
173 *
174 * @param pTimer The timer.
175 * @param iTick The current tick.
176 * @param pvUser The user argument.
177 */
178static DECLCALLBACK(void) tstRTR0TimerCallbackChangeInterval(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
179{
180 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
181 uint32_t iShot = ASMAtomicIncU32(&pState->cShots) - 1;
182
183 if (iShot < RT_ELEMENTS(pState->aShotNsTSes))
184 pState->aShotNsTSes[iShot] = RTTimeSystemNanoTS();
185 if (pState->fPeriodic)
186 RTR0TESTR0_CHECK_MSG(iShot + 1 == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
187 else
188 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
189
190 if (!(iShot % pState->u.ChgInt.cStepsBetween))
191 {
192 if (pState->u.ChgInt.fDirection)
193 {
194 pState->u.ChgInt.cNsCurInterval += pState->u.ChgInt.cNsChangeStep;
195 if ( pState->u.ChgInt.cNsCurInterval > pState->u.ChgInt.cNsMaxInterval
196 || pState->u.ChgInt.cNsCurInterval < pState->u.ChgInt.cNsMinInterval
197 || !pState->u.ChgInt.cNsCurInterval)
198 {
199 pState->u.ChgInt.cNsCurInterval = pState->u.ChgInt.cNsMaxInterval;
200 pState->u.ChgInt.fDirection = false;
201 }
202 }
203 else
204 {
205 pState->u.ChgInt.cNsCurInterval -= pState->u.ChgInt.cNsChangeStep;
206 if ( pState->u.ChgInt.cNsCurInterval < pState->u.ChgInt.cNsMinInterval
207 || pState->u.ChgInt.cNsCurInterval > pState->u.ChgInt.cNsMaxInterval
208 || pState->u.ChgInt.cNsCurInterval)
209 {
210 pState->u.ChgInt.cNsCurInterval = pState->u.ChgInt.cNsMinInterval;
211 pState->u.ChgInt.fDirection = true;
212 }
213 }
214
215 RTR0TESTR0_CHECK_RC(RTTimerChangeInterval(pTimer, pState->u.ChgInt.cNsCurInterval), VINF_SUCCESS);
216 }
217
218 if (iShot == pState->iActionShot)
219 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStop(pTimer), VINF_SUCCESS);
220}
221
222
223/**
224 * Callback which increments destroy the timer when it fires.
225 *
226 * @param pTimer The timer.
227 * @param iTick The current tick.
228 * @param pvUser The user argument.
229 */
230static DECLCALLBACK(void) tstRTR0TimerCallbackDestroyOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
231{
232 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
233 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
234
235 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
236 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
237 if (pState->fPeriodic)
238 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
239 else
240 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
241
242 if (iShot == pState->iActionShot + 1)
243 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerDestroy(pTimer), VINF_SUCCESS);
244}
245
246
247/**
248 * Callback which increments restarts a timer once.
249 *
250 * @param pTimer The timer.
251 * @param iTick The current tick.
252 * @param pvUser The user argument.
253 */
254static DECLCALLBACK(void) tstRTR0TimerCallbackRestartOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
255{
256 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
257 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
258
259 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
260 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
261 if (pState->fPeriodic)
262 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
263 else
264 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
265
266 if (iShot == pState->iActionShot + 1)
267 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStart(pTimer, 10000000 /* 10ms */), VINF_SUCCESS);
268}
269
270
271/**
272 * Callback which increments a 32-bit counter.
273 *
274 * @param pTimer The timer.
275 * @param iTick The current tick.
276 * @param pvUser The user argument.
277 */
278static DECLCALLBACK(void) tstRTR0TimerCallbackU32Counter(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
279{
280 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
281 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
282 NOREF(pTimer);
283
284 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
285 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
286 if (pState->fPeriodic)
287 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
288 else
289 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
290}
291
292
293#ifdef SOME_UNUSED_FUNCTION
294/**
295 * Checks that the interval between two timer shots are within the specified
296 * range.
297 *
298 * @returns 0 if ok, 1 if bad.
299 * @param iShot The shot number (for bitching).
300 * @param uPrevTS The time stamp of the previous shot (ns).
301 * @param uThisTS The timer stamp of this shot (ns).
302 * @param uMin The minimum interval (ns).
303 * @param uMax The maximum interval (ns).
304 */
305static int tstRTR0TimerCheckShotInterval(uint32_t iShot, uint64_t uPrevTS, uint64_t uThisTS, uint32_t uMin, uint32_t uMax)
306{
307 uint64_t uDelta = uThisTS - uPrevTS;
308 RTR0TESTR0_CHECK_MSG_RET(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin), 1);
309 RTR0TESTR0_CHECK_MSG_RET(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax), 1);
310 return 0;
311}
312#endif
313
314
315/**
316 * Checks that the interval between timer shots are within a certain range.
317 *
318 * @returns Number of violations (i.e. 0 is ok).
319 * @param pState The state.
320 * @param uStartNsTS The start time stamp (ns).
321 * @param uMin The minimum interval (ns).
322 * @param uMax The maximum interval (ns).
323 */
324static int tstRTR0TimerCheckShotIntervals(PTSTRTR0TIMERS1 pState, uint64_t uStartNsTS, uint32_t uMin, uint32_t uMax)
325{
326 uint64_t uMaxDelta = 0;
327 uint64_t uMinDelta = UINT64_MAX;
328 uint32_t cBadShots = 0;
329 uint32_t cShots = pState->cShots;
330 uint64_t uPrevTS = uStartNsTS;
331 for (uint32_t iShot = 0; iShot < cShots; iShot++)
332 {
333 uint64_t uThisTS = pState->aShotNsTSes[iShot];
334 uint64_t uDelta = uThisTS - uPrevTS;
335 if (uDelta > uMaxDelta)
336 uMaxDelta = uDelta;
337 if (uDelta < uMinDelta)
338 uMinDelta = uDelta;
339 cBadShots += !(uDelta >= uMin && uDelta <= uMax);
340
341 RTR0TESTR0_CHECK_MSG(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin));
342 RTR0TESTR0_CHECK_MSG(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax));
343
344 uPrevTS = uThisTS;
345 }
346
347 RTR0TestR0Info("uMaxDelta=%llu uMinDelta=%llu\n", uMaxDelta, uMinDelta);
348 return cBadShots;
349}
350
351
352/**
353 * Service request callback function.
354 *
355 * @returns VBox status code.
356 * @param pSession The caller's session.
357 * @param u64Arg 64-bit integer argument.
358 * @param pReqHdr The request header. Input / Output. Optional.
359 */
360DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
361 uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
362{
363 RTR0TESTR0_SRV_REQ_PROLOG_RET(pReqHdr);
364 NOREF(pSession);
365
366 /*
367 * Common parameter and state variables.
368 */
369 uint32_t const cNsSysHz = RTTimerGetSystemGranularity();
370 uint32_t const cNsMaxHighResHz = 10000; /** @todo need API for this */
371 TSTRTR0TIMERS1 State;
372 if ( cNsSysHz < UINT32_C(1000)
373 || cNsSysHz > UINT32_C(1000000000)
374 || cNsMaxHighResHz < UINT32_C(1)
375 || cNsMaxHighResHz > UINT32_C(1000000000))
376 {
377 RTR0TESTR0_CHECK_MSG(cNsSysHz > UINT32_C(1000) && cNsSysHz < UINT32_C(1000000000), ("%u", cNsSysHz));
378 RTR0TESTR0_CHECK_MSG(cNsMaxHighResHz > UINT32_C(1) && cNsMaxHighResHz < UINT32_C(1000000000), ("%u", cNsMaxHighResHz));
379 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
380 return VINF_SUCCESS;
381 }
382
383 /*
384 * The big switch.
385 */
386 switch (uOperation)
387 {
388 RTR0TESTR0_IMPLEMENT_SANITY_CASES();
389 RTR0TESTR0_IMPLEMENT_DEFAULT_CASE(uOperation);
390
391 case TSTRTR0TIMER_ONE_SHOT_BASIC:
392 case TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES:
393 {
394 /* Create a one-shot timer and take one shot. */
395 PRTTIMER pTimer;
396 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
397 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State),
398 VINF_SUCCESS);
399
400 do /* break loop */
401 {
402 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
403 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
404 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
405 RTThreadSleep(5);
406 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
407
408 /* check that it is restartable. */
409 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
410 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
411 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
412 RTThreadSleep(5);
413 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
414
415 /* check that it respects the timeout value and can be cancelled. */
416 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
417 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
418 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
419 RTThreadSleep(1);
420 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
421
422 /* Check some double starts and stops (shall not assert). */
423 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
424 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
425 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
426 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
427 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VERR_TIMER_SUSPENDED);
428 RTThreadSleep(1);
429 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
430 } while (0);
431 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
432 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
433 break;
434 }
435
436#if 1 /* might have to disable this for some host... */
437 case TSTRTR0TIMER_ONE_SHOT_RESTART:
438 case TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES:
439 {
440 /* Create a one-shot timer and restart it in the callback handler. */
441 PRTTIMER pTimer;
442 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
443 for (uint32_t iTest = 0; iTest < 2; iTest++)
444 {
445 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State),
446 VINF_SUCCESS);
447
448 RT_ZERO(State);
449 State.iActionShot = 0;
450 ASMAtomicWriteU32(&State.cShots, State.cShots);
451 do /* break loop */
452 {
453 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
454 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; i++)
455 RTThreadSleep(5);
456 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 2, ("cShots=%u\n", State.cShots));
457 } while (0);
458 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
459 }
460 break;
461 }
462#endif
463
464#if 1 /* might have to disable this for some host... */
465 case TSTRTR0TIMER_ONE_SHOT_DESTROY:
466 case TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES:
467 {
468 /* Create a one-shot timer and destroy it in the callback handler. */
469 PRTTIMER pTimer;
470 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
471 for (uint32_t iTest = 0; iTest < 2; iTest++)
472 {
473 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State),
474 VINF_SUCCESS);
475
476 RT_ZERO(State);
477 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
478 State.iActionShot = 0;
479 ASMAtomicWriteU32(&State.cShots, State.cShots);
480 do /* break loop */
481 {
482 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
483 for (uint32_t i = 0; i < 1000 && (ASMAtomicUoReadU32(&State.cShots) < 1 || State.rc == VERR_IPE_UNINITIALIZED_STATUS); i++)
484 RTThreadSleep(5);
485 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
486 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
487 } while (0);
488 if (RT_FAILURE(State.rc))
489 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
490 }
491 break;
492 }
493#endif
494
495 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC:
496 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC_HIRES:
497 {
498 PRTTIMER pTimer = NULL;
499 RTCPUSET OnlineSet;
500 RTMpGetOnlineSet(&OnlineSet);
501 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
502 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
503 {
504 RT_ZERO(State);
505 State.iActionShot = 0;
506 State.rc = VINF_SUCCESS;
507 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
508 ASMAtomicWriteU32(&State.cShots, State.cShots);
509
510 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
511 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
512 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackSpecific, &State);
513 if (rc == VERR_NOT_SUPPORTED)
514 {
515 RTR0TestR0Info("specific timer are not supported, skipping\n");
516 break;
517 }
518 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
519
520 for (uint32_t i = 0; i < 5 && !RTR0TestR0HaveErrors(); i++)
521 {
522 ASMAtomicWriteU32(&State.cShots, 0);
523 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
524 uint64_t cNsElapsed = RTTimeSystemNanoTS();
525 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; j++)
526 RTThreadSleep(5);
527 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
528 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1,
529 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
530 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed ));
531 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
532 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
533 }
534
535 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
536 pTimer = NULL;
537 if (RTR0TestR0HaveErrors())
538 break;
539
540 RTMpGetOnlineSet(&OnlineSet);
541 }
542 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
543 break;
544 }
545
546 case TSTRTR0TIMER_PERIODIC_BASIC:
547 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES:
548 {
549 /* Create a periodic timer running at 10 HZ. */
550 uint32_t const u10HzAsNs = 100000000;
551 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2;
552 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2;
553 PRTTIMER pTimer;
554 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
555 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, u10HzAsNs, fFlags, tstRTR0TimerCallbackU32Counter, &State),
556 VINF_SUCCESS);
557
558 for (uint32_t iTest = 0; iTest < 2; iTest++)
559 {
560 RT_ZERO(State);
561 State.fPeriodic = true;
562 ASMAtomicWriteU32(&State.cShots, State.cShots);
563
564 uint64_t uStartNsTS = RTTimeSystemNanoTS();
565 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
566 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
567 RTThreadSleep(10);
568 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
569 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 10, ("cShots=%u\n", State.cShots));
570 if (tstRTR0TimerCheckShotIntervals(&State, uStartNsTS, u10HzAsNsMin, u10HzAsNsMax))
571 break;
572 }
573 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
574 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
575 break;
576 }
577
578 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS:
579 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES:
580 {
581 /* create, start, stop & destroy high res timers a number of times. */
582 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
583 for (uint32_t i = 0; i < 40; i++)
584 {
585 PRTTIMER pTimer;
586 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackU32Counter, &State),
587 VINF_SUCCESS);
588 for (uint32_t j = 0; j < 10; j++)
589 {
590 RT_ZERO(State);
591 State.fPeriodic = true;
592 ASMAtomicWriteU32(&State.cShots, State.cShots); /* ordered, necessary? */
593
594 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
595 for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
596 RTThreadSleep(1);
597 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
598 }
599 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
600 }
601 break;
602 }
603
604 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL:
605 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES:
606 {
607 /* Initialize the test parameters, using the u64Arg value for selecting variations. */
608 RT_ZERO(State);
609 State.cShots = 0;
610 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
611 State.iActionShot = 42;
612 State.fPeriodic = true;
613 State.u.ChgInt.fDirection = !!(u64Arg & 1);
614 if (uOperation == TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES)
615 {
616 State.u.ChgInt.cNsMaxInterval = RT_MAX(cNsMaxHighResHz * 10, 20000000); /* 10x / 20 ms */
617 State.u.ChgInt.cNsMinInterval = RT_MAX(cNsMaxHighResHz, 10000); /* min / 10 us */
618 }
619 else
620 {
621 State.u.ChgInt.cNsMaxInterval = cNsSysHz * 4;
622 State.u.ChgInt.cNsMinInterval = cNsSysHz;
623 }
624 State.u.ChgInt.cNsChangeStep = (State.u.ChgInt.cNsMaxInterval - State.u.ChgInt.cNsMinInterval) / 10;
625 State.u.ChgInt.cNsCurInterval = State.u.ChgInt.fDirection
626 ? State.u.ChgInt.cNsMaxInterval : State.u.ChgInt.cNsMinInterval;
627 State.u.ChgInt.cStepsBetween = u64Arg & 4 ? 1 : 3;
628 RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMinInterval > 1000, ("%u\n", State.u.ChgInt.cNsMinInterval));
629 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));
630 ASMAtomicWriteU32(&State.cShots, State.cShots);
631
632 /* create the timer and check if RTTimerChangeInterval is supported. */
633 PRTTIMER pTimer;
634 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
635 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackChangeInterval, &State),
636 VINF_SUCCESS);
637 int rc = RTTimerChangeInterval(pTimer, State.u.ChgInt.cNsMinInterval);
638 if (rc == VERR_NOT_SUPPORTED)
639 {
640 RTR0TestR0Info("RTTimerChangeInterval not supported, skipped");
641 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
642 break;
643 }
644
645 /* do the test. */
646 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u64Arg & 2 ? State.u.ChgInt.cNsCurInterval : 0), VINF_SUCCESS);
647 for (uint32_t k = 0;
648 k < 1000
649 && ASMAtomicReadU32(&State.cShots) <= State.iActionShot
650 && State.rc == VERR_IPE_UNINITIALIZED_STATUS;
651 k++)
652 RTThreadSleep(10);
653
654 rc = RTTimerStop(pTimer);
655 RTR0TESTR0_CHECK_MSG_BREAK(rc == VERR_TIMER_SUSPENDED || rc == VINF_SUCCESS, ("rc = %Rrc (RTTimerStop)\n", rc));
656 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
657 break;
658 }
659
660 case TSTRTR0TIMER_PERIODIC_SPECIFIC:
661 case TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES:
662 {
663 PRTTIMER pTimer = NULL;
664 RTCPUSET OnlineSet;
665 RTMpGetOnlineSet(&OnlineSet);
666 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
667 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
668 {
669 RT_ZERO(State);
670 State.iActionShot = 0;
671 State.rc = VINF_SUCCESS;
672 State.fPeriodic = true;
673 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
674 ASMAtomicWriteU32(&State.cShots, State.cShots);
675
676 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
677 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
678 int rc = RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackSpecific, &State);
679 if (rc == VERR_NOT_SUPPORTED)
680 {
681 RTR0TestR0Info("specific timer are not supported, skipping\n");
682 break;
683 }
684 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
685
686 for (uint32_t i = 0; i < 3 && !RTR0TestR0HaveErrors(); i++)
687 {
688 ASMAtomicWriteU32(&State.cShots, 0);
689 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
690 uint64_t cNsElapsed = RTTimeSystemNanoTS();
691 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 8; j++)
692 RTThreadSleep(5);
693 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
694 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
695 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) > 5,
696 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
697 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed));
698 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
699 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
700 }
701
702 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
703 pTimer = NULL;
704 if (RTR0TestR0HaveErrors())
705 break;
706
707 RTMpGetOnlineSet(&OnlineSet);
708 }
709 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
710 break;
711 }
712
713 case TSTRTR0TIMER_PERIODIC_OMNI:
714 case TSTRTR0TIMER_PERIODIC_OMNI_HIRES:
715 {
716 /* Create a periodic timer running at max host frequency, but no more than 1000 Hz. */
717 uint32_t cNsInterval = cNsSysHz;
718 while (cNsInterval < UINT32_C(1000000))
719 cNsInterval *= 2;
720 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)RTMemAllocZ(sizeof(paStates[0]) * RTCPUSET_MAX_CPUS);
721 RTR0TESTR0_CHECK_MSG_BREAK(paStates, ("%d\n", RTCPUSET_MAX_CPUS));
722
723 PRTTIMER pTimer;
724 uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
725 | RTTIMER_FLAGS_CPU_ALL;
726 int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates);
727 if (rc == VERR_NOT_SUPPORTED)
728 RTR0TESTR0_SKIP_BREAK();
729 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
730
731 for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
732 {
733 /* reset the state */
734 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
735 {
736 paStates[iCpu].u64Start = 0;
737 paStates[iCpu].u64Last = 0;
738 ASMAtomicWriteU32(&paStates[iCpu].cTicks, 0);
739 }
740
741 /* run it for 1 second. */
742 RTCPUSET OnlineSet;
743 uint64_t uStartNsTS = RTTimeSystemNanoTS();
744 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
745 RTMpGetOnlineSet(&OnlineSet);
746
747 for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT32_C(1000000000); i++)
748 RTThreadSleep(2);
749
750 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
751 uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
752
753 /* Do a min/max on the start and stop times and calculate the test period. */
754 uint64_t u64MinStart = UINT64_MAX;
755 uint64_t u64MaxStop = 0;
756 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
757 {
758 if (paStates[iCpu].u64Start)
759 {
760 if (paStates[iCpu].u64Start < u64MinStart)
761 u64MinStart = paStates[iCpu].u64Start;
762 if (paStates[iCpu].u64Last > u64MaxStop)
763 u64MaxStop = paStates[iCpu].u64Last;
764 }
765 }
766 RTR0TESTR0_CHECK_MSG(u64MinStart < u64MaxStop, ("%llu, %llu", u64MinStart, u64MaxStop));
767 uint64_t cNsElapsed = u64MaxStop - u64MinStart;
768 RTR0TESTR0_CHECK_MSG(cNsElapsed <= cNsElapsedX + 100000, ("%llu, %llu", cNsElapsed, cNsElapsedX)); /* the fudge factor is time drift */
769 uint32_t cAvgTicks = cNsElapsed / cNsInterval + 1;
770
771 /* Check tick counts. ASSUMES no cpu on- or offlining.
772 This only catches really bad stuff. */
773 uint32_t cMinTicks = cAvgTicks - cAvgTicks / 10;
774 uint32_t cMaxTicks = cAvgTicks + cAvgTicks / 10 + 1;
775 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
776 if (paStates[iCpu].cTicks)
777 {
778 RTR0TESTR0_CHECK_MSG(RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
779 RTR0TESTR0_CHECK_MSG(paStates[iCpu].cTicks <= cMaxTicks && paStates[iCpu].cTicks >= cMinTicks,
780 ("min=%u, ticks=%u, avg=%u max=%u, iCpu=%u, interval=%'u, elapsed=%'llu/%'llu\n",
781 cMinTicks, paStates[iCpu].cTicks, cAvgTicks, cMaxTicks, iCpu,
782 cNsInterval, cNsElapsed, cNsElapsedX));
783 }
784 else
785 RTR0TESTR0_CHECK_MSG(!RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
786 }
787
788 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
789 RTMemFree(paStates);
790 break;
791 }
792 }
793
794 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
795 /* The error indicator is the '!' in the message buffer. */
796 return VINF_SUCCESS;
797}
798
Note: See TracBrowser for help on using the repository browser.

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