tstTSC.cpp revision 08c7d253571e79245d86f41f942113ef1a989b3b
/* $Id$ */
/** @file
* innotek Portable Runtime Testcase - SMP TSC testcase.
*/
/*
* Copyright (C) 2006-2007 innotek GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef struct TSCDATA
{
/** The TSC. */
/** The APIC ID. */
/** Did it succeed? */
bool volatile fRead;
/** Did it fail? */
bool volatile fFailed;
/** The thread handle. */
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** The number of CPUs waiting on their user event semaphore. */
static volatile uint32_t g_cWaiting;
/** The number of CPUs ready (in spin) to do the TSC read. */
/** The variable the CPUs are spinning on.
* 0: Spin.
* 1: Go ahead.
* 2: You're too late, back to square one. */
/** The number of CPUs that managed to read the TSC. */
/** The number of CPUs that failed to read the TSC. */
/** Indicator forcing the threads to quit. */
static volatile bool g_fDone;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/**
* Thread function for catching the other cpus.
*
* @returns VINF_SUCCESS (we don't care).
* @param Thread The thread handle.
* @param pvUser PTSCDATA.
*/
{
while (!g_fDone)
{
/*
* Wait.
*/
if (g_fDone)
break;
/*
* Spin.
*/
while (!g_fDone)
{
if (u32Go == 0)
continue;
if (u32Go == 1)
{
/* do the reading. */
)
{
/* succeeded. */
break;
}
}
/* failed */
break;
}
}
return VINF_SUCCESS;
}
int main()
{
RTR3Init();
/*
* This is only relevant to on SMP systems.
*/
const unsigned cCpus = RTSystemProcessorGetCount();
if (cCpus <= 1)
{
RTPrintf("tstTSC: SKIPPED - Only relevant on SMP systems\n");
return 0;
}
/*
* Create the threads.
*/
uint32_t i;
{
return 1;
}
/* ourselves. */
/* the others */
for (i = 1; i < cCpus; i++)
{
int rc = RTThreadCreate(&s_aData[i].Thread, ThreadFunction, &s_aData[i], 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "OTHERCPU");
if (RT_FAILURE(rc))
{
ASMAtomicXchgSize(&g_fDone, true);
while (i-- > 1)
{
}
return 1;
}
}
/*
* Retry untill we get lucky (or give up).
*/
{
if (cTries > 10240)
{
break;
}
/*
* Wait for the other threads to get ready (brute force active wait, I'm lazy).
*/
i = 0;
{
if (i++ > _2G32)
break;
RTThreadSleep(i & 0xf);
}
{
RTPrintf("tstTSC: FAILURE - threads failed to get waiting (%d != %d (i=%d))\n", g_cWaiting + 1, cCpus, i);
break;
}
/*
* Send them spinning.
*/
ASMAtomicXchgU32(&g_cReady, 0);
ASMAtomicXchgU32(&g_u32Go, 0);
ASMAtomicXchgU32(&g_cRead, 0);
ASMAtomicXchgU32(&g_cFailed, 0);
for (i = 1; i < cCpus; i++)
{
if (RT_FAILURE(rc))
}
/* wait for them to get ready. */
i = 0;
{
if (i++ > _2G32)
break;
}
{
RTPrintf("tstTSC: FAILURE - threads failed to get ready (%d != %d, i=%d)\n", g_cWaiting + 1, cCpus, i);
break;
}
/*
* Flip the "go" switch and do our readings.
* We give the other threads the slack it takes to two extra TSC and APIC ID reads.
*/
/* Compose our own result. */
)
{
/* succeeded. */
}
else
{
/* failed */
}
/*
* Wait a little while to let the other ones to finish.
*/
i = 0;
{
if (i++ > _2G32)
break;
if (i > _1M)
RTThreadSleep(i & 0xf);
}
{
RTPrintf("tstTSC: FAILURE - threads failed to complete reading (%d + %d != %d)\n", g_cRead, g_cFailed, cCpus);
break;
}
/*
* If everone succeeded, print the results.
*/
if (!g_cFailed)
{
/* sort it by apic id first. */
bool fDone;
do
{
{
fDone = false;
}
} while (!fDone);
RTPrintf(" # ID TSC delta0 (decimal)\n"
"-----------------------------------------\n");
for (i = 1; i < cCpus; i++)
break;
}
}
/*
* Destroy the threads.
*/
ASMAtomicXchgSize(&g_fDone, true);
for (i = 0; i < cCpus; i++)
{
if (RT_FAILURE(rc))
}
for (i = 0; i < cCpus; i++)
{
if (RT_FAILURE(rc))
}
}