VirtualBox

Changeset 32572 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Sep 16, 2010 4:18:12 PM (14 years ago)
Author:
vboxsync
Message:

VMM,SUPDrv,IPRT: More changes for related to the priodic preemption timer. (still disabled)

Location:
trunk/src/VBox/VMM
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r32489 r32572  
    23742374    /* Fudge factor. */
    23752375    /** @todo make this configurable. */
     2376#if 0 /* what's wrong with this expression? I end up with uHz = 0 after this multiplication... */
    23762377    uHz *= 110 + pVCpu->idCpu == pVM->tm.s.idTimerCpu;
     2378#else
     2379    if (pVCpu->idCpu == pVM->tm.s.idTimerCpu)
     2380        uHz *= 111;
     2381    else
     2382        uHz *= 110;
     2383#endif
    23772384    uHz /= 100;
    23782385
     2386    //LogAlways(("TMCalcHostTimerFrequency->%u\n", uHz));
    23792387    return uHz;
    23802388}
  • trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp

    r32489 r32572  
    5757#include <iprt/memobj.h>
    5858#include <iprt/mp.h>
     59#include <iprt/cpuset.h>
     60#include <iprt/spinlock.h>
     61#include <iprt/timer.h>
     62
     63
     64/*******************************************************************************
     65*   Defined Constants And Macros                                               *
     66*******************************************************************************/
     67#ifdef DOXYGEN_RUNNING
     68/** Define this to enable the periodic preemption timer. */
     69# define GVMM_SCHED_WITH_PPT
     70#endif
    5971
    6072
     
    97109# define GVMM_MAX_HANDLES   128
    98110#endif
     111
     112/**
     113 * Per host CPU GVMM data.
     114 */
     115typedef struct GVMMHOSTCPU
     116{
     117    /** Magic number (GVMMHOSTCPU_MAGIC). */
     118    uint32_t volatile   u32Magic;
     119    /** The CPU ID. */
     120    RTCPUID             idCpu;
     121    /** The CPU set index. */
     122    uint32_t            idxCpuSet;
     123
     124#ifdef GVMM_SCHED_WITH_PPT
     125    /** Periodic preemption timer data. */
     126    struct
     127    {
     128        /** The handle to the periodic preemption timer. */
     129        PRTTIMER            pTimer;
     130        /** Spinlock protecting the data below. */
     131        RTSPINLOCK          hSpinlock;
     132        /** The smalles Hz that we need to care about. (static) */
     133        uint32_t            uMinHz;
     134        /** The number of ticks between each historization. */
     135        uint32_t            cTicksHistoriziationInterval;
     136        /** The current historization tick (counting up to
     137         * cTicksHistoriziationInterval and then resetting). */
     138        uint32_t            iTickHistorization;
     139        /** The current timer interval.  This is set to 0 when inactive. */
     140        uint32_t            cNsInterval;
     141        /** The current timer frequency.  This is set to 0 when inactive. */
     142        uint32_t            uTimerHz;
     143        /** The current max frequency reported by the EMTs.
     144         * This gets historicize and reset by the timer callback.  This is
     145         * read without holding the spinlock, so needs atomic updating. */
     146        uint32_t volatile   uDesiredHz;
     147        /** Whether the timer was started or not. */
     148        bool volatile       fStarted;
     149        /** Set if we're starting timer. */
     150        bool volatile       fStarting;
     151        /** The index of the next history entry (mod it). */
     152        uint32_t            iHzHistory;
     153        /** Hitoricized uDesiredHz values.  The array wraps around, new entries
     154         * are added at iHzHistory. This is updated approximately every
     155         * GVMMHOSTCPU_PPT_HIST_INTERVAL_NS by the timer callback. */
     156        uint32_t            aHzHistory[32];
     157        /** Statistics counter for recording the number of interval changes. */
     158        uint64_t            cChanges;
     159        /** Statistics counter for recording the number of timer starts. */
     160        uint64_t            cStarts;
     161    } Ppt;
     162#endif /* GVMM_SCHED_WITH_PPT */
     163
     164} GVMMHOSTCPU;
     165/** Pointer to the per host CPU GVMM data. */
     166typedef GVMMHOSTCPU *PGVMMHOSTCPU;
     167/** The GVMMHOSTCPU::u32Magic value (Petra, Tanya & Rachel Haden). */
     168#define GVMMHOSTCPU_MAGIC   UINT32_C(0x19711011)
     169/** The interval on history entry should cover (approximately) give in
     170 *  nanoseconds. */
     171#define GVMMHOSTCPU_PPT_HIST_INTERVAL_NS    UINT32_C(20000000)
     172
    99173
    100174/**
     
    148222     */
    149223    uint32_t            nsEarlyWakeUp2;
     224
     225    /** The number of entries in the host CPU array (aHostCpus). */
     226    uint32_t            cHostCpus;
     227    /** Per host CPU data (variable length). */
     228    GVMMHOSTCPU         aHostCpus[1];
    150229} GVMM;
    151230/** Pointer to the GVMM instance data. */
     
    198277static int gvmmR0ByVM(PVM pVM, PGVM *ppGVM, PGVMM *ppGVMM, bool fTakeUsedLock);
    199278static int gvmmR0ByVMAndEMT(PVM pVM, VMCPUID idCpu, PGVM *ppGVM, PGVMM *ppGVMM);
     279#ifdef GVMM_SCHED_WITH_PPT
     280static DECLCALLBACK(void) gvmmR0SchedPeriodicPreemptionTimerCallback(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
     281#endif
    200282
    201283
     
    214296     * Allocate and initialize the instance data.
    215297     */
    216     PGVMM pGVMM = (PGVMM)RTMemAllocZ(sizeof(*pGVMM));
     298    uint32_t cHostCpus = RTMpGetArraySize();
     299    AssertMsgReturn(cHostCpus > 0 && cHostCpus < _64K, ("%d", (int)cHostCpus), VERR_INTERNAL_ERROR_2);
     300
     301    PGVMM pGVMM = (PGVMM)RTMemAllocZ(RT_UOFFSETOF(GVMM, aHostCpus[cHostCpus]));
    217302    if (!pGVMM)
    218303        return VERR_NO_MEMORY;
     
    250335            pGVMM->nsEarlyWakeUp2    =  50000 /* ns (0.050 ms) */;
    251336
    252             g_pGVMM = pGVMM;
    253             LogFlow(("GVMMR0Init: pGVMM=%p\n", pGVMM));
    254             return VINF_SUCCESS;
    255         }
    256 
     337            /* The host CPU data. */
     338            pGVMM->cHostCpus = cHostCpus;
     339            uint32_t    iCpu = cHostCpus;
     340            RTCPUSET    PossibleSet;
     341            RTMpGetSet(&PossibleSet);
     342            while (iCpu-- > 0)
     343            {
     344                pGVMM->aHostCpus[iCpu].idxCpuSet        = iCpu;
     345#ifdef GVMM_SCHED_WITH_PPT
     346                pGVMM->aHostCpus[iCpu].Ppt.pTimer       = NULL;
     347                pGVMM->aHostCpus[iCpu].Ppt.hSpinlock    = NIL_RTSPINLOCK;
     348                pGVMM->aHostCpus[iCpu].Ppt.uMinHz       = 5; /** @todo Add some API which figures this one out. (not *that* important) */
     349                pGVMM->aHostCpus[iCpu].Ppt.cTicksHistoriziationInterval = 1;
     350                //pGVMM->aHostCpus[iCpu].Ppt.iTickHistorization           = 0;
     351                //pGVMM->aHostCpus[iCpu].Ppt.cNsInterval  = 0;
     352                //pGVMM->aHostCpus[iCpu].Ppt.uTimerHz     = 0;
     353                //pGVMM->aHostCpus[iCpu].Ppt.uDesiredHz   = 0;
     354                //pGVMM->aHostCpus[iCpu].Ppt.fStarted     = false;
     355                //pGVMM->aHostCpus[iCpu].Ppt.fStarting    = false;
     356                //pGVMM->aHostCpus[iCpu].Ppt.iHzHistory   = 0;
     357                //pGVMM->aHostCpus[iCpu].Ppt.aHzHistory   = {0};
     358#endif
     359
     360                if (RTCpuSetIsMember(&PossibleSet, iCpu))
     361                {
     362                    pGVMM->aHostCpus[iCpu].idCpu        = RTMpCpuIdFromSetIndex(iCpu);
     363                    pGVMM->aHostCpus[iCpu].u32Magic     = GVMMHOSTCPU_MAGIC;
     364
     365#ifdef GVMM_SCHED_WITH_PPT
     366                    rc = RTTimerCreateEx(&pGVMM->aHostCpus[iCpu].Ppt.pTimer,
     367                                         50*1000*1000 /* whatever */,
     368                                         RTTIMER_FLAGS_CPU(iCpu) | RTTIMER_FLAGS_HIGH_RES,
     369                                         gvmmR0SchedPeriodicPreemptionTimerCallback,
     370                                         &pGVMM->aHostCpus[iCpu]);
     371                    if (RT_SUCCESS(rc))
     372                        rc = RTSpinlockCreate(&pGVMM->aHostCpus[iCpu].Ppt.hSpinlock);
     373                    if (RT_FAILURE(rc))
     374                    {
     375                        while (iCpu < cHostCpus)
     376                        {
     377                            RTTimerDestroy(pGVMM->aHostCpus[iCpu].Ppt.pTimer);
     378                            RTSpinlockDestroy(pGVMM->aHostCpus[iCpu].Ppt.hSpinlock);
     379                            pGVMM->aHostCpus[iCpu].Ppt.hSpinlock = NIL_RTSPINLOCK;
     380                            iCpu++;
     381                        }
     382                        break;
     383                    }
     384#endif
     385                }
     386                else
     387                {
     388                    pGVMM->aHostCpus[iCpu].idCpu        = NIL_RTCPUID;
     389                    pGVMM->aHostCpus[iCpu].u32Magic     = 0;
     390                }
     391            }
     392            if (RT_SUCCESS(rc))
     393            {
     394                g_pGVMM = pGVMM;
     395                LogFlow(("GVMMR0Init: pGVMM=%p cHostCpus=%u\n", pGVMM, cHostCpus));
     396                return VINF_SUCCESS;
     397            }
     398
     399            /* bail out. */
     400            RTSemFastMutexDestroy(pGVMM->UsedLock);
     401            pGVMM->UsedLock = NIL_RTSEMFASTMUTEX;
     402        }
    257403        RTSemFastMutexDestroy(pGVMM->CreateDestroyLock);
     404        pGVMM->CreateDestroyLock = NIL_RTSEMFASTMUTEX;
    258405    }
    259406
     
    282429    }
    283430
    284     pGVMM->u32Magic++;
    285 
     431    /*
     432     * First of all, stop all active timers.
     433     */
     434    uint32_t cActiveTimers = 0;
     435    uint32_t iCpu = pGVMM->cHostCpus;
     436    while (iCpu-- > 0)
     437    {
     438        ASMAtomicWriteU32(&pGVMM->aHostCpus[iCpu].u32Magic, ~GVMMHOSTCPU_MAGIC);
     439#ifdef GVMM_SCHED_WITH_PPT
     440        if (    pGVMM->aHostCpus[iCpu].Ppt.pTimer != NULL
     441            &&  RT_SUCCESS(RTTimerStop(pGVMM->aHostCpus[iCpu].Ppt.pTimer)))
     442            cActiveTimers++;
     443#endif
     444    }
     445    if (cActiveTimers)
     446        RTThreadSleep(1); /* fudge */
     447
     448    /*
     449     * Invalidate the and free resources.
     450     */
     451    pGVMM->u32Magic = ~GVMM_MAGIC;
    286452    RTSemFastMutexDestroy(pGVMM->UsedLock);
    287453    pGVMM->UsedLock = NIL_RTSEMFASTMUTEX;
     
    295461        pGVMM->iUsedHead = 0;
    296462    }
     463
     464#ifdef GVMM_SCHED_WITH_PPT
     465    iCpu = pGVMM->cHostCpus;
     466    while (iCpu-- > 0)
     467    {
     468        RTTimerDestroy(pGVMM->aHostCpus[iCpu].Ppt.pTimer);
     469        pGVMM->aHostCpus[iCpu].Ppt.pTimer = NULL;
     470        RTSpinlockDestroy(pGVMM->aHostCpus[iCpu].Ppt.hSpinlock);
     471        pGVMM->aHostCpus[iCpu].Ppt.hSpinlock = NIL_RTSPINLOCK;
     472    }
     473#endif
    297474
    298475    RTMemFree(pGVMM);
     
    18862063
    18872064
     2065#ifdef GVMM_SCHED_WITH_PPT
     2066/**
     2067 * Timer callback for the periodic preemption timer.
     2068 *
     2069 * @param   pTimer      The timer handle.
     2070 * @param   pvUser      Pointer to the per cpu structure.
     2071 * @param   iTick       The current tick.
     2072 */
     2073static DECLCALLBACK(void) gvmmR0SchedPeriodicPreemptionTimerCallback(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
     2074{
     2075    PGVMMHOSTCPU pCpu = (PGVMMHOSTCPU)pvUser;
     2076
     2077    /*
     2078     * Termination check
     2079     */
     2080    if (pCpu->u32Magic != GVMMHOSTCPU_MAGIC)
     2081        return;
     2082
     2083    /*
     2084     * Do the house keeping.
     2085     */
     2086    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     2087    RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2088
     2089    if (++pCpu->Ppt.iTickHistorization >= pCpu->Ppt.cTicksHistoriziationInterval)
     2090    {
     2091        /*
     2092         * Historicize the max frequency.
     2093         */
     2094        uint32_t iHzHistory = ++pCpu->Ppt.iHzHistory % RT_ELEMENTS(pCpu->Ppt.aHzHistory);
     2095        pCpu->Ppt.aHzHistory[iHzHistory] = pCpu->Ppt.uDesiredHz;
     2096        pCpu->Ppt.iTickHistorization = 0;
     2097        pCpu->Ppt.uDesiredHz         = 0;
     2098
     2099        /*
     2100         * Check if the current timer frequency.
     2101         */
     2102        uint32_t uHistMaxHz = 0;
     2103        for (uint32_t i = 0; i < RT_ELEMENTS(pCpu->Ppt.aHzHistory); i++)
     2104            if (pCpu->Ppt.aHzHistory[i] > uHistMaxHz)
     2105                uHistMaxHz = pCpu->Ppt.aHzHistory[i];
     2106        if (uHistMaxHz == pCpu->Ppt.uTimerHz)
     2107            RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2108        else if (uHistMaxHz)
     2109        {
     2110            /*
     2111             * Reprogram it.
     2112             */
     2113            pCpu->Ppt.cChanges++;
     2114            pCpu->Ppt.iTickHistorization    = 0;
     2115            pCpu->Ppt.uTimerHz              = uHistMaxHz;
     2116            uint32_t const cNsInterval      = UINT32_C(1000000000) / uHistMaxHz;
     2117            pCpu->Ppt.cNsInterval           = cNsInterval;
     2118            if (cNsInterval < GVMMHOSTCPU_PPT_HIST_INTERVAL_NS)
     2119                pCpu->Ppt.cTicksHistoriziationInterval = (  GVMMHOSTCPU_PPT_HIST_INTERVAL_NS
     2120                                                          + GVMMHOSTCPU_PPT_HIST_INTERVAL_NS / 2 - 1)
     2121                                                       / cNsInterval;
     2122            else
     2123                pCpu->Ppt.cTicksHistoriziationInterval = 1;
     2124            RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2125
     2126            /*SUPR0Printf("Cpu%u: change to %u Hz / %u ns\n", pCpu->idxCpuSet, uHistMaxHz, cNsInterval);*/
     2127            RTTimerChangeInterval(pTimer, cNsInterval);
     2128        }
     2129        else
     2130        {
     2131            /*
     2132             * Stop it.
     2133             */
     2134            pCpu->Ppt.fStarted    = false;
     2135            pCpu->Ppt.uTimerHz    = 0;
     2136            pCpu->Ppt.cNsInterval = 0;
     2137            RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2138
     2139            /*SUPR0Printf("Cpu%u: stopping (%u Hz)\n", pCpu->idxCpuSet, uHistMaxHz);*/
     2140            RTTimerStop(pTimer);
     2141        }
     2142    }
     2143    else
     2144        RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2145}
     2146#endif /* GVMM_SCHED_WITH_PPT */
     2147
    18882148
    18892149/**
     
    18912151 *
    18922152 * The caller must have disabled preemption!
     2153 * The caller must check that the host can do high resolution timers.
    18932154 *
    18942155 * @param   pVM         The VM handle.
     
    18982159GVMMR0DECL(void) GVMMR0SchedUpdatePeriodicPreemptionTimer(PVM pVM, RTCPUID idHostCpu, uint32_t uHz)
    18992160{
    1900 
     2161#ifdef GVMM_SCHED_WITH_PPT
     2162    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
     2163    Assert(RTTimerCanDoHighResolution());
     2164
     2165    /*
     2166     * Resolve the per CPU data.
     2167     */
     2168    uint32_t    iCpu  = RTMpCpuIdToSetIndex(idHostCpu);
     2169    PGVMM       pGVMM = g_pGVMM;
     2170    if (   !VALID_PTR(pGVMM)
     2171        || pGVMM->u32Magic != GVMM_MAGIC)
     2172        return;
     2173    AssertMsgReturnVoid(iCpu < pGVMM->cHostCpus, ("iCpu=%d cHostCpus=%d\n", iCpu, pGVMM->cHostCpus));
     2174    PGVMMHOSTCPU pCpu = &pGVMM->aHostCpus[iCpu];
     2175    AssertMsgReturnVoid(   pCpu->u32Magic == GVMMHOSTCPU_MAGIC
     2176                        && pCpu->idCpu    == idHostCpu,
     2177                        ("u32Magic=%#x idCpu=% idHostCpu=%d\n", pCpu->u32Magic, pCpu->idCpu, idHostCpu));
     2178
     2179    /*
     2180     * Check whether we need to do anything about the timer.
     2181     * We have to be a little bit careful since we might be race the timer
     2182     * callback here.
     2183     */
     2184    if (uHz > 20000)
     2185        uHz = 20000;
     2186    if (RT_UNLIKELY(   uHz > ASMAtomicReadU32(&pCpu->Ppt.uDesiredHz)
     2187                    && uHz >= pCpu->Ppt.uMinHz
     2188                    && !pCpu->Ppt.fStarting /* solaris paranoia */))
     2189    {
     2190        RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     2191        RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2192
     2193        pCpu->Ppt.uDesiredHz = uHz;
     2194        uint32_t cNsInterval = 0;
     2195        if (!pCpu->Ppt.fStarted)
     2196        {
     2197            pCpu->Ppt.cStarts++;
     2198            pCpu->Ppt.fStarted              = true;
     2199            pCpu->Ppt.fStarting             = true;
     2200            pCpu->Ppt.iTickHistorization    = 0;
     2201            pCpu->Ppt.uTimerHz              = uHz;
     2202            pCpu->Ppt.cNsInterval           = cNsInterval = UINT32_C(1000000000) / uHz;
     2203            if (cNsInterval < GVMMHOSTCPU_PPT_HIST_INTERVAL_NS)
     2204                pCpu->Ppt.cTicksHistoriziationInterval = (  GVMMHOSTCPU_PPT_HIST_INTERVAL_NS
     2205                                                          + GVMMHOSTCPU_PPT_HIST_INTERVAL_NS / 2 - 1)
     2206                                                       / cNsInterval;
     2207            else
     2208                pCpu->Ppt.cTicksHistoriziationInterval = 1;
     2209        }
     2210
     2211        RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2212
     2213        if (cNsInterval)
     2214        {
     2215            RTTimerChangeInterval(pCpu->Ppt.pTimer, cNsInterval);
     2216            int rc = RTTimerStart(pCpu->Ppt.pTimer, cNsInterval);
     2217            AssertRC(rc);
     2218
     2219            RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2220            if (RT_FAILURE(rc))
     2221                pCpu->Ppt.fStarted = false;
     2222            pCpu->Ppt.fStarting = false;
     2223            RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2224        }
     2225    }
     2226#endif /* GVMM_SCHED_WITH_PPT */
    19012227}
    19022228
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