VirtualBox

Ignore:
Timestamp:
Sep 12, 2014 2:03:14 PM (10 years ago)
Author:
vboxsync
Message:

HostDrivers/Support: Readjust TSC deltas if the master goes offline, and other code refactoring in preparation of recomputing deltas lazily.

File:
1 edited

Legend:

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

    r52621 r52725  
    167167                                                  RTCPUID idCpu, uint8_t idApic, uint64_t iTick);
    168168static void                 supdrvGipInitCpu(PSUPGLOBALINFOPAGE pGip, PSUPGIPCPU pCpu, uint64_t u64NanoTS);
    169 static int                  supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, uint32_t *pidxMaster);
     169static int                  supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster);
     170static int                  supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker);
    170171static int                  supdrvIOCtl_ResumeSuspendedKbds(void);
    171172
     
    56445645            do
    56455646            {
    5646                 rc = supdrvMeasureTscDeltas(pDevExt, pGip, NULL /* pidxMaster */);
     5647                rc = supdrvMeasureTscDeltas(pDevExt, NULL /* pidxMaster */);
    56475648                if (rc == VERR_TRY_AGAIN)
    56485649                {
     
    56555656            if (RT_SUCCESS(rc))
    56565657            {
    5657 #if 0
    5658                 unsigned iCpu;
    5659                 SUPR0Printf("cTries=%u\n", cTries);
    5660                 for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
    5661                     SUPR0Printf("Cpu[%3u].delta=%ld\n", iCpu, pGip->aCPUs[iCpu].i64TSCDelta);
    5662 #endif
    5663 
    56645658                /*
    56655659                 * Create the timer.
     
    59385932    }
    59395933
     5934    /* Reset the TSC delta, we will recalculate it lazily. */
     5935    ASMAtomicWriteS64(&pGip->aCPUs[i].i64TSCDelta, INT64_MAX);
     5936
    59405937    /* commit it */
    59415938    ASMAtomicWriteSize(&pGip->aCPUs[i].enmState, SUPGIPCPUSTATE_OFFLINE);
     
    59805977                supdrvGipMpEventOffline(pDevExt, idCpu);
    59815978                break;
    5982 
    59835979        }
    59845980    }
     
    59975993            bool        fIgnored;
    59985994            unsigned    i;
     5995            int64_t     iTSCDelta;
     5996            uint32_t    idxNewGipMaster;
    59995997            RTCPUID     idNewGipMaster = NIL_RTCPUID;
    60005998            RTCPUSET    OnlineCpus;
     
    60046002            {
    60056003                RTCPUID idCurCpu = RTMpCpuIdFromSetIndex(i);
    6006                 if (    RTCpuSetIsMember(&OnlineCpus, idCurCpu)
    6007                     &&  idCurCpu != idGipMaster)
     6004                if (   RTCpuSetIsMember(&OnlineCpus, idCurCpu)
     6005                    && idCurCpu != idGipMaster)
    60086006                {
    60096007                    idNewGipMaster = idCurCpu;
     
    60156013            ASMAtomicCmpXchgSize(&pDevExt->idGipMaster, idNewGipMaster, idGipMaster, fIgnored);
    60166014            NOREF(fIgnored);
     6015
     6016            /*
     6017             * Adjust all the TSC deltas against the new GIP master.
     6018             */
     6019            if (pGip)
     6020            {
     6021                idxNewGipMaster = supdrvGipCpuIndexFromCpuId(pGip, idNewGipMaster);
     6022                iTSCDelta       = pGip->aCPUs[idxNewGipMaster].i64TSCDelta;
     6023                Assert(iTSCDelta != UINT64_MAX);
     6024                for (i = 0; i < pGip->cCpus; i++)
     6025                {
     6026                    PSUPGIPCPU pGipCpu      = &pGip->aCPUs[i];
     6027                    int64_t    iWorkerDelta = pGipCpu->i64TSCDelta;
     6028                    if (iWorkerDelta != INT64_MAX)
     6029                        iWorkerDelta -= iTSCDelta;
     6030                    ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, iWorkerDelta);
     6031                }
     6032                Assert(pGip->aCPUs[idxNewGipMaster].i64TSCDelta == 0);
     6033            }
    60176034        }
    60186035    }
     
    60436060 *     earlier.
    60446061 */
    6045 static DECLCALLBACK(void) supdrvDetermineTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
     6062static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
    60466063{
    60476064    PSUPGLOBALINFOPAGE pGip      = (PSUPGLOBALINFOPAGE)pvUser1;
     
    60536070    PSUPGIPCPU         pGipCpuWorker = &pGip->aCPUs[idxWorker];
    60546071    uint64_t           uMinCmpReadTime = UINT64_MAX;
    6055     int                cTriesLeft = 8;
     6072    int                cTriesLeft = 12;
    60566073
    60576074    if (   idCpu != idMaster
     
    61116128        for (i = 0; i < GIP_TSC_DELTA_LOOPS; i++)
    61126129        {
     6130            ASMCompilerBarrier();
    61136131            if (idCpu == idMaster)
    61146132            {
     
    62266244
    62276245/**
     6246 * Measures the TSC delta between the master GIP CPU and one specified worker
     6247 * CPU.
     6248 *
     6249 * @returns VBox status code.
     6250 * @param   pDevExt         Pointer to the device instance data.
     6251 * @param   idxWorker       The index of the worker CPU from the GIP's array of
     6252 *                          CPUs.
     6253 *
     6254 * @remarks This can be called with preemption disabled!
     6255 */
     6256static int supdrvMeasureTscDeltaOne(PSUPDRVDEVEXT pDevExt, uint32_t idxWorker)
     6257{
     6258    PSUPGLOBALINFOPAGE pGip  = pDevExt->pGip;
     6259    RTCPUID    idMaster      = pDevExt->idGipMaster;
     6260    uint32_t   idxMaster     = supdrvGipCpuIndexFromCpuId(pGip, idMaster);
     6261    PSUPGIPCPU pGipCpuWorker = &pGip->aCPUs[idxWorker];
     6262    int        rc            = VERR_CPU_OFFLINE;
     6263
     6264    if (idxWorker == idxMaster)
     6265    {
     6266        ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, 0);
     6267        return VINF_SUCCESS;
     6268    }
     6269
     6270    /* Set the master TSC as the initiator. */
     6271    while (ASMAtomicCmpXchgU32(&g_idTscDeltaInitiator, idMaster, NIL_RTCPUID) == false)
     6272        ASMNopPause();
     6273
     6274    if (RTCpuSetIsMember(&pGip->OnlineCpuSet, pGipCpuWorker->idCpu))
     6275    {
     6276        /* Fire TSC-read workers on all CPUs but only synchronize between master and one worker to ease memory contention. */
     6277        ASMAtomicWriteU32(&g_pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP);
     6278        rc = RTMpOnAll(supdrvMeasureTscDeltaCallback, pGip, &pGipCpuWorker->idCpu);
     6279        if (RT_SUCCESS(rc))
     6280        {
     6281            if (RT_UNLIKELY(pGipCpuWorker->i64TSCDelta == INT64_MAX))
     6282                rc = VERR_UNRESOLVED_ERROR;
     6283        }
     6284    }
     6285
     6286    ASMAtomicWriteU32(&g_idTscDeltaInitiator, NIL_RTCPUID);
     6287    return rc;
     6288}
     6289
     6290
     6291/**
    62286292 * Measures the TSC deltas between CPUs.
    62296293 *
    62306294 * @param   pDevExt     Pointer to the device instance data.
    6231  * @param   pGip        Pointer to the GIP.
    62326295 * @param   pidxMaster  Where to store the index of the chosen master TSC if we
    62336296 *                      managed to determine the TSC deltas successfully.
     
    62396302 *          supdrvGipInitOnCpu().
    62406303 */
    6241 static int supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, PSUPGLOBALINFOPAGE pGip, uint32_t *pidxMaster)
     6304static int supdrvMeasureTscDeltas(PSUPDRVDEVEXT pDevExt, uint32_t *pidxMaster)
    62426305{
    62436306    PSUPGIPCPU pGipCpuMaster;
    62446307    unsigned   iCpu;
     6308    PSUPGLOBALINFOPAGE pGip   = pDevExt->pGip;
     6309    uint32_t   idxMaster      = UINT32_MAX;
     6310    int        rc             = VINF_SUCCESS;
    62456311    uint32_t   cMpOnOffEvents = ASMAtomicReadU32(&g_cMpOnOffEvents);
    62466312    uint32_t   cOnlineCpus    = pGip->cOnlineCpus;
    62476313
    6248     /* Pick the first CPU which is online as the master TSC. */
    6249     uint32_t idxMaster = UINT32_MAX;
     6314    /*
     6315     * Pick the first CPU online as the master TSC and make it the new GIP master.
     6316     *                                                                                                                                        .
     6317     * Technically we can simply use "idGipMaster" but doing this gives us master as CPU 0                                                    .
     6318     * in most cases making it nicer/easier for comparisons. It is safe to update the GIP
     6319     * master as this point since the sync/async timer isn't created yet.
     6320     */
    62506321    supdrvClearTscSamples(pGip, true /* fClearDeltas */);
    62516322    for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
     
    62596330        }
    62606331    }
     6332    AssertReturn(idxMaster != UINT32_MAX, VERR_CPU_NOT_FOUND);
     6333    pGipCpuMaster = &pGip->aCPUs[idxMaster];
     6334    ASMAtomicWriteSize(&pDevExt->idGipMaster, pGipCpuMaster->idCpu);
     6335
    62616336    AssertReturn(cOnlineCpus > 0, VERR_INTERNAL_ERROR_5);
    6262     AssertReturn(idxMaster != UINT32_MAX, VERR_CPU_NOT_FOUND);
    6263 
    62646337    if (pGip->cOnlineCpus <= 1)
    62656338    {
     
    62696342    }
    62706343
    6271     /* Pick the master TSC as the initiator. */
    6272     pGipCpuMaster = &pGip->aCPUs[idxMaster];
    6273     ASMAtomicWriteU32(&g_idTscDeltaInitiator, pGipCpuMaster->idCpu);
    6274 
    62756344    for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
    62766345    {
     
    62796348            && RTCpuSetIsMember(&pGip->OnlineCpuSet, pGipCpuWorker->idCpu))
    62806349        {
    6281             int rc;
    6282 
    6283             /* Fire TSC-read workers on all CPUs but only synchronize between master and one worker to memory contention. */
    6284             ASMAtomicWriteU32(&g_pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP);
    6285             rc = RTMpOnAll(supdrvDetermineTscDeltaCallback, pGip, &pGipCpuWorker->idCpu);
     6350            rc = supdrvMeasureTscDeltaOne(pDevExt, iCpu);
    62866351            if (RT_FAILURE(rc))
    62876352            {
    6288                 SUPR0Printf("supdrvMeasureTscDeltas: RTMpOnAll failed. rc=%d\n", rc);
    6289                 return rc;
    6290             }
    6291 
    6292             if (RT_UNLIKELY(pGipCpuWorker->i64TSCDelta == INT64_MAX))
    6293             {
    6294                 SUPR0Printf("Failed to measure TSC deltas for CPU[%u] idCpu=%u\n", iCpu, pGipCpuWorker->idCpu);
    6295                 return VERR_UNRESOLVED_ERROR;
     6353                SUPR0Printf("supdrvMeasureTscDeltaOne failed. rc=%d CPU[%u].idCpu=%u Master[%u].idCpu=%u\n", rc, iCpu,
     6354                            pGipCpuWorker->idCpu, idxMaster, pDevExt->idGipMaster, pGipCpuMaster->idCpu);
     6355                break;
    62966356            }
    62976357
     
    62996359            {
    63006360                SUPR0Printf("One or more CPUs transitioned between online & offline states. I are confused, retrying...\n");
    6301                 return VERR_TRY_AGAIN;
    6302             }
    6303         }
    6304     }
    6305 
    6306     ASMAtomicWriteU32(&g_idTscDeltaInitiator, NIL_RTCPUID);
    6307 
    6308     if (RT_LIKELY(!pGipCpuMaster->i64TSCDelta))
    6309     {
    6310         if (pidxMaster)
    6311             *pidxMaster = idxMaster;
    6312         return VINF_SUCCESS;
    6313     }
    6314     return VERR_INTERNAL_ERROR_4;
     6361                rc = VERR_TRY_AGAIN;
     6362                break;
     6363            }
     6364        }
     6365    }
     6366
     6367    if (   RT_SUCCESS(rc)
     6368        && !pGipCpuMaster->i64TSCDelta
     6369        && pidxMaster)
     6370    {
     6371        *pidxMaster = idxMaster;
     6372    }
     6373    return rc;
    63156374}
    63166375
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