VirtualBox

Changeset 54321 in vbox


Ignore:
Timestamp:
Feb 20, 2015 4:25:43 AM (10 years ago)
Author:
vboxsync
Message:

SUPDrv: Worked around (fudged) for hyper-threading issue by picking a different master CPU to measure against if we suspect (based on APIC ID) that the master and worker CPUs are threads on the same core. Fixed missing u64TSCSample reset for worker that caused master switching to assert. Center deltas around GIP_TSC_DELTA_INITIAL_MASTER_VALUE instead of 0, should provide better delta spread when testing the fake huge delta. Implemented an alternative TSC delta calculation algorithm that does a pretty decent job on the macbook pro (ivy bridge) - tstSupTscDelta -i1000 shows max spread of 17 tick over 4 runs, where as the current code shows 187 twice then 310 and 278. Not sure how expensive it is in comparison, needs testing and tuning. Not enabled of course.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.c

    r54318 r54321  
    71167116    if (pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED)
    71177117    {
    7118         RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, iCpuSet);
     7118        RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, iCpuSet);
    71197119#ifdef SUPDRV_USE_TSC_DELTA_THREAD
    71207120        RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
     
    71787178        ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX);
    71797179        /* Remove this CPU from the set of CPUs that we have obtained the TSC deltas. */
    7180         RTCpuSetDel(&pDevExt->TscDeltaObtainedCpuSet, iCpuSet);
     7180        RTCpuSetDelByIndex(&pDevExt->TscDeltaObtainedCpuSet, iCpuSet);
    71817181    }
    71827182
     
    72447244
    72457245            for (i = 0; i < RTCPUSET_MAX_CPUS; i++)
    7246             {
    7247                 RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i);
    7248                 if (   RTCpuSetIsMember(&OnlineCpus, idCurCpu)
    7249                     && idCurCpu != idGipMaster)
     7246                if (RTCpuSetIsMemberByIndex(&OnlineCpus, i))
    72507247                {
    7251                     idNewGipMaster = idCurCpu;
    7252                     break;
     7248                    RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i);
     7249                    if (idCurCpu != idGipMaster)
     7250                    {
     7251                        idNewGipMaster = idCurCpu;
     7252                        break;
     7253                    }
    72537254                }
    7254             }
    72557255
    72567256            Log(("supdrvGipMpEvent: Gip master %#lx -> %#lx\n", (long)idGipMaster, (long)idNewGipMaster));
     
    72627262
    72637263
     7264/*
     7265 * Select TSC delta measurement algorithm.
     7266 */
     7267#if 1
     7268# define GIP_TSC_DELTA_METHOD_1
     7269#else
     7270# define GIP_TSC_DELTA_METHOD_2
     7271#endif
     7272
     7273
     7274#ifdef GIP_TSC_DELTA_METHOD_2
     7275
     7276/**
     7277 * TSC delta measurment algorithm \#2 result entry.
     7278 */
     7279typedef struct SUPDRVTSCDELTAMETHOD2ENTRY
     7280{
     7281    uint32_t    iSeqMine;
     7282    uint32_t    iSeqOther;
     7283    uint64_t    uTsc;
     7284} SUPDRVTSCDELTAMETHOD2ENTRY;
     7285
     7286/**
     7287 * TSC delta measurment algorithm \#2 Data.
     7288 */
     7289typedef struct SUPDRVTSCDELTAMETHOD2
     7290{
     7291    /** Padding to make sure the iCurSeqNo is in its own cache line.
     7292     * ASSUMES cacheline sizes <= 128 bytes. */
     7293    uint32_t                    au32CacheLinePaddingBefore[128 / sizeof(uint32_t)];
     7294    /** The current sequence number of this worker. */
     7295    uint32_t volatile           iCurSeqNo;
     7296    /** Padding to make sure the iCurSeqNo is in its own cache line.
     7297     * ASSUMES cacheline sizes <= 128 bytes. */
     7298    uint32_t                    au32CacheLinePaddingAfter[128 / sizeof(uint32_t) - 1];
     7299    /** Result table. */
     7300    SUPDRVTSCDELTAMETHOD2ENTRY  aResults[96];
     7301} SUPDRVTSCDELTAMETHOD2;
     7302/** Pointer to the data for TSC delta mesurment algorithm \#2 .*/
     7303typedef SUPDRVTSCDELTAMETHOD2 *PSUPDRVTSCDELTAMETHOD2;
     7304
     7305#endif /* GIP_TSC_DELTA_METHOD_2 */
     7306
     7307/**
     7308 * Argument package/state passed by supdrvMeasureTscDeltaOne to the RTMpOn
     7309 * callback worker.
     7310 */
     7311typedef struct SUPDRVGIPTSCDELTARGS
     7312{
     7313    PSUPDRVDEVEXT           pDevExt;
     7314    PSUPGIPCPU              pWorker;
     7315    PSUPGIPCPU              pMaster;
     7316    RTCPUID                 idMaster;
     7317#ifdef GIP_TSC_DELTA_METHOD_2
     7318    PSUPDRVTSCDELTAMETHOD2  pMasterData;
     7319    PSUPDRVTSCDELTAMETHOD2  pWorkerData;
     7320    uint32_t                cHits;
     7321    /*uint32_t                cOffByOne;*/
     7322    uint32_t                iAttempt;       /**< 1-base outer loop counter. */
     7323    bool                    fLagMaster;
     7324    bool                    fLagWorker;
     7325#endif
     7326} SUPDRVGIPTSCDELTARGS;
     7327typedef SUPDRVGIPTSCDELTARGS *PSUPDRVGIPTSCDELTARGS;
     7328
     7329
     7330#ifdef GIP_TSC_DELTA_METHOD_2
     7331/*
     7332 * TSC delta measurement algorithm \#2 configuration and code - Experimental!!
     7333 */
     7334# undef  GIP_TSC_DELTA_LOOPS
     7335# undef  GIP_TSC_DELTA_READ_TIME_LOOPS
     7336# undef  GIP_TSC_DELTA_PRIMER_LOOPS
     7337# define GIP_TSC_DELTA_LOOPS             17
     7338# define GIP_TSC_DELTA_PRIMER_LOOPS      1
     7339# define GIP_TSC_DELTA_READ_TIME_LOOPS   GIP_TSC_DELTA_PRIMER_LOOPS /* no read-time-loops necessary */
     7340
     7341
     7342static int supdrvTscDeltaMethod2Init(PSUPDRVGIPTSCDELTARGS pArgs)
     7343{
     7344    uint32_t const fFlags = /*RTMEMALLOCEX_FLAGS_ANY_CTX |*/ RTMEMALLOCEX_FLAGS_ZEROED;
     7345    int rc = RTMemAllocEx(sizeof(*pArgs->pMasterData), 0, fFlags, (void **)&pArgs->pWorkerData);
     7346    if (RT_SUCCESS(rc))
     7347        rc = RTMemAllocEx(sizeof(*pArgs->pMasterData), 0, fFlags, (void **)&pArgs->pMasterData);
     7348    return rc;
     7349}
     7350
     7351
     7352static void supdrvTscDeltaMethod2Term(PSUPDRVGIPTSCDELTARGS pArgs)
     7353{
     7354    RTMemFreeEx(pArgs->pMasterData, sizeof(*pArgs->pMasterData));
     7355    RTMemFreeEx(pArgs->pWorkerData, sizeof(*pArgs->pWorkerData));
     7356    /*SUPR0Printf("cHits=%d cOffByOne=%d m=%d w=%d\n", pArgs->cHits, pArgs->cOffByOne, pArgs->pMaster->idApic, pArgs->pWorker->idApic);*/
     7357}
     7358
     7359
     7360static void supdrvTscDeltaMethod2Looped(PSUPDRVGIPTSCDELTARGS pArgs, RTCPUID idCpu, unsigned iLoop)
     7361{
     7362    if (pArgs->idMaster == idCpu)
     7363    {
     7364        if (iLoop < GIP_TSC_DELTA_PRIMER_LOOPS)
     7365        {
     7366            if (iLoop == 0)
     7367                pArgs->iAttempt++;
     7368
     7369            /* Lag during the priming to be nice to everyone.. */
     7370            pArgs->fLagMaster = true;
     7371            pArgs->fLagWorker = true;
     7372        }
     7373        else if (iLoop < (GIP_TSC_DELTA_LOOPS - GIP_TSC_DELTA_PRIMER_LOOPS) / 4)
     7374        {
     7375            /* 25 % of the body without lagging. */
     7376            pArgs->fLagMaster = false;
     7377            pArgs->fLagWorker = false;
     7378        }
     7379        else if (iLoop < (GIP_TSC_DELTA_LOOPS - GIP_TSC_DELTA_PRIMER_LOOPS) / 4 * 2)
     7380        {
     7381            /* 25 % of the body with both lagging. */
     7382            pArgs->fLagMaster = true;
     7383            pArgs->fLagWorker = true;
     7384        }
     7385        else
     7386        {
     7387            /* 50% of the body with alternating lag. */
     7388            pArgs->fLagMaster = (iLoop & 1) == 0;
     7389            pArgs->fLagWorker = (iLoop & 1) == 1;
     7390        }
     7391    }
     7392}
     7393
     7394
     7395/**
     7396 * The core function of the 2nd TSC delta mesurment algorithm.
     7397 * 
     7398 * The idea here is that we have the two CPUs execute the exact same code
     7399 * collecting a largish set of TSC samples.  The code has one data dependency on
     7400 * the other CPU which intention it is to synchronize the execution as well as
     7401 * help cross references the two sets of TSC samples (the sequence numbers). 
     7402 *
     7403 * The @a fLag parameter is used to modify the execution a tiny bit on one or
     7404 * both of the CPUs.  When @a fLag differs between the CPUs, it is thought that
     7405 * it will help with making the CPUs enter lock step execution occationally.
     7406 *
     7407 */
     7408static void supdrvTscDeltaMethod2CollectData(PSUPDRVTSCDELTAMETHOD2 pMyData, uint32_t volatile *piOtherSeqNo, bool fLag)
     7409{
     7410    SUPDRVTSCDELTAMETHOD2ENTRY *pEntry = &pMyData->aResults[0];
     7411    uint32_t                    cLeft  = RT_ELEMENTS(pMyData->aResults);
     7412
     7413    ASMAtomicWriteU32(&pMyData->iCurSeqNo, 0);
     7414    ASMSerializeInstruction();
     7415    while (cLeft-- > 0)
     7416    {
     7417        uint64_t uTsc;
     7418        uint32_t iSeqMine  = ASMAtomicIncU32(&pMyData->iCurSeqNo);
     7419        uint32_t iSeqOther = ASMAtomicReadU32(piOtherSeqNo);
     7420        ASMCompilerBarrier();
     7421        ASMSerializeInstruction(); /* Way better result than with ASMMemoryFenceSSE2() in this position! */
     7422        uTsc = ASMReadTSC();
     7423        ASMAtomicIncU32(&pMyData->iCurSeqNo);
     7424        ASMCompilerBarrier();
     7425        ASMSerializeInstruction();
     7426        pEntry->iSeqMine  = iSeqMine;
     7427        pEntry->iSeqOther = iSeqOther;
     7428        pEntry->uTsc      = uTsc;
     7429        pEntry++;
     7430        ASMSerializeInstruction();
     7431        if (fLag)
     7432            ASMNopPause();
     7433    }
     7434}
     7435
     7436
     7437static void supdrvTscDeltaMethod2ProcessDataSet(PSUPDRVGIPTSCDELTARGS pArgs, PSUPDRVTSCDELTAMETHOD2 pMyData,
     7438                                                bool fIsMaster, uint32_t cResults,
     7439                                                PSUPDRVTSCDELTAMETHOD2 pOtherData, int64_t iMasterTscDelta,
     7440                                                int64_t volatile *piWorkerTscDelta)
     7441{
     7442    uint32_t cHits      = 0;
     7443#if 0
     7444    uint32_t cOffByOne  = 0;
     7445#endif
     7446    uint32_t idxResult  = 0;
     7447    int64_t  iBestDelta = *piWorkerTscDelta;
     7448
     7449    if (cResults > RT_ELEMENTS(pMyData->aResults))
     7450        cResults = RT_ELEMENTS(pMyData->aResults);
     7451
     7452    for (idxResult = 0; idxResult < cResults; idxResult++)
     7453    {
     7454        uint32_t idxOther = pMyData->aResults[idxResult].iSeqOther;
     7455        if (idxOther & 1)
     7456        {
     7457            idxOther >>= 1;
     7458            if (idxOther < RT_ELEMENTS(pOtherData->aResults))
     7459            {
     7460                if (pOtherData->aResults[idxOther].iSeqOther == pMyData->aResults[idxResult].iSeqMine)
     7461                {
     7462                    int64_t iDelta;
     7463                    if (fIsMaster)
     7464                        iDelta = pOtherData->aResults[idxOther].uTsc
     7465                               - (pMyData->aResults[idxResult].uTsc - iMasterTscDelta);
     7466                    else
     7467                        iDelta = (pOtherData->aResults[idxResult].uTsc - iMasterTscDelta)
     7468                               - pMyData->aResults[idxOther].uTsc;
     7469                    if (  iDelta >= GIP_TSC_DELTA_INITIAL_MASTER_VALUE
     7470                        ? iDelta < iBestDelta
     7471                        : iDelta > iBestDelta || iBestDelta == INT64_MAX)
     7472                        iBestDelta = iDelta;
     7473                    cHits++;
     7474                }
     7475            }
     7476        }
     7477#if 0  /* Can be used to detect battles between threads on the same core. Decided to change the master instead.  */
     7478        else
     7479        {
     7480            idxOther >>= 1;
     7481            if (   idxOther < RT_ELEMENTS(pOtherData->aResults)
     7482                && pOtherData->aResults[idxOther].iSeqOther == pMyData->aResults[idxResult].iSeqMine)
     7483                cOffByOne++;
     7484        }
     7485#endif
     7486    }
     7487
     7488    if (cHits > 0)
     7489        *piWorkerTscDelta = iBestDelta;
     7490    pArgs->cHits     += cHits;
     7491#if 0
     7492    pArgs->cOffByOne += cOffByOne;
     7493#endif
     7494}
     7495
     7496
     7497static void supdrvTscDeltaMethod2ProcessDataOnMaster(PSUPDRVGIPTSCDELTARGS pArgs, bool fFinalLoop)
     7498{
     7499    supdrvTscDeltaMethod2ProcessDataSet(pArgs,
     7500                                        pArgs->pMasterData,
     7501                                        true /*fIsMaster*/,
     7502                                        RT_ELEMENTS(pArgs->pMasterData->aResults),
     7503                                        pArgs->pWorkerData,
     7504                                        pArgs->pMaster->i64TSCDelta,
     7505                                        &pArgs->pWorker->i64TSCDelta);
     7506
     7507    supdrvTscDeltaMethod2ProcessDataSet(pArgs,
     7508                                        pArgs->pWorkerData,
     7509                                        false /*fIsMaster*/,
     7510                                        ASMAtomicReadU32(&pArgs->pWorkerData->iCurSeqNo) >> 1,
     7511                                        pArgs->pMasterData,
     7512                                        pArgs->pMaster->i64TSCDelta,
     7513                                        &pArgs->pWorker->i64TSCDelta);
     7514}
     7515
     7516#endif /* GIP_TSC_DELTA_METHOD_2 */
     7517
     7518
    72647519/**
    72657520 * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs
     
    72677522 *
    72687523 * @param   idCpu       The CPU we are current scheduled on.
    7269  * @param   pvUser1     Opaque pointer to the device instance data.
    7270  * @param   pvUser2     Pointer to the SUPGIPCPU entry of the worker CPU.
     7524 * @param   pvUser1     Pointer to a parameter package (SUPDRVGIPTSCDELTARGS).
     7525 * @param   pvUser2     Unused.
    72717526 *
    72727527 * @remarks Measuring TSC deltas between the CPUs is tricky because we need to
     
    72977552static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
    72987553{
    7299     PSUPDRVDEVEXT      pDevExt          = (PSUPDRVDEVEXT)pvUser1;
     7554    PSUPDRVGIPTSCDELTARGS pArgs = (PSUPDRVGIPTSCDELTARGS)pvUser1;
     7555    PSUPDRVDEVEXT      pDevExt          = pArgs->pDevExt;
    73007556    PSUPGLOBALINFOPAGE pGip             = pDevExt->pGip;
    7301     PSUPGIPCPU         pGipCpuWorker    = (PSUPGIPCPU)pvUser2;
    7302     uint32_t           idWorker         = pGipCpuWorker->idCpu;
    7303     RTCPUID            idMaster         = ASMAtomicUoReadU32(&pDevExt->idTscDeltaInitiator);
    7304     unsigned           idxMaster        = supdrvGipFindCpuIndexForCpuId(pGip, idMaster);
    7305     PSUPGIPCPU         pGipCpuMaster    = &pGip->aCPUs[idxMaster];
     7557    PSUPGIPCPU         pGipCpuWorker    = pArgs->pWorker;
     7558    PSUPGIPCPU         pGipCpuMaster    = pArgs->pMaster;
     7559    RTCPUID            idMaster         = pArgs->idMaster;
    73067560    int                cTriesLeft;
    73077561
     7562    /* A bit of paranoia first. */
     7563    if (!pGipCpuMaster || !pGipCpuWorker)
     7564        return;
     7565
     7566    /* If the CPU isn't part of the measurement, return immediately. */
    73087567    if (   idCpu != idMaster
    7309         && idCpu != idWorker)
     7568        && idCpu != pGipCpuWorker->idCpu)
    73107569        return;
    73117570
     
    73697628        for (i = 0; i < GIP_TSC_DELTA_LOOPS; i++)
    73707629        {
     7630#ifdef GIP_TSC_DELTA_METHOD_2
     7631            supdrvTscDeltaMethod2Looped(pArgs, idCpu, i);
     7632#endif
    73717633            if (idCpu == idMaster)
    73727634            {
     
    73757637                 */
    73767638                RTCCUINTREG uFlags;
    7377                 Assert(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD);
     7639                AssertMsg(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD,
     7640                          ("%#llx idMaster=%#x idWorker=%#x (idGipMaster=%#x)\n",
     7641                           pGipCpuMaster->u64TSCSample, idMaster, pGipCpuWorker->idCpu, pDevExt->idGipMaster));
    73787642                ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_START);
    73797643
     
    73857649                { /* nothing */ }
    73867650
     7651#ifdef GIP_TSC_DELTA_METHOD_1
    73877652                do
    73887653                {
     
    73917656                } while (pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD);
    73927657
     7658#elif defined(GIP_TSC_DELTA_METHOD_2)
     7659                supdrvTscDeltaMethod2CollectData(pArgs->pMasterData, &pArgs->pWorkerData->iCurSeqNo, pArgs->fLagMaster);
     7660#else
     7661# error "tsc delta method not selected"
     7662#endif
     7663
     7664                /* Sync up with worker. */
    73937665                ASMSetFlags(uFlags);
    73947666
     
    73967668                { /* nothing */ }
    73977669
     7670                /* Process the data. */
    73987671                if (i > GIP_TSC_DELTA_PRIMER_LOOPS + GIP_TSC_DELTA_READ_TIME_LOOPS)
    73997672                {
     7673#ifdef GIP_TSC_DELTA_METHOD_1
    74007674                    if (pGipCpuWorker->u64TSCSample != GIP_TSC_DELTA_RSVD)
    74017675                    {
    74027676                        int64_t iDelta = pGipCpuWorker->u64TSCSample
    74037677                                       - (pGipCpuMaster->u64TSCSample - pGipCpuMaster->i64TSCDelta);
    7404                         if (  iDelta >= 0
     7678                        if (  iDelta >= GIP_TSC_DELTA_INITIAL_MASTER_VALUE
    74057679                            ? iDelta < pGipCpuWorker->i64TSCDelta
    74067680                            : iDelta > pGipCpuWorker->i64TSCDelta || pGipCpuWorker->i64TSCDelta == INT64_MAX)
    74077681                            pGipCpuWorker->i64TSCDelta = iDelta;
    74087682                    }
     7683#elif defined(GIP_TSC_DELTA_METHOD_2)
     7684                    if (i > GIP_TSC_DELTA_PRIMER_LOOPS)
     7685                        supdrvTscDeltaMethod2ProcessDataOnMaster(pArgs, i == GIP_TSC_DELTA_LOOPS - 1);
     7686#else
     7687# error "tsc delta method not selected"
     7688#endif
    74097689                }
    74107690
     7691                /* Reset our TSC sample and tell the worker to move on. */
    74117692                ASMAtomicWriteU64(&pGipCpuMaster->u64TSCSample, GIP_TSC_DELTA_RSVD);
    74127693                ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP);
     
    74277708                ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_WORKER_READY);
    74287709
     7710#ifdef GIP_TSC_DELTA_METHOD_1
    74297711                /*
    74307712                 * Keep reading the TSC until we notice that the master has read his. Reading
     
    74607742                }
    74617743
     7744#elif defined(GIP_TSC_DELTA_METHOD_2)
     7745                supdrvTscDeltaMethod2CollectData(pArgs->pWorkerData, &pArgs->pMasterData->iCurSeqNo, pArgs->fLagWorker);
     7746#else
     7747# error "tsc delta method not selected"
     7748#endif
     7749
     7750                /* Tell master we're done collecting our data. */
    74627751                ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_WORKER_DONE);
     7752
     7753                /* Wait for the master to process the data. */
    74637754                while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) == GIP_TSC_DELTA_SYNC_WORKER_DONE)
    74647755                    ASMNopPause();
     
    74667757        }
    74677758
     7759        /*
     7760         * We must reset the worker TSC sample value in case it gets picked as a
     7761         * GIP master later on (it's trashed above, naturally).
     7762         */
     7763        if (idCpu == idMaster)
     7764            ASMAtomicWriteU64(&pGipCpuWorker->u64TSCSample, GIP_TSC_DELTA_RSVD);
     7765
     7766        /*
     7767         * Success? If so, stop trying.
     7768         */
    74687769        if (pGipCpuWorker->i64TSCDelta != INT64_MAX)
    74697770        {
    74707771            if (idCpu == idMaster)
    74717772            {
    7472                 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet);
    7473                 RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet);
     7773                RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuMaster->iCpuSet);
     7774                RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuMaster->iCpuSet);
    74747775            }
    74757776            else
    74767777            {
    7477                 RTCpuSetDel(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
    7478                 RTCpuSetAdd(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
     7778                RTCpuSetDelByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
     7779                RTCpuSetAddByIndex(&pDevExt->TscDeltaObtainedCpuSet, pGipCpuWorker->iCpuSet);
    74797780            }
    74807781            break;
     
    75217822static int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker)
    75227823{
    7523     int rc;
    7524     PSUPGLOBALINFOPAGE pGip;
    7525     PSUPGIPCPU pGipCpuWorker;
    7526     RTCPUID idMaster;
    7527 
    7528     AssertReturn(pDevExt, VERR_INVALID_PARAMETER);
    7529     AssertReturn(pDevExt->pGip, VERR_INVALID_PARAMETER);
    7530 
    7531     pGip          = pDevExt->pGip;
    7532     idMaster      = pDevExt->idGipMaster;
    7533     pGipCpuWorker = &pGip->aCPUs[idxWorker];
    7534 
     7824    int                 rc;
     7825    PSUPGLOBALINFOPAGE  pGip          = pDevExt->pGip;
     7826    RTCPUID             idMaster      = pDevExt->idGipMaster;
     7827    PSUPGIPCPU          pGipCpuWorker = &pGip->aCPUs[idxWorker];
     7828    PSUPGIPCPU          pGipCpuMaster;
     7829    uint32_t            iGipCpuMaster;
     7830
     7831    /* Validate input a bit. */
     7832    AssertReturn(pGip, VERR_INVALID_PARAMETER);
    75357833    Assert(pGip->enmUseTscDelta > SUPGIPUSETSCDELTA_ZERO_CLAIMED);
    75367834
     
    75457843    }
    75467844
    7547     /* Set the master TSC as the initiator. */
     7845    /*
     7846     * If the CPU has hyper-threading and the APIC IDs of the master and worker are adjacent,
     7847     * try pick a different master.  (This fudge only works with multi core systems.)
     7848     * ASSUMES related threads have adjacent APIC IDs.  ASSUMES two threads per core.
     7849     */
     7850    iGipCpuMaster = supdrvGipFindCpuIndexForCpuId(pGip, idMaster);
     7851    AssertReturn(iGipCpuMaster < pGip->cCpus, VERR_INVALID_CPU_ID);
     7852    pGipCpuMaster = &pGip->aCPUs[iGipCpuMaster];
     7853    if (   (pGipCpuMaster->idApic & ~1) == (pGipCpuWorker->idApic & ~1)
     7854        && ASMHasCpuId()
     7855        && ASMIsValidStdRange(ASMCpuId_EAX(0))
     7856        && (ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_HTT)
     7857        && pGip->cOnlineCpus > 2)
     7858    {
     7859        uint32_t i;
     7860        for (i = 0; i < pGip->cCpus; i++)
     7861            if (   i != iGipCpuMaster
     7862                && i != idxWorker
     7863                && pGip->aCPUs[i].enmState == SUPGIPCPUSTATE_ONLINE
     7864                && pGip->aCPUs[i].i64TSCDelta != INT64_MAX
     7865                && pGip->aCPUs[i].idCpu  != NIL_RTCPUID
     7866                && pGip->aCPUs[i].idCpu  != idMaster              /* paranoia starts here... */
     7867                && pGip->aCPUs[i].idCpu  != pGipCpuWorker->idCpu
     7868                && pGip->aCPUs[i].idApic != pGipCpuWorker->idApic
     7869                && pGip->aCPUs[i].idApic != pGipCpuMaster->idApic)
     7870            {
     7871                iGipCpuMaster = i;
     7872                pGipCpuMaster = &pGip->aCPUs[i];
     7873                idMaster = pGipCpuMaster->idCpu;
     7874                break;
     7875            }
     7876    }
     7877
     7878    /*
     7879     * Set the master TSC as the initiator.  This serializes delta measurments.
     7880     */
    75487881    while (!ASMAtomicCmpXchgU32(&pDevExt->idTscDeltaInitiator, idMaster, NIL_RTCPUID))
    75497882    {
     
    75527885         * being executed and that can take a good while to be done.
    75537886         */
    7554         RTThreadSleep(1);
    7555     }
    7556 
    7557     if (RTCpuSetIsMember(&pGip->OnlineCpuSet, pGipCpuWorker->idCpu))
    7558     {
    7559         /* Fire TSC-read workers on all CPUs but only synchronize between master and one worker to ease memory contention. */
    7560         ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX);
    7561         ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP);
    7562         rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, pDevExt, pGipCpuWorker);
     7887        RTThreadSleep(1); /** @todo r=bird: This won't work with preemption disabled, not on real OSes anyway. */
     7888    }
     7889
     7890    if (RTCpuSetIsMemberByIndex(&pGip->OnlineCpuSet, pGipCpuWorker->iCpuSet))
     7891    {
     7892        /*
     7893         * Initialize data package for the RTMpOnAll callback.
     7894         */
     7895        SUPDRVGIPTSCDELTARGS Args;
     7896        RT_ZERO(Args);
     7897        Args.pWorker  = pGipCpuWorker;
     7898        Args.pMaster  = pGipCpuMaster;
     7899        Args.idMaster = idMaster;
     7900        Args.pDevExt  = pDevExt;
     7901#ifdef GIP_TSC_DELTA_METHOD_1
     7902        rc = VINF_SUCCESS;
     7903#elif defined(GIP_TSC_DELTA_METHOD_2)
     7904        rc = supdrvTscDeltaMethod2Init(&Args);
     7905#else
     7906# error "huh?"
     7907#endif
    75637908        if (RT_SUCCESS(rc))
    75647909        {
    7565             if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX))
     7910            /*
     7911             * Fire TSC-read workers on all CPUs but only synchronize between master
     7912             * and one worker to ease memory contention.
     7913             */
     7914            ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX);
     7915            ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP);
     7916
     7917            rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, &Args, NULL);
     7918            if (RT_SUCCESS(rc))
    75667919            {
    7567                 /*
    7568                  * Work the TSC delta applicability rating.  It starts
    7569                  * optimistic in supdrvGipInit, we downgrade it here.
    7570                  */
    7571                 SUPGIPUSETSCDELTA enmRating;
    7572                 if (   pGipCpuWorker->i64TSCDelta >  GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO
    7573                     || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO)
    7574                     enmRating = SUPGIPUSETSCDELTA_NOT_ZERO;
    7575                 else if (   pGipCpuWorker->i64TSCDelta >  GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO
    7576                          || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO)
    7577                     enmRating = SUPGIPUSETSCDELTA_ROUGHLY_ZERO;
     7920                if (RT_LIKELY(pGipCpuWorker->i64TSCDelta != INT64_MAX))
     7921                {
     7922                    /*
     7923                     * Work the TSC delta applicability rating.  It starts
     7924                     * optimistic in supdrvGipInit, we downgrade it here.
     7925                     */
     7926                    SUPGIPUSETSCDELTA enmRating;
     7927                    if (   pGipCpuWorker->i64TSCDelta >  GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO
     7928                        || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_ROUGHLY_ZERO)
     7929                        enmRating = SUPGIPUSETSCDELTA_NOT_ZERO;
     7930                    else if (   pGipCpuWorker->i64TSCDelta >  GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO
     7931                             || pGipCpuWorker->i64TSCDelta < -GIP_TSC_DELTA_THRESHOLD_PRACTICALLY_ZERO)
     7932                        enmRating = SUPGIPUSETSCDELTA_ROUGHLY_ZERO;
     7933                    else
     7934                        enmRating = SUPGIPUSETSCDELTA_PRACTICALLY_ZERO;
     7935                    if (pGip->enmUseTscDelta < enmRating)
     7936                    {
     7937                        AssertCompile(sizeof(pGip->enmUseTscDelta) == sizeof(uint32_t));
     7938                        ASMAtomicWriteU32((uint32_t volatile *)&pGip->enmUseTscDelta, enmRating);
     7939                    }
     7940                }
    75787941                else
    7579                     enmRating = SUPGIPUSETSCDELTA_PRACTICALLY_ZERO;
    7580                 if (pGip->enmUseTscDelta < enmRating)
    7581                 {
    7582                     AssertCompile(sizeof(pGip->enmUseTscDelta) == sizeof(uint32_t));
    7583                     ASMAtomicWriteU32((uint32_t volatile *)&pGip->enmUseTscDelta, enmRating);
    7584                 }
     7942                    rc = VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED;
    75857943            }
    7586             else
    7587                 rc = VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED;
    7588         }
     7944        }
     7945
     7946#ifdef GIP_TSC_DELTA_METHOD_2
     7947        supdrvTscDeltaMethod2Term(&Args);
     7948#endif
    75897949    }
    75907950    else
     
    76127972    PSUPGIPCPU pGipCpuMaster;
    76137973    unsigned   iCpu;
     7974    unsigned   iOddEven;
    76147975    PSUPGLOBALINFOPAGE pGip   = pDevExt->pGip;
    76157976    uint32_t   idxMaster      = UINT32_MAX;
     
    76347995        {
    76357996            PSUPGIPCPU pGipCpu = &pGip->aCPUs[idxCpu];
    7636             if (RTCpuSetIsMember(&pGip->OnlineCpuSet, pGipCpu->idCpu))
     7997            if (RTCpuSetIsMemberByIndex(&pGip->OnlineCpuSet, pGipCpu->iCpuSet))
    76377998            {
    76387999                idxMaster = idxCpu;
     
    76568017
    76578018    /*
    7658      * Loop thru the GIP CPU array and get deltas for each CPU (except the master).
    7659      */
    7660     for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
    7661     {
    7662         PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu];
    7663         if (   iCpu != idxMaster
    7664             && RTCpuSetIsMember(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet))
    7665         {
    7666             rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
    7667             if (RT_FAILURE(rc))
     8019     * Loop thru the GIP CPU array and get deltas for each CPU (except the
     8020     * master).   We do the CPUs with the even numbered APIC IDs first so that
     8021     * we've got alternative master CPUs to pick from on hyper-threaded systems.
     8022     */
     8023    for (iOddEven = 0; iOddEven < 2; iOddEven++)
     8024    {
     8025        for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
     8026        {
     8027            PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[iCpu];
     8028            if (   iCpu != idxMaster
     8029                && (iOddEven > 0 || (pGipCpuWorker->idApic & 1) == 0)
     8030                && RTCpuSetIsMemberByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet))
    76688031            {
    7669                 SUPR0Printf("supdrvMeasureTscDeltaOne failed. rc=%d CPU[%u].idCpu=%u Master[%u].idCpu=%u\n", rc, iCpu,
    7670                             pGipCpuWorker->idCpu, idxMaster, pDevExt->idGipMaster, pGipCpuMaster->idCpu);
    7671                 break;
    7672             }
    7673 
    7674             if (ASMAtomicReadU32(&pDevExt->cMpOnOffEvents) != cMpOnOffEvents)
    7675             {
    7676                 SUPR0Printf("One or more CPUs transitioned between online & offline states. I'm confused, retry...\n");
    7677                 rc = VERR_TRY_AGAIN;
    7678                 break;
     8032                rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
     8033                if (RT_FAILURE(rc))
     8034                {
     8035                    SUPR0Printf("supdrvMeasureTscDeltaOne failed. rc=%d CPU[%u].idCpu=%u Master[%u].idCpu=%u\n", rc, iCpu,
     8036                                pGipCpuWorker->idCpu, idxMaster, pDevExt->idGipMaster, pGipCpuMaster->idCpu);
     8037                    break;
     8038                }
     8039
     8040                if (ASMAtomicReadU32(&pDevExt->cMpOnOffEvents) != cMpOnOffEvents)
     8041                {
     8042                    SUPR0Printf("One or more CPUs transitioned between online & offline states. I'm confused, retry...\n");
     8043                    rc = VERR_TRY_AGAIN;
     8044                    break;
     8045                }
    76798046            }
    76808047        }
     
    83818748                 *        thread. Check if anyone uses/needs fAsync before implementing this. */
    83828749                RTSpinlockAcquire(pDevExt->hTscDeltaSpinlock);
    8383                 RTCpuSetAdd(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
     8750                RTCpuSetAddByIndex(&pDevExt->TscDeltaCpuSet, pGipCpuWorker->iCpuSet);
    83848751                if (   pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Listening
    83858752                    || pDevExt->enmTscDeltaThreadState == kTscDeltaThreadState_Measuring)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette