VirtualBox

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


Ignore:
Timestamp:
Jun 7, 2013 7:09:25 PM (12 years ago)
Author:
vboxsync
Message:

VMM: Optimize STAM enumeration. Multi pattern expressions are not optimized yet.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMR3/STAM.cpp

    r46443 r46447  
    748748            if (!iDiff)
    749749            {
    750                 *piChild = iChild;
     750                if (piChild)
     751                    *piChild = iChild;
    751752                return pParent->papChildren[iChild];
    752753            }
     
    758759                if (iFirst >= iEnd)
    759760                {
    760                     *piChild = iChild;
     761                    if (piChild)
     762                        *piChild = iChild;
    761763                    break;
    762764                }
     
    766768                if (iChild == iFirst)
    767769                {
    768                     *piChild = iChild ? iChild - 1 : 0;
     770                    if (piChild)
     771                        *piChild = iChild ? iChild - 1 : 0;
    769772                    break;
    770773                }
     
    786789        if (iDiff <= 0)
    787790        {
    788             *piChild = iChild;
     791            if (piChild)
     792                *piChild = iChild;
    789793            return !iDiff ? pParent->papChildren[iChild] : NULL;
    790794        }
    791795    }
    792     *piChild = 0;
     796    if (piChild)
     797        *piChild = 0;
    793798    return NULL;
    794799}
     
    796801
    797802/**
    798  * Find the next sample description node.
    799  *
    800  * This is for use with insertion in the big list.
    801  *
    802  * @returns Pointer to the next sample description. NULL if not found (i.e.
     803 * Find the next sample descriptor node.
     804 *
     805 * This is for use with insertion in the big list and pattern range lookups.
     806 *
     807 * @returns Pointer to the next sample descriptor. NULL if not found (i.e.
    803808 *          we're at the end of the list).
    804809 * @param   pLookup             The current node.
     
    835840        else
    836841        {
    837             /* One level up, resuming after the current. */
     842            /*
     843             * One level up, resuming after the current.
     844             */
    838845            iCur = pCur->iParent + 1;
    839846            pCur = pCur->pParent;
     
    842849        }
    843850    }
     851}
     852
     853
     854/**
     855 * Look up a sample descriptor by name.
     856 *
     857 * @returns Pointer to a sample descriptor.
     858 * @param   pRoot               The root node.
     859 * @param   pszName             The name to lookup.
     860 */
     861static PSTAMDESC stamR3LookupFindDesc(PSTAMLOOKUP pRoot, const char *pszName)
     862{
     863    Assert(!pRoot->pParent);
     864    while (*pszName++ == '/')
     865    {
     866        const char *pszEnd = strchr(pszName, '/');
     867        uint32_t    cch    = pszEnd ? pszEnd - pszName : strlen(pszName);
     868        PSTAMLOOKUP pChild = stamR3LookupFindChild(pRoot, pszName, cch, NULL);
     869        if (!pChild)
     870            break;
     871        if (!pszEnd)
     872            return pChild->pDesc;
     873        pszName = pszEnd;
     874        pRoot   = pChild;
     875    }
     876
     877    return NULL;
     878}
     879
     880
     881/**
     882 * Finds the first sample descriptor for a given lookup range.
     883 *
     884 * This is for pattern range lookups.
     885 *
     886 * @returns Pointer to the first descriptor.
     887 * @param   pFirst              The first node in the range.
     888 * @param   pLast               The last node in the range.
     889 */
     890static PSTAMDESC stamR3LookupFindFirstDescForRange(PSTAMLOOKUP pFirst, PSTAMLOOKUP pLast)
     891{
     892    if (pFirst->pDesc)
     893        return pFirst->pDesc;
     894
     895    PSTAMLOOKUP pCur = pFirst;
     896    uint32_t    iCur = 0;
     897    for (;;)
     898    {
     899        uint32_t cChildren = pCur->cChildren;
     900        if (iCur < pCur->cChildren)
     901        {
     902            /*
     903             * Check all children.
     904             */
     905            PSTAMLOOKUP *papChildren = pCur->papChildren;
     906            do
     907            {
     908                PSTAMLOOKUP pChild = pCur->papChildren[iCur];
     909                if (pChild->pDesc)
     910                    return pChild->pDesc;
     911                if (pChild->cChildren > 0)
     912                {
     913                    /* One level down. */
     914                    iCur = 0;
     915                    pCur = pChild;
     916                    break;
     917                }
     918                if (pChild == pLast)
     919                    return NULL;
     920            } while (++iCur < cChildren);
     921        }
     922        else
     923        {
     924            /*
     925             * One level up, checking current and its 'older' sibilings.
     926             */
     927            if (pCur == pLast)
     928                return NULL;
     929            iCur = pCur->iParent + 1;
     930            pCur = pCur->pParent;
     931            if (!pCur)
     932                break;
     933        }
     934    }
     935
     936    return NULL;
     937}
     938
     939
     940/**
     941 * Finds the first sample descriptor for a given lookup range.
     942 *
     943 * This is for pattern range lookups.
     944 *
     945 * @returns Pointer to the first descriptor.
     946 * @param   pFirst              The first node in the range.
     947 * @param   pLast               The last node in the range.
     948 */
     949static PSTAMDESC stamR3LookupFindLastDescForRange(PSTAMLOOKUP pFirst, PSTAMLOOKUP pLast)
     950{
     951    PSTAMLOOKUP pCur = pLast;
     952    uint32_t    iCur = pCur->cChildren - 1;
     953    for (;;)
     954    {
     955        if (iCur < pCur->cChildren)
     956        {
     957            /*
     958             * Check children backwards, depth first.
     959             */
     960            PSTAMLOOKUP *papChildren = pCur->papChildren;
     961            do
     962            {
     963                PSTAMLOOKUP pChild = pCur->papChildren[iCur];
     964                if (pChild->cChildren > 0)
     965                {
     966                    /* One level down. */
     967                    iCur = pChild->cChildren - 1;
     968                    pCur = pChild;
     969                    break;
     970                }
     971
     972                if (pChild->pDesc)
     973                    return pChild->pDesc;
     974                if (pChild == pFirst)
     975                    return NULL;
     976            } while (iCur-- > 0); /* (underflow handled above) */
     977        }
     978        else
     979        {
     980            /*
     981             * One level up, checking current and its 'older' sibilings.
     982             */
     983            if (pCur->pDesc)
     984                return pCur->pDesc;
     985            if (pCur == pFirst)
     986                return NULL;
     987            iCur = pCur->iParent - 1; /* (underflow handled above) */
     988            pCur = pCur->pParent;
     989            if (!pCur)
     990                break;
     991        }
     992    }
     993
     994    return NULL;
     995}
     996
     997
     998/**
     999 * Look up the first and last descriptors for a (single) pattern expression.
     1000 *
     1001 * This is used to optimize pattern enumerations and doesn't have to return 100%
     1002 * accurate results if that costs too much.
     1003 *
     1004 * @returns Pointer to the first descriptor in the range.
     1005 * @param   pRoot               The root node.
     1006 * @param   pList               The descriptor list anchor.
     1007 * @param   pszPat              The name patter to lookup.
     1008 * @param   ppLastDesc          Where to store the address of the last
     1009 *                              descriptor (approximate).
     1010 */
     1011static PSTAMDESC stamR3LookupFindPatternDescRange(PSTAMLOOKUP pRoot, PRTLISTANCHOR pList, const char *pszPat,
     1012                                                  PSTAMDESC *ppLastDesc)
     1013{
     1014    Assert(!pRoot->pParent);
     1015
     1016    /*
     1017     * If there is an early enough wildcard, the whole list needs to be searched.
     1018     */
     1019    if (   pszPat[0] == '*' || pszPat[0] == '?'
     1020        || pszPat[1] == '*' || pszPat[1] == '?')
     1021    {
     1022        *ppLastDesc = RTListGetLast(pList, STAMDESC, ListEntry);
     1023        return RTListGetFirst(pList, STAMDESC, ListEntry);
     1024    }
     1025
     1026    /*
     1027     * All statistics starts with a slash.
     1028     */
     1029    while (   *pszPat++ == '/'
     1030           && pRoot->cDescsInTree > 0
     1031           && pRoot->cChildren    > 0)
     1032    {
     1033        const char *pszEnd = strchr(pszPat, '/');
     1034        uint32_t    cch    = pszEnd ? pszEnd - pszPat : strlen(pszPat);
     1035        if (!cch)
     1036            break;
     1037
     1038        const char *pszPat1 = (const char *)memchr(pszPat, '*', cch);
     1039        const char *pszPat2 = (const char *)memchr(pszPat, '?', cch);
     1040        if (pszPat1 || pszPat2)
     1041        {
     1042            /* We've narrowed it down to a sub-tree now. */
     1043            PSTAMLOOKUP pFirst = pRoot->papChildren[0];
     1044            PSTAMLOOKUP pLast  = pRoot->papChildren[pRoot->cChildren - 1];
     1045            /** @todo narrow the range further if both pszPat1/2 != pszPat. */
     1046
     1047            *ppLastDesc = stamR3LookupFindLastDescForRange(pFirst, pLast);
     1048            return stamR3LookupFindFirstDescForRange(pFirst, pLast);
     1049        }
     1050
     1051        PSTAMLOOKUP pChild = stamR3LookupFindChild(pRoot, pszPat, cch, NULL);
     1052        if (!pChild)
     1053            break;
     1054
     1055        /* Advance */
     1056        if (!pszEnd)
     1057            return *ppLastDesc = pChild->pDesc;
     1058        pszPat = pszEnd;
     1059        pRoot  = pChild;
     1060    }
     1061
     1062    /* No match. */
     1063    *ppLastDesc = NULL;
     1064    return NULL;
    8441065}
    8451066
     
    20362257
    20372258/**
     2259 * Checks if the string contains a pattern expression or not.
     2260 *
     2261 * @returns true / false.
     2262 * @param   pszPat              The potential pattern.
     2263 */
     2264static bool stamR3IsPattern(const char *pszPat)
     2265{
     2266    return strchr(pszPat, '*') != NULL
     2267        || strchr(pszPat, '?') != NULL;
     2268}
     2269
     2270
     2271/**
    20382272 * Match a name against an array of patterns.
    20392273 *
     
    21332367{
    21342368    int rc = VINF_SUCCESS;
    2135 
    2136     /*
    2137      * All
     2369    PSTAMDESC pCur;
     2370
     2371    /*
     2372     * All.
    21382373     */
    21392374    if (!pszPat || !*pszPat || !strcmp(pszPat, "*"))
     
    21432378
    21442379        STAM_LOCK_RD(pUVM);
    2145         PSTAMDESC pCur;
    21462380        RTListForEach(&pUVM->stam.s.List, pCur, STAMDESC, ListEntry)
    21472381        {
     
    21622396
    21632397        STAM_LOCK_RD(pUVM);
    2164         /** @todo This needs to be optimized since the GUI is using this path for the VM info dialog.
    2165          * Note that it's doing exact matching. Organizing the samples in a tree would speed up thing
    2166          * no end (at least for debug and profile builds). */
    2167         PSTAMDESC pCur;
     2398#ifdef STAM_WITH_LOOKUP_TREE
     2399        if (!stamR3IsPattern(pszPat))
     2400        {
     2401            pCur = stamR3LookupFindDesc(pUVM->stam.s.pRoot, pszPat);
     2402            if (pCur)
     2403                rc = pfnCallback(pCur, pvArg);
     2404        }
     2405        else
     2406        {
     2407            PSTAMDESC pLast;
     2408            pCur = stamR3LookupFindPatternDescRange(pUVM->stam.s.pRoot, &pUVM->stam.s.List, pszPat, &pLast);
     2409            if (pCur)
     2410            {
     2411                for (;;)
     2412                {
     2413                    if (RTStrSimplePatternMatch(pszPat, pCur->pszName))
     2414                    {
     2415                        rc = pfnCallback(pCur, pvArg);
     2416                        if (rc)
     2417                            break;
     2418                    }
     2419                    if (pCur == pLast)
     2420                        break;
     2421                    pCur = RTListNodeGetNext(&pCur->ListEntry, STAMDESC, ListEntry);
     2422                }
     2423                Assert(pLast);
     2424            }
     2425            else
     2426                Assert(!pLast);
     2427
     2428        }
     2429#else
    21682430        RTListForEach(&pUVM->stam.s.List, pCur, STAMDESC, ListEntry)
    21692431        {
     
    21752437            }
    21762438        }
     2439#endif
    21772440        STAM_UNLOCK_RD(pUVM);
    21782441    }
     
    22002463        STAM_LOCK_RD(pUVM);
    22012464        unsigned iExpression = 0;
    2202         PSTAMDESC pCur;
    22032465        RTListForEach(&pUVM->stam.s.List, pCur, STAMDESC, ListEntry)
    22042466        {
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