tstTSC.cpp revision 43a30045886b1e6bec2b2726db20c0bd7edcce0d
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/* $Id$ */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** @file
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * innotek Portable Runtime Testcase - SMP TSC testcase.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
00550544656e1a1537bad42c4f4bacef814637cavboxsync/*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Copyright (C) 2006-2007 innotek GmbH
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * available from http://www.virtualbox.org. This file is free software;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * you can redistribute it and/or modify it under the terms of the GNU
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * General Public License as published by the Free Software Foundation,
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Header Files *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync#include <iprt/runtime.h>
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Structures and Typedefs *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsynctypedef struct TSCDATA
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** The TSC. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync uint64_t volatile TSC;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** The APIC ID. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync uint8_t volatile u8ApicId;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** Did it succeed? */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync bool volatile fRead;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** Did it fail? */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync bool volatile fFailed;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /** The thread handle. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTTHREAD Thread;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync} TSCDATA, *PTSCDATA;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Global Variables *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The number of CPUs waiting on their user event semaphore. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic volatile uint32_t g_cWaiting;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The number of CPUs ready (in spin) to do the TSC read. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic volatile uint32_t g_cReady;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The variable the CPUs are spinning on.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * 0: Spin.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * 1: Go ahead.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * 2: You're too late, back to square one. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic volatile uint32_t g_u32Go;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The number of CPUs that managed to read the TSC. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic volatile uint32_t g_cRead;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** The number of CPUs that failed to read the TSC. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic volatile uint32_t g_cFailed;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/** Indicator forcing the threads to quit. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic volatile bool g_fDone;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/*******************************************************************************
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync* Internal Functions *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync*******************************************************************************/
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic DECLCALLBACK(int) ThreadFunction(RTTHREAD Thread, void *pvUser);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync/**
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Thread function for catching the other cpus.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync *
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @returns VINF_SUCCESS (we don't care).
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @param Thread The thread handle.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * @param pvUser PTSCDATA.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsyncstatic DECLCALLBACK(int) ThreadFunction(RTTHREAD Thread, void *pvUser)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync PTSCDATA pTscData = (PTSCDATA)pvUser;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync while (!g_fDone)
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync {
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync /*
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync * Wait.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicIncU32(&g_cWaiting);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTThreadUserWait(Thread, RT_INDEFINITE_WAIT);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTThreadUserReset(Thread);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicDecU32(&g_cWaiting);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (g_fDone)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Spin.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicIncU32(&g_cReady);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync while (!g_fDone)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId1 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint64_t TSC1 = ASMReadTSC();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint32_t u32Go = g_u32Go;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (u32Go == 0)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync continue;
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync if (u32Go == 1)
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync {
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync /* do the reading. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId2 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint64_t TSC2 = ASMReadTSC();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId3 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint64_t TSC3 = ASMReadTSC();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId4 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if ( ApicId1 == ApicId2
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && ApicId1 == ApicId3
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && ApicId1 == ApicId4
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && TSC3 - TSC1 < 2250 /* WARNING: This is just a guess, increase if it doesn't work for you. */
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync && TSC2 - TSC1 < TSC3 - TSC1
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync )
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* succeeded. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync pTscData->TSC = TSC2;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync pTscData->u8ApicId = ApicId1;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync pTscData->fFailed = false;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync pTscData->fRead = true;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicIncU32(&g_cRead);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync /* failed */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync pTscData->fFailed = true;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync pTscData->fRead = false;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicIncU32(&g_cFailed);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return VINF_SUCCESS;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync}
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsyncint main()
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync{
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTR3Init();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * This is only relevant to on SMP systems.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const unsigned cCpus = RTSystemProcessorGetCount();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (cCpus <= 1)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("tstTSC: SKIPPED - Only relevant on SMP systems\n");
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return 0;
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync }
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Create the threads.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync static TSCDATA s_aData[254];
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync uint32_t i;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (cCpus > RT_ELEMENTS(s_aData))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("tstTSC: FAILED - too many CPUs (%u)\n", cCpus);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return 1;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
6bea637fe631bf8f14128c36c5da0fe98c0fa4edvboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* ourselves. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync s_aData[0].Thread = RTThreadSelf();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync /* the others */
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync for (i = 1; i < cCpus; i++)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = RTThreadCreate(&s_aData[i].Thread, ThreadFunction, &s_aData[i], 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "OTHERCPU");
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_FAILURE(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("tstTSC: FAILURE - RTThreatCreate failed when creating thread #%u, rc=%Rrc!\n", i, rc);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgSize(&g_fDone, true);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync while (i-- > 1)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTThreadUserSignal(s_aData[i].Thread);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTThreadWait(s_aData[i].Thread, 5000, NULL);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return 1;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Retry untill we get lucky (or give up).
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync for (unsigned cTries = 0; ; cTries++)
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (cTries > 10240)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("tstTSC: FAILURE - %d attempts, giving.\n", cTries);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Wait for the other threads to get ready (brute force active wait, I'm lazy).
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync i = 0;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync while (g_cWaiting < cCpus - 1)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (i++ > _2G32)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTThreadSleep(i & 0xf);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (g_cWaiting != cCpus - 1)
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync {
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync RTPrintf("tstTSC: FAILURE - threads failed to get waiting (%d != %d (i=%d))\n", g_cWaiting + 1, cCpus, i);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Send them spinning.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgU32(&g_cReady, 0);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgU32(&g_u32Go, 0);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgU32(&g_cRead, 0);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgU32(&g_cFailed, 0);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync for (i = 1; i < cCpus; i++)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync ASMAtomicXchgSize(&s_aData[i].fFailed, false);
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync ASMAtomicXchgSize(&s_aData[i].fRead, false);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgU8(&s_aData[i].u8ApicId, 0xff);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = RTThreadUserSignal(s_aData[i].Thread);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_FAILURE(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("tstTSC: WARNING - RTThreadUserSignal(%#u) -> rc=%Rrc!\n", i, rc);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* wait for them to get ready. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync i = 0;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync while (g_cReady < cCpus - 1)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (i++ > _2G32)
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync break;
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (g_cReady != cCpus - 1)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("tstTSC: FAILURE - threads failed to get ready (%d != %d, i=%d)\n", g_cWaiting + 1, cCpus, i);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Flip the "go" switch and do our readings.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * We give the other threads the slack it takes to two extra TSC and APIC ID reads.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId1 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint64_t TSC1 = ASMReadTSC();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgU32(&g_u32Go, 1);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId2 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint64_t TSC2 = ASMReadTSC();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId3 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint64_t TSC3 = ASMReadTSC();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId4 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint64_t TSC4 = ASMReadTSC();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgU32(&g_u32Go, 2);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId5 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint64_t TSC5 = ASMReadTSC();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync const uint8_t ApicId6 = ASMGetApicId();
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* Compose our own result. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if ( ApicId1 == ApicId2
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && ApicId1 == ApicId3
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && ApicId1 == ApicId4
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && ApicId1 == ApicId5
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && ApicId1 == ApicId6
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && TSC5 - TSC1 < 2750 /* WARNING: This is just a guess, increase if it doesn't work for you. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && TSC4 - TSC1 < TSC5 - TSC1
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && TSC3 - TSC1 < TSC4 - TSC1
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync && TSC2 - TSC1 < TSC3 - TSC1
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync )
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* succeeded. */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync s_aData[0].TSC = TSC2;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync s_aData[0].u8ApicId = ApicId1;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync s_aData[0].fFailed = false;
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync s_aData[0].fRead = true;
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync ASMAtomicIncU32(&g_cRead);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync else
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /* failed */
00550544656e1a1537bad42c4f4bacef814637cavboxsync s_aData[0].fFailed = true;
00550544656e1a1537bad42c4f4bacef814637cavboxsync s_aData[0].fRead = false;
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync ASMAtomicIncU32(&g_cFailed);
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync /*
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync * Wait a little while to let the other ones to finish.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync i = 0;
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync while (g_cRead + g_cFailed < cCpus)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync if (i++ > _2G32)
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (i > _1M)
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync RTThreadSleep(i & 0xf);
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (g_cRead + g_cFailed != cCpus)
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync {
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync RTPrintf("tstTSC: FAILURE - threads failed to complete reading (%d + %d != %d)\n", g_cRead, g_cFailed, cCpus);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
b84a3f2aac9529d5c5840512b12d81bc62d0e665vboxsync }
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync * If everone succeeded, print the results.
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (!g_cFailed)
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync {
968c867cc19737e4e1fd97c396fcf75a3d52dd27vboxsync RTPrintf(" # ID TSC\n"
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync "-----------------------\n");
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync for (i = 0; i < cCpus; i++)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("%2d %02x %RX64\n", i, s_aData[i].u8ApicId, s_aData[i].TSC);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("(Needed %u attempt%s.)\n", cTries + 1, cTries ? "s" : "");
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync break;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync /*
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync * Destroy the threads.
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync */
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync ASMAtomicXchgSize(&g_fDone, true);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync for (i = 1; i < cCpus; i++)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = RTThreadUserSignal(s_aData[i].Thread);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_FAILURE(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("tstTSC: WARNING - RTThreadUserSignal(%#u) -> rc=%Rrc! (2)\n", i, rc);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync for (i = 1; i < cCpus; i++)
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync {
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync int rc = RTThreadWait(s_aData[i].Thread, 5000, NULL);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync if (RT_FAILURE(rc))
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync RTPrintf("tstTSC: WARNING - RTThreadWait(%#u) -> rc=%Rrc!\n", i, rc);
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync }
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync return g_cFailed != 0 || g_cRead != cCpus;
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync}
0b74a2f80aba476dc8be8bc1c63891fc53945986vboxsync