VirtualBox

Changeset 20750 in vbox


Ignore:
Timestamp:
Jun 21, 2009 9:14:52 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
48866
Message:

TMTimerSetRelative: Optimized the common case and added some more statistics to make sure I've got the right source for the virtual sync assertions.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/vm.h

    r20663 r20750  
    926926        struct TM   s;
    927927#endif
    928         char        padding[1920];      /* multiple of 32 */
     928        char        padding[2048];      /* multiple of 32 */
    929929    } tm;
    930930
  • trunk/src/VBox/VMM/TM.cpp

    r20733 r20750  
    578578    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRZ,                          STAMTYPE_PROFILE, "/TM/TimerSetRZ",                  STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSet calls made in ring-0 / RC.");
    579579
    580     STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeR3,                  STAMTYPE_PROFILE, "/TM/TimerSetRelativeR3",          STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3.");
    581     STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRZ,                  STAMTYPE_PROFILE, "/TM/TimerSetRelativeRZ",          STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC.");
     580    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelative,                    STAMTYPE_COUNTER, "/TM/TimerSetRelative",                STAMUNIT_OCCURENCES, "Calls");
     581    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeR3,                  STAMTYPE_PROFILE, "/TM/TimerSetRelative/R3",         STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetRelative calls made in ring-3.");
     582    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRZ,                  STAMTYPE_PROFILE, "/TM/TimerSetRelative/RZ",         STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerSetReltaive calls made in ring-0 / RC.");
     583    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeRacyVirtSync,        STAMTYPE_COUNTER, "/TM/TimerSetRelative/RacyVirtSync",   STAMUNIT_OCCURENCES, "Potentially racy virtual sync timer update.");
     584    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeOpt,                 STAMTYPE_COUNTER, "/TM/TimerSetRelative/Opt",            STAMUNIT_OCCURENCES, "Optimized path taken.");
     585    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStActive,            STAMTYPE_COUNTER, "/TM/TimerSetRelative/StActive",       STAMUNIT_OCCURENCES, "ACTIVE");
     586    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStExpDeliver,        STAMTYPE_COUNTER, "/TM/TimerSetRelative/StExpDeliver",   STAMUNIT_OCCURENCES, "EXPIRED_DELIVER");
     587    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStOther,             STAMTYPE_COUNTER, "/TM/TimerSetRelative/StOther",        STAMUNIT_OCCURENCES, "Other states");
     588    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStPendStop,          STAMTYPE_COUNTER, "/TM/TimerSetRelative/StPendStop",     STAMUNIT_OCCURENCES, "PENDING_STOP");
     589    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStPendStopSched,     STAMTYPE_COUNTER, "/TM/TimerSetRelative/StPendStopSched",STAMUNIT_OCCURENCES, "PENDING_STOP_SCHEDULE");
     590    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStPendSched,         STAMTYPE_COUNTER, "/TM/TimerSetRelative/StPendSched",    STAMUNIT_OCCURENCES, "PENDING_SCHEDULE");
     591    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStPendResched,       STAMTYPE_COUNTER, "/TM/TimerSetRelative/StPendResched",  STAMUNIT_OCCURENCES, "PENDING_RESCHEDULE");
     592    STAM_REG(pVM, &pVM->tm.s.StatTimerSetRelativeStStopped,           STAMTYPE_COUNTER, "/TM/TimerSetRelative/StStopped",      STAMUNIT_OCCURENCES, "STOPPED");
    582593
    583594    STAM_REG(pVM, &pVM->tm.s.StatTimerStopR3,                         STAMTYPE_PROFILE, "/TM/TimerStopR3",                 STAMUNIT_TICKS_PER_CALL, "Profiling TMTimerStop calls made in ring-3.");
  • trunk/src/VBox/VMM/TMInternal.h

    r20733 r20750  
    487487    /** TMTimerSetRelative
    488488     * @{ */
     489    STAMCOUNTER                 StatTimerSetRelative;
    489490    STAMPROFILE                 StatTimerSetRelativeRZ;
    490491    STAMPROFILE                 StatTimerSetRelativeR3;
     492    STAMCOUNTER                 StatTimerSetRelativeOpt;
     493    STAMCOUNTER                 StatTimerSetRelativeRacyVirtSync;
     494    STAMCOUNTER                 StatTimerSetRelativeStStopped;
     495    STAMCOUNTER                 StatTimerSetRelativeStExpDeliver;
     496    STAMCOUNTER                 StatTimerSetRelativeStActive;
     497    STAMCOUNTER                 StatTimerSetRelativeStPendStop;
     498    STAMCOUNTER                 StatTimerSetRelativeStPendStopSched;
     499    STAMCOUNTER                 StatTimerSetRelativeStPendSched;
     500    STAMCOUNTER                 StatTimerSetRelativeStPendResched;
     501    STAMCOUNTER                 StatTimerSetRelativeStOther;
    491502    /** @} */
    492503    /** TMTimerStop
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r20733 r20750  
    743743
    744744/**
     745 * Links a timer into the active list of a timer queue.
     746 *
     747 * The caller must have taken the TM semaphore before calling this function.
     748 *
     749 * @param   pQueue          The queue.
     750 * @param   pTimer          The timer.
     751 * @param   u64Expire       The timer expiration time.
     752 */
     753DECL_FORCE_INLINE(void) tmTimerActiveLink(PTMTIMERQUEUE pQueue, PTMTIMER pTimer, uint64_t u64Expire)
     754{
     755    PTMTIMER pCur = TMTIMER_GET_HEAD(pQueue);
     756    if (pCur)
     757    {
     758        for (;; pCur = TMTIMER_GET_NEXT(pCur))
     759        {
     760            if (pCur->u64Expire > u64Expire)
     761            {
     762                const PTMTIMER pPrev = TMTIMER_GET_PREV(pCur);
     763                TMTIMER_SET_NEXT(pTimer, pCur);
     764                TMTIMER_SET_PREV(pTimer, pPrev);
     765                if (pPrev)
     766                    TMTIMER_SET_NEXT(pPrev, pTimer);
     767                else
     768                {
     769                    TMTIMER_SET_HEAD(pQueue, pTimer);
     770                    pQueue->u64Expire = u64Expire;
     771                }
     772                TMTIMER_SET_PREV(pCur, pTimer);
     773                return;
     774            }
     775            if (!pCur->offNext)
     776            {
     777                TMTIMER_SET_NEXT(pCur, pTimer);
     778                TMTIMER_SET_PREV(pTimer, pCur);
     779                return;
     780            }
     781        }
     782    }
     783    else
     784    {
     785        TMTIMER_SET_HEAD(pQueue, pTimer);
     786        pQueue->u64Expire = u64Expire;
     787    }
     788}
     789
     790
     791/**
    745792 * Arm a timer with a (new) expire time.
    746793 *
     
    884931
    885932/**
     933 * Optimized TMTimerSetRelative code path.
     934 *
     935 * @returns VBox status code.
     936 *
     937 * @param   pVM             The VM handle.
     938 * @param   pTimer          The timer handle.
     939 * @param   cTicksToNext    Clock ticks until the next time expiration.
     940 * @param   pu64Now         Where to return the current time stamp used.
     941 *                          Optional.
     942 */
     943static int tmTimerSetRelativeOptimizedStart(PVM pVM, PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
     944{
     945    Assert(!pTimer->offPrev);
     946    Assert(!pTimer->offNext);
     947    Assert(pTimer->enmState == TMTIMERSTATE_ACTIVE);
     948
     949    /*
     950     * Calculate and set the expiration time.
     951     */
     952    TMCLOCK const   enmClock  = pTimer->enmClock;
     953    uint64_t const  u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
     954    pTimer->u64Expire         = u64Expire;
     955    Log2(("tmTimerSetRelativeOptimizedStart: %p:{.pszDesc='%s', .u64Expire=%'RU64} cTicksToNext=%'RU64\n", pTimer, R3STRING(pTimer->pszDesc), u64Expire, cTicksToNext));
     956
     957    /*
     958     * Link the timer into the active list.
     959     */
     960    tmTimerActiveLink(&pVM->tm.s.CTX_SUFF(paTimerQueues)[enmClock], pTimer, u64Expire);
     961
     962    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeOpt);
     963    tmUnlock(pVM);
     964    return VINF_SUCCESS;
     965}
     966
     967
     968/**
    886969 * Arm a timer with a expire time relative to the current time.
    887970 *
     
    896979    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
    897980    TMTIMER_ASSERT_CRITSECT(pTimer);
    898     PVM         pVM      = pTimer->CTX_SUFF(pVM);
    899     TMCLOCK     enmClock = pTimer->enmClock;
    900     bool        fOwnLock = false;
    901     int         rc;
    902 
    903     /** @todo find the most frequently used paths and make them skip tmSchedule and tmTimerTryWithLink. */
     981    PVM             pVM = pTimer->CTX_SUFF(pVM);
     982    int             rc;
     983
     984#ifdef VBOX_WITH_STATISTICS
     985    /* Gather optimization info. */
     986    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelative);
     987    TMTIMERSTATE enmOrgState = pTimer->enmState;
     988    switch (enmOrgState)
     989    {
     990        case TMTIMERSTATE_STOPPED:                  STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeStStopped); break;
     991        case TMTIMERSTATE_EXPIRED_DELIVER:          STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeStExpDeliver); break;
     992        case TMTIMERSTATE_ACTIVE:                   STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeStActive); break;
     993        case TMTIMERSTATE_PENDING_STOP:             STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeStPendStop); break;
     994        case TMTIMERSTATE_PENDING_STOP_SCHEDULE:    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeStPendStopSched); break;
     995        case TMTIMERSTATE_PENDING_SCHEDULE:         STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeStPendSched); break;
     996        case TMTIMERSTATE_PENDING_RESCHEDULE:       STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeStPendResched); break;
     997        default:                                    STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeStOther); break;
     998    }
     999#endif
     1000
     1001    /*
     1002     * Try to take the TM lock and optimize the common cases.
     1003     *
     1004     * With the TM lock we can safely make optimizations like immediate
     1005     * scheduling and we can also be 100% sure that we're not racing the
     1006     * running of the timer queues. As an additional restraint we require the
     1007     * timer to have a critical section associated with to be 100% there aren't
     1008     * concurrent operations on the timer. (This latter isn't necessary any
     1009     * longer as this isn't supported for any timers, critsect or not.)
     1010     *
     1011     * Note! Lock ordering doesn't apply when we only tries to
     1012     *       get the innermost locks.
     1013     */
     1014    bool fOwnTMLock = RT_SUCCESS(tmTryLock(pVM));
     1015#if 1
     1016    if (    fOwnTMLock
     1017        &&  pTimer->pCritSect)
     1018    {
     1019        TMTIMERSTATE enmState = pTimer->enmState;
     1020        if (RT_LIKELY(  (   enmState == TMTIMERSTATE_EXPIRED_DELIVER
     1021                         || enmState == TMTIMERSTATE_STOPPED)
     1022                      && tmTimerTry(pTimer, TMTIMERSTATE_ACTIVE, enmState)))
     1023        {
     1024            tmTimerSetRelativeOptimizedStart(pVM, pTimer, cTicksToNext, pu64Now);
     1025            STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     1026            return VINF_SUCCESS;
     1027        }
     1028
     1029        /* Optimize other states when it becomes necessary. */
     1030    }
     1031#endif
     1032
     1033    /*
     1034     * Unoptimized path.
     1035     */
     1036    TMCLOCK const   enmClock = pTimer->enmClock;
     1037    bool            fOwnVirtSyncLock;
     1038    fOwnVirtSyncLock = !fOwnTMLock
     1039                    && enmClock == TMCLOCK_VIRTUAL_SYNC
     1040                    && RT_SUCCESS(tmVirtualSyncTryLock(pVM));
    9041041    for (int cRetries = 1000; ; cRetries--)
    9051042    {
    906         /*
    907          * Try to take the appropriate lock to increase the likelyhood
    908          * that we don't race timer queue running and to some extend
    909          * clock queries.
    910          */
    911         if (!fOwnLock)
    912         {
    913             if (enmClock == TMCLOCK_VIRTUAL_SYNC)
    914                 fOwnLock = RT_SUCCESS(tmVirtualSyncTryLock(pVM));
    915             else
    916                 fOwnLock = RT_SUCCESS(tmTryLock(pVM));
    917         }
    918 
    9191043        /*
    9201044         * Change to any of the SET_EXPIRE states if valid and then to SCHEDULE or RESCHEDULE.
    9211045         */
    922         TMTIMERSTATE    enmState = pTimer->enmState;
     1046        TMTIMERSTATE enmState = pTimer->enmState;
    9231047        switch (enmState)
    9241048        {
     1049            case TMTIMERSTATE_STOPPED:
     1050                if (tmClock == TMCLOCK_VIRTUAL_SYNC)
     1051                {
     1052                    /** @todo To fix assertion in tmR3TimerQueueRunVirtualSync:
     1053                     *              Figure a safe way of activating this timer while the queue is
     1054                     *              being run.
     1055                     *        (99.9% sure this that the assertion is caused by DevAPIC.cpp
     1056                     *        re-starting the timer in respons to a initial_count write.) */
     1057                }
     1058                /* fall thru */
    9251059            case TMTIMERSTATE_EXPIRED_DELIVER:
    926             case TMTIMERSTATE_STOPPED:
    9271060                if (tmTimerTryWithLink(pTimer, TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE, enmState))
    9281061                {
     
    10291162            break;
    10301163        }
     1164
     1165        /*
     1166         * Retry to gain locks.
     1167         */
     1168        if (!fOwnTMLock)
     1169        {
     1170            fOwnTMLock = RT_SUCCESS(tmTryLock(pVM));
     1171            if (    !fOwnTMLock
     1172                &&  enmClock == TMCLOCK_VIRTUAL_SYNC
     1173                &&  !fOwnVirtSyncLock)
     1174                fOwnVirtSyncLock = RT_SUCCESS(tmVirtualSyncTryLock(pVM));
     1175        }
     1176
    10311177    } /* for (;;) */
    10321178
     
    10341180     * Clean up and return.
    10351181     */
    1036     if (fOwnLock)
    1037     {
    1038         if (enmClock == TMCLOCK_VIRTUAL_SYNC)
    1039             tmVirtualSyncUnlock(pVM);
    1040         else
    1041             tmUnlock(pVM);
    1042     }
     1182    if (fOwnVirtSyncLock)
     1183        tmVirtualSyncUnlock(pVM);
     1184    if (fOwnTMLock)
     1185        tmUnlock(pVM);
     1186
     1187    if (    !fOwnTMLock
     1188        &&  !fOwnVirtSyncLock
     1189        &&  enmClock == TMCLOCK_VIRTUAL_SYNC)
     1190        STAM_COUNTER_INC(&pVM->tm.s.StatTimerSetRelativeRacyVirtSync);
    10431191
    10441192    STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
Note: See TracChangeset for help on using the changeset viewer.

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