VirtualBox

Changeset 80650 in vbox


Ignore:
Timestamp:
Sep 8, 2019 10:33:08 AM (5 years ago)
Author:
vboxsync
Message:

STAM: More by-prefix optimizations.

File:
1 edited

Legend:

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

    r80648 r80650  
    10001000
    10011001/**
    1002  * Finds the first sample descriptor for a given lookup range.
     1002 * Finds the last sample descriptor for a given lookup range.
    10031003 *
    10041004 * This is for pattern range lookups.
     
    11331133 *
    11341134 * @returns Pointer to the first descriptor in the range.
    1135  * @param   pRoot               The root node.
    1136  * @param   pchPrefix           The name prefix.
    1137  * @param   cchPrefix           The name prefix length (can be shorter than the
    1138  *                              actual string).
     1135 * @param   pRoot       The root node.
     1136 * @param   pchPrefix   The name prefix.
     1137 * @param   cchPrefix   The name prefix length (can be shorter than the
     1138 *                      actual string).
     1139 * @param   ppLastDesc  Where to store the address of the last descriptor.
    11391140 * @sa      stamR3LookupFindPatternDescRange
    11401141 */
    1141 static PSTAMDESC stamR3LookupFindFirstByPrefix(PSTAMLOOKUP pRoot, const char *pchPrefix, uint32_t cchPrefix)
    1142 {
     1142static PSTAMDESC stamR3LookupFindByPrefixRange(PSTAMLOOKUP pRoot, const char *pchPrefix, uint32_t cchPrefix,
     1143                                               PSTAMDESC *ppLastDesc)
     1144
     1145{
     1146    *ppLastDesc = NULL;
    11431147    Assert(!pRoot->pParent);
    1144 
    1145     /*
    1146      * All statistics starts with a slash.
    1147      */
    1148     while (   cchPrefix > 0
     1148    AssertReturn(cchPrefix > 0, NULL);
     1149
     1150    /*
     1151     * We start with a root slash.
     1152     */
     1153    if (!cchPrefix || *pchPrefix != '/')
     1154        return NULL;
     1155
     1156    /*
     1157     * Walk thru the prefix component by component, since that's how
     1158     * the lookup tree is organized.
     1159     */
     1160    while (   cchPrefix
    11491161           && *pchPrefix == '/'
    11501162           && pRoot->cDescsInTree > 0
     
    11571169        if (!pszEnd)
    11581170        {
    1159             /* We've narrowed it down to a sub-tree now. */
    1160             for (size_t i = 0; i < pRoot->cChildren; i++)
     1171            /*
     1172             * We've narrowed it down to a sub-tree now.  If we've no more prefix to work
     1173             * with now (e.g. '/Devices/'), the prefix matches all the children.  Otherwise,
     1174             * traverse the children to find the ones matching the prefix.
     1175             */
     1176            if (!cchPrefix)
    11611177            {
    1162                 PSTAMLOOKUP pCur = pRoot->papChildren[i];
    1163                 if (pCur->cch >= cchPrefix)
     1178                *ppLastDesc = stamR3LookupFindLastDescForRange(pRoot->papChildren[0], pRoot->papChildren[pRoot->cChildren - 1]);
     1179                return stamR3LookupFindFirstDescForRange(pRoot->papChildren[0], pRoot->papChildren[pRoot->cChildren - 1]);
     1180            }
     1181
     1182            size_t iEnd = pRoot->cChildren;
     1183            if (iEnd < 16)
     1184            {
     1185                /* Linear scan of the children: */
     1186                for (size_t i = 0; i < pRoot->cChildren; i++)
    11641187                {
    1165                     int iDiff = memcmp(pCur->szName, pchPrefix, cchPrefix);
    1166                     if (iDiff == 0)
    1167                         return stamR3LookupFindFirstDescForRange(pCur, pRoot->papChildren[pRoot->cChildren - 1]);
    1168                     if (iDiff > 0)
    1169                         break;
     1188                    PSTAMLOOKUP pCur = pRoot->papChildren[i];
     1189                    if (pCur->cch >= cchPrefix)
     1190                    {
     1191                        int iDiff = memcmp(pCur->szName, pchPrefix, cchPrefix);
     1192                        if (iDiff == 0)
     1193                        {
     1194                            size_t iLast = i;
     1195                            while (++iLast < pRoot->cChildren)
     1196                            {
     1197                                PSTAMLOOKUP pCur2 = pRoot->papChildren[iLast];
     1198                                if (   pCur2->cch < cchPrefix
     1199                                    || memcmp(pCur2->szName, pchPrefix, cchPrefix) != 0)
     1200                                    break;
     1201                            }
     1202                            iLast--;
     1203
     1204                            *ppLastDesc = stamR3LookupFindLastDescForRange(pCur, pRoot->papChildren[iLast]);
     1205                            return stamR3LookupFindFirstDescForRange(pCur, pRoot->papChildren[iLast]);
     1206                        }
     1207                        if (iDiff > 0)
     1208                            break;
     1209                    }
    11701210                }
    11711211            }
    1172             break;
    1173         }
    1174 
    1175         uint32_t    cchElement = pszEnd - pchPrefix;
    1176         PSTAMLOOKUP pChild = stamR3LookupFindChild(pRoot, pchPrefix, cchElement, NULL);
     1212            else
     1213            {
     1214                /* Binary search to find something matching the prefix, followed
     1215                   by a reverse scan to locate the first child: */
     1216                size_t iFirst = 0;
     1217                size_t i      = iEnd / 2;
     1218                for (;;)
     1219                {
     1220                    PSTAMLOOKUP pCur = pRoot->papChildren[i];
     1221                    int iDiff;
     1222                    if (pCur->cch >= cchPrefix)
     1223                        iDiff = memcmp(pCur->szName, pchPrefix, cchPrefix);
     1224                    else
     1225                    {
     1226                        iDiff = memcmp(pCur->szName, pchPrefix, pCur->cch);
     1227                        if (!iDiff)
     1228                            iDiff = 1;
     1229                    }
     1230                    if (iDiff > 0)
     1231                    {
     1232                        if (iFirst < i)
     1233                            iEnd = i;
     1234                        else
     1235                            return NULL;
     1236                    }
     1237                    else if (iDiff < 0)
     1238                    {
     1239                        i += 1;
     1240                        if (i < iEnd)
     1241                            iFirst = i;
     1242                        else
     1243                            return NULL;
     1244                    }
     1245                    else
     1246                    {
     1247                        /* Match.  Reverse scan to find the first. */
     1248                        iFirst = i;
     1249                        while (   iFirst > 0
     1250                               && (pCur = pRoot->papChildren[iFirst - 1])->cch >= cchPrefix
     1251                               && memcmp(pCur->szName, pchPrefix, cchPrefix) == 0)
     1252                            iFirst--;
     1253
     1254                        /* Forward scan to find the last.*/
     1255                        size_t iLast = i;
     1256                        while (++iLast < pRoot->cChildren)
     1257                        {
     1258                            pCur = pRoot->papChildren[iLast];
     1259                            if (   pCur->cch < cchPrefix
     1260                                || memcmp(pCur->szName, pchPrefix, cchPrefix) != 0)
     1261                                break;
     1262                        }
     1263                        iLast--;
     1264
     1265                        *ppLastDesc = stamR3LookupFindLastDescForRange(pRoot->papChildren[iFirst], pRoot->papChildren[iLast]);
     1266                        return stamR3LookupFindFirstDescForRange(pRoot->papChildren[iFirst], pRoot->papChildren[iLast]);
     1267                    }
     1268
     1269                    i = iFirst + (iEnd - iFirst) / 2;
     1270                }
     1271            }
     1272            break;
     1273        }
     1274
     1275        /* Find child matching the path component:  */
     1276        uint32_t    cchChild = pszEnd - pchPrefix;
     1277        PSTAMLOOKUP pChild   = stamR3LookupFindChild(pRoot, pchPrefix, cchChild, NULL);
    11771278        if (!pChild)
    11781279            break;
    11791280
    1180         /* Advance */
    1181         cchPrefix -= cchElement;
     1281        /* Advance: */
     1282        cchPrefix -= cchChild;
    11821283        pchPrefix  = pszEnd;
    11831284        pRoot      = pChild;
     
    17511852    STAM_LOCK_WR(pUVM);
    17521853
    1753     PSTAMDESC pCur = stamR3LookupFindFirstByPrefix(pUVM->stam.s.pRoot, pszPrefix, (uint32_t)cchPrefix);
    1754     while (pCur)
    1755     {
    1756         PSTAMDESC const pNext   = RTListNodeGetNext(&pCur->ListEntry, STAMDESC, ListEntry);
    1757         size_t const    cchName = strlen(pCur->pszName);
    1758         if (   cchName >= cchPrefix
    1759             && memcmp(pCur->pszName, pszPrefix, cchPrefix) == 0)
     1854    PSTAMDESC pLast;
     1855    PSTAMDESC pCur = stamR3LookupFindByPrefixRange(pUVM->stam.s.pRoot, pszPrefix, (uint32_t)cchPrefix, &pLast);
     1856    if (pCur)
     1857        for (;;)
     1858        {
     1859            PSTAMDESC const pNext = RTListNodeGetNext(&pCur->ListEntry, STAMDESC, ListEntry);
     1860            Assert(strncmp(pCur->pszName, pszPrefix, cchPrefix) == 0);
     1861
    17601862            rc = stamR3DestroyDesc(pCur);
    1761         else
    1762             break;
    1763 
    1764         /* advance. */
    1765         pCur = pNext;
    1766     }
     1863
     1864            /* advance. */
     1865            if (pCur == pLast)
     1866                break;
     1867            pCur = pNext;
     1868        }
    17671869
    17681870    STAM_UNLOCK_WR(pUVM);
     
    26612763
    26622764/**
    2663  * Checks if the string contains a pattern expression or not.
    2664  *
    2665  * @returns true / false.
    2666  * @param   pszPat              The potential pattern.
    2667  */
    2668 static bool stamR3IsPattern(const char *pszPat)
    2669 {
    2670     return strchr(pszPat, '*') != NULL
    2671         || strchr(pszPat, '?') != NULL;
    2672 }
    2673 
    2674 
    2675 /**
    26762765 * Match a name against an array of patterns.
    26772766 *
     
    27992888        STAM_LOCK_RD(pUVM);
    28002889#ifdef STAM_WITH_LOOKUP_TREE
    2801         if (!stamR3IsPattern(pszPat))
     2890        size_t const cchPat      = strlen(pszPat);
     2891        const char  *pszAsterisk = (const char *)memchr(pszPat, '*',  cchPat);
     2892        const char  *pszQuestion = (const char *)memchr(pszPat, '?',  cchPat);
     2893        if (!pszAsterisk && !pszQuestion)
    28022894        {
    28032895            pCur = stamR3LookupFindDesc(pUVM->stam.s.pRoot, pszPat);
     
    28092901            }
    28102902        }
     2903        /* Is this a prefix expression where we can use the lookup tree to
     2904           efficiently figure out the exact range? */
     2905        else if (   pszAsterisk == &pszPat[cchPat - 1]
     2906                 && pszPat[0] == '/'
     2907                 && !pszQuestion)
     2908        {
     2909            PSTAMDESC pLast;
     2910            pCur = stamR3LookupFindByPrefixRange(pUVM->stam.s.pRoot, pszPat, (uint32_t)(cchPat - 1), &pLast);
     2911            if (pCur)
     2912            {
     2913                for (;;)
     2914                {
     2915                    Assert(strncmp(pCur->pszName, pszPat, cchPat - 1) == 0);
     2916                    if (fUpdateRing0)
     2917                        stamR3Refresh(pUVM, pCur, &bmRefreshedGroups);
     2918                    rc = pfnCallback(pCur, pvArg);
     2919                    if (rc)
     2920                        break;
     2921                    if (pCur == pLast)
     2922                        break;
     2923                    pCur = RTListNodeGetNext(&pCur->ListEntry, STAMDESC, ListEntry);
     2924                }
     2925                Assert(pLast);
     2926            }
     2927            else
     2928                Assert(!pLast);
     2929        }
    28112930        else
    28122931        {
     2932            /* It's a more complicated pattern.  Find the approximate range
     2933               and scan it for matches. */
    28132934            PSTAMDESC pLast;
    28142935            pCur = stamR3LookupFindPatternDescRange(pUVM->stam.s.pRoot, &pUVM->stam.s.List, pszPat, &pLast);
     
    28332954            else
    28342955                Assert(!pLast);
    2835 
    28362956        }
    28372957#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