VirtualBox

忽略:
時間撮記:
2007-5-25 下午01:15:39 (18 年 以前)
作者:
vboxsync
訊息:

Create a speciallized version of the RTTimeNanoTS code in timesup.cpp for calculating the virtual time. I hope this will eliminate the w32_2 trouble and related issues seen on the black box and my laptop.

檔案:
修改 1 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/VMM/VMMAll/TMAllVirtual.cpp

    r2861 r2869  
    4747
    4848
     49/**
     50 * This is (mostly) the same as rtTimeNanoTSInternal() except
     51 * for the two globals which live in TM.
     52 *
     53 * @returns Nanosecond timestamp.
     54 * @param   pVM     The VM handle.
     55 */
     56static uint64_t tmVirtualGetRawNanoTS(PVM pVM)
     57{
     58    uint64_t    u64Delta;
     59    uint32_t    u32NanoTSFactor0;
     60    uint64_t    u64TSC;
     61    uint64_t    u64NanoTS;
     62    uint32_t    u32UpdateIntervalTSC;
     63
     64    /*
     65     * Read the GIP data.
     66     */
     67    for (;;)
     68    {
     69        uint32_t u32TransactionId;
     70        PCSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage;
     71#ifdef IN_RING3
     72        if (RT_UNLIKELY(!pGip || pGip->u32Magic != SUPGLOBALINFOPAGE_MAGIC))
     73            return RTTimeSystemNanoTS();
     74#endif
     75
     76        if (pGip->u32Mode != SUPGIPMODE_ASYNC_TSC)
     77        {
     78            u32TransactionId = pGip->aCPUs[0].u32TransactionId;
     79#ifdef __L4__
     80            Assert((u32TransactionId & 1) == 0);
     81#endif
     82            u32UpdateIntervalTSC = pGip->aCPUs[0].u32UpdateIntervalTSC;
     83            u64NanoTS = pGip->aCPUs[0].u64NanoTS;
     84            u64TSC = pGip->aCPUs[0].u64TSC;
     85            u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
     86            u64Delta = ASMReadTSC();
     87            if (RT_UNLIKELY(    pGip->aCPUs[0].u32TransactionId != u32TransactionId
     88                            ||  (u32TransactionId & 1)))
     89                continue;
     90        }
     91        else
     92        {
     93            /* SUPGIPMODE_ASYNC_TSC */
     94            PCSUPGIPCPU pGipCpu;
     95
     96            uint8_t u8ApicId = ASMGetApicId();
     97            if (RT_LIKELY(u8ApicId < RT_ELEMENTS(pGip->aCPUs)))
     98                pGipCpu = &pGip->aCPUs[u8ApicId];
     99            else
     100            {
     101                AssertMsgFailed(("%x\n", u8ApicId));
     102                pGipCpu = &pGip->aCPUs[0];
     103            }
     104
     105            u32TransactionId = pGipCpu->u32TransactionId;
     106#ifdef __L4__
     107            Assert((u32TransactionId & 1) == 0);
     108#endif
     109            u32UpdateIntervalTSC = pGipCpu->u32UpdateIntervalTSC;
     110            u64NanoTS = pGipCpu->u64NanoTS;
     111            u64TSC = pGipCpu->u64TSC;
     112            u32NanoTSFactor0 = pGip->u32UpdateIntervalNS;
     113            u64Delta = ASMReadTSC();
     114            if (RT_UNLIKELY(u8ApicId != ASMGetApicId()))
     115                continue;
     116            if (RT_UNLIKELY(    pGipCpu->u32TransactionId != u32TransactionId
     117                            ||  (u32TransactionId & 1)))
     118                continue;
     119        }
     120        break;
     121    }
     122
     123    /*
     124     * Calc NanoTS delta.
     125     */
     126    u64Delta -= u64TSC;
     127    if (u64Delta > u32UpdateIntervalTSC)
     128    {
     129        /*
     130         * We've expired the interval, cap it. If we're here for the 2nd
     131         * time without any GIP update inbetween, the checks against
     132         * pVM->tm.s.u64VirtualRawPrev below will force 1ns stepping.
     133         */
     134        u64Delta = u32UpdateIntervalTSC;
     135    }
     136#if !defined(_MSC_VER) || defined(__AMD64__) /* GCC makes very pretty code from these two inline calls, while MSC cannot. */
     137    u64Delta = ASMMult2xU32RetU64((uint32_t)u64Delta, u32NanoTSFactor0);
     138    u64Delta = ASMDivU64ByU32RetU32(u64Delta, u32UpdateIntervalTSC);
     139#else
     140    __asm
     141    {
     142        mov     eax, dword ptr [u64Delta]
     143        mul     dword ptr [u32NanoTSFactor0]
     144        div     dword ptr [u32UpdateIntervalTSC]
     145        mov     dword ptr [u64Delta], eax
     146        xor     edx, edx
     147        mov     dword ptr [u64Delta + 4], edx
     148    }
     149#endif
     150
     151    /*
     152     * Calculate the time and compare it with the previously returned value.
     153     *
     154     * Since this function is called *very* frequently when the VM is running
     155     * and then mostly on EMT, we can restrict the valid range of the delta
     156     * (-1s to 2*GipUpdates) and simplify/optimize the default path.
     157     */
     158    u64NanoTS += u64Delta;
     159    uint64_t u64PrevNanoTS = ASMAtomicReadU64(&pVM->tm.s.u64VirtualRawPrev);
     160    uint64_t u64DeltaPrev = u64NanoTS - u64PrevNanoTS;
     161    if (RT_LIKELY(u64DeltaPrev < 1000000000 /* 1s */))
     162        /* frequent - less than 1s since last call. */;
     163    else if (   (int64_t)u64DeltaPrev < 0
     164             && (int64_t)u64DeltaPrev + u32NanoTSFactor0 * 2 > 0)
     165    {
     166        /* occasional - u64NanoTS is in the 'past' relative to previous returns. */
     167        ASMAtomicIncU32(&pVM->tm.s.c1nsVirtualRawSteps);
     168        u64NanoTS = u64PrevNanoTS + 1;
     169    }
     170    else if (u64PrevNanoTS)
     171    {
     172        /* Something has gone bust, if negative offset it's real bad.*/
     173        ASMAtomicIncU32(&pVM->tm.s.cVirtualRawBadRawPrev);
     174        if ((int64_t)u64DeltaPrev < 0)
     175            LogRel(("TM: u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64 u64Delta=%#RX64\n",
     176                    u64DeltaPrev, u64PrevNanoTS, u64NanoTS, u64Delta));
     177        else
     178            Log(("TM: u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64 u64Delta=%#RX64 (debugging?)\n",
     179                 u64DeltaPrev, u64PrevNanoTS, u64NanoTS, u64Delta));
     180#ifdef DEBUG_bird
     181        AssertMsgFailed(("u64DeltaPrev=%RI64 u64PrevNanoTS=0x%016RX64 u64NanoTS=0x%016RX64 u64Delta=%#RX64\n",
     182                         u64DeltaPrev, u64PrevNanoTS, u64NanoTS, u64Delta));
     183#endif
     184    }
     185    /* else: We're resuming (see TMVirtualResume). */
     186    if (RT_LIKELY(ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualRawPrev, u64NanoTS, u64PrevNanoTS)))
     187        return u64NanoTS;
     188
     189    /*
     190     * Attempt updating the previous value, provided we're still ahead of it.
     191     *
     192     * There is no point in recalculating u64NanoTS because we got preemted or if
     193     * we raced somebody while the GIP was updated, since these are events
     194     * that might occure at any point in the return path as well.
     195     */
     196    for (int cTries = 100;;)
     197    {
     198        u64PrevNanoTS = ASMAtomicReadU64(&pVM->tm.s.u64VirtualRawPrev);
     199        if (u64PrevNanoTS >= u64NanoTS)
     200            break;
     201        if (ASMAtomicCmpXchgU64(&pVM->tm.s.u64VirtualRawPrev, u64NanoTS, u64PrevNanoTS))
     202            break;
     203        AssertBreak(--cTries <= 0, );
     204    }
     205
     206    return u64NanoTS;
     207}
     208
     209
    49210
    50211/**
     
    60221     * warp drive has been enabled.
    61222     */
    62     uint64_t u64 = RTTimeNanoTS();
     223    uint64_t u64 = tmVirtualGetRawNanoTS(pVM);
    63224    u64 -= pVM->tm.s.u64VirtualWarpDriveStart;
    64225    u64 *= pVM->tm.s.u32VirtualWarpDrivePercentage;
     
    68229    /*
    69230     * Now we apply the virtual time offset.
    70      * (Which is the negate RTTimeNanoTS() value for when the virtual machine
    71      * started if it had been running continuously without any suspends.)
     231     * (Which is the negated tmVirtualGetRawNanoTS() value for when the virtual
     232     * machine started if it had been running continuously without any suspends.)
    72233     */
    73234    u64 -= pVM->tm.s.u64VirtualOffset;
     
    85246{
    86247    if (RT_LIKELY(!pVM->tm.s.fVirtualWarpDrive))
    87         return RTTimeNanoTS() - pVM->tm.s.u64VirtualOffset;
     248        return tmVirtualGetRawNanoTS(pVM) - pVM->tm.s.u64VirtualOffset;
    88249    return tmVirtualGetRawNonNormal(pVM);
    89250}
     
    209370         *  - We might be on a different CPU which TSC isn't quite in sync with the
    210371         *    other CPUs in the system.
    211          *  - RTTimeNanoTS() is returning sligtly different values in GC, R0 and R3 because
    212          *    of the static variable it uses with the previous read time.
    213372         *  - Another thread is racing us and we might have been preemnted while inside
    214373         *    this function.
     
    350509    {
    351510        STAM_COUNTER_INC(&pVM->tm.s.StatVirtualResume);
    352         pVM->tm.s.u64VirtualWarpDriveStart = RTTimeNanoTS();
     511        pVM->tm.s.u64VirtualRawPrev = 0;
     512        pVM->tm.s.u64VirtualWarpDriveStart = tmVirtualGetRawNanoTS(pVM);
    353513        pVM->tm.s.u64VirtualOffset = pVM->tm.s.u64VirtualWarpDriveStart - pVM->tm.s.u64Virtual;
    354514        pVM->tm.s.fVirtualTicking = true;
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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