VirtualBox

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

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

IPRT: linux kernel timer changes, testcase. hrtimers are not working reliably yet.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: tstRTR0Timer.cpp 32648 2010-09-20 16:17:03Z 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* Header Files *
29*******************************************************************************/
30#include <iprt/timer.h>
31
32#include <iprt/asm.h>
33#include <iprt/err.h>
34#include <iprt/param.h>
35#include <iprt/string.h>
36#include <iprt/thread.h>
37#include <iprt/time.h>
38#include <VBox/sup.h>
39#include "tstRTR0Timer.h"
40#include "tstRTR0Common.h"
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45typedef struct
46{
47 /** Array of nano second timestamp of the first few shots. */
48 uint64_t volatile aShotNsTSes[10];
49 /** The number of shots. */
50 uint32_t volatile cShots;
51} TSTRTR0TIMERS1;
52typedef TSTRTR0TIMERS1 *PTSTRTR0TIMERS1;
53
54
55/**
56 * Callback which increments restarts a timer once.
57 *
58 * @param pTimer The timer.
59 * @param iTick The current tick.
60 * @param pvUser The user argument.
61 */
62static DECLCALLBACK(void) tstRTR0TimerCallbackRestartOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
63{
64 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
65 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
66
67 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
68 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
69
70 if (iShot == 1)
71 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 10000000 /* 10ms */), VINF_SUCCESS);
72}
73
74
75/**
76 * Callback which increments a 32-bit counter.
77 *
78 * @param pTimer The timer.
79 * @param iTick The current tick.
80 * @param pvUser The user argument.
81 */
82static DECLCALLBACK(void) tstRTR0TimerCallbackU32Counter(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
83{
84 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
85 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
86
87 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
88 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
89}
90
91
92/**
93 * Checks that the interval between two timer shots are within the specified
94 * range.
95 *
96 * @returns 0 if ok, 1 if bad.
97 * @param iShot The shot number (for bitching).
98 * @param uPrevTS The time stamp of the previous shot (ns).
99 * @param uThisTS The timer stamp of this shot (ns).
100 * @param uMin The minimum interval (ns).
101 * @param uMax The maximum interval (ns).
102 */
103static int tstRTR0TimerCheckShotInterval(uint32_t iShot, uint64_t uPrevTS, uint64_t uThisTS, uint32_t uMin, uint32_t uMax)
104{
105 uint64_t uDelta = uThisTS - uPrevTS;
106 RTR0TESTR0_CHECK_MSG_RET(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin), 1);
107 RTR0TESTR0_CHECK_MSG_RET(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax), 1);
108 return 0;
109}
110
111
112/**
113 * Checks that the interval between timer shots are within a certain range.
114 *
115 * @returns Number of violations (i.e. 0 is ok).
116 * @param pState The state.
117 * @param uStartNsTS The start time stamp (ns).
118 * @param uMin The minimum interval (ns).
119 * @param uMax The maximum interval (ns).
120 */
121static int tstRTR0TimerCheckShotIntervals(PTSTRTR0TIMERS1 pState, uint64_t uStartNsTS, uint32_t uMin, uint32_t uMax)
122{
123 uint64_t uMaxDelta = 0;
124 uint64_t uMinDelta = UINT64_MAX;
125 uint32_t cBadShots = 0;
126 uint32_t cShots = pState->cShots;
127 uint64_t uPrevTS = uStartNsTS;
128 for (uint32_t iShot = 0; iShot < cShots; iShot++)
129 {
130 uint64_t uThisTS = pState->aShotNsTSes[iShot];
131 uint64_t uDelta = uThisTS - uPrevTS;
132 if (uDelta > uMaxDelta)
133 uMaxDelta = uDelta;
134 if (uDelta < uMinDelta)
135 uMinDelta = uDelta;
136 cBadShots += !(uDelta >= uMin && uDelta <= uMax);
137
138 RTR0TESTR0_CHECK_MSG(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin));
139 RTR0TESTR0_CHECK_MSG(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax));
140
141 uPrevTS = uThisTS;
142 }
143
144 RTR0TestR0Info("uMaxDelta=%llu uMinDelta=%llu\n", uMaxDelta, uMinDelta);
145 return cBadShots;
146}
147
148
149/**
150 * Service request callback function.
151 *
152 * @returns VBox status code.
153 * @param pSession The caller's session.
154 * @param u64Arg 64-bit integer argument.
155 * @param pReqHdr The request header. Input / Output. Optional.
156 */
157DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
158 uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
159{
160 RTR0TESTR0_SRV_REQ_PROLOG_RET(pReqHdr);
161 if (u64Arg)
162 return VERR_INVALID_PARAMETER;
163
164 /*
165 * The big switch.
166 */
167 TSTRTR0TIMERS1 State;
168 switch (uOperation)
169 {
170 RTR0TESTR0_IMPLEMENT_SANITY_CASES();
171 RTR0TESTR0_IMPLEMENT_DEFAULT_CASE(uOperation);
172
173 case TSTRTR0TIMER_ONE_SHOT_BASIC:
174 case TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES:
175 {
176 /* Create a one-shot timer and take one shot. */
177 PRTTIMER pTimer;
178 uint32_t fFlags = uOperation != TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES ? RTTIMER_FLAGS_HIGH_RES : 0;
179 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State),
180 VINF_SUCCESS);
181
182 do /* break loop */
183 {
184 RT_ZERO(State);
185 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
186 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
187 RTThreadSleep(5);
188 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
189
190 /* check that it is restartable. */
191 RT_ZERO(State);
192 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
193 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
194 RTThreadSleep(5);
195 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
196
197 /* check that it respects the timeout value and can be cancelled. */
198 RT_ZERO(State);
199 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
200 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
201 RTThreadSleep(1);
202 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
203
204 /* Check some double starts and stops (shall not assert). */
205 RT_ZERO(State);
206 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
207 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
208 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
209 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VERR_TIMER_SUSPENDED);
210 RTThreadSleep(1);
211 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
212 } while (0);
213 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
214 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
215 break;
216 }
217
218#if 1 /* might have to disable this for some host... */
219 case TSTRTR0TIMER_ONE_SHOT_RESTART:
220 case TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES:
221 {
222 /* Create a one-shot timer and restart it in the callback handler. */
223 PRTTIMER pTimer;
224 uint32_t fFlags = uOperation != TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES ? RTTIMER_FLAGS_HIGH_RES : 0;
225 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State),
226 VINF_SUCCESS);
227
228 do /* break loop */
229 {
230 RT_ZERO(State);
231 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
232 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; i++)
233 RTThreadSleep(5);
234 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 2, ("cShots=%u\n", State.cShots));
235 } while (0);
236 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
237 break;
238 }
239#endif
240
241 case TSTRTR0TIMER_PERIODIC_BASIC:
242 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES:
243 {
244 /* Create a periodic timer running at 10 HZ. */
245 uint32_t const u10HzAsNs = 100000000;
246 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2;
247 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2;
248 PRTTIMER pTimer;
249 uint32_t fFlags = uOperation != TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES ? RTTIMER_FLAGS_HIGH_RES : 0;
250 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, u10HzAsNs, fFlags, tstRTR0TimerCallbackU32Counter, &State),
251 VINF_SUCCESS);
252
253 for (uint32_t iTest = 0; iTest < 2; iTest++)
254 {
255 RT_ZERO(State);
256 uint64_t uStartNsTS = RTTimeSystemNanoTS();
257 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
258 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
259 RTThreadSleep(10);
260 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
261 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 10, ("cShots=%u\n", State.cShots));
262 if (tstRTR0TimerCheckShotIntervals(&State, uStartNsTS, u10HzAsNsMin, u10HzAsNsMax))
263 break;
264 }
265 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
266 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
267 break;
268 }
269 }
270
271 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
272 /* The error indicator is the '!' in the message buffer. */
273 return VINF_SUCCESS;
274}
275
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