VirtualBox

Changeset 105716 in vbox for trunk


Ignore:
Timestamp:
Aug 17, 2024 12:12:41 AM (5 months ago)
Author:
vboxsync
Message:

VMM/IEM: Added a 'tbtop' info item for getting details on the most used TBs. bugref:10720

File:
1 edited

Legend:

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

    r105713 r105716  
    7373#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
    7474static FNDBGFINFOARGVINT iemR3InfoTb;
     75static FNDBGFINFOARGVINT iemR3InfoTbTop;
    7576#endif
    7677#ifdef VBOX_WITH_DEBUGGER
     
    10311032#endif
    10321033#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
    1033     DBGFR3InfoRegisterInternalArgv(pVM, "tb",   "IEM translation block", iemR3InfoTb, DBGFINFO_FLAGS_RUN_ON_EMT);
     1034    DBGFR3InfoRegisterInternalArgv(pVM, "tb",    "IEM translation block", iemR3InfoTb, DBGFINFO_FLAGS_RUN_ON_EMT);
     1035    DBGFR3InfoRegisterInternalArgv(pVM, "tbtop", "IEM translation blocks most used or most recently used",
     1036                                   iemR3InfoTbTop, DBGFINFO_FLAGS_RUN_ON_EMT);
    10341037#endif
    10351038#ifdef VBOX_WITH_DEBUGGER
     
    17731776
    17741777#if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8)
     1778
    17751779/**
    17761780 * @callback_method_impl{FNDBGFINFOARGVINT, tb}
     
    19451949    }
    19461950}
     1951
     1952
     1953/**
     1954 * @callback_method_impl{FNDBGFINFOARGVINT, tbtop}
     1955 */
     1956static DECLCALLBACK(void) iemR3InfoTbTop(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)
     1957{
     1958    /*
     1959     * Parse arguments.
     1960     */
     1961    static RTGETOPTDEF const s_aOptions[] =
     1962    {
     1963        { "--cpu",                  'c', RTGETOPT_REQ_UINT32   },
     1964        { "--vcpu",                 'c', RTGETOPT_REQ_UINT32   },
     1965        { "--dis",                  'd', RTGETOPT_REQ_NOTHING  },
     1966        { "--disas",                'd', RTGETOPT_REQ_NOTHING  },
     1967        { "--disasm",               'd', RTGETOPT_REQ_NOTHING  },
     1968        { "--disassemble",          'd', RTGETOPT_REQ_NOTHING  },
     1969        { "--no-dis",               'D', RTGETOPT_REQ_NOTHING  },
     1970        { "--no-disas",             'D', RTGETOPT_REQ_NOTHING  },
     1971        { "--no-disasm",            'D', RTGETOPT_REQ_NOTHING  },
     1972        { "--no-disassemble",       'D', RTGETOPT_REQ_NOTHING  },
     1973        { "--most-freq",            'f', RTGETOPT_REQ_NOTHING  },
     1974        { "--most-frequent",        'f', RTGETOPT_REQ_NOTHING  },
     1975        { "--most-frequently",      'f', RTGETOPT_REQ_NOTHING  },
     1976        { "--most-frequently-used", 'f', RTGETOPT_REQ_NOTHING  },
     1977        { "--most-recent",          'r', RTGETOPT_REQ_NOTHING  },
     1978        { "--most-recently",        'r', RTGETOPT_REQ_NOTHING  },
     1979        { "--most-recently-used",   'r', RTGETOPT_REQ_NOTHING  },
     1980        { "--count",                'n', RTGETOPT_REQ_UINT32   },
     1981    };
     1982
     1983    RTGETOPTSTATE State;
     1984    int rc = RTGetOptInit(&State, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 0 /*iFirst*/, 0 /*fFlags*/);
     1985    AssertRCReturnVoid(rc);
     1986
     1987    PVMCPU const    pVCpuThis    = VMMGetCpu(pVM);
     1988    PVMCPU          pVCpu        = pVCpuThis ? pVCpuThis : VMMGetCpuById(pVM, 0);
     1989    enum { kTbTop_MostFrequentlyUsed, kTbTop_MostRececentlyUsed }
     1990                    enmTop       = kTbTop_MostFrequentlyUsed;
     1991    bool            fDisassemble = false;
     1992    uint32_t const  cTopDefault  = 64;
     1993    uint32_t const  cTopMin      = 1;
     1994    uint32_t const  cTopMax      = 1024;
     1995    uint32_t        cTop         = cTopDefault;
     1996
     1997    RTGETOPTUNION ValueUnion;
     1998    while ((rc = RTGetOpt(&State, &ValueUnion)) != 0)
     1999    {
     2000        switch (rc)
     2001        {
     2002            case 'c':
     2003                if (ValueUnion.u32 >= pVM->cCpus)
     2004                    pHlp->pfnPrintf(pHlp, "error: Invalid CPU ID: %u\n", ValueUnion.u32);
     2005                else if (!pVCpu || pVCpu->idCpu != ValueUnion.u32)
     2006                    pVCpu = VMMGetCpuById(pVM, ValueUnion.u32);
     2007                break;
     2008
     2009            case 'd':
     2010                fDisassemble = true;
     2011                break;
     2012
     2013            case 'D':
     2014                fDisassemble = true;
     2015                break;
     2016
     2017            case 'f':
     2018                enmTop = kTbTop_MostFrequentlyUsed;
     2019                break;
     2020
     2021            case 'r':
     2022                enmTop = kTbTop_MostRececentlyUsed;
     2023                break;
     2024
     2025            case VINF_GETOPT_NOT_OPTION:
     2026                rc = RTStrToUInt32Full(ValueUnion.psz, 0, &cTop);
     2027                if (RT_FAILURE(rc))
     2028                {
     2029                    pHlp->pfnPrintf(pHlp, "error: failed to convert '%s' to a number: %Rrc\n", ValueUnion.psz, rc);
     2030                    return;
     2031                }
     2032                ValueUnion.u32 = cTop;
     2033                RT_FALL_THROUGH();
     2034            case 'n':
     2035                if (!ValueUnion.u32)
     2036                    cTop = cTopDefault;
     2037                else
     2038                {
     2039                    cTop = RT_MAX(RT_MIN(ValueUnion.u32, cTopMax), cTopMin);
     2040                    if (cTop != ValueUnion.u32)
     2041                        pHlp->pfnPrintf(pHlp, "warning: adjusted %u to %u (valid range: [%u..%u], 0 for default (%d))",
     2042                                        ValueUnion.u32, cTop, cTopMin, cTopMax, cTopDefault);
     2043                }
     2044                break;
     2045
     2046            case 'h':
     2047                pHlp->pfnPrintf(pHlp,
     2048                                "Usage: info tbtop [options]\n"
     2049                                "\n"
     2050                                "Options:\n"
     2051                                "  -c<n>, --cpu=<n>, --vcpu=<n>\n"
     2052                                "    Selects the CPU which TBs we're looking at. Default: Caller / 0\n"
     2053                                "  -d, --dis[as[m]], --disassemble\n"
     2054                                "    Show full TB disassembly.\n"
     2055                                "  -D, --no-dis[as[m]], --no-disassemble\n"
     2056                                "    Do not show TB diassembly. The default.\n"
     2057                                "  -f, --most-freq[ent[ly[-used]]]\n"
     2058                                "    Shows the most frequently used TBs (IEMTB::cUsed). The default.\n"
     2059                                "  -r, --most-recent[ly[-used]]\n"
     2060                                "    Shows the most recently used TBs (IEMTB::msLastUsed).\n"
     2061                                "  -n<num>, --count=<num>\n"
     2062                                "    The number of TBs to display. Default: %u\n"
     2063                                "    This is also what non-option arguments will be taken as.\n"
     2064                                , cTopDefault);
     2065                return;
     2066
     2067            default:
     2068                pHlp->pfnGetOptError(pHlp, rc, &ValueUnion, &State);
     2069                return;
     2070        }
     2071    }
     2072
     2073    /* Currently, only do work on the same EMT. */
     2074    if (pVCpu != pVCpuThis)
     2075    {
     2076        pHlp->pfnPrintf(pHlp, "TODO: Cross EMT calling not supported yet: targeting %u, caller on %d\n",
     2077                        pVCpu->idCpu, pVCpuThis ? (int)pVCpuThis->idCpu : -1);
     2078        return;
     2079    }
     2080
     2081    /*
     2082     * Collect the data by scanning the TB allocation map.
     2083     */
     2084    struct IEMTBTOPENTRY
     2085    {
     2086        /** Pointer to the translation block. */
     2087        PCIEMTB     pTb;
     2088        /** The sorting key. */
     2089        uint64_t    uSortKey;
     2090    }               aTop[cTopMax] = { { NULL, 0 }, };
     2091    uint32_t        cValid        = 0;
     2092    PIEMTBALLOCATOR pTbAllocator  = pVCpu->iem.s.pTbAllocatorR3;
     2093    if (pTbAllocator)
     2094    {
     2095        uint32_t const cTbsPerChunk = pTbAllocator->cTbsPerChunk;
     2096        for (uint32_t iChunk = 0; iChunk < pTbAllocator->cAllocatedChunks; iChunk++)
     2097        {
     2098            for (uint32_t iTb = 0; iTb < cTbsPerChunk; iTb++)
     2099            {
     2100                PCIEMTB const pTb = &pTbAllocator->aChunks[iChunk].paTbs[iTb];
     2101                AssertContinue(pTb);
     2102                if (pTb->fFlags & IEMTB_F_TYPE_MASK)
     2103                {
     2104                    /* Extract and compose the sort key. */
     2105                    uint64_t const uSortKey = enmTop == kTbTop_MostFrequentlyUsed
     2106                                            ? RT_MAKE_U64(pTb->msLastUsed, pTb->cUsed)
     2107                                            : RT_MAKE_U64(pTb->cUsed, pTb->msLastUsed);
     2108
     2109                    /*
     2110                     * Discard the key if it's smaller than the smallest in the table when it is full.
     2111                     */
     2112                    if (   cValid   >= cTop
     2113                        && uSortKey <= aTop[cTop - 1].uSortKey)
     2114                    { /* discard it */ }
     2115                    else
     2116                    {
     2117                        /*
     2118                         * Do binary search to find the insert location
     2119                         */
     2120                        uint32_t idx;
     2121                        if (cValid > 0)
     2122                        {
     2123                            uint32_t idxEnd   = cValid;
     2124                            uint32_t idxStart = 0;
     2125                            idx = cValid / 2;
     2126                            for (;;)
     2127                            {
     2128                                if (uSortKey > aTop[idx].uSortKey)
     2129                                {
     2130                                    if (idx > idxStart)
     2131                                        idxEnd = idx;
     2132                                    else
     2133                                        break;
     2134                                }
     2135                                else if (uSortKey < aTop[idx].uSortKey)
     2136                                {
     2137                                    idx += 1;
     2138                                    if (idx < idxEnd)
     2139                                        idxStart = idx;
     2140                                    else
     2141                                        break;
     2142                                }
     2143                                else
     2144                                {
     2145                                    do
     2146                                        idx++;
     2147                                    while (idx < cValid && uSortKey == aTop[idx].uSortKey);
     2148                                    break;
     2149                                }
     2150                                idx = idxStart + (idxEnd - idxStart) / 2;
     2151                            }
     2152                            AssertContinue(idx < RT_ELEMENTS(aTop));
     2153
     2154                            /*
     2155                             * Shift entries as needed.
     2156                             */
     2157                            if (cValid >= cTop)
     2158                            {
     2159                                if (idx != cTop - 1U)
     2160                                    memmove(&aTop[idx + 1], &aTop[idx], (cTop - idx - 1) * sizeof(aTop[0]));
     2161                            }
     2162                            else
     2163                            {
     2164                                if (idx != cValid)
     2165                                    memmove(&aTop[idx + 1], &aTop[idx], (cValid - idx) * sizeof(aTop[0]));
     2166                                cValid++;
     2167                            }
     2168                        }
     2169                        else
     2170                        {
     2171                            /* Special case: The first insertion. */
     2172                            cValid = 1;
     2173                            idx    = 0;
     2174                        }
     2175
     2176                        /*
     2177                         * Fill in the new entry.
     2178                         */
     2179                        aTop[idx].uSortKey = uSortKey;
     2180                        aTop[idx].pTb      = pTb;
     2181                    }
     2182                }
     2183            }
     2184        }
     2185    }
     2186
     2187    /*
     2188     * Display the result.
     2189     */
     2190    if (cTop > cValid)
     2191        cTop = cValid;
     2192    pHlp->pfnPrintf(pHlp, "Displaying the top %u TBs for CPU #%u ordered by %s:\n",
     2193                    cTop, pVCpu->idCpu, enmTop == kTbTop_MostFrequentlyUsed ? "cUsed" : "msLastUsed");
     2194    if (fDisassemble)
     2195        pHlp->pfnPrintf(pHlp, "================================================================================\n");
     2196
     2197    for (uint32_t idx = 0; idx < cTop; idx++)
     2198    {
     2199        if (fDisassemble && idx)
     2200            pHlp->pfnPrintf(pHlp, "\n------------------------------- %u -------------------------------\n", idx);
     2201
     2202        PCIEMTB pTb = aTop[idx].pTb;
     2203        switch (pTb->fFlags & IEMTB_F_TYPE_MASK)
     2204        {
     2205# ifdef VBOX_WITH_IEM_NATIVE_RECOMPILER
     2206            case IEMTB_F_TYPE_NATIVE:
     2207                pHlp->pfnPrintf(pHlp, "PC=%RGp cUsed=%u msLastUsed=%u fFlags=%#010x - native\n",
     2208                                pTb->GCPhysPc, pTb->cUsed, pTb->msLastUsed, pTb->fFlags);
     2209                if (fDisassemble)
     2210                    iemNativeDisassembleTb(pVCpu, pTb, pHlp);
     2211                break;
     2212# endif
     2213
     2214            case IEMTB_F_TYPE_THREADED:
     2215                pHlp->pfnPrintf(pHlp, "PC=%RGp cUsed=%u msLastUsed=%u fFlags=%#010x - threaded\n",
     2216                                pTb->GCPhysPc, pTb->cUsed, pTb->msLastUsed, pTb->fFlags);
     2217                if (fDisassemble)
     2218                    iemThreadedDisassembleTb(pTb, pHlp);
     2219                break;
     2220
     2221            default:
     2222                pHlp->pfnPrintf(pHlp, "PC=%RGp cUsed=%u msLastUsed=%u fFlags=%#010x - ???\n",
     2223                                pTb->GCPhysPc, pTb->cUsed, pTb->msLastUsed, pTb->fFlags);
     2224                break;
     2225        }
     2226    }
     2227}
     2228
    19472229#endif /* VBOX_WITH_IEM_RECOMPILER && !VBOX_VMM_TARGET_ARMV8 */
    19482230
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