VirtualBox

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

Last change on this file since 39872 was 39083, checked in by vboxsync, 13 years ago

IPRT: -Wunused-parameter.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.1 KB
Line 
1/* $Id: tstRTR0Timer.cpp 39083 2011-10-22 00:28:46Z vboxsync $ */
2/** @file
3 * IPRT R0 Testcase - Timers.
4 */
5
6/*
7 * Copyright (C) 2009-2010 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);
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);
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);
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);
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 do /* break loop */
451 {
452 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
453 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; i++)
454 RTThreadSleep(5);
455 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 2, ("cShots=%u\n", State.cShots));
456 } while (0);
457 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
458 }
459 break;
460 }
461#endif
462
463#if 1 /* might have to disable this for some host... */
464 case TSTRTR0TIMER_ONE_SHOT_DESTROY:
465 case TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES:
466 {
467 /* Create a one-shot timer and destroy it in the callback handler. */
468 PRTTIMER pTimer;
469 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
470 for (uint32_t iTest = 0; iTest < 2; iTest++)
471 {
472 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State),
473 VINF_SUCCESS);
474
475 RT_ZERO(State);
476 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
477 State.iActionShot = 0;
478 do /* break loop */
479 {
480 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
481 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; i++)
482 RTThreadSleep(5);
483 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
484 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
485 } while (0);
486 if (RT_FAILURE(State.rc))
487 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
488 }
489 break;
490 }
491#endif
492
493 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC:
494 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC_HIRES:
495 {
496 PRTTIMER pTimer = NULL;
497 RTCPUSET OnlineSet;
498 RTMpGetOnlineSet(&OnlineSet);
499 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
500 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
501 {
502 RT_ZERO(State);
503 State.iActionShot = 0;
504 State.rc = VINF_SUCCESS;
505 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
506
507 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
508 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
509 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackSpecific, &State);
510 if (rc == VERR_NOT_SUPPORTED)
511 {
512 RTR0TestR0Info("specific timer are not supported, skipping\n");
513 break;
514 }
515 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
516
517 for (uint32_t i = 0; i < 5 && !RTR0TestR0HaveErrors(); i++)
518 {
519 ASMAtomicWriteU32(&State.cShots, 0);
520 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
521 uint64_t cNsElapsed = RTTimeSystemNanoTS();
522 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; j++)
523 RTThreadSleep(5);
524 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
525 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1,
526 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
527 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed ));
528 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
529 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
530 }
531
532 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
533 pTimer = NULL;
534 if (RTR0TestR0HaveErrors())
535 break;
536
537 RTMpGetOnlineSet(&OnlineSet);
538 }
539 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
540 break;
541 }
542
543 case TSTRTR0TIMER_PERIODIC_BASIC:
544 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES:
545 {
546 /* Create a periodic timer running at 10 HZ. */
547 uint32_t const u10HzAsNs = 100000000;
548 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2;
549 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2;
550 PRTTIMER pTimer;
551 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
552 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, u10HzAsNs, fFlags, tstRTR0TimerCallbackU32Counter, &State),
553 VINF_SUCCESS);
554
555 for (uint32_t iTest = 0; iTest < 2; iTest++)
556 {
557 RT_ZERO(State);
558 State.fPeriodic = true;
559 uint64_t uStartNsTS = RTTimeSystemNanoTS();
560 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
561 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
562 RTThreadSleep(10);
563 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
564 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 10, ("cShots=%u\n", State.cShots));
565 if (tstRTR0TimerCheckShotIntervals(&State, uStartNsTS, u10HzAsNsMin, u10HzAsNsMax))
566 break;
567 }
568 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
569 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
570 break;
571 }
572
573 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS:
574 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES:
575 {
576 /* create, start, stop & destroy high res timers a number of times. */
577 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
578 for (uint32_t i = 0; i < 40; i++)
579 {
580 PRTTIMER pTimer;
581 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackU32Counter, &State),
582 VINF_SUCCESS);
583 for (uint32_t j = 0; j < 10; j++)
584 {
585 RT_ZERO(State);
586 State.fPeriodic = true;
587 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
588 for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
589 RTThreadSleep(1);
590 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
591 }
592 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
593 }
594 break;
595 }
596
597 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL:
598 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES:
599 {
600 /* Initialize the test parameters, using the u64Arg value for selecting variations. */
601 RT_ZERO(State);
602 State.cShots = 0;
603 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
604 State.iActionShot = 42;
605 State.fPeriodic = true;
606 State.u.ChgInt.fDirection = !!(u64Arg & 1);
607 if (uOperation == TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES)
608 {
609 State.u.ChgInt.cNsMaxInterval = RT_MAX(cNsMaxHighResHz * 10, 20000000); /* 10x / 20 ms */
610 State.u.ChgInt.cNsMinInterval = RT_MAX(cNsMaxHighResHz, 10000); /* min / 10 us */
611 }
612 else
613 {
614 State.u.ChgInt.cNsMaxInterval = cNsSysHz * 4;
615 State.u.ChgInt.cNsMinInterval = cNsSysHz;
616 }
617 State.u.ChgInt.cNsChangeStep = (State.u.ChgInt.cNsMaxInterval - State.u.ChgInt.cNsMinInterval) / 10;
618 State.u.ChgInt.cNsCurInterval = State.u.ChgInt.fDirection
619 ? State.u.ChgInt.cNsMaxInterval : State.u.ChgInt.cNsMinInterval;
620 State.u.ChgInt.cStepsBetween = u64Arg & 4 ? 1 : 3;
621 RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMinInterval > 1000, ("%u\n", State.u.ChgInt.cNsMinInterval));
622 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));
623
624 /* create the timer and check if RTTimerChangeInterval is supported. */
625 PRTTIMER pTimer;
626 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
627 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackChangeInterval, &State),
628 VINF_SUCCESS);
629 int rc = RTTimerChangeInterval(pTimer, State.u.ChgInt.cNsMinInterval);
630 if (rc == VERR_NOT_SUPPORTED)
631 {
632 RTR0TestR0Info("RTTimerChangeInterval not supported, skipped");
633 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
634 break;
635 }
636
637 /* do the test. */
638 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u64Arg & 2 ? State.u.ChgInt.cNsCurInterval : 0), VINF_SUCCESS);
639 for (uint32_t k = 0;
640 k < 1000
641 && ASMAtomicReadU32(&State.cShots) <= State.iActionShot
642 && State.rc == VERR_IPE_UNINITIALIZED_STATUS;
643 k++)
644 RTThreadSleep(10);
645
646 rc = RTTimerStop(pTimer);
647 RTR0TESTR0_CHECK_MSG_BREAK(rc == VERR_TIMER_SUSPENDED || rc == VINF_SUCCESS, ("rc = %Rrc (RTTimerStop)\n", rc));
648 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
649 break;
650 }
651
652 case TSTRTR0TIMER_PERIODIC_SPECIFIC:
653 case TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES:
654 {
655 PRTTIMER pTimer = NULL;
656 RTCPUSET OnlineSet;
657 RTMpGetOnlineSet(&OnlineSet);
658 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
659 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
660 {
661 RT_ZERO(State);
662 State.iActionShot = 0;
663 State.rc = VINF_SUCCESS;
664 State.fPeriodic = true;
665 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
666
667 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
668 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
669 int rc = RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackSpecific, &State);
670 if (rc == VERR_NOT_SUPPORTED)
671 {
672 RTR0TestR0Info("specific timer are not supported, skipping\n");
673 break;
674 }
675 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
676
677 for (uint32_t i = 0; i < 3 && !RTR0TestR0HaveErrors(); i++)
678 {
679 ASMAtomicWriteU32(&State.cShots, 0);
680 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
681 uint64_t cNsElapsed = RTTimeSystemNanoTS();
682 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 8; j++)
683 RTThreadSleep(5);
684 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
685 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
686 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) > 5,
687 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
688 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed));
689 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
690 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
691 }
692
693 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
694 pTimer = NULL;
695 if (RTR0TestR0HaveErrors())
696 break;
697
698 RTMpGetOnlineSet(&OnlineSet);
699 }
700 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
701 break;
702 }
703
704 case TSTRTR0TIMER_PERIODIC_OMNI:
705 case TSTRTR0TIMER_PERIODIC_OMNI_HIRES:
706 {
707 /* Create a periodic timer running at max host frequency, but no more than 1000 Hz. */
708 uint32_t cNsInterval = cNsSysHz;
709 while (cNsInterval < UINT32_C(1000000))
710 cNsInterval *= 2;
711 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)RTMemAllocZ(sizeof(paStates[0]) * RTCPUSET_MAX_CPUS);
712 RTR0TESTR0_CHECK_MSG_BREAK(paStates, ("%d\n", RTCPUSET_MAX_CPUS));
713
714 PRTTIMER pTimer;
715 uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
716 | RTTIMER_FLAGS_CPU_ALL;
717 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates),
718 VINF_SUCCESS);
719
720 for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
721 {
722 /* reset the state */
723 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
724 {
725 paStates[iCpu].u64Start = 0;
726 paStates[iCpu].u64Last = 0;
727 ASMAtomicWriteU32(&paStates[iCpu].cTicks, 0);
728 }
729
730 /* run it for 1 second. */
731 RTCPUSET OnlineSet;
732 uint64_t uStartNsTS = RTTimeSystemNanoTS();
733 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
734 RTMpGetOnlineSet(&OnlineSet);
735
736 for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT32_C(1000000000); i++)
737 RTThreadSleep(2);
738
739 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
740 uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
741
742 /* Do a min/max on the start and stop times and calculate the test period. */
743 uint64_t u64MinStart = UINT64_MAX;
744 uint64_t u64MaxStop = 0;
745 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
746 {
747 if (paStates[iCpu].u64Start)
748 {
749 if (paStates[iCpu].u64Start < u64MinStart)
750 u64MinStart = paStates[iCpu].u64Start;
751 if (paStates[iCpu].u64Last > u64MaxStop)
752 u64MaxStop = paStates[iCpu].u64Last;
753 }
754 }
755 RTR0TESTR0_CHECK_MSG(u64MinStart < u64MaxStop, ("%llu, %llu", u64MinStart, u64MaxStop));
756 uint64_t cNsElapsed = u64MaxStop - u64MinStart;
757 RTR0TESTR0_CHECK_MSG(cNsElapsed <= cNsElapsedX + 100000, ("%llu, %llu", cNsElapsed, cNsElapsedX)); /* the fudge factor is time drift */
758 uint32_t cAvgTicks = cNsElapsed / cNsInterval + 1;
759
760 /* Check tick counts. ASSUMES no cpu on- or offlining.
761 This only catches really bad stuff. */
762 uint32_t cMinTicks = cAvgTicks - cAvgTicks / 10;
763 uint32_t cMaxTicks = cAvgTicks + cAvgTicks / 10 + 1;
764 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
765 if (paStates[iCpu].cTicks)
766 {
767 RTR0TESTR0_CHECK_MSG(RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
768 RTR0TESTR0_CHECK_MSG(paStates[iCpu].cTicks <= cMaxTicks && paStates[iCpu].cTicks >= cMinTicks,
769 ("min=%u, ticks=%u, avg=%u max=%u, iCpu=%u, interval=%'u, elapsed=%'llu/%'llu\n",
770 cMinTicks, paStates[iCpu].cTicks, cAvgTicks, cMaxTicks, iCpu,
771 cNsInterval, cNsElapsed, cNsElapsedX));
772 }
773 else
774 RTR0TESTR0_CHECK_MSG(!RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
775 }
776
777 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
778 RTMemFree(paStates);
779 break;
780 }
781 }
782
783 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
784 /* The error indicator is the '!' in the message buffer. */
785 return VINF_SUCCESS;
786}
787
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