VirtualBox

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

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

header (C) fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.8 KB
Line 
1/* $Id: tstRTR0Timer.cpp 44528 2013-02-04 14:27:54Z 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; 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 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates),
727 VINF_SUCCESS);
728
729 for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
730 {
731 /* reset the state */
732 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
733 {
734 paStates[iCpu].u64Start = 0;
735 paStates[iCpu].u64Last = 0;
736 ASMAtomicWriteU32(&paStates[iCpu].cTicks, 0);
737 }
738
739 /* run it for 1 second. */
740 RTCPUSET OnlineSet;
741 uint64_t uStartNsTS = RTTimeSystemNanoTS();
742 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
743 RTMpGetOnlineSet(&OnlineSet);
744
745 for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT32_C(1000000000); i++)
746 RTThreadSleep(2);
747
748 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
749 uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
750
751 /* Do a min/max on the start and stop times and calculate the test period. */
752 uint64_t u64MinStart = UINT64_MAX;
753 uint64_t u64MaxStop = 0;
754 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
755 {
756 if (paStates[iCpu].u64Start)
757 {
758 if (paStates[iCpu].u64Start < u64MinStart)
759 u64MinStart = paStates[iCpu].u64Start;
760 if (paStates[iCpu].u64Last > u64MaxStop)
761 u64MaxStop = paStates[iCpu].u64Last;
762 }
763 }
764 RTR0TESTR0_CHECK_MSG(u64MinStart < u64MaxStop, ("%llu, %llu", u64MinStart, u64MaxStop));
765 uint64_t cNsElapsed = u64MaxStop - u64MinStart;
766 RTR0TESTR0_CHECK_MSG(cNsElapsed <= cNsElapsedX + 100000, ("%llu, %llu", cNsElapsed, cNsElapsedX)); /* the fudge factor is time drift */
767 uint32_t cAvgTicks = cNsElapsed / cNsInterval + 1;
768
769 /* Check tick counts. ASSUMES no cpu on- or offlining.
770 This only catches really bad stuff. */
771 uint32_t cMinTicks = cAvgTicks - cAvgTicks / 10;
772 uint32_t cMaxTicks = cAvgTicks + cAvgTicks / 10 + 1;
773 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
774 if (paStates[iCpu].cTicks)
775 {
776 RTR0TESTR0_CHECK_MSG(RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
777 RTR0TESTR0_CHECK_MSG(paStates[iCpu].cTicks <= cMaxTicks && paStates[iCpu].cTicks >= cMinTicks,
778 ("min=%u, ticks=%u, avg=%u max=%u, iCpu=%u, interval=%'u, elapsed=%'llu/%'llu\n",
779 cMinTicks, paStates[iCpu].cTicks, cAvgTicks, cMaxTicks, iCpu,
780 cNsInterval, cNsElapsed, cNsElapsedX));
781 }
782 else
783 RTR0TESTR0_CHECK_MSG(!RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
784 }
785
786 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
787 RTMemFree(paStates);
788 break;
789 }
790 }
791
792 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
793 /* The error indicator is the '!' in the message buffer. */
794 return VINF_SUCCESS;
795}
796
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