VirtualBox

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

Last change on this file since 32753 was 32753, checked in by vboxsync, 14 years ago

tstRTR0Timer: fixes, works on linux now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.0 KB
Line 
1/* $Id: tstRTR0Timer.cpp 32753 2010-09-24 09:57:49Z 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
123 RTR0TESTR0_CHECK_MSG(iCpu < RTCPUSET_MAX_CPUS, ("iCpu=%d idCpu=%u\n", iCpu, idCpu));
124 if (iCpu < RTCPUSET_MAX_CPUS)
125 {
126 uint32_t iCountedTick = ASMAtomicIncU32(&paStates[iCpu].cTicks);
127 RTR0TESTR0_CHECK_MSG(iCountedTick == iTick,
128 ("iCountedTick=%u iTick=%u iCpu=%d idCpu=%u\n", iCountedTick, iTick, iCpu, idCpu));
129 paStates[iCpu].u64Last = RTTimeSystemNanoTS();
130 if (!paStates[iCpu].u64Start)
131 {
132 paStates[iCpu].u64Start = paStates[iCpu].u64Last;
133 RTR0TESTR0_CHECK_MSG(iCountedTick == 1, ("iCountedTick=%u iCpu=%d idCpu=%u\n", iCountedTick, iCpu, idCpu));
134 }
135 }
136}
137
138
139/**
140 * Callback which increments a 32-bit counter.
141 *
142 * @param pTimer The timer.
143 * @param iTick The current tick.
144 * @param pvUser The user argument.
145 */
146static DECLCALLBACK(void) tstRTR0TimerCallbackSpecific(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
147{
148 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
149 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
150
151 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
152 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
153
154 RTCPUID idCpu = RTMpCpuId();
155 if (pState->u.Specific.idCpu != idCpu)
156 pState->u.Specific.fFailed = true;
157 RTR0TESTR0_CHECK_MSG(pState->u.Specific.idCpu == idCpu, ("idCpu=%u, expected %u\n", idCpu, pState->u.Specific.idCpu));
158
159 if (pState->fPeriodic)
160 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
161 else
162 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
163}
164
165
166/**
167 * Callback which changes the interval at each invocation.
168 *
169 * The changes are goverened by TSTRTR0TIMERS1::ChangeInterval. The callback
170 * calls RTTimerStop at iActionShot.
171 *
172 * @param pTimer The timer.
173 * @param iTick The current tick.
174 * @param pvUser The user argument.
175 */
176static DECLCALLBACK(void) tstRTR0TimerCallbackChangeInterval(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
177{
178 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
179 uint32_t iShot = ASMAtomicIncU32(&pState->cShots) - 1;
180
181 if (iShot < RT_ELEMENTS(pState->aShotNsTSes))
182 pState->aShotNsTSes[iShot] = RTTimeSystemNanoTS();
183 if (pState->fPeriodic)
184 RTR0TESTR0_CHECK_MSG(iShot + 1 == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
185 else
186 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
187
188 if (!(iShot % pState->u.ChgInt.cStepsBetween))
189 {
190 if (pState->u.ChgInt.fDirection)
191 {
192 pState->u.ChgInt.cNsCurInterval += pState->u.ChgInt.cNsChangeStep;
193 if ( pState->u.ChgInt.cNsCurInterval > pState->u.ChgInt.cNsMaxInterval
194 || pState->u.ChgInt.cNsCurInterval < pState->u.ChgInt.cNsMinInterval
195 || !pState->u.ChgInt.cNsCurInterval)
196 {
197 pState->u.ChgInt.cNsCurInterval = pState->u.ChgInt.cNsMaxInterval;
198 pState->u.ChgInt.fDirection = false;
199 }
200 }
201 else
202 {
203 pState->u.ChgInt.cNsCurInterval -= pState->u.ChgInt.cNsChangeStep;
204 if ( pState->u.ChgInt.cNsCurInterval < pState->u.ChgInt.cNsMinInterval
205 || pState->u.ChgInt.cNsCurInterval > pState->u.ChgInt.cNsMaxInterval
206 || pState->u.ChgInt.cNsCurInterval)
207 {
208 pState->u.ChgInt.cNsCurInterval = pState->u.ChgInt.cNsMinInterval;
209 pState->u.ChgInt.fDirection = true;
210 }
211 }
212
213 RTR0TESTR0_CHECK_RC(RTTimerChangeInterval(pTimer, pState->u.ChgInt.cNsCurInterval), VINF_SUCCESS);
214 }
215
216 if (iShot == pState->iActionShot)
217 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStop(pTimer), VINF_SUCCESS);
218}
219
220
221/**
222 * Callback which increments destroy the timer when it fires.
223 *
224 * @param pTimer The timer.
225 * @param iTick The current tick.
226 * @param pvUser The user argument.
227 */
228static DECLCALLBACK(void) tstRTR0TimerCallbackDestroyOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
229{
230 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
231 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
232
233 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
234 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
235 if (pState->fPeriodic)
236 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
237 else
238 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
239
240 if (iShot == pState->iActionShot + 1)
241 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerDestroy(pTimer), VINF_SUCCESS);
242}
243
244
245/**
246 * Callback which increments restarts a timer once.
247 *
248 * @param pTimer The timer.
249 * @param iTick The current tick.
250 * @param pvUser The user argument.
251 */
252static DECLCALLBACK(void) tstRTR0TimerCallbackRestartOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
253{
254 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
255 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
256
257 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
258 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
259 if (pState->fPeriodic)
260 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
261 else
262 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
263
264 if (iShot == pState->iActionShot + 1)
265 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStart(pTimer, 10000000 /* 10ms */), VINF_SUCCESS);
266}
267
268
269/**
270 * Callback which increments a 32-bit counter.
271 *
272 * @param pTimer The timer.
273 * @param iTick The current tick.
274 * @param pvUser The user argument.
275 */
276static DECLCALLBACK(void) tstRTR0TimerCallbackU32Counter(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
277{
278 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
279 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
280
281 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
282 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
283 if (pState->fPeriodic)
284 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
285 else
286 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
287}
288
289
290/**
291 * Checks that the interval between two timer shots are within the specified
292 * range.
293 *
294 * @returns 0 if ok, 1 if bad.
295 * @param iShot The shot number (for bitching).
296 * @param uPrevTS The time stamp of the previous shot (ns).
297 * @param uThisTS The timer stamp of this shot (ns).
298 * @param uMin The minimum interval (ns).
299 * @param uMax The maximum interval (ns).
300 */
301static int tstRTR0TimerCheckShotInterval(uint32_t iShot, uint64_t uPrevTS, uint64_t uThisTS, uint32_t uMin, uint32_t uMax)
302{
303 uint64_t uDelta = uThisTS - uPrevTS;
304 RTR0TESTR0_CHECK_MSG_RET(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin), 1);
305 RTR0TESTR0_CHECK_MSG_RET(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax), 1);
306 return 0;
307}
308
309
310/**
311 * Checks that the interval between timer shots are within a certain range.
312 *
313 * @returns Number of violations (i.e. 0 is ok).
314 * @param pState The state.
315 * @param uStartNsTS The start time stamp (ns).
316 * @param uMin The minimum interval (ns).
317 * @param uMax The maximum interval (ns).
318 */
319static int tstRTR0TimerCheckShotIntervals(PTSTRTR0TIMERS1 pState, uint64_t uStartNsTS, uint32_t uMin, uint32_t uMax)
320{
321 uint64_t uMaxDelta = 0;
322 uint64_t uMinDelta = UINT64_MAX;
323 uint32_t cBadShots = 0;
324 uint32_t cShots = pState->cShots;
325 uint64_t uPrevTS = uStartNsTS;
326 for (uint32_t iShot = 0; iShot < cShots; iShot++)
327 {
328 uint64_t uThisTS = pState->aShotNsTSes[iShot];
329 uint64_t uDelta = uThisTS - uPrevTS;
330 if (uDelta > uMaxDelta)
331 uMaxDelta = uDelta;
332 if (uDelta < uMinDelta)
333 uMinDelta = uDelta;
334 cBadShots += !(uDelta >= uMin && uDelta <= uMax);
335
336 RTR0TESTR0_CHECK_MSG(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin));
337 RTR0TESTR0_CHECK_MSG(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax));
338
339 uPrevTS = uThisTS;
340 }
341
342 RTR0TestR0Info("uMaxDelta=%llu uMinDelta=%llu\n", uMaxDelta, uMinDelta);
343 return cBadShots;
344}
345
346
347/**
348 * Service request callback function.
349 *
350 * @returns VBox status code.
351 * @param pSession The caller's session.
352 * @param u64Arg 64-bit integer argument.
353 * @param pReqHdr The request header. Input / Output. Optional.
354 */
355DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
356 uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
357{
358 RTR0TESTR0_SRV_REQ_PROLOG_RET(pReqHdr);
359
360 /*
361 * Common parameter and state variables.
362 */
363 uint32_t const cNsSysHz = RTTimerGetSystemGranularity();
364 uint32_t const cNsMaxHighResHz = 10000; /** @todo need API for this */
365 TSTRTR0TIMERS1 State;
366 if ( cNsSysHz < UINT32_C(1000)
367 || cNsSysHz > UINT32_C(1000000000)
368 || cNsMaxHighResHz < UINT32_C(1)
369 || cNsMaxHighResHz > UINT32_C(1000000000))
370 {
371 RTR0TESTR0_CHECK_MSG(cNsSysHz > UINT32_C(1000) && cNsSysHz < UINT32_C(1000000000), ("%u", cNsSysHz));
372 RTR0TESTR0_CHECK_MSG(cNsMaxHighResHz > UINT32_C(1) && cNsMaxHighResHz < UINT32_C(1000000000), ("%u", cNsMaxHighResHz));
373 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
374 return VINF_SUCCESS;
375 }
376
377 /*
378 * The big switch.
379 */
380 switch (uOperation)
381 {
382 RTR0TESTR0_IMPLEMENT_SANITY_CASES();
383 RTR0TESTR0_IMPLEMENT_DEFAULT_CASE(uOperation);
384
385 case TSTRTR0TIMER_ONE_SHOT_BASIC:
386 case TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES:
387 {
388 /* Create a one-shot timer and take one shot. */
389 PRTTIMER pTimer;
390 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
391 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State),
392 VINF_SUCCESS);
393
394 do /* break loop */
395 {
396 RT_ZERO(State);
397 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
398 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
399 RTThreadSleep(5);
400 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
401
402 /* check that it is restartable. */
403 RT_ZERO(State);
404 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
405 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
406 RTThreadSleep(5);
407 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
408
409 /* check that it respects the timeout value and can be cancelled. */
410 RT_ZERO(State);
411 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
412 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
413 RTThreadSleep(1);
414 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
415
416 /* Check some double starts and stops (shall not assert). */
417 RT_ZERO(State);
418 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
419 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
420 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
421 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VERR_TIMER_SUSPENDED);
422 RTThreadSleep(1);
423 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
424 } while (0);
425 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
426 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
427 break;
428 }
429
430#if 1 /* might have to disable this for some host... */
431 case TSTRTR0TIMER_ONE_SHOT_RESTART:
432 case TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES:
433 {
434 /* Create a one-shot timer and restart it in the callback handler. */
435 PRTTIMER pTimer;
436 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
437 for (uint32_t iTest = 0; iTest < 2; iTest++)
438 {
439 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State),
440 VINF_SUCCESS);
441
442 RT_ZERO(State);
443 State.iActionShot = 0;
444 do /* break loop */
445 {
446 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
447 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; i++)
448 RTThreadSleep(5);
449 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 2, ("cShots=%u\n", State.cShots));
450 } while (0);
451 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
452 }
453 break;
454 }
455#endif
456
457#if 1 /* might have to disable this for some host... */
458 case TSTRTR0TIMER_ONE_SHOT_DESTROY:
459 case TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES:
460 {
461 /* Create a one-shot timer and destroy it in the callback handler. */
462 PRTTIMER pTimer;
463 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
464 for (uint32_t iTest = 0; iTest < 2; iTest++)
465 {
466 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State),
467 VINF_SUCCESS);
468
469 RT_ZERO(State);
470 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
471 State.iActionShot = 0;
472 do /* break loop */
473 {
474 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
475 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; i++)
476 RTThreadSleep(5);
477 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
478 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
479 } while (0);
480 if (RT_FAILURE(State.rc))
481 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
482 }
483 break;
484 }
485#endif
486
487 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC:
488 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC_HIRES:
489 {
490 PRTTIMER pTimer = NULL;
491 RTCPUSET OnlineSet;
492 RTMpGetOnlineSet(&OnlineSet);
493 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
494 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
495 {
496 RT_ZERO(State);
497 State.iActionShot = 0;
498 State.rc = VINF_SUCCESS;
499 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
500
501 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
502 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
503 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackSpecific, &State);
504 if (rc == VERR_NOT_SUPPORTED)
505 {
506 RTR0TestR0Info("specific timer are not supported, skipping\n");
507 break;
508 }
509 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
510
511 for (uint32_t i = 0; i < 5 && !RTR0TestR0HaveErrors(); i++)
512 {
513 ASMAtomicWriteU32(&State.cShots, 0);
514 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
515 uint64_t cNsElapsed = RTTimeSystemNanoTS();
516 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; j++)
517 RTThreadSleep(5);
518 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
519 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1,
520 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
521 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed ));
522 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
523 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
524 }
525
526 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
527 pTimer = NULL;
528 if (RTR0TestR0HaveErrors())
529 break;
530
531 RTMpGetOnlineSet(&OnlineSet);
532 }
533 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
534 break;
535 }
536
537 case TSTRTR0TIMER_PERIODIC_BASIC:
538 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES:
539 {
540 /* Create a periodic timer running at 10 HZ. */
541 uint32_t const u10HzAsNs = 100000000;
542 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2;
543 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2;
544 PRTTIMER pTimer;
545 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
546 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, u10HzAsNs, fFlags, tstRTR0TimerCallbackU32Counter, &State),
547 VINF_SUCCESS);
548
549 for (uint32_t iTest = 0; iTest < 2; iTest++)
550 {
551 RT_ZERO(State);
552 State.fPeriodic = true;
553 uint64_t uStartNsTS = RTTimeSystemNanoTS();
554 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
555 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
556 RTThreadSleep(10);
557 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
558 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 10, ("cShots=%u\n", State.cShots));
559 if (tstRTR0TimerCheckShotIntervals(&State, uStartNsTS, u10HzAsNsMin, u10HzAsNsMax))
560 break;
561 }
562 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
563 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
564 break;
565 }
566
567 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS:
568 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES:
569 {
570 /* create, start, stop & destroy high res timers a number of times. */
571 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
572 for (uint32_t i = 0; i < 40; i++)
573 {
574 PRTTIMER pTimer;
575 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackU32Counter, &State),
576 VINF_SUCCESS);
577 for (uint32_t j = 0; j < 10; j++)
578 {
579 RT_ZERO(State);
580 State.fPeriodic = true;
581 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
582 for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
583 RTThreadSleep(1);
584 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
585 }
586 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
587 }
588 break;
589 }
590
591 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL:
592 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES:
593 {
594 /* Initialize the test parameters, using the u64Arg value for selecting variations. */
595 RT_ZERO(State);
596 State.cShots = 0;
597 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
598 State.iActionShot = 42;
599 State.fPeriodic = true;
600 State.u.ChgInt.fDirection = !!(u64Arg & 1);
601 if (uOperation == TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES)
602 {
603 State.u.ChgInt.cNsMaxInterval = RT_MAX(cNsMaxHighResHz * 10, 20000000); /* 10x / 20 ms */
604 State.u.ChgInt.cNsMinInterval = RT_MAX(cNsMaxHighResHz, 10000); /* min / 10 us */
605 }
606 else
607 {
608 State.u.ChgInt.cNsMaxInterval = cNsSysHz * 4;
609 State.u.ChgInt.cNsMinInterval = cNsSysHz;
610 }
611 State.u.ChgInt.cNsChangeStep = (State.u.ChgInt.cNsMaxInterval - State.u.ChgInt.cNsMinInterval) / 10;
612 State.u.ChgInt.cNsCurInterval = State.u.ChgInt.fDirection
613 ? State.u.ChgInt.cNsMaxInterval : State.u.ChgInt.cNsMinInterval;
614 State.u.ChgInt.cStepsBetween = u64Arg & 4 ? 1 : 3;
615 RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMinInterval > 1000, ("%u\n", State.u.ChgInt.cNsMinInterval));
616 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));
617
618 /* create the timer and check if RTTimerChangeInterval is supported. */
619 PRTTIMER pTimer;
620 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
621 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackChangeInterval, &State),
622 VINF_SUCCESS);
623 int rc = RTTimerChangeInterval(pTimer, State.u.ChgInt.cNsMinInterval);
624 if (rc == VERR_NOT_SUPPORTED)
625 {
626 RTR0TestR0Info("RTTimerChangeInterval not supported, skipped");
627 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
628 break;
629 }
630
631 /* do the test. */
632 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u64Arg & 2 ? State.u.ChgInt.cNsCurInterval : 0), VINF_SUCCESS);
633 for (uint32_t k = 0;
634 k < 1000
635 && ASMAtomicReadU32(&State.cShots) <= State.iActionShot
636 && State.rc == VERR_IPE_UNINITIALIZED_STATUS;
637 k++)
638 RTThreadSleep(10);
639
640 rc = RTTimerStop(pTimer);
641 RTR0TESTR0_CHECK_MSG_BREAK(rc == VERR_TIMER_SUSPENDED || rc == VINF_SUCCESS, ("rc = %Rrc (RTTimerStop)\n", rc));
642 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
643 break;
644 }
645
646 case TSTRTR0TIMER_PERIODIC_SPECIFIC:
647 case TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES:
648 {
649 PRTTIMER pTimer = NULL;
650 RTCPUSET OnlineSet;
651 RTMpGetOnlineSet(&OnlineSet);
652 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
653 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
654 {
655 RT_ZERO(State);
656 State.iActionShot = 0;
657 State.rc = VINF_SUCCESS;
658 State.fPeriodic = true;
659 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
660
661 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
662 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
663 int rc = RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackSpecific, &State);
664 if (rc == VERR_NOT_SUPPORTED)
665 {
666 RTR0TestR0Info("specific timer are not supported, skipping\n");
667 break;
668 }
669 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
670
671 for (uint32_t i = 0; i < 3 && !RTR0TestR0HaveErrors(); i++)
672 {
673 ASMAtomicWriteU32(&State.cShots, 0);
674 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
675 uint64_t cNsElapsed = RTTimeSystemNanoTS();
676 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 8; j++)
677 RTThreadSleep(5);
678 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
679 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
680 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) > 5,
681 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
682 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed));
683 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
684 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
685 }
686
687 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
688 pTimer = NULL;
689 if (RTR0TestR0HaveErrors())
690 break;
691
692 RTMpGetOnlineSet(&OnlineSet);
693 }
694 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
695 break;
696 }
697
698 case TSTRTR0TIMER_PERIODIC_OMNI:
699 case TSTRTR0TIMER_PERIODIC_OMNI_HIRES:
700 {
701 /* Create a periodic timer running at max host frequency, but no more than 1000 Hz. */
702 uint32_t cNsInterval = cNsSysHz;
703 while (cNsInterval < UINT32_C(1000000))
704 cNsInterval *= 2;
705 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)RTMemAllocZ(sizeof(paStates[0]) * RTCPUSET_MAX_CPUS);
706 RTR0TESTR0_CHECK_MSG_BREAK(paStates, ("%d\n", RTCPUSET_MAX_CPUS));
707
708 PRTTIMER pTimer;
709 uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
710 | RTTIMER_FLAGS_CPU_ALL;
711 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates),
712 VINF_SUCCESS);
713
714 for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
715 {
716 /* reset the state */
717 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
718 {
719 paStates[iCpu].u64Start = 0;
720 paStates[iCpu].u64Last = 0;
721 ASMAtomicWriteU32(&paStates[iCpu].cTicks, 0);
722 }
723
724 /* run it for 1 second. */
725 RTCPUSET OnlineSet;
726 uint64_t uStartNsTS = RTTimeSystemNanoTS();
727 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
728 RTMpGetOnlineSet(&OnlineSet);
729
730 for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT32_C(1000000000); i++)
731 RTThreadSleep(2);
732
733 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
734 uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
735
736 /* Do a min/max on the start and stop times and calculate the test period. */
737 uint64_t u64MinStart = UINT64_MAX;
738 uint64_t u64MaxStop = 0;
739 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
740 {
741 if (paStates[iCpu].u64Start)
742 {
743 if (paStates[iCpu].u64Start < u64MinStart)
744 u64MinStart = paStates[iCpu].u64Start;
745 if (paStates[iCpu].u64Last > u64MaxStop)
746 u64MaxStop = paStates[iCpu].u64Last;
747 }
748 }
749 RTR0TESTR0_CHECK_MSG(u64MinStart < u64MaxStop, ("%llu, %llu", u64MinStart, u64MaxStop));
750 uint64_t cNsElapsed = u64MaxStop - u64MinStart;
751 RTR0TESTR0_CHECK_MSG(cNsElapsed <= cNsElapsedX + 1000, ("%llu, %llu", cNsElapsed, cNsElapsedX));
752 uint32_t cAvgTicks = cNsElapsed / cNsInterval + 1;
753
754 /* Check tick counts. ASSUMES no cpu on- or offlining.
755 This only catches really bad stuff. */
756 uint32_t cMinTicks = cAvgTicks - cAvgTicks / 10;
757 uint32_t cMaxTicks = cAvgTicks + cAvgTicks / 10 + 1;
758 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
759 if (paStates[iCpu].cTicks)
760 {
761 RTR0TESTR0_CHECK_MSG(RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
762 RTR0TESTR0_CHECK_MSG(paStates[iCpu].cTicks <= cMaxTicks && paStates[iCpu].cTicks >= cMinTicks,
763 ("min=%u, ticks=%u, avg=%u max=%u, iCpu=%u, interval=%'u, elapsed=%'llu/%'llu\n",
764 cMinTicks, paStates[iCpu].cTicks, cAvgTicks, cMaxTicks, iCpu,
765 cNsInterval, cNsElapsed, cNsElapsedX));
766 }
767 else
768 RTR0TESTR0_CHECK_MSG(!RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
769 }
770
771 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
772 RTMemFree(paStates);
773 break;
774 }
775 }
776
777 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
778 /* The error indicator is the '!' in the message buffer. */
779 return VINF_SUCCESS;
780}
781
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