VirtualBox

Changeset 54357 in vbox


Ignore:
Timestamp:
Feb 22, 2015 7:14:39 PM (10 years ago)
Author:
vboxsync
Message:

SUPDrvGip.cpp: First part of the less noisy tsc-delta-measurment synchronization w/ timeout revamp.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostDrivers/Support/SUPDrvGip.cpp

    r54355 r54357  
    25502550    uint64_t                    au64CacheLinePaddingBefore[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t)];
    25512551    /** The synchronization variable, holds values GIP_TSC_DELTA_SYNC_*. */
    2552     volatile uint32_t           uVar1;
     2552    volatile uint32_t           uSyncVar;
    25532553    /** Unused. */
    2554     volatile uint32_t           uVar2;
    2555 
    2556     /** Start RDTSC value.  This does not need to be in its own cache line, it's
    2557      * just put here to save stack space. */
     2554    volatile uint32_t           u32Padding;
     2555
     2556    /** Padding to make sure the uVar1 is in its own cache line. */
     2557    uint64_t                    au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 1];
     2558
     2559    /** Start RDTSC value.  Put here mainly to save stack space. */
    25582560    uint64_t                    uTscStart;
    2559     /** Max number of ticks we can allow to elapse in the RTMpOn callback.
    2560      * This is estimated from the CPU frequency...  */
    2561     uint64_t                    cMaxTicks;
    2562 
    2563     /** Padding to make sure the uVar1 is in its own cache line. */
    2564     uint64_t                    au64CacheLinePaddingAfter[GIP_TSC_DELTA_CACHE_LINE_SIZE / sizeof(uint64_t) - 2];
    25652561} SUPTSCDELTASYNC2;
    25662562AssertCompileSize(SUPTSCDELTASYNC2, GIP_TSC_DELTA_CACHE_LINE_SIZE * 2 + sizeof(uint64_t));
     
    25752571{
    25762572    /** The device extension.   */
    2577     PSUPDRVDEVEXT           pDevExt;
     2573    PSUPDRVDEVEXT               pDevExt;
    25782574    /** Pointer to the GIP CPU array entry for the worker. */
    2579     PSUPGIPCPU              pWorker;
     2575    PSUPGIPCPU                  pWorker;
    25802576    /** Pointer to the GIP CPU array entry for the master. */
    2581     PSUPGIPCPU              pMaster;
     2577    PSUPGIPCPU                  pMaster;
    25822578    /** Pointer to the master's synchronization struct (on stack). */
    2583     PSUPTSCDELTASYNC2       pSyncMaster;
     2579    PSUPTSCDELTASYNC2 volatile  pSyncMaster;
    25842580    /** Pointer to the worker's synchronization struct (on stack). */
    2585     PSUPTSCDELTASYNC2       pSyncWorker;
     2581    PSUPTSCDELTASYNC2 volatile  pSyncWorker;
     2582    /** The maximum number of ticks to spend in supdrvMeasureTscDeltaCallback.
     2583     * (This is what we need a rough TSC frequency for.)  */
     2584    uint64_t                    cMaxTscTicks;
     2585    /** Used to abort synchronization setup. */
     2586    bool volatile               fAbortSetup;
    25862587
    25872588#if 0
     
    26112612 * @{
    26122613 */
    2613 #define TSCDELTA_MASTER_SYNC_BEFORE(a_pTscDeltaSync) \
     2614#define TSCDELTA_MASTER_SYNC_BEFORE(a_pSync1, a_pMySync, a_pOtherSync) \
    26142615    do {\
    2615         ASMAtomicWriteU32(&(a_pTscDeltaSync)->u, GIP_TSC_DELTA_SYNC_START); \
     2616        ASMAtomicWriteU32(&(a_pSync1)->u, GIP_TSC_DELTA_SYNC_START); \
    26162617        \
    26172618        /* Disable interrupts only in the master for as short a period \
     
    26192620        uFlags = ASMIntDisableFlags(); \
    26202621        \
    2621         while (ASMAtomicReadU32(&(a_pTscDeltaSync)->u) == GIP_TSC_DELTA_SYNC_START) \
     2622        while (ASMAtomicReadU32(&(a_pSync1)->u) == GIP_TSC_DELTA_SYNC_START) \
    26222623        { /* nothing */ } \
    26232624    } while (0)
    2624 #define TSCDELTA_MASTER_SYNC_AFTER(a_pTscDeltaSync) \
     2625#define TSCDELTA_MASTER_SYNC_AFTER(a_pSync1, a_pMySync, a_pOtherSync) \
    26252626    do {\
    26262627        /* Sync up with worker. */ \
    26272628        ASMSetFlags(uFlags); \
    26282629        \
    2629         while (ASMAtomicReadU32(&(a_pTscDeltaSync)->u) != GIP_TSC_DELTA_SYNC_WORKER_DONE) \
     2630        while (ASMAtomicReadU32(&(a_pSync1)->u) != GIP_TSC_DELTA_SYNC_WORKER_DONE) \
    26302631        { /* nothing */ } \
    26312632    } while (0)
    2632 #define TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(a_pTscDeltaSync) \
     2633#define TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(a_pSync1, a_pMySync, a_pOtherSync) \
    26332634    do {\
    2634         ASMAtomicWriteU32(&(a_pTscDeltaSync)->u, GIP_TSC_DELTA_SYNC_STOP); \
     2635        ASMAtomicWriteU32(&(a_pSync1)->u, GIP_TSC_DELTA_SYNC_STOP); \
    26352636    } while (0)
    26362637
    2637 #define TSCDELTA_OTHER_SYNC_BEFORE(a_pTscDeltaSync, a_MidSyncExpr) \
     2638#define TSCDELTA_OTHER_SYNC_BEFORE(a_pSync1, a_pMySync, a_pOtherSync, a_MidSyncExpr) \
    26382639    do { \
    2639         while (ASMAtomicReadU32(&(a_pTscDeltaSync)->u) != GIP_TSC_DELTA_SYNC_START) \
     2640        while (ASMAtomicReadU32(&(a_pSync1)->u) != GIP_TSC_DELTA_SYNC_START) \
    26402641        { /* nothing */ } \
    26412642        a_MidSyncExpr; \
    2642         ASMAtomicWriteU32(&(a_pTscDeltaSync)->u, GIP_TSC_DELTA_SYNC_WORKER_READY); \
     2643        ASMAtomicWriteU32(&(a_pSync1)->u, GIP_TSC_DELTA_SYNC_WORKER_READY); \
    26432644    } while (0)
    2644 #define TSCDELTA_OTHER_SYNC_AFTER(a_pTscDeltaSync) \
     2645#define TSCDELTA_OTHER_SYNC_AFTER(a_pSync1, a_pMySync, a_pOtherSync) \
    26452646    do { \
    26462647        /* Tell master we're done collecting our data. */ \
    2647         ASMAtomicWriteU32(&(a_pTscDeltaSync)->u, GIP_TSC_DELTA_SYNC_WORKER_DONE); \
     2648        ASMAtomicWriteU32(&(a_pSync1)->u, GIP_TSC_DELTA_SYNC_WORKER_DONE); \
    26482649        \
    26492650        /* Wait for the master to process the data. */ \
    2650         while (ASMAtomicReadU32(&(a_pTscDeltaSync)->u) == GIP_TSC_DELTA_SYNC_WORKER_DONE) \
     2651        while (ASMAtomicReadU32(&(a_pSync1)->u) == GIP_TSC_DELTA_SYNC_WORKER_DONE) \
    26512652            ASMNopPause(); \
    26522653    } while (0)
     
    26822683 *
    26832684 * @param   pArgs               The argument/state data.
    2684  * @param   pSync               The synchronization structure
     2685 * @param   pSync1              The synchronization structure
    26852686 *                              (pDevExt->pTscDeltaSync).
    26862687 * @param   fIsMaster           Set if master, clear if worker.
    26872688 * @param   iTry                The attempt number.
    26882689 */
    2689 static void supdrvTscDeltaMethod1Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC pSync, bool fIsMaster, uint32_t iTry)
     2690static void supdrvTscDeltaMethod1Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC pSync1,
     2691                                      PSUPTSCDELTASYNC2 pMySync, PSUPTSCDELTASYNC2 pOtherSync, bool fIsMaster, uint32_t iTry)
    26902692{
    26912693    PSUPGIPCPU  pGipCpuWorker   = pArgs->pWorker;
     
    27062708                      ("%#llx idMaster=%#x idWorker=%#x (idGipMaster=%#x)\n",
    27072709                       pGipCpuMaster->u64TSCSample, pGipCpuMaster->idCpu, pGipCpuWorker->idCpu, pArgs->pDevExt->idGipMaster));
    2708             TSCDELTA_MASTER_SYNC_BEFORE(pSync);
     2710            TSCDELTA_MASTER_SYNC_BEFORE(pSync1, pMySync, pOtherSync);
    27092711
    27102712            do
     
    27142716            } while (pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD);
    27152717
    2716             TSCDELTA_MASTER_SYNC_AFTER(pSync);
     2718            TSCDELTA_MASTER_SYNC_AFTER(pSync1, pMySync, pOtherSync);
    27172719
    27182720            /* Process the data. */
     
    27322734            /* Reset our TSC sample and tell the worker to move on. */
    27332735            ASMAtomicWriteU64(&pGipCpuMaster->u64TSCSample, GIP_TSC_DELTA_RSVD);
    2734             TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pSync);
     2736            TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pSync1, pMySync, pOtherSync);
    27352737        }
    27362738        else
     
    27442746
    27452747            ASMAtomicReadU64(&pGipCpuMaster->u64TSCSample);     /* Warm the cache line. */
    2746             TSCDELTA_OTHER_SYNC_BEFORE(pSync, Assert(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD));
     2748            TSCDELTA_OTHER_SYNC_BEFORE(pSync1, pMySync, pOtherSync, Assert(pGipCpuMaster->u64TSCSample == GIP_TSC_DELTA_RSVD));
    27472749
    27482750            /*
     
    27792781            }
    27802782
    2781             TSCDELTA_OTHER_SYNC_AFTER(pSync);
     2783            TSCDELTA_OTHER_SYNC_AFTER(pSync1, pMySync, pOtherSync);
    27822784        }
    27832785    }
     
    29482950 *
    29492951 * @param   pArgs               The argument/state data.
    2950  * @param   pSync               The synchronization structure
     2952 * @param   pSync1               The synchronization structure
    29512953 *                              (pDevExt->pTscDeltaSync).
    29522954 * @param   fIsMaster           Set if master, clear if worker.
    29532955 * @param   iTry                The attempt number.
    29542956 */
    2955 static void supdrvTscDeltaMethod2Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC pSync, bool fIsMaster, uint32_t iTry)
     2957static void supdrvTscDeltaMethod2Loop(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC pSync1,
     2958                                      PSUPTSCDELTASYNC2 pMySync, PSUPTSCDELTASYNC2 pOtherSync, bool fIsMaster, uint32_t iTry)
    29562959{
    29572960    unsigned iLoop;
     
    30003003             * Sync up with the worker and collect data.
    30013004             */
    3002             TSCDELTA_MASTER_SYNC_BEFORE(pSync);
     3005            TSCDELTA_MASTER_SYNC_BEFORE(pSync1, pMySync, pOtherSync);
    30033006            supdrvTscDeltaMethod2CollectData(pArgs->M2.pMasterData, &pArgs->M2.pWorkerData->iCurSeqNo, pArgs->M2.fLagMaster);
    3004             TSCDELTA_MASTER_SYNC_AFTER(pSync);
     3007            TSCDELTA_MASTER_SYNC_AFTER(pSync1, pMySync, pOtherSync);
    30053008
    30063009            /*
     
    30123015                supdrvTscDeltaMethod2ProcessDataOnMaster(pArgs, iLoop);
    30133016
    3014             TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pSync);
     3017            TSCDELTA_MASTER_KICK_OTHER_OUT_OF_AFTER(pSync1, pMySync, pOtherSync);
    30153018        }
    30163019        else
     
    30193022             * The worker.
    30203023             */
    3021             TSCDELTA_OTHER_SYNC_BEFORE(pSync, (void)0);
     3024            TSCDELTA_OTHER_SYNC_BEFORE(pSync1, pMySync, pOtherSync, (void)0);
    30223025            supdrvTscDeltaMethod2CollectData(pArgs->M2.pWorkerData, &pArgs->M2.pMasterData->iCurSeqNo, pArgs->M2.fLagWorker);
    3023             TSCDELTA_OTHER_SYNC_AFTER(pSync);
     3026            TSCDELTA_OTHER_SYNC_AFTER(pSync1, pMySync, pOtherSync);
    30243027        }
    30253028
     
    30683071
    30693072/** Prestart wait. */
    3070 #define GIP_TSC_DELTA_SYNC2_PRESTART_WAIT    UINT32_C(0xffe)
    3071 
    3072 /** Start measurement of TSC delta. */
    3073 #define GIP_TSC_DELTA_SYNC2_START            UINT32_C(1)
    3074 /** Worker thread is ready for reading the TSC. */
    3075 #define GIP_TSC_DELTA_SYNC2_WORKER_READY     UINT32_C(2)
    3076 /** Worker thread is done updating TSC delta info. */
    3077 #define GIP_TSC_DELTA_SYNC2_WORKER_DONE      UINT32_C(3)
    3078 /** When IPRT is isn't concurrent safe: Master is ready and will wait for worker
    3079  *  with a timeout. */
    3080 #define GIP_TSC_DELTA_SYNC2_PRESTART_MASTER  UINT32_C(4)
    3081 
    3082 
    3083 /**
    3084  * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs
     3073#define GIP_TSC_DELTA_SYNC2_PRESTART_WAIT    UINT32_C(0x0ffe)
     3074/** Prestart aborted. */
     3075#define GIP_TSC_DELTA_SYNC2_PRESTART_ABORT   UINT32_C(0x0fff)
     3076/** Start testing. */
     3077#define GIP_TSC_DELTA_SYNC2_START            UINT32_C(0x1000)
     3078
     3079
     3080/** The other party won't touch the sync struct ever again. */
     3081#define GIP_TSC_DELTA_SYNC2_FINAL            UINT32_C(0x1fff)
     3082
     3083
     3084
     3085static int supdrvMeasureTscDeltaCallbackAbortSyncSetup(PSUPDRVGIPTSCDELTARGS pArgs, PSUPTSCDELTASYNC2 pMySync,
     3086                                                       bool fIsMaster, bool fTimeout)
     3087{
     3088    PSUPTSCDELTASYNC2 volatile *ppMySync    = fIsMaster ? &pArgs->pSyncMaster : &pArgs->pSyncWorker;
     3089    PSUPTSCDELTASYNC2 volatile *ppOtherSync = fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster;
     3090#if defined(DEBUG_bird) && defined(RT_OS_WINDOWS)
     3091    uint32_t iTry = 0;
     3092#endif
     3093
     3094    /*
     3095     * Clear our sync pointer and make sure the abort flag is set.
     3096     */
     3097    ASMAtomicWriteNullPtr(ppMySync);
     3098    ASMAtomicWriteBool(&pArgs->fAbortSetup, true);
     3099
     3100    /*
     3101     * Make sure the other party is out of there and won't be touching our
     3102     * sync state again (would cause stack corruption).
     3103     */
     3104    while (ASMAtomicReadPtrT(ppOtherSync, PSUPTSCDELTASYNC2) != NULL)
     3105    {
     3106        ASMNopPause();
     3107        ASMNopPause();
     3108        ASMNopPause();
     3109#if defined(DEBUG_bird) && defined(RT_OS_WINDOWS)
     3110if (++iTry == 0) __debugbreak();
     3111#endif
     3112    }
     3113
     3114    return 0;
     3115}
     3116
     3117
     3118/**
     3119 * This is used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs
    30853120 * and compute the delta between them.
    30863121 *
     3122 * To reduce code size a good when timeout handling was added, a dummy return
     3123 * value had to be added (saves 1-3 lines per timeout case), thus this
     3124 * 'Unwrapped' function and the dummy 0 return value.
     3125 *
     3126 * @returns 0 (dummy, ignored)
    30873127 * @param   idCpu       The CPU we are current scheduled on.
    3088  * @param   pvUser1     Pointer to a parameter package (SUPDRVGIPTSCDELTARGS).
    3089  * @param   pvUser2     Unused.
     3128 * @param   pArgs       Pointer to a parameter package.
    30903129 *
    30913130 * @remarks Measuring TSC deltas between the CPUs is tricky because we need to
     
    30953134 *          doing this on x86 CPUs.
    30963135 */
    3097 static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
    3098 {
    3099     PSUPDRVGIPTSCDELTARGS   pArgs = (PSUPDRVGIPTSCDELTARGS)pvUser1;
    3100     PSUPDRVDEVEXT           pDevExt          = pArgs->pDevExt;
    3101     PSUPTSCDELTASYNC        pSync            = pDevExt->pTscDeltaSync;
    3102     PSUPGIPCPU              pGipCpuWorker    = pArgs->pWorker;
    3103     PSUPGIPCPU              pGipCpuMaster    = pArgs->pMaster;
    3104     bool const              fIsMaster        = idCpu == pGipCpuMaster->idCpu;
    3105     uint32_t                iTry;
    3106 #if 0
    3107     PSUPTSCDELTASYNC2       pOtherSync;
    3108     SUPTSCDELTASYNC2        MySync;
    3109 #endif
     3136static int supdrvMeasureTscDeltaCallbackUnwrapped(RTCPUID idCpu, PSUPDRVGIPTSCDELTARGS pArgs)
     3137{
     3138    PSUPDRVDEVEXT               pDevExt          = pArgs->pDevExt;
     3139    PSUPTSCDELTASYNC            pSync1           = pDevExt->pTscDeltaSync;
     3140    PSUPGIPCPU                  pGipCpuWorker    = pArgs->pWorker;
     3141    PSUPGIPCPU                  pGipCpuMaster    = pArgs->pMaster;
     3142    bool const                  fIsMaster        = idCpu == pGipCpuMaster->idCpu;
     3143    uint32_t                    iTry;
     3144    PSUPTSCDELTASYNC2 volatile *ppMySync         = fIsMaster ? &pArgs->pSyncMaster : &pArgs->pSyncWorker;
     3145    PSUPTSCDELTASYNC2 volatile *ppOtherSync      = fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster;
     3146    SUPTSCDELTASYNC2            MySync;
     3147    PSUPTSCDELTASYNC2           pOtherSync;
    31103148
    31113149    /* A bit of paranoia first. */
    31123150    if (!pGipCpuMaster || !pGipCpuWorker)
    3113         return;
     3151        return 0;
    31143152
    31153153    /*
     
    31183156    if (   !fIsMaster
    31193157        && idCpu != pGipCpuWorker->idCpu)
    3120         return;
    3121 
    3122 #if 0
     3158        return 0;
     3159
    31233160    /*
    31243161     * Set up my synchronization stuff and wait for the other party to show up.
    3125      * We don't wait forever since the other party may have gone fishing after
    3126      * we checked it out in supdrvMeasureTscDeltaOne, and then there is of course
    3127      * windows and it's BSOD if we waste too much time here.
    3128      */
     3162     *
     3163     * We don't wait forever since the other party may be off fishing (offline,
     3164     * spinning with ints disables, whatever), we must play nice to the rest of
     3165     * the system as this context generally isn't one in which we will get
     3166     * preempted and we may hold up a number of lower priority interrupts.
     3167     */
     3168    ASMAtomicWriteU32(&MySync.uSyncVar, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT);
     3169    ASMAtomicWritePtr(ppMySync, &MySync);
     3170    MySync.uTscStart = ASMReadTSC();
     3171
     3172    /* Look for the partner, might not be here yet... Special abort considerations. */
     3173    iTry = 0;
     3174    while ((pOtherSync = ASMAtomicReadPtrT(ppOtherSync, PSUPTSCDELTASYNC2)) == NULL)
     3175    {
     3176        ASMNopPause();
     3177        if (   ASMAtomicReadBool(&pArgs->fAbortSetup)
     3178            || !RTMpIsCpuOnline(fIsMaster ? pGipCpuWorker->idCpu : pGipCpuWorker->idCpu) )
     3179            return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
     3180        if (   (iTry++ & 0xff) == 0
     3181            && ASMReadTSC() - MySync.uTscStart > pArgs->cMaxTscTicks)
     3182            return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, true /*fTimeout*/);
     3183#if defined(DEBUG_bird) && defined(RT_OS_WINDOWS)
     3184if (iTry == 0) __debugbreak();
     3185#endif
     3186        ASMNopPause();
     3187    }
     3188
     3189    /* I found my partner, waiting to be found... Special abort considerations. */
    31293190    if (fIsMaster)
    3130     {
    3131         MySync.uVar1 = GIP_TSC_DELTA_SYNC2_PRESTART_WAIT;
    3132         ASMSerializeInstruction(); ASMCompilerBarrier();
    3133         ASMAtomicWritePtr(&pArgs->pSyncMaster, &MySync);
    3134     }
    3135     else
    3136     {
    3137         MySync.uVar1 = GIP_TSC_DELTA_SYNC2_PRESTART_WAIT;
    3138         ASMSerializeInstruction(); ASMCompilerBarrier();
    3139         ASMAtomicWritePtr(&pArgs->pSyncWorker, &MySync);
    3140     }
    3141 
    3142     MySync.uTscStart = ASMReadTSC();
    3143     MySync.cMaxTicks = u64CpuHz
    3144 
    3145     while ((pOtherSync = ASMAtomicReadPtr((void * volatile *)(fIsMaster ? &pArgs->pSyncWorker : &pArgs->pSyncMaster))) != NULL)
    3146     {
    3147         uint32_t cInner = 10240;
    3148         while (   cInner-- > 0
    3149                && ASMAtomicUoReadU32(MySync.uVar1) == GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)
    3150             ASMNopPause();
    3151 
    3152     }
     3191        if (!ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_START, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)) /* parnaoia */
     3192            return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
     3193
     3194    iTry = 0;
     3195    while (ASMAtomicReadU32(&MySync.uSyncVar) == GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)
     3196    {
     3197        ASMNopPause();
     3198        if (ASMAtomicReadBool(&pArgs->fAbortSetup))
     3199            return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
     3200        if (   (iTry++ & 0xff) == 0
     3201            && ASMReadTSC() - MySync.uTscStart > pArgs->cMaxTscTicks)
     3202        {
     3203            if (   fIsMaster
     3204                && !ASMAtomicCmpXchgU32(&MySync.uSyncVar, GIP_TSC_DELTA_SYNC2_PRESTART_ABORT, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT))
     3205                break; /* race #1: slave has moved on, handle timeout in loop instead. */
     3206            return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, true /*fTimeout*/);
     3207        }
     3208#if defined(DEBUG_bird) && defined(RT_OS_WINDOWS)
     3209if (iTry == 0) __debugbreak();
    31533210#endif
    3154 
    3155 
    3156     /* If the IPRT API isn't concurrent safe, the master and worker wait for each other
    3157        with a timeout to avoid deadlocking the entire system. */
    3158     if (!RTMpOnAllIsConcurrentSafe())
    3159     {
    3160         /** @todo This was introduced for Windows, but since Windows doesn't use this
    3161          *        code path any longer (as DPC timeouts BSOD regardless of interrupts,
    3162          *        see @bugref{6710} comment 81), eventually phase it out. */
    3163         uint64_t       uTscNow;
    3164         uint64_t       uTscStart;
    3165         uint64_t const cWaitTicks = 130000;  /* Arbitrary value, can be tweaked later. */
    3166 
    3167         ASMSerializeInstruction();
    3168         uTscStart = ASMReadTSC();
    3169         if (fIsMaster)
    3170         {
    3171             ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_PRESTART_MASTER);
    3172             while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) != GIP_TSC_DELTA_SYNC_PRESTART_WORKER)
    3173             {
    3174                 ASMSerializeInstruction();
    3175                 uTscNow = ASMReadTSC();
    3176                 if (uTscNow - uTscStart > cWaitTicks)
    3177                 {
    3178                     /* Set the worker delta to indicate failure, not the master. */
    3179                     ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX);
    3180                     return;
    3181                 }
    3182 
    3183                 ASMNopPause();
    3184             }
    3185         }
    3186         else
    3187         {
    3188             while (ASMAtomicReadU32(&pDevExt->pTscDeltaSync->u) != GIP_TSC_DELTA_SYNC_PRESTART_MASTER)
    3189             {
    3190                 ASMSerializeInstruction();
    3191                 uTscNow = ASMReadTSC();
    3192                 if (uTscNow - uTscStart > cWaitTicks)
    3193                 {
    3194                     ASMAtomicWriteS64(&pGipCpuWorker->i64TSCDelta, INT64_MAX);
    3195                     return;
    3196                 }
    3197 
    3198                 ASMNopPause();
    3199             }
    3200             ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_PRESTART_WORKER);
    3201         }
    3202     }
     3211    }
     3212
     3213    if (!fIsMaster)
     3214        if (!ASMAtomicCmpXchgU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_START, GIP_TSC_DELTA_SYNC2_PRESTART_WAIT)) /* race #1 */
     3215            return supdrvMeasureTscDeltaCallbackAbortSyncSetup(pArgs, &MySync, fIsMaster, false /*fTimeout*/);
    32033216
    32043217    /*
     
    32083221    for (iTry = 0; iTry < 12; iTry++)
    32093222    {
     3223        if (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_START)
     3224            break;
     3225
    32103226        /*
    32113227         * Do the measurements.
    32123228         */
    32133229#ifdef GIP_TSC_DELTA_METHOD_1
    3214         supdrvTscDeltaMethod1Loop(pArgs, pSync, fIsMaster, iTry);
     3230        supdrvTscDeltaMethod1Loop(pArgs, pSync1, &MySync, pOtherSync, fIsMaster, iTry);
    32153231#elif defined(GIP_TSC_DELTA_METHOD_2)
    3216         supdrvTscDeltaMethod2Loop(pArgs, pSync, fIsMaster, iTry);
     3232        supdrvTscDeltaMethod2Loop(pArgs, pSync1, &MySync, pOtherSync, fIsMaster, iTry);
    32173233#else
    32183234# error "huh??"
    32193235#endif
     3236        if (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_START)
     3237            break;
    32203238
    32213239        /*
     
    32373255        }
    32383256    }
    3239 }
    3240 
    3241 
    3242 /**
    3243  * Clears TSC delta related variables.
    3244  *
    3245  * Clears all TSC samples as well as the delta synchronization variable on the
    3246  * all the per-CPU structs.  Optionally also clears the per-cpu deltas too.
    3247  *
    3248  * @param   pDevExt         Pointer to the device instance data.
    3249  * @param   fClearDeltas    Whether the deltas are also to be cleared.
    3250  */
    3251 DECLINLINE(void) supdrvClearTscSamples(PSUPDRVDEVEXT pDevExt, bool fClearDeltas)
    3252 {
    3253     unsigned iCpu;
    3254     PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
    3255     for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
    3256     {
    3257         PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu];
    3258         ASMAtomicWriteU64(&pGipCpu->u64TSCSample, GIP_TSC_DELTA_RSVD);
    3259         if (fClearDeltas)
    3260             ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, INT64_MAX);
    3261     }
    3262     ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP);
     3257
     3258    /*
     3259     * End the synchroniziation dance.  We tell the other that we're done,
     3260     * then wait for the same kind of reply.
     3261     */
     3262    ASMAtomicWriteU32(&pOtherSync->uSyncVar, GIP_TSC_DELTA_SYNC2_FINAL);
     3263    ASMAtomicWriteNullPtr(ppMySync);
     3264    iTry = 0;
     3265    while (ASMAtomicReadU32(&MySync.uSyncVar) != GIP_TSC_DELTA_SYNC2_FINAL)
     3266    {
     3267        iTry++;
     3268        if (   iTry == 0
     3269            && !RTMpIsCpuOnline(fIsMaster ? pGipCpuWorker->idCpu : pGipCpuWorker->idCpu))
     3270            break; /* this really shouldn't happen. */
     3271#if defined(DEBUG_bird) && defined(RT_OS_WINDOWS)
     3272if (iTry == 0) __debugbreak();
     3273#endif
     3274        ASMNopPause();
     3275    }
     3276
     3277    return 0;
     3278}
     3279
     3280/**
     3281 * Callback used by supdrvMeasureInitialTscDeltas() to read the TSC on two CPUs
     3282 * and compute the delta between them.
     3283 *
     3284 * @param   idCpu       The CPU we are current scheduled on.
     3285 * @param   pvUser1     Pointer to a parameter package (SUPDRVGIPTSCDELTARGS).
     3286 * @param   pvUser2     Unused.
     3287 */
     3288static DECLCALLBACK(void) supdrvMeasureTscDeltaCallback(RTCPUID idCpu, void *pvUser1, void *pvUser2)
     3289{
     3290    supdrvMeasureTscDeltaCallbackUnwrapped(idCpu, (PSUPDRVGIPTSCDELTARGS)pvUser1);
    32633291}
    32643292
     
    33483376    if (RTCpuSetIsMemberByIndex(&pGip->OnlineCpuSet, pGipCpuWorker->iCpuSet))
    33493377    {
     3378        /** @todo we need to check that the master is online...
     3379         * The old supdrvMeasureTscDeltaCallback code would spin forever. */
    33503380        /*
    33513381         * Initialize data package for the RTMpOnAll callback.
     
    33533383        SUPDRVGIPTSCDELTARGS Args;
    33543384        RT_ZERO(Args);
    3355         Args.pWorker     = pGipCpuWorker;
    3356         Args.pMaster     = pGipCpuMaster;
    3357         Args.pDevExt     = pDevExt;
    3358         Args.pSyncMaster = NULL;
    3359         Args.pSyncWorker = NULL;
     3385        Args.pWorker      = pGipCpuWorker;
     3386        Args.pMaster      = pGipCpuMaster;
     3387        Args.pDevExt      = pDevExt;
     3388        Args.pSyncMaster  = NULL;
     3389        Args.pSyncWorker  = NULL;
     3390#if 0 /* later */
     3391        Args.cMaxTscTicks = ASMAtomicReadU64(&pGip->u64CpuHz) / 2048; /* 488 us */
     3392#else
     3393        Args.cMaxTscTicks = ASMAtomicReadU64(&pGip->u64CpuHz) / 1024; /* 976 us */
     3394#endif
     3395
    33603396#ifdef GIP_TSC_DELTA_METHOD_1
    33613397        rc = supdrvTscDeltaMethod1Init(&Args);
     
    34203456
    34213457/**
     3458 * Clears TSC delta related variables.
     3459 *
     3460 * Clears all TSC samples as well as the delta synchronization variable on the
     3461 * all the per-CPU structs.  Optionally also clears the per-cpu deltas too.
     3462 *
     3463 * @param   pDevExt         Pointer to the device instance data.
     3464 * @param   fClearDeltas    Whether the deltas are also to be cleared.
     3465 */
     3466static void supdrvClearTscSamples(PSUPDRVDEVEXT pDevExt, bool fClearDeltas)
     3467{
     3468    unsigned iCpu;
     3469    PSUPGLOBALINFOPAGE pGip = pDevExt->pGip;
     3470    for (iCpu = 0; iCpu < pGip->cCpus; iCpu++)
     3471    {
     3472        PSUPGIPCPU pGipCpu = &pGip->aCPUs[iCpu];
     3473        ASMAtomicWriteU64(&pGipCpu->u64TSCSample, GIP_TSC_DELTA_RSVD);
     3474        if (fClearDeltas)
     3475            ASMAtomicWriteS64(&pGipCpu->i64TSCDelta, INT64_MAX);
     3476    }
     3477    ASMAtomicWriteU32(&pDevExt->pTscDeltaSync->u, GIP_TSC_DELTA_SYNC_STOP);
     3478}
     3479
     3480
     3481/**
    34223482 * Performs the initial measurements of the TSC deltas between CPUs.
    34233483 *
     
    39444004        cTries = 256;
    39454005
    3946     if (cMsWaitRetry > 1000)
     4006    if (cMsWaitRetry == 0)
     4007        cMsWaitRetry = 2;
     4008    else if (cMsWaitRetry > 1000)
    39474009        cMsWaitRetry = 1000;
    39484010
     
    40454107        cTries--;
    40464108
    4047         if (cMsWaitRetry)
    4048         {
    4049             rc = RTThreadSleep(cMsWaitRetry);
    4050             if (rc == VERR_INTERRUPTED)
    4051                 break;
    4052         }
     4109        /* Always delay between retries (be nice to the rest of the system
     4110           and avoid the BSOD hounds). */
     4111        rc = RTThreadSleep(cMsWaitRetry);
     4112        if (rc == VERR_INTERRUPTED)
     4113            break;
    40534114    }
    40544115
     
    41724233                rc = supdrvMeasureTscDeltaOne(pDevExt, iGipCpu);
    41734234                Assert(pGip->aCPUs[iGipCpu].i64TSCDelta != INT64_MAX || RT_FAILURE_NP(rc));
     4235                /** @todo should probably delay on failure... dpc watchdogs   */
    41744236            }
    41754237            else
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