summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Runtime/testcase/tstRTR0Timer.cpp
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Runtime/testcase/tstRTR0Timer.cpp')
-rw-r--r--src/VBox/Runtime/testcase/tstRTR0Timer.cpp172
1 files changed, 157 insertions, 15 deletions
diff --git a/src/VBox/Runtime/testcase/tstRTR0Timer.cpp b/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
index 8e12602e..ad41354b 100644
--- a/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
+++ b/src/VBox/Runtime/testcase/tstRTR0Timer.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,6 +31,7 @@
#include <iprt/timer.h>
#include <iprt/asm.h>
+#include <iprt/asm-amd64-x86.h>
#include <iprt/cpuset.h>
#include <iprt/err.h>
#include <iprt/mem.h>
@@ -107,6 +108,53 @@ typedef struct TSTRTR0TIMEROMNI1
typedef TSTRTR0TIMEROMNI1 *PTSTRTR0TIMEROMNI1;
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/**
+ * Latency data.
+ */
+static struct TSTRTR0TIMEROMNILATENCY
+{
+ /** The number of samples. */
+ volatile uint32_t cSamples;
+ uint32_t auPadding[3];
+ struct
+ {
+ uint64_t uTsc;
+ uint64_t uNanoTs;
+ } aSamples[4096];
+} g_aOmniLatency[16];
+
+
+/**
+ * Callback for the omni timer latency test, adds a sample to g_aOmniLatency.
+ *
+ * @param pTimer The timer.
+ * @param iTick The current tick.
+ * @param pvUser The user argument.
+ */
+static DECLCALLBACK(void) tstRTR0TimerCallbackLatencyOmni(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
+{
+ RTCPUID idCpu = RTMpCpuId();
+ uint32_t iCpu = RTMpCpuIdToSetIndex(idCpu);
+ NOREF(pTimer); NOREF(pvUser); NOREF(iTick);
+
+ RTR0TESTR0_CHECK_MSG(iCpu < RT_ELEMENTS(g_aOmniLatency), ("iCpu=%d idCpu=%u\n", iCpu, idCpu));
+ if (iCpu < RT_ELEMENTS(g_aOmniLatency))
+ {
+ uint32_t iSample = g_aOmniLatency[iCpu].cSamples;
+ if (iSample < RT_ELEMENTS(g_aOmniLatency[iCpu].aSamples))
+ {
+ g_aOmniLatency[iCpu].aSamples[iSample].uTsc = ASMReadTSC();
+ g_aOmniLatency[iCpu].aSamples[iSample].uNanoTs = RTTimeSystemNanoTS();
+ g_aOmniLatency[iCpu].cSamples = iSample + 1;
+ }
+ }
+}
+
+
+
/**
* Callback which increments a 32-bit counter.
*
@@ -394,33 +442,38 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
/* Create a one-shot timer and take one shot. */
PRTTIMER pTimer;
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
- RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State),
- VINF_SUCCESS);
+ int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TestR0Info("one-shot timer are not supported, skipping\n");
+ break;
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
do /* break loop */
{
- RT_ZERO(State);
+ RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
RTThreadSleep(5);
RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
/* check that it is restartable. */
- RT_ZERO(State);
+ RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
RTThreadSleep(5);
RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
/* check that it respects the timeout value and can be cancelled. */
- RT_ZERO(State);
+ RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
RTThreadSleep(1);
RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
/* Check some double starts and stops (shall not assert). */
- RT_ZERO(State);
+ RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
@@ -442,11 +495,17 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
for (uint32_t iTest = 0; iTest < 2; iTest++)
{
- RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State),
- VINF_SUCCESS);
+ int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TestR0Info("one-shot timer are not supported, skipping\n");
+ break;
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
RT_ZERO(State);
State.iActionShot = 0;
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
do /* break loop */
{
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
@@ -469,16 +528,22 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
for (uint32_t iTest = 0; iTest < 2; iTest++)
{
- RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State),
- VINF_SUCCESS);
+ int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TestR0Info("one-shot timer are not supported, skipping\n");
+ break;
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
RT_ZERO(State);
State.rc = VERR_IPE_UNINITIALIZED_STATUS;
State.iActionShot = 0;
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
do /* break loop */
{
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
- for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; i++)
+ for (uint32_t i = 0; i < 1000 && (ASMAtomicUoReadU32(&State.cShots) < 1 || State.rc == VERR_IPE_UNINITIALIZED_STATUS); i++)
RTThreadSleep(5);
RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
@@ -503,13 +568,14 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
State.iActionShot = 0;
State.rc = VINF_SUCCESS;
State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
fFlags |= RTTIMER_FLAGS_CPU(iCpu);
int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackSpecific, &State);
if (rc == VERR_NOT_SUPPORTED)
{
- RTR0TestR0Info("specific timer are not supported, skipping\n");
+ RTR0TestR0Info("one-shot specific timer are not supported, skipping\n");
break;
}
RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
@@ -556,6 +622,8 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
{
RT_ZERO(State);
State.fPeriodic = true;
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
+
uint64_t uStartNsTS = RTTimeSystemNanoTS();
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
@@ -584,6 +652,8 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
{
RT_ZERO(State);
State.fPeriodic = true;
+ ASMAtomicWriteU32(&State.cShots, State.cShots); /* ordered, necessary? */
+
RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
RTThreadSleep(1);
@@ -620,6 +690,7 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
State.u.ChgInt.cStepsBetween = u64Arg & 4 ? 1 : 3;
RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMinInterval > 1000, ("%u\n", State.u.ChgInt.cNsMinInterval));
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));
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
/* create the timer and check if RTTimerChangeInterval is supported. */
PRTTIMER pTimer;
@@ -663,6 +734,7 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
State.rc = VINF_SUCCESS;
State.fPeriodic = true;
State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
+ ASMAtomicWriteU32(&State.cShots, State.cShots);
uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
fFlags |= RTTIMER_FLAGS_CPU(iCpu);
@@ -714,8 +786,12 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
PRTTIMER pTimer;
uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
| RTTIMER_FLAGS_CPU_ALL;
- RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates),
- VINF_SUCCESS);
+ int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TESTR0_SKIP_BREAK();
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
{
@@ -778,6 +854,72 @@ DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOpe
RTMemFree(paStates);
break;
}
+
+ case TSTRTR0TIMER_LATENCY_OMNI:
+ case TSTRTR0TIMER_LATENCY_OMNI_HIRES:
+ {
+ /*
+ * Create a periodic timer running at max host frequency, but no more than 1000 Hz.
+ */
+ PRTTIMER pTimer;
+ uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
+ | RTTIMER_FLAGS_CPU_ALL;
+ uint32_t cNsInterval = cNsSysHz;
+ while (cNsInterval < UINT32_C(1000000))
+ cNsInterval *= 2;
+ int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackLatencyOmni, NULL);
+ if (rc == VERR_NOT_SUPPORTED)
+ {
+ RTR0TESTR0_SKIP_BREAK();
+ }
+ RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
+
+ /*
+ * Reset the state and run the test for 4 seconds.
+ */
+ RT_ZERO(g_aOmniLatency);
+
+ RTCPUSET OnlineSet;
+ uint64_t uStartNsTS = RTTimeSystemNanoTS();
+ RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
+ RTMpGetOnlineSet(&OnlineSet);
+
+ for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT64_C(4000000000); i++)
+ RTThreadSleep(2);
+
+ RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
+ uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
+
+ /*
+ * Process the result.
+ */
+ int32_t cNsLow = cNsInterval / 4 * 3; /* 75% */
+ int32_t cNsHigh = cNsInterval / 4 * 5; /* 125% */
+ uint32_t cTotal = 0;
+ uint32_t cLow = 0;
+ uint32_t cHigh = 0;
+ for (uint32_t iCpu = 0; iCpu < RT_ELEMENTS(g_aOmniLatency); iCpu++)
+ {
+ uint32_t cSamples = g_aOmniLatency[iCpu].cSamples;
+ if (cSamples > 1)
+ {
+ cTotal += cSamples - 1;
+ for (uint32_t iSample = 1; iSample < cSamples; iSample++)
+ {
+ int64_t cNsDelta = g_aOmniLatency[iCpu].aSamples[iSample - 1].uNanoTs
+ - g_aOmniLatency[iCpu].aSamples[iSample].uNanoTs;
+ if (cNsDelta < cNsLow)
+ cLow++;
+ else if (cNsDelta > cNsHigh)
+ cHigh++;
+ }
+ }
+ }
+ RTR0TestR0Info("125%%: %u; 75%%: %u; total: %u", cHigh, cLow, cTotal);
+ RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
+ break;
+ }
+
}
RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);