tstTSC.cpp revision 7043865c42bccb88eabf015de27b029ef057ed82
46f059bea92bedbd395793702c73946ead235586vboxsync/* $Id$ */
46f059bea92bedbd395793702c73946ead235586vboxsync/** @file
46f059bea92bedbd395793702c73946ead235586vboxsync * IPRT Testcase - SMP TSC testcase.
46f059bea92bedbd395793702c73946ead235586vboxsync */
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync/*
46f059bea92bedbd395793702c73946ead235586vboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
46f059bea92bedbd395793702c73946ead235586vboxsync *
46f059bea92bedbd395793702c73946ead235586vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
46f059bea92bedbd395793702c73946ead235586vboxsync * available from http://www.virtualbox.org. This file is free software;
46f059bea92bedbd395793702c73946ead235586vboxsync * you can redistribute it and/or modify it under the terms of the GNU
46f059bea92bedbd395793702c73946ead235586vboxsync * General Public License (GPL) as published by the Free Software
46f059bea92bedbd395793702c73946ead235586vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * The contents of this file may alternatively be used under the terms
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * of the Common Development and Distribution License Version 1.0
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution, in which case the provisions of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * CDDL are applicable instead of those of the GPL.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * You may elect to license modified versions of this file under the
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * terms and conditions of either the GPL or the CDDL or both.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync *
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
46f059bea92bedbd395793702c73946ead235586vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
46f059bea92bedbd395793702c73946ead235586vboxsync * additional information or have any questions.
46f059bea92bedbd395793702c73946ead235586vboxsync */
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync/*******************************************************************************
46f059bea92bedbd395793702c73946ead235586vboxsync* Header Files *
46f059bea92bedbd395793702c73946ead235586vboxsync*******************************************************************************/
46f059bea92bedbd395793702c73946ead235586vboxsync#include <iprt/runtime.h>
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync/*******************************************************************************
46f059bea92bedbd395793702c73946ead235586vboxsync* Structures and Typedefs *
46f059bea92bedbd395793702c73946ead235586vboxsync*******************************************************************************/
46f059bea92bedbd395793702c73946ead235586vboxsynctypedef struct TSCDATA
46f059bea92bedbd395793702c73946ead235586vboxsync{
46f059bea92bedbd395793702c73946ead235586vboxsync /** The TSC. */
46f059bea92bedbd395793702c73946ead235586vboxsync uint64_t volatile TSC;
46f059bea92bedbd395793702c73946ead235586vboxsync /** The APIC ID. */
46f059bea92bedbd395793702c73946ead235586vboxsync uint8_t volatile u8ApicId;
46f059bea92bedbd395793702c73946ead235586vboxsync /** Did it succeed? */
46f059bea92bedbd395793702c73946ead235586vboxsync bool volatile fRead;
46f059bea92bedbd395793702c73946ead235586vboxsync /** Did it fail? */
46f059bea92bedbd395793702c73946ead235586vboxsync bool volatile fFailed;
46f059bea92bedbd395793702c73946ead235586vboxsync /** The thread handle. */
46f059bea92bedbd395793702c73946ead235586vboxsync RTTHREAD Thread;
46f059bea92bedbd395793702c73946ead235586vboxsync} TSCDATA, *PTSCDATA;
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync/*******************************************************************************
46f059bea92bedbd395793702c73946ead235586vboxsync* Global Variables *
46f059bea92bedbd395793702c73946ead235586vboxsync*******************************************************************************/
46f059bea92bedbd395793702c73946ead235586vboxsync/** The number of CPUs waiting on their user event semaphore. */
46f059bea92bedbd395793702c73946ead235586vboxsyncstatic volatile uint32_t g_cWaiting;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync/** The number of CPUs ready (in spin) to do the TSC read. */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsyncstatic volatile uint32_t g_cReady;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync/** The variable the CPUs are spinning on.
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync * 0: Spin.
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync * 1: Go ahead.
46f059bea92bedbd395793702c73946ead235586vboxsync * 2: You're too late, back to square one. */
46f059bea92bedbd395793702c73946ead235586vboxsyncstatic volatile uint32_t g_u32Go;
46f059bea92bedbd395793702c73946ead235586vboxsync/** The number of CPUs that managed to read the TSC. */
46f059bea92bedbd395793702c73946ead235586vboxsyncstatic volatile uint32_t g_cRead;
46f059bea92bedbd395793702c73946ead235586vboxsync/** The number of CPUs that failed to read the TSC. */
46f059bea92bedbd395793702c73946ead235586vboxsyncstatic volatile uint32_t g_cFailed;
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync/** Indicator forcing the threads to quit. */
46f059bea92bedbd395793702c73946ead235586vboxsyncstatic volatile bool g_fDone;
46f059bea92bedbd395793702c73946ead235586vboxsync
1bef0d3fd3b2fe689a4eaa9ebf0647b8bf7c662evboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync/*******************************************************************************
46f059bea92bedbd395793702c73946ead235586vboxsync* Internal Functions *
46f059bea92bedbd395793702c73946ead235586vboxsync*******************************************************************************/
46f059bea92bedbd395793702c73946ead235586vboxsyncstatic DECLCALLBACK(int) ThreadFunction(RTTHREAD Thread, void *pvUser);
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync/**
46f059bea92bedbd395793702c73946ead235586vboxsync * Thread function for catching the other cpus.
46f059bea92bedbd395793702c73946ead235586vboxsync *
46f059bea92bedbd395793702c73946ead235586vboxsync * @returns VINF_SUCCESS (we don't care).
46f059bea92bedbd395793702c73946ead235586vboxsync * @param Thread The thread handle.
46f059bea92bedbd395793702c73946ead235586vboxsync * @param pvUser PTSCDATA.
46f059bea92bedbd395793702c73946ead235586vboxsync */
46f059bea92bedbd395793702c73946ead235586vboxsyncstatic DECLCALLBACK(int) ThreadFunction(RTTHREAD Thread, void *pvUser)
46f059bea92bedbd395793702c73946ead235586vboxsync{
46f059bea92bedbd395793702c73946ead235586vboxsync PTSCDATA pTscData = (PTSCDATA)pvUser;
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync while (!g_fDone)
46f059bea92bedbd395793702c73946ead235586vboxsync {
46f059bea92bedbd395793702c73946ead235586vboxsync /*
46f059bea92bedbd395793702c73946ead235586vboxsync * Wait.
46f059bea92bedbd395793702c73946ead235586vboxsync */
46f059bea92bedbd395793702c73946ead235586vboxsync ASMAtomicIncU32(&g_cWaiting);
46f059bea92bedbd395793702c73946ead235586vboxsync RTThreadUserWait(Thread, RT_INDEFINITE_WAIT);
46f059bea92bedbd395793702c73946ead235586vboxsync RTThreadUserReset(Thread);
46f059bea92bedbd395793702c73946ead235586vboxsync ASMAtomicDecU32(&g_cWaiting);
46f059bea92bedbd395793702c73946ead235586vboxsync if (g_fDone)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync break;
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync /*
46f059bea92bedbd395793702c73946ead235586vboxsync * Spin.
46f059bea92bedbd395793702c73946ead235586vboxsync */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync ASMAtomicIncU32(&g_cReady);
46f059bea92bedbd395793702c73946ead235586vboxsync while (!g_fDone)
46f059bea92bedbd395793702c73946ead235586vboxsync {
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId1 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint64_t TSC1 = ASMReadTSC();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint32_t u32Go = g_u32Go;
46f059bea92bedbd395793702c73946ead235586vboxsync if (u32Go == 0)
46f059bea92bedbd395793702c73946ead235586vboxsync continue;
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync if (u32Go == 1)
46f059bea92bedbd395793702c73946ead235586vboxsync {
46f059bea92bedbd395793702c73946ead235586vboxsync /* do the reading. */
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId2 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint64_t TSC2 = ASMReadTSC();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId3 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint64_t TSC3 = ASMReadTSC();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId4 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync if ( ApicId1 == ApicId2
46f059bea92bedbd395793702c73946ead235586vboxsync && ApicId1 == ApicId3
46f059bea92bedbd395793702c73946ead235586vboxsync && ApicId1 == ApicId4
46f059bea92bedbd395793702c73946ead235586vboxsync && TSC3 - TSC1 < 2250 /* WARNING: This is just a guess, increase if it doesn't work for you. */
46f059bea92bedbd395793702c73946ead235586vboxsync && TSC2 - TSC1 < TSC3 - TSC1
46f059bea92bedbd395793702c73946ead235586vboxsync )
46f059bea92bedbd395793702c73946ead235586vboxsync {
46f059bea92bedbd395793702c73946ead235586vboxsync /* succeeded. */
46f059bea92bedbd395793702c73946ead235586vboxsync pTscData->TSC = TSC2;
46f059bea92bedbd395793702c73946ead235586vboxsync pTscData->u8ApicId = ApicId1;
46f059bea92bedbd395793702c73946ead235586vboxsync pTscData->fFailed = false;
46f059bea92bedbd395793702c73946ead235586vboxsync pTscData->fRead = true;
46f059bea92bedbd395793702c73946ead235586vboxsync ASMAtomicIncU32(&g_cRead);
46f059bea92bedbd395793702c73946ead235586vboxsync break;
46f059bea92bedbd395793702c73946ead235586vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /* failed */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync pTscData->fFailed = true;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync pTscData->fRead = false;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync ASMAtomicIncU32(&g_cFailed);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync break;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync return VINF_SUCCESS;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync}
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsyncint main()
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync{
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTR3Init();
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /*
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync * This is only relevant to on SMP systems.
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync const unsigned cCpus = RTMpGetOnlineCount();
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync if (cCpus <= 1)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTPrintf("tstTSC: SKIPPED - Only relevant on SMP systems\n");
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync return 0;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /*
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync * Create the threads.
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync static TSCDATA s_aData[254];
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync uint32_t i;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync if (cCpus > RT_ELEMENTS(s_aData))
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTPrintf("tstTSC: FAILED - too many CPUs (%u)\n", cCpus);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync return 1;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /* ourselves. */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync s_aData[0].Thread = RTThreadSelf();
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /* the others */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync for (i = 1; i < cCpus; i++)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync int rc = RTThreadCreate(&s_aData[i].Thread, ThreadFunction, &s_aData[i], 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "OTHERCPU");
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync if (RT_FAILURE(rc))
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTPrintf("tstTSC: FAILURE - RTThreatCreate failed when creating thread #%u, rc=%Rrc!\n", i, rc);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync ASMAtomicXchgSize(&g_fDone, true);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync while (i-- > 1)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTThreadUserSignal(s_aData[i].Thread);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTThreadWait(s_aData[i].Thread, 5000, NULL);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync return 1;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /*
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync * Retry untill we get lucky (or give up).
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync for (unsigned cTries = 0; ; cTries++)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync if (cTries > 10240)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTPrintf("tstTSC: FAILURE - %d attempts, giving.\n", cTries);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync break;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /*
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync * Wait for the other threads to get ready (brute force active wait, I'm lazy).
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync i = 0;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync while (g_cWaiting < cCpus - 1)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync if (i++ > _2G32)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync break;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTThreadSleep(i & 0xf);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync if (g_cWaiting != cCpus - 1)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTPrintf("tstTSC: FAILURE - threads failed to get waiting (%d != %d (i=%d))\n", g_cWaiting + 1, cCpus, i);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync break;
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /*
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync * Send them spinning.
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync ASMAtomicXchgU32(&g_cReady, 0);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync ASMAtomicXchgU32(&g_u32Go, 0);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync ASMAtomicXchgU32(&g_cRead, 0);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync ASMAtomicXchgU32(&g_cFailed, 0);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync for (i = 1; i < cCpus; i++)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync ASMAtomicXchgSize(&s_aData[i].fFailed, false);
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync ASMAtomicXchgSize(&s_aData[i].fRead, false);
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync ASMAtomicXchgU8(&s_aData[i].u8ApicId, 0xff);
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync int rc = RTThreadUserSignal(s_aData[i].Thread);
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync if (RT_FAILURE(rc))
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync RTPrintf("tstTSC: WARNING - RTThreadUserSignal(%#u) -> rc=%Rrc!\n", i, rc);
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync }
57134cc31d26d91192e87a4541b4f82fbdb2c297vboxsync
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /* wait for them to get ready. */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync i = 0;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync while (g_cReady < cCpus - 1)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync if (i++ > _2G32)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync break;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync }
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync if (g_cReady != cCpus - 1)
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync {
46f059bea92bedbd395793702c73946ead235586vboxsync RTPrintf("tstTSC: FAILURE - threads failed to get ready (%d != %d, i=%d)\n", g_cWaiting + 1, cCpus, i);
46f059bea92bedbd395793702c73946ead235586vboxsync break;
46f059bea92bedbd395793702c73946ead235586vboxsync }
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync /*
46f059bea92bedbd395793702c73946ead235586vboxsync * Flip the "go" switch and do our readings.
46f059bea92bedbd395793702c73946ead235586vboxsync * We give the other threads the slack it takes to two extra TSC and APIC ID reads.
46f059bea92bedbd395793702c73946ead235586vboxsync */
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId1 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint64_t TSC1 = ASMReadTSC();
46f059bea92bedbd395793702c73946ead235586vboxsync ASMAtomicXchgU32(&g_u32Go, 1);
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId2 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint64_t TSC2 = ASMReadTSC();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId3 = ASMGetApicId();
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync const uint64_t TSC3 = ASMReadTSC();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId4 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint64_t TSC4 = ASMReadTSC();
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync ASMAtomicXchgU32(&g_u32Go, 2);
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId5 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint64_t TSC5 = ASMReadTSC();
46f059bea92bedbd395793702c73946ead235586vboxsync const uint8_t ApicId6 = ASMGetApicId();
46f059bea92bedbd395793702c73946ead235586vboxsync
46f059bea92bedbd395793702c73946ead235586vboxsync /* Compose our own result. */
46f059bea92bedbd395793702c73946ead235586vboxsync if ( ApicId1 == ApicId2
46f059bea92bedbd395793702c73946ead235586vboxsync && ApicId1 == ApicId3
46f059bea92bedbd395793702c73946ead235586vboxsync && ApicId1 == ApicId4
46f059bea92bedbd395793702c73946ead235586vboxsync && ApicId1 == ApicId5
46f059bea92bedbd395793702c73946ead235586vboxsync && ApicId1 == ApicId6
46f059bea92bedbd395793702c73946ead235586vboxsync && TSC5 - TSC1 < 2750 /* WARNING: This is just a guess, increase if it doesn't work for you. */
46f059bea92bedbd395793702c73946ead235586vboxsync && TSC4 - TSC1 < TSC5 - TSC1
46f059bea92bedbd395793702c73946ead235586vboxsync && TSC3 - TSC1 < TSC4 - TSC1
46f059bea92bedbd395793702c73946ead235586vboxsync && TSC2 - TSC1 < TSC3 - TSC1
46f059bea92bedbd395793702c73946ead235586vboxsync )
46f059bea92bedbd395793702c73946ead235586vboxsync {
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync /* succeeded. */
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync s_aData[0].TSC = TSC2;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync s_aData[0].u8ApicId = ApicId1;
df2e37f58f19997178bb9be53867a17509a3a2f9vboxsync s_aData[0].fFailed = false;
46f059bea92bedbd395793702c73946ead235586vboxsync s_aData[0].fRead = true;
46f059bea92bedbd395793702c73946ead235586vboxsync ASMAtomicIncU32(&g_cRead);
46f059bea92bedbd395793702c73946ead235586vboxsync }
46f059bea92bedbd395793702c73946ead235586vboxsync else
46f059bea92bedbd395793702c73946ead235586vboxsync {
46f059bea92bedbd395793702c73946ead235586vboxsync /* failed */
46f059bea92bedbd395793702c73946ead235586vboxsync s_aData[0].fFailed = true;
46f059bea92bedbd395793702c73946ead235586vboxsync s_aData[0].fRead = false;
46f059bea92bedbd395793702c73946ead235586vboxsync ASMAtomicIncU32(&g_cFailed);
}
/*
* Wait a little while to let the other ones to finish.
*/
i = 0;
while (g_cRead + g_cFailed < cCpus)
{
if (i++ > _2G32)
break;
if (i > _1M)
RTThreadSleep(i & 0xf);
}
if (g_cRead + g_cFailed != cCpus)
{
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
{
for (i = 1, fDone = true; i < cCpus; i++)
if (s_aData[i - 1].u8ApicId > s_aData[i].u8ApicId)
{
TSCDATA Tmp = s_aData[i - 1];
s_aData[i - 1] = s_aData[i];
s_aData[i] = Tmp;
fDone = false;
}
} while (!fDone);
RTPrintf(" # ID TSC delta0 (decimal)\n"
"-----------------------------------------\n");
RTPrintf("%2d %02x %RX64\n", 0, s_aData[0].u8ApicId, s_aData[0].TSC);
for (i = 1; i < cCpus; i++)
RTPrintf("%2d %02x %RX64 %s%lld\n", i, s_aData[i].u8ApicId, s_aData[i].TSC,
s_aData[i].TSC > s_aData[0].TSC ? "+" : "", s_aData[i].TSC - s_aData[0].TSC);
RTPrintf("(Needed %u attempt%s.)\n", cTries + 1, cTries ? "s" : "");
break;
}
}
/*
* Destroy the threads.
*/
ASMAtomicXchgSize(&g_fDone, true);
for (i = 0; i < cCpus; i++)
if (s_aData[i].Thread != RTThreadSelf())
{
int rc = RTThreadUserSignal(s_aData[i].Thread);
if (RT_FAILURE(rc))
RTPrintf("tstTSC: WARNING - RTThreadUserSignal(%#u) -> rc=%Rrc! (2)\n", i, rc);
}
for (i = 0; i < cCpus; i++)
if (s_aData[i].Thread != RTThreadSelf())
{
int rc = RTThreadWait(s_aData[i].Thread, 5000, NULL);
if (RT_FAILURE(rc))
RTPrintf("tstTSC: WARNING - RTThreadWait(%#u) -> rc=%Rrc!\n", i, rc);
}
return g_cFailed != 0 || g_cRead != cCpus;
}