- Timestamp:
- Aug 17, 2024 12:12:41 AM (5 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/IEMR3.cpp
r105713 r105716 73 73 #if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8) 74 74 static FNDBGFINFOARGVINT iemR3InfoTb; 75 static FNDBGFINFOARGVINT iemR3InfoTbTop; 75 76 #endif 76 77 #ifdef VBOX_WITH_DEBUGGER … … 1031 1032 #endif 1032 1033 #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); 1034 1037 #endif 1035 1038 #ifdef VBOX_WITH_DEBUGGER … … 1773 1776 1774 1777 #if defined(VBOX_WITH_IEM_RECOMPILER) && !defined(VBOX_VMM_TARGET_ARMV8) 1778 1775 1779 /** 1776 1780 * @callback_method_impl{FNDBGFINFOARGVINT, tb} … … 1945 1949 } 1946 1950 } 1951 1952 1953 /** 1954 * @callback_method_impl{FNDBGFINFOARGVINT, tbtop} 1955 */ 1956 static 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 1947 2229 #endif /* VBOX_WITH_IEM_RECOMPILER && !VBOX_VMM_TARGET_ARMV8 */ 1948 2230
Note:
See TracChangeset
for help on using the changeset viewer.