15ffd83dbSDimitry Andric //===-- Statistics.cpp - Debug Info quality metrics -----------------------===// 25ffd83dbSDimitry Andric // 35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65ffd83dbSDimitry Andric // 75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 85ffd83dbSDimitry Andric 95ffd83dbSDimitry Andric #include "llvm-dwarfdump.h" 100b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 110b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 120b57cec5SDimitry Andric #include "llvm/ADT/StringSet.h" 130b57cec5SDimitry Andric #include "llvm/DebugInfo/DIContext.h" 140b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFContext.h" 150b57cec5SDimitry Andric #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" 160b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h" 178bcb0991SDimitry Andric #include "llvm/Support/JSON.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #define DEBUG_TYPE "dwarfdump" 200b57cec5SDimitry Andric using namespace llvm; 215ffd83dbSDimitry Andric using namespace llvm::dwarfdump; 225ffd83dbSDimitry Andric using namespace llvm::object; 230b57cec5SDimitry Andric 248bcb0991SDimitry Andric /// This represents the number of categories of debug location coverage being 258bcb0991SDimitry Andric /// calculated. The first category is the number of variables with 0% location 268bcb0991SDimitry Andric /// coverage, but the last category is the number of variables with 100% 278bcb0991SDimitry Andric /// location coverage. 288bcb0991SDimitry Andric constexpr int NumOfCoverageCategories = 12; 298bcb0991SDimitry Andric 305ffd83dbSDimitry Andric namespace { 310b57cec5SDimitry Andric /// Holds statistics for one function (or other entity that has a PC range and 320b57cec5SDimitry Andric /// contains variables, such as a compile unit). 330b57cec5SDimitry Andric struct PerFunctionStats { 340b57cec5SDimitry Andric /// Number of inlined instances of this function. 350b57cec5SDimitry Andric unsigned NumFnInlined = 0; 365ffd83dbSDimitry Andric /// Number of out-of-line instances of this function. 375ffd83dbSDimitry Andric unsigned NumFnOutOfLine = 0; 380b57cec5SDimitry Andric /// Number of inlined instances that have abstract origins. 390b57cec5SDimitry Andric unsigned NumAbstractOrigins = 0; 400b57cec5SDimitry Andric /// Number of variables and parameters with location across all inlined 410b57cec5SDimitry Andric /// instances. 420b57cec5SDimitry Andric unsigned TotalVarWithLoc = 0; 430b57cec5SDimitry Andric /// Number of constants with location across all inlined instances. 440b57cec5SDimitry Andric unsigned ConstantMembers = 0; 455ffd83dbSDimitry Andric /// Number of arificial variables, parameters or members across all instances. 465ffd83dbSDimitry Andric unsigned NumArtificial = 0; 470b57cec5SDimitry Andric /// List of all Variables and parameters in this function. 480b57cec5SDimitry Andric StringSet<> VarsInFunction; 490b57cec5SDimitry Andric /// Compile units also cover a PC range, but have this flag set to false. 500b57cec5SDimitry Andric bool IsFunction = false; 510b57cec5SDimitry Andric /// Function has source location information. 520b57cec5SDimitry Andric bool HasSourceLocation = false; 530b57cec5SDimitry Andric /// Number of function parameters. 540b57cec5SDimitry Andric unsigned NumParams = 0; 550b57cec5SDimitry Andric /// Number of function parameters with source location. 560b57cec5SDimitry Andric unsigned NumParamSourceLocations = 0; 570b57cec5SDimitry Andric /// Number of function parameters with type. 580b57cec5SDimitry Andric unsigned NumParamTypes = 0; 590b57cec5SDimitry Andric /// Number of function parameters with a DW_AT_location. 600b57cec5SDimitry Andric unsigned NumParamLocations = 0; 615ffd83dbSDimitry Andric /// Number of local variables. 625ffd83dbSDimitry Andric unsigned NumLocalVars = 0; 635ffd83dbSDimitry Andric /// Number of local variables with source location. 645ffd83dbSDimitry Andric unsigned NumLocalVarSourceLocations = 0; 655ffd83dbSDimitry Andric /// Number of local variables with type. 665ffd83dbSDimitry Andric unsigned NumLocalVarTypes = 0; 675ffd83dbSDimitry Andric /// Number of local variables with DW_AT_location. 685ffd83dbSDimitry Andric unsigned NumLocalVarLocations = 0; 690b57cec5SDimitry Andric }; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric /// Holds accumulated global statistics about DIEs. 720b57cec5SDimitry Andric struct GlobalStats { 730b57cec5SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations. 74*e8d8bef9SDimitry Andric unsigned TotalBytesCovered = 0; 75*e8d8bef9SDimitry Andric /// Total number of parent DIE PC range bytes covered by DW_AT_Locations. 760b57cec5SDimitry Andric unsigned ScopeBytesCovered = 0; 77480093f4SDimitry Andric /// Total number of PC range bytes in each variable's enclosing scope. 78480093f4SDimitry Andric unsigned ScopeBytes = 0; 798bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations with 808bcb0991SDimitry Andric /// the debug entry values (DW_OP_entry_value). 818bcb0991SDimitry Andric unsigned ScopeEntryValueBytesCovered = 0; 828bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations of 838bcb0991SDimitry Andric /// formal parameters. 848bcb0991SDimitry Andric unsigned ParamScopeBytesCovered = 0; 855ffd83dbSDimitry Andric /// Total number of PC range bytes in each parameter's enclosing scope. 86480093f4SDimitry Andric unsigned ParamScopeBytes = 0; 878bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations with 888bcb0991SDimitry Andric /// the debug entry values (DW_OP_entry_value) (only for parameters). 898bcb0991SDimitry Andric unsigned ParamScopeEntryValueBytesCovered = 0; 908bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations (only for local 918bcb0991SDimitry Andric /// variables). 925ffd83dbSDimitry Andric unsigned LocalVarScopeBytesCovered = 0; 935ffd83dbSDimitry Andric /// Total number of PC range bytes in each local variable's enclosing scope. 945ffd83dbSDimitry Andric unsigned LocalVarScopeBytes = 0; 958bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations with 968bcb0991SDimitry Andric /// the debug entry values (DW_OP_entry_value) (only for local variables). 975ffd83dbSDimitry Andric unsigned LocalVarScopeEntryValueBytesCovered = 0; 988bcb0991SDimitry Andric /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line). 990b57cec5SDimitry Andric unsigned CallSiteEntries = 0; 1008bcb0991SDimitry Andric /// Total number of call site DIEs (DW_TAG_call_site). 1018bcb0991SDimitry Andric unsigned CallSiteDIEs = 0; 1028bcb0991SDimitry Andric /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter). 1038bcb0991SDimitry Andric unsigned CallSiteParamDIEs = 0; 1040b57cec5SDimitry Andric /// Total byte size of concrete functions. This byte size includes 1050b57cec5SDimitry Andric /// inline functions contained in the concrete functions. 1068bcb0991SDimitry Andric unsigned FunctionSize = 0; 1070b57cec5SDimitry Andric /// Total byte size of inlined functions. This is the total number of bytes 1080b57cec5SDimitry Andric /// for the top inline functions within concrete functions. This can help 1090b57cec5SDimitry Andric /// tune the inline settings when compiling to match user expectations. 1108bcb0991SDimitry Andric unsigned InlineFunctionSize = 0; 1118bcb0991SDimitry Andric }; 1128bcb0991SDimitry Andric 1138bcb0991SDimitry Andric /// Holds accumulated debug location statistics about local variables and 1148bcb0991SDimitry Andric /// formal parameters. 1158bcb0991SDimitry Andric struct LocationStats { 1168bcb0991SDimitry Andric /// Map the scope coverage decile to the number of variables in the decile. 1178bcb0991SDimitry Andric /// The first element of the array (at the index zero) represents the number 1188bcb0991SDimitry Andric /// of variables with the no debug location at all, but the last element 1198bcb0991SDimitry Andric /// in the vector represents the number of fully covered variables within 1208bcb0991SDimitry Andric /// its scope. 1218bcb0991SDimitry Andric std::vector<unsigned> VarParamLocStats{ 1228bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1238bcb0991SDimitry Andric /// Map non debug entry values coverage. 1248bcb0991SDimitry Andric std::vector<unsigned> VarParamNonEntryValLocStats{ 1258bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1268bcb0991SDimitry Andric /// The debug location statistics for formal parameters. 1278bcb0991SDimitry Andric std::vector<unsigned> ParamLocStats{ 1288bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1298bcb0991SDimitry Andric /// Map non debug entry values coverage for formal parameters. 1308bcb0991SDimitry Andric std::vector<unsigned> ParamNonEntryValLocStats{ 1318bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1328bcb0991SDimitry Andric /// The debug location statistics for local variables. 1335ffd83dbSDimitry Andric std::vector<unsigned> LocalVarLocStats{ 1348bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1358bcb0991SDimitry Andric /// Map non debug entry values coverage for local variables. 1365ffd83dbSDimitry Andric std::vector<unsigned> LocalVarNonEntryValLocStats{ 1378bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1388bcb0991SDimitry Andric /// Total number of local variables and function parameters processed. 1398bcb0991SDimitry Andric unsigned NumVarParam = 0; 1408bcb0991SDimitry Andric /// Total number of formal parameters processed. 1418bcb0991SDimitry Andric unsigned NumParam = 0; 1428bcb0991SDimitry Andric /// Total number of local variables processed. 1438bcb0991SDimitry Andric unsigned NumVar = 0; 1440b57cec5SDimitry Andric }; 1455ffd83dbSDimitry Andric } // namespace 1460b57cec5SDimitry Andric 1478bcb0991SDimitry Andric /// Collect debug location statistics for one DIE. 148*e8d8bef9SDimitry Andric static void collectLocStats(uint64_t ScopeBytesCovered, uint64_t BytesInScope, 1498bcb0991SDimitry Andric std::vector<unsigned> &VarParamLocStats, 1508bcb0991SDimitry Andric std::vector<unsigned> &ParamLocStats, 1515ffd83dbSDimitry Andric std::vector<unsigned> &LocalVarLocStats, 1525ffd83dbSDimitry Andric bool IsParam, bool IsLocalVar) { 153*e8d8bef9SDimitry Andric auto getCoverageBucket = [ScopeBytesCovered, BytesInScope]() -> unsigned { 1548bcb0991SDimitry Andric // No debug location at all for the variable. 155*e8d8bef9SDimitry Andric if (ScopeBytesCovered == 0) 1568bcb0991SDimitry Andric return 0; 1578bcb0991SDimitry Andric // Fully covered variable within its scope. 158*e8d8bef9SDimitry Andric if (ScopeBytesCovered >= BytesInScope) 1598bcb0991SDimitry Andric return NumOfCoverageCategories - 1; 1608bcb0991SDimitry Andric // Get covered range (e.g. 20%-29%). 161*e8d8bef9SDimitry Andric unsigned LocBucket = 100 * (double)ScopeBytesCovered / BytesInScope; 1628bcb0991SDimitry Andric LocBucket /= 10; 1638bcb0991SDimitry Andric return LocBucket + 1; 1648bcb0991SDimitry Andric }; 1658bcb0991SDimitry Andric 1668bcb0991SDimitry Andric unsigned CoverageBucket = getCoverageBucket(); 1678bcb0991SDimitry Andric VarParamLocStats[CoverageBucket]++; 1688bcb0991SDimitry Andric if (IsParam) 1698bcb0991SDimitry Andric ParamLocStats[CoverageBucket]++; 1708bcb0991SDimitry Andric else if (IsLocalVar) 1715ffd83dbSDimitry Andric LocalVarLocStats[CoverageBucket]++; 1725ffd83dbSDimitry Andric } 1735ffd83dbSDimitry Andric /// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName 1745ffd83dbSDimitry Andric /// and DeclLine. The identifier aims to be unique for any unique entities, 1755ffd83dbSDimitry Andric /// but keeping the same among different instances of the same entity. 1765ffd83dbSDimitry Andric static std::string constructDieID(DWARFDie Die, 1775ffd83dbSDimitry Andric StringRef Prefix = StringRef()) { 1785ffd83dbSDimitry Andric std::string IDStr; 1795ffd83dbSDimitry Andric llvm::raw_string_ostream ID(IDStr); 1805ffd83dbSDimitry Andric ID << Prefix 1815ffd83dbSDimitry Andric << Die.getName(DINameKind::LinkageName); 1825ffd83dbSDimitry Andric 1835ffd83dbSDimitry Andric // Prefix + Name is enough for local variables and parameters. 1845ffd83dbSDimitry Andric if (!Prefix.empty() && !Prefix.equals("g")) 1855ffd83dbSDimitry Andric return ID.str(); 1865ffd83dbSDimitry Andric 1875ffd83dbSDimitry Andric auto DeclFile = Die.findRecursively(dwarf::DW_AT_decl_file); 1885ffd83dbSDimitry Andric std::string File; 1895ffd83dbSDimitry Andric if (DeclFile) { 1905ffd83dbSDimitry Andric DWARFUnit *U = Die.getDwarfUnit(); 1915ffd83dbSDimitry Andric if (const auto *LT = U->getContext().getLineTableForUnit(U)) 1925ffd83dbSDimitry Andric if (LT->getFileNameByIndex( 1935ffd83dbSDimitry Andric dwarf::toUnsigned(DeclFile, 0), U->getCompilationDir(), 1945ffd83dbSDimitry Andric DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) 1955ffd83dbSDimitry Andric File = std::string(sys::path::filename(File)); 1965ffd83dbSDimitry Andric } 1975ffd83dbSDimitry Andric ID << ":" << (File.empty() ? "/" : File); 1985ffd83dbSDimitry Andric ID << ":" 1995ffd83dbSDimitry Andric << dwarf::toUnsigned(Die.findRecursively(dwarf::DW_AT_decl_line), 0); 2005ffd83dbSDimitry Andric return ID.str(); 2018bcb0991SDimitry Andric } 2028bcb0991SDimitry Andric 203*e8d8bef9SDimitry Andric /// Return the number of bytes in the overlap of ranges A and B. 204*e8d8bef9SDimitry Andric static uint64_t calculateOverlap(DWARFAddressRange A, DWARFAddressRange B) { 205*e8d8bef9SDimitry Andric uint64_t Lower = std::max(A.LowPC, B.LowPC); 206*e8d8bef9SDimitry Andric uint64_t Upper = std::min(A.HighPC, B.HighPC); 207*e8d8bef9SDimitry Andric if (Lower >= Upper) 208*e8d8bef9SDimitry Andric return 0; 209*e8d8bef9SDimitry Andric return Upper - Lower; 210*e8d8bef9SDimitry Andric } 211*e8d8bef9SDimitry Andric 2120b57cec5SDimitry Andric /// Collect debug info quality metrics for one DIE. 213480093f4SDimitry Andric static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, 214480093f4SDimitry Andric std::string VarPrefix, uint64_t BytesInScope, 215480093f4SDimitry Andric uint32_t InlineDepth, 2160b57cec5SDimitry Andric StringMap<PerFunctionStats> &FnStatMap, 2178bcb0991SDimitry Andric GlobalStats &GlobalStats, 2188bcb0991SDimitry Andric LocationStats &LocStats) { 2190b57cec5SDimitry Andric bool HasLoc = false; 2200b57cec5SDimitry Andric bool HasSrcLoc = false; 2210b57cec5SDimitry Andric bool HasType = false; 222*e8d8bef9SDimitry Andric uint64_t TotalBytesCovered = 0; 223*e8d8bef9SDimitry Andric uint64_t ScopeBytesCovered = 0; 2248bcb0991SDimitry Andric uint64_t BytesEntryValuesCovered = 0; 2258bcb0991SDimitry Andric auto &FnStats = FnStatMap[FnPrefix]; 2268bcb0991SDimitry Andric bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter; 2278bcb0991SDimitry Andric bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable; 2285ffd83dbSDimitry Andric bool IsConstantMember = Die.getTag() == dwarf::DW_TAG_member && 2295ffd83dbSDimitry Andric Die.find(dwarf::DW_AT_const_value); 2300b57cec5SDimitry Andric 2318bcb0991SDimitry Andric if (Die.getTag() == dwarf::DW_TAG_call_site || 2328bcb0991SDimitry Andric Die.getTag() == dwarf::DW_TAG_GNU_call_site) { 2338bcb0991SDimitry Andric GlobalStats.CallSiteDIEs++; 2340b57cec5SDimitry Andric return; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric 2378bcb0991SDimitry Andric if (Die.getTag() == dwarf::DW_TAG_call_site_parameter || 2388bcb0991SDimitry Andric Die.getTag() == dwarf::DW_TAG_GNU_call_site_parameter) { 2398bcb0991SDimitry Andric GlobalStats.CallSiteParamDIEs++; 2408bcb0991SDimitry Andric return; 2418bcb0991SDimitry Andric } 2428bcb0991SDimitry Andric 2435ffd83dbSDimitry Andric if (!IsParam && !IsLocalVar && !IsConstantMember) { 2440b57cec5SDimitry Andric // Not a variable or constant member. 2450b57cec5SDimitry Andric return; 2460b57cec5SDimitry Andric } 2470b57cec5SDimitry Andric 2485ffd83dbSDimitry Andric // Ignore declarations of global variables. 2495ffd83dbSDimitry Andric if (IsLocalVar && Die.find(dwarf::DW_AT_declaration)) 2505ffd83dbSDimitry Andric return; 2515ffd83dbSDimitry Andric 2520b57cec5SDimitry Andric if (Die.findRecursively(dwarf::DW_AT_decl_file) && 2530b57cec5SDimitry Andric Die.findRecursively(dwarf::DW_AT_decl_line)) 2540b57cec5SDimitry Andric HasSrcLoc = true; 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric if (Die.findRecursively(dwarf::DW_AT_type)) 2570b57cec5SDimitry Andric HasType = true; 2580b57cec5SDimitry Andric 2598bcb0991SDimitry Andric auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool { 2608bcb0991SDimitry Andric DWARFUnit *U = Die.getDwarfUnit(); 2618bcb0991SDimitry Andric DataExtractor Data(toStringRef(D), 2628bcb0991SDimitry Andric Die.getDwarfUnit()->getContext().isLittleEndian(), 0); 2635ffd83dbSDimitry Andric DWARFExpression Expression(Data, U->getAddressByteSize(), 2645ffd83dbSDimitry Andric U->getFormParams().Format); 2658bcb0991SDimitry Andric // Consider the expression containing the DW_OP_entry_value as 2668bcb0991SDimitry Andric // an entry value. 2678bcb0991SDimitry Andric return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { 2688bcb0991SDimitry Andric return Op.getCode() == dwarf::DW_OP_entry_value || 2698bcb0991SDimitry Andric Op.getCode() == dwarf::DW_OP_GNU_entry_value; 2708bcb0991SDimitry Andric }); 2718bcb0991SDimitry Andric }; 2728bcb0991SDimitry Andric 2730b57cec5SDimitry Andric if (Die.find(dwarf::DW_AT_const_value)) { 2740b57cec5SDimitry Andric // This catches constant members *and* variables. 2750b57cec5SDimitry Andric HasLoc = true; 276*e8d8bef9SDimitry Andric ScopeBytesCovered = BytesInScope; 277*e8d8bef9SDimitry Andric TotalBytesCovered = BytesInScope; 2780b57cec5SDimitry Andric } else { 2790b57cec5SDimitry Andric // Handle variables and function arguments. 280480093f4SDimitry Andric Expected<std::vector<DWARFLocationExpression>> Loc = 281480093f4SDimitry Andric Die.getLocations(dwarf::DW_AT_location); 282480093f4SDimitry Andric if (!Loc) { 283480093f4SDimitry Andric consumeError(Loc.takeError()); 2840b57cec5SDimitry Andric } else { 285480093f4SDimitry Andric HasLoc = true; 286480093f4SDimitry Andric // Get PC coverage. 287480093f4SDimitry Andric auto Default = find_if( 288480093f4SDimitry Andric *Loc, [](const DWARFLocationExpression &L) { return !L.Range; }); 289480093f4SDimitry Andric if (Default != Loc->end()) { 2900b57cec5SDimitry Andric // Assume the entire range is covered by a single location. 291*e8d8bef9SDimitry Andric ScopeBytesCovered = BytesInScope; 292*e8d8bef9SDimitry Andric TotalBytesCovered = BytesInScope; 293480093f4SDimitry Andric } else { 294*e8d8bef9SDimitry Andric // Caller checks this Expected result already, it cannot fail. 295*e8d8bef9SDimitry Andric auto ScopeRanges = cantFail(Die.getParent().getAddressRanges()); 296480093f4SDimitry Andric for (auto Entry : *Loc) { 297*e8d8bef9SDimitry Andric TotalBytesCovered += Entry.Range->HighPC - Entry.Range->LowPC; 298*e8d8bef9SDimitry Andric uint64_t ScopeBytesCoveredByEntry = 0; 299*e8d8bef9SDimitry Andric // Calculate how many bytes of the parent scope this entry covers. 300*e8d8bef9SDimitry Andric // FIXME: In section 2.6.2 of the DWARFv5 spec it says that "The 301*e8d8bef9SDimitry Andric // address ranges defined by the bounded location descriptions of a 302*e8d8bef9SDimitry Andric // location list may overlap". So in theory a variable can have 303*e8d8bef9SDimitry Andric // multiple simultaneous locations, which would make this calculation 304*e8d8bef9SDimitry Andric // misleading because we will count the overlapped areas 305*e8d8bef9SDimitry Andric // twice. However, clang does not currently emit DWARF like this. 306*e8d8bef9SDimitry Andric for (DWARFAddressRange R : ScopeRanges) { 307*e8d8bef9SDimitry Andric ScopeBytesCoveredByEntry += calculateOverlap(*Entry.Range, R); 308*e8d8bef9SDimitry Andric } 309*e8d8bef9SDimitry Andric ScopeBytesCovered += ScopeBytesCoveredByEntry; 310480093f4SDimitry Andric if (IsEntryValue(Entry.Expr)) 311*e8d8bef9SDimitry Andric BytesEntryValuesCovered += ScopeBytesCoveredByEntry; 312480093f4SDimitry Andric } 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric } 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric 3178bcb0991SDimitry Andric // Calculate the debug location statistics. 3188bcb0991SDimitry Andric if (BytesInScope) { 3198bcb0991SDimitry Andric LocStats.NumVarParam++; 3208bcb0991SDimitry Andric if (IsParam) 3218bcb0991SDimitry Andric LocStats.NumParam++; 3228bcb0991SDimitry Andric else if (IsLocalVar) 3238bcb0991SDimitry Andric LocStats.NumVar++; 3248bcb0991SDimitry Andric 325*e8d8bef9SDimitry Andric collectLocStats(ScopeBytesCovered, BytesInScope, LocStats.VarParamLocStats, 3265ffd83dbSDimitry Andric LocStats.ParamLocStats, LocStats.LocalVarLocStats, IsParam, 3278bcb0991SDimitry Andric IsLocalVar); 3288bcb0991SDimitry Andric // Non debug entry values coverage statistics. 329*e8d8bef9SDimitry Andric collectLocStats(ScopeBytesCovered - BytesEntryValuesCovered, BytesInScope, 3308bcb0991SDimitry Andric LocStats.VarParamNonEntryValLocStats, 3318bcb0991SDimitry Andric LocStats.ParamNonEntryValLocStats, 3325ffd83dbSDimitry Andric LocStats.LocalVarNonEntryValLocStats, IsParam, IsLocalVar); 3338bcb0991SDimitry Andric } 3348bcb0991SDimitry Andric 3350b57cec5SDimitry Andric // Collect PC range coverage data. 3360b57cec5SDimitry Andric if (DWARFDie D = 3370b57cec5SDimitry Andric Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin)) 3380b57cec5SDimitry Andric Die = D; 3395ffd83dbSDimitry Andric 3405ffd83dbSDimitry Andric std::string VarID = constructDieID(Die, VarPrefix); 3415ffd83dbSDimitry Andric FnStats.VarsInFunction.insert(VarID); 3425ffd83dbSDimitry Andric 343*e8d8bef9SDimitry Andric GlobalStats.TotalBytesCovered += TotalBytesCovered; 3440b57cec5SDimitry Andric if (BytesInScope) { 345*e8d8bef9SDimitry Andric GlobalStats.ScopeBytesCovered += ScopeBytesCovered; 346480093f4SDimitry Andric GlobalStats.ScopeBytes += BytesInScope; 3478bcb0991SDimitry Andric GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered; 3488bcb0991SDimitry Andric if (IsParam) { 349*e8d8bef9SDimitry Andric GlobalStats.ParamScopeBytesCovered += ScopeBytesCovered; 350480093f4SDimitry Andric GlobalStats.ParamScopeBytes += BytesInScope; 3518bcb0991SDimitry Andric GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered; 3528bcb0991SDimitry Andric } else if (IsLocalVar) { 353*e8d8bef9SDimitry Andric GlobalStats.LocalVarScopeBytesCovered += ScopeBytesCovered; 3545ffd83dbSDimitry Andric GlobalStats.LocalVarScopeBytes += BytesInScope; 3555ffd83dbSDimitry Andric GlobalStats.LocalVarScopeEntryValueBytesCovered += 3565ffd83dbSDimitry Andric BytesEntryValuesCovered; 3578bcb0991SDimitry Andric } 358480093f4SDimitry Andric assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes); 3590b57cec5SDimitry Andric } 3605ffd83dbSDimitry Andric 3615ffd83dbSDimitry Andric if (IsConstantMember) { 3625ffd83dbSDimitry Andric FnStats.ConstantMembers++; 3635ffd83dbSDimitry Andric return; 3645ffd83dbSDimitry Andric } 3655ffd83dbSDimitry Andric 3665ffd83dbSDimitry Andric FnStats.TotalVarWithLoc += (unsigned)HasLoc; 3675ffd83dbSDimitry Andric 3685ffd83dbSDimitry Andric if (Die.find(dwarf::DW_AT_artificial)) { 3695ffd83dbSDimitry Andric FnStats.NumArtificial++; 3705ffd83dbSDimitry Andric return; 3715ffd83dbSDimitry Andric } 3725ffd83dbSDimitry Andric 3738bcb0991SDimitry Andric if (IsParam) { 3740b57cec5SDimitry Andric FnStats.NumParams++; 3750b57cec5SDimitry Andric if (HasType) 3760b57cec5SDimitry Andric FnStats.NumParamTypes++; 3770b57cec5SDimitry Andric if (HasSrcLoc) 3780b57cec5SDimitry Andric FnStats.NumParamSourceLocations++; 3790b57cec5SDimitry Andric if (HasLoc) 3800b57cec5SDimitry Andric FnStats.NumParamLocations++; 3818bcb0991SDimitry Andric } else if (IsLocalVar) { 3825ffd83dbSDimitry Andric FnStats.NumLocalVars++; 3830b57cec5SDimitry Andric if (HasType) 3845ffd83dbSDimitry Andric FnStats.NumLocalVarTypes++; 3850b57cec5SDimitry Andric if (HasSrcLoc) 3865ffd83dbSDimitry Andric FnStats.NumLocalVarSourceLocations++; 3870b57cec5SDimitry Andric if (HasLoc) 3885ffd83dbSDimitry Andric FnStats.NumLocalVarLocations++; 3890b57cec5SDimitry Andric } 3900b57cec5SDimitry Andric } 3910b57cec5SDimitry Andric 3920b57cec5SDimitry Andric /// Recursively collect debug info quality metrics. 393480093f4SDimitry Andric static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix, 394480093f4SDimitry Andric std::string VarPrefix, uint64_t BytesInScope, 395480093f4SDimitry Andric uint32_t InlineDepth, 3960b57cec5SDimitry Andric StringMap<PerFunctionStats> &FnStatMap, 3978bcb0991SDimitry Andric GlobalStats &GlobalStats, 3988bcb0991SDimitry Andric LocationStats &LocStats) { 3990b57cec5SDimitry Andric const dwarf::Tag Tag = Die.getTag(); 4005ffd83dbSDimitry Andric // Skip function types. 4015ffd83dbSDimitry Andric if (Tag == dwarf::DW_TAG_subroutine_type) 4025ffd83dbSDimitry Andric return; 4035ffd83dbSDimitry Andric 4045ffd83dbSDimitry Andric // Handle any kind of lexical scope. 4050b57cec5SDimitry Andric const bool IsFunction = Tag == dwarf::DW_TAG_subprogram; 4060b57cec5SDimitry Andric const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block; 4070b57cec5SDimitry Andric const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine; 4080b57cec5SDimitry Andric if (IsFunction || IsInlinedFunction || IsBlock) { 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric // Reset VarPrefix when entering a new function. 4110b57cec5SDimitry Andric if (Die.getTag() == dwarf::DW_TAG_subprogram || 4120b57cec5SDimitry Andric Die.getTag() == dwarf::DW_TAG_inlined_subroutine) 4130b57cec5SDimitry Andric VarPrefix = "v"; 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric // Ignore forward declarations. 4160b57cec5SDimitry Andric if (Die.find(dwarf::DW_AT_declaration)) 4170b57cec5SDimitry Andric return; 4180b57cec5SDimitry Andric 4190b57cec5SDimitry Andric // Check for call sites. 4200b57cec5SDimitry Andric if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line)) 4210b57cec5SDimitry Andric GlobalStats.CallSiteEntries++; 4220b57cec5SDimitry Andric 4230b57cec5SDimitry Andric // PC Ranges. 4240b57cec5SDimitry Andric auto RangesOrError = Die.getAddressRanges(); 4250b57cec5SDimitry Andric if (!RangesOrError) { 4260b57cec5SDimitry Andric llvm::consumeError(RangesOrError.takeError()); 4270b57cec5SDimitry Andric return; 4280b57cec5SDimitry Andric } 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric auto Ranges = RangesOrError.get(); 4310b57cec5SDimitry Andric uint64_t BytesInThisScope = 0; 4320b57cec5SDimitry Andric for (auto Range : Ranges) 4330b57cec5SDimitry Andric BytesInThisScope += Range.HighPC - Range.LowPC; 4340b57cec5SDimitry Andric 4350b57cec5SDimitry Andric // Count the function. 4360b57cec5SDimitry Andric if (!IsBlock) { 4370b57cec5SDimitry Andric // Skip over abstract origins. 4380b57cec5SDimitry Andric if (Die.find(dwarf::DW_AT_inline)) 4390b57cec5SDimitry Andric return; 4405ffd83dbSDimitry Andric std::string FnID = constructDieID(Die); 4415ffd83dbSDimitry Andric // We've seen an instance of this function. 4425ffd83dbSDimitry Andric auto &FnStats = FnStatMap[FnID]; 4435ffd83dbSDimitry Andric FnStats.IsFunction = true; 4440b57cec5SDimitry Andric if (IsInlinedFunction) { 4450b57cec5SDimitry Andric FnStats.NumFnInlined++; 4460b57cec5SDimitry Andric if (Die.findRecursively(dwarf::DW_AT_abstract_origin)) 4470b57cec5SDimitry Andric FnStats.NumAbstractOrigins++; 4485ffd83dbSDimitry Andric } else { 4495ffd83dbSDimitry Andric FnStats.NumFnOutOfLine++; 4500b57cec5SDimitry Andric } 4510b57cec5SDimitry Andric if (Die.findRecursively(dwarf::DW_AT_decl_file) && 4520b57cec5SDimitry Andric Die.findRecursively(dwarf::DW_AT_decl_line)) 4530b57cec5SDimitry Andric FnStats.HasSourceLocation = true; 4545ffd83dbSDimitry Andric // Update function prefix. 4555ffd83dbSDimitry Andric FnPrefix = FnID; 4560b57cec5SDimitry Andric } 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric if (BytesInThisScope) { 4590b57cec5SDimitry Andric BytesInScope = BytesInThisScope; 4600b57cec5SDimitry Andric if (IsFunction) 4610b57cec5SDimitry Andric GlobalStats.FunctionSize += BytesInThisScope; 4620b57cec5SDimitry Andric else if (IsInlinedFunction && InlineDepth == 0) 4630b57cec5SDimitry Andric GlobalStats.InlineFunctionSize += BytesInThisScope; 4640b57cec5SDimitry Andric } 4650b57cec5SDimitry Andric } else { 4660b57cec5SDimitry Andric // Not a scope, visit the Die itself. It could be a variable. 467480093f4SDimitry Andric collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth, 468480093f4SDimitry Andric FnStatMap, GlobalStats, LocStats); 4690b57cec5SDimitry Andric } 4700b57cec5SDimitry Andric 4710b57cec5SDimitry Andric // Set InlineDepth correctly for child recursion 4720b57cec5SDimitry Andric if (IsFunction) 4730b57cec5SDimitry Andric InlineDepth = 0; 4740b57cec5SDimitry Andric else if (IsInlinedFunction) 4750b57cec5SDimitry Andric ++InlineDepth; 4760b57cec5SDimitry Andric 4770b57cec5SDimitry Andric // Traverse children. 4780b57cec5SDimitry Andric unsigned LexicalBlockIndex = 0; 4795ffd83dbSDimitry Andric unsigned FormalParameterIndex = 0; 4800b57cec5SDimitry Andric DWARFDie Child = Die.getFirstChild(); 4810b57cec5SDimitry Andric while (Child) { 4820b57cec5SDimitry Andric std::string ChildVarPrefix = VarPrefix; 4830b57cec5SDimitry Andric if (Child.getTag() == dwarf::DW_TAG_lexical_block) 4840b57cec5SDimitry Andric ChildVarPrefix += toHex(LexicalBlockIndex++) + '.'; 4855ffd83dbSDimitry Andric if (Child.getTag() == dwarf::DW_TAG_formal_parameter) 4865ffd83dbSDimitry Andric ChildVarPrefix += 'p' + toHex(FormalParameterIndex++) + '.'; 4870b57cec5SDimitry Andric 488480093f4SDimitry Andric collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, BytesInScope, 489480093f4SDimitry Andric InlineDepth, FnStatMap, GlobalStats, LocStats); 4900b57cec5SDimitry Andric Child = Child.getSibling(); 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric } 4930b57cec5SDimitry Andric 494*e8d8bef9SDimitry Andric /// Print human-readable output. 4950b57cec5SDimitry Andric /// \{ 496*e8d8bef9SDimitry Andric static void printDatum(json::OStream &J, const char *Key, json::Value Value) { 497*e8d8bef9SDimitry Andric J.attribute(Key, Value); 4980b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n'); 4990b57cec5SDimitry Andric } 5005ffd83dbSDimitry Andric 501*e8d8bef9SDimitry Andric static void printLocationStats(json::OStream &J, const char *Key, 5028bcb0991SDimitry Andric std::vector<unsigned> &LocationStats) { 503*e8d8bef9SDimitry Andric J.attribute( 504*e8d8bef9SDimitry Andric (Twine(Key) + " with 0% of parent scope covered by DW_AT_location").str(), 505*e8d8bef9SDimitry Andric LocationStats[0]); 5065ffd83dbSDimitry Andric LLVM_DEBUG( 5075ffd83dbSDimitry Andric llvm::dbgs() << Key 5085ffd83dbSDimitry Andric << " with 0% of parent scope covered by DW_AT_location: \\" 5098bcb0991SDimitry Andric << LocationStats[0] << '\n'); 510*e8d8bef9SDimitry Andric J.attribute( 511*e8d8bef9SDimitry Andric (Twine(Key) + " with (0%,10%) of parent scope covered by DW_AT_location") 512*e8d8bef9SDimitry Andric .str(), 513*e8d8bef9SDimitry Andric LocationStats[1]); 5145ffd83dbSDimitry Andric LLVM_DEBUG(llvm::dbgs() 5155ffd83dbSDimitry Andric << Key 5165ffd83dbSDimitry Andric << " with (0%,10%) of parent scope covered by DW_AT_location: " 5178bcb0991SDimitry Andric << LocationStats[1] << '\n'); 5188bcb0991SDimitry Andric for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) { 519*e8d8bef9SDimitry Andric J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," + 520*e8d8bef9SDimitry Andric Twine(i * 10) + "%) of parent scope covered by DW_AT_location") 521*e8d8bef9SDimitry Andric .str(), 522*e8d8bef9SDimitry Andric LocationStats[i]); 5238bcb0991SDimitry Andric LLVM_DEBUG(llvm::dbgs() 524480093f4SDimitry Andric << Key << " with [" << (i - 1) * 10 << "%," << i * 10 5255ffd83dbSDimitry Andric << "%) of parent scope covered by DW_AT_location: " 5265ffd83dbSDimitry Andric << LocationStats[i]); 5278bcb0991SDimitry Andric } 528*e8d8bef9SDimitry Andric J.attribute( 529*e8d8bef9SDimitry Andric (Twine(Key) + " with 100% of parent scope covered by DW_AT_location") 530*e8d8bef9SDimitry Andric .str(), 531*e8d8bef9SDimitry Andric LocationStats[NumOfCoverageCategories - 1]); 5325ffd83dbSDimitry Andric LLVM_DEBUG( 5335ffd83dbSDimitry Andric llvm::dbgs() << Key 5345ffd83dbSDimitry Andric << " with 100% of parent scope covered by DW_AT_location: " 5358bcb0991SDimitry Andric << LocationStats[NumOfCoverageCategories - 1]); 5368bcb0991SDimitry Andric } 5375ffd83dbSDimitry Andric 538*e8d8bef9SDimitry Andric static void printSectionSizes(json::OStream &J, const SectionSizes &Sizes) { 5395ffd83dbSDimitry Andric for (const auto &DebugSec : Sizes.DebugSectionSizes) 540*e8d8bef9SDimitry Andric J.attribute((Twine("#bytes in ") + DebugSec.getKey()).str(), 541*e8d8bef9SDimitry Andric int64_t(DebugSec.getValue())); 5425ffd83dbSDimitry Andric } 5435ffd83dbSDimitry Andric 5440b57cec5SDimitry Andric /// \} 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric /// Collect debug info quality metrics for an entire DIContext. 5470b57cec5SDimitry Andric /// 5480b57cec5SDimitry Andric /// Do the impossible and reduce the quality of the debug info down to a few 5490b57cec5SDimitry Andric /// numbers. The idea is to condense the data into numbers that can be tracked 5500b57cec5SDimitry Andric /// over time to identify trends in newer compiler versions and gauge the effect 5510b57cec5SDimitry Andric /// of particular optimizations. The raw numbers themselves are not particularly 5520b57cec5SDimitry Andric /// useful, only the delta between compiling the same program with different 5530b57cec5SDimitry Andric /// compilers is. 5545ffd83dbSDimitry Andric bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, 5555ffd83dbSDimitry Andric const Twine &Filename, 5565ffd83dbSDimitry Andric raw_ostream &OS) { 5570b57cec5SDimitry Andric StringRef FormatName = Obj.getFileFormatName(); 5580b57cec5SDimitry Andric GlobalStats GlobalStats; 5598bcb0991SDimitry Andric LocationStats LocStats; 5600b57cec5SDimitry Andric StringMap<PerFunctionStats> Statistics; 5610b57cec5SDimitry Andric for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) 5620b57cec5SDimitry Andric if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) 563480093f4SDimitry Andric collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats, 564480093f4SDimitry Andric LocStats); 5650b57cec5SDimitry Andric 5665ffd83dbSDimitry Andric /// Collect the sizes of debug sections. 5675ffd83dbSDimitry Andric SectionSizes Sizes; 5685ffd83dbSDimitry Andric calculateSectionSizes(Obj, Sizes, Filename); 5695ffd83dbSDimitry Andric 5700b57cec5SDimitry Andric /// The version number should be increased every time the algorithm is changed 5710b57cec5SDimitry Andric /// (including bug fixes). New metrics may be added without increasing the 5720b57cec5SDimitry Andric /// version. 573*e8d8bef9SDimitry Andric unsigned Version = 6; 5740b57cec5SDimitry Andric unsigned VarParamTotal = 0; 5750b57cec5SDimitry Andric unsigned VarParamUnique = 0; 5760b57cec5SDimitry Andric unsigned VarParamWithLoc = 0; 5770b57cec5SDimitry Andric unsigned NumFunctions = 0; 5780b57cec5SDimitry Andric unsigned NumInlinedFunctions = 0; 5790b57cec5SDimitry Andric unsigned NumFuncsWithSrcLoc = 0; 5800b57cec5SDimitry Andric unsigned NumAbstractOrigins = 0; 5810b57cec5SDimitry Andric unsigned ParamTotal = 0; 5820b57cec5SDimitry Andric unsigned ParamWithType = 0; 5830b57cec5SDimitry Andric unsigned ParamWithLoc = 0; 5840b57cec5SDimitry Andric unsigned ParamWithSrcLoc = 0; 5855ffd83dbSDimitry Andric unsigned LocalVarTotal = 0; 5865ffd83dbSDimitry Andric unsigned LocalVarWithType = 0; 5875ffd83dbSDimitry Andric unsigned LocalVarWithSrcLoc = 0; 5885ffd83dbSDimitry Andric unsigned LocalVarWithLoc = 0; 5890b57cec5SDimitry Andric for (auto &Entry : Statistics) { 5900b57cec5SDimitry Andric PerFunctionStats &Stats = Entry.getValue(); 5915ffd83dbSDimitry Andric unsigned TotalVars = Stats.VarsInFunction.size() * 5925ffd83dbSDimitry Andric (Stats.NumFnInlined + Stats.NumFnOutOfLine); 5935ffd83dbSDimitry Andric // Count variables in global scope. 5945ffd83dbSDimitry Andric if (!Stats.IsFunction) 5955ffd83dbSDimitry Andric TotalVars = 5965ffd83dbSDimitry Andric Stats.NumLocalVars + Stats.ConstantMembers + Stats.NumArtificial; 5970b57cec5SDimitry Andric unsigned Constants = Stats.ConstantMembers; 5980b57cec5SDimitry Andric VarParamWithLoc += Stats.TotalVarWithLoc + Constants; 5990b57cec5SDimitry Andric VarParamTotal += TotalVars; 6000b57cec5SDimitry Andric VarParamUnique += Stats.VarsInFunction.size(); 6010b57cec5SDimitry Andric LLVM_DEBUG(for (auto &V 6020b57cec5SDimitry Andric : Stats.VarsInFunction) llvm::dbgs() 6030b57cec5SDimitry Andric << Entry.getKey() << ": " << V.getKey() << "\n"); 6040b57cec5SDimitry Andric NumFunctions += Stats.IsFunction; 6050b57cec5SDimitry Andric NumFuncsWithSrcLoc += Stats.HasSourceLocation; 6060b57cec5SDimitry Andric NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined; 6070b57cec5SDimitry Andric NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins; 6080b57cec5SDimitry Andric ParamTotal += Stats.NumParams; 6090b57cec5SDimitry Andric ParamWithType += Stats.NumParamTypes; 6100b57cec5SDimitry Andric ParamWithLoc += Stats.NumParamLocations; 6110b57cec5SDimitry Andric ParamWithSrcLoc += Stats.NumParamSourceLocations; 6125ffd83dbSDimitry Andric LocalVarTotal += Stats.NumLocalVars; 6135ffd83dbSDimitry Andric LocalVarWithType += Stats.NumLocalVarTypes; 6145ffd83dbSDimitry Andric LocalVarWithLoc += Stats.NumLocalVarLocations; 6155ffd83dbSDimitry Andric LocalVarWithSrcLoc += Stats.NumLocalVarSourceLocations; 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric // Print summary. 6190b57cec5SDimitry Andric OS.SetBufferSize(1024); 620*e8d8bef9SDimitry Andric json::OStream J(OS, 2); 621*e8d8bef9SDimitry Andric J.objectBegin(); 622*e8d8bef9SDimitry Andric J.attribute("version", Version); 6230b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n"; 6240b57cec5SDimitry Andric llvm::dbgs() << "---------------------------------\n"); 6255ffd83dbSDimitry Andric 626*e8d8bef9SDimitry Andric printDatum(J, "file", Filename.str()); 627*e8d8bef9SDimitry Andric printDatum(J, "format", FormatName); 6285ffd83dbSDimitry Andric 629*e8d8bef9SDimitry Andric printDatum(J, "#functions", NumFunctions); 630*e8d8bef9SDimitry Andric printDatum(J, "#functions with location", NumFuncsWithSrcLoc); 631*e8d8bef9SDimitry Andric printDatum(J, "#inlined functions", NumInlinedFunctions); 632*e8d8bef9SDimitry Andric printDatum(J, "#inlined functions with abstract origins", NumAbstractOrigins); 6335ffd83dbSDimitry Andric 6345ffd83dbSDimitry Andric // This includes local variables and formal parameters. 635*e8d8bef9SDimitry Andric printDatum(J, "#unique source variables", VarParamUnique); 636*e8d8bef9SDimitry Andric printDatum(J, "#source variables", VarParamTotal); 637*e8d8bef9SDimitry Andric printDatum(J, "#source variables with location", VarParamWithLoc); 6385ffd83dbSDimitry Andric 639*e8d8bef9SDimitry Andric printDatum(J, "#call site entries", GlobalStats.CallSiteEntries); 640*e8d8bef9SDimitry Andric printDatum(J, "#call site DIEs", GlobalStats.CallSiteDIEs); 641*e8d8bef9SDimitry Andric printDatum(J, "#call site parameter DIEs", GlobalStats.CallSiteParamDIEs); 6425ffd83dbSDimitry Andric 643*e8d8bef9SDimitry Andric printDatum(J, "sum_all_variables(#bytes in parent scope)", 6445ffd83dbSDimitry Andric GlobalStats.ScopeBytes); 645*e8d8bef9SDimitry Andric printDatum(J, 646*e8d8bef9SDimitry Andric "sum_all_variables(#bytes in any scope covered by DW_AT_location)", 647*e8d8bef9SDimitry Andric GlobalStats.TotalBytesCovered); 648*e8d8bef9SDimitry Andric printDatum(J, 6495ffd83dbSDimitry Andric "sum_all_variables(#bytes in parent scope covered by " 6505ffd83dbSDimitry Andric "DW_AT_location)", 6515ffd83dbSDimitry Andric GlobalStats.ScopeBytesCovered); 652*e8d8bef9SDimitry Andric printDatum(J, 6535ffd83dbSDimitry Andric "sum_all_variables(#bytes in parent scope covered by " 6545ffd83dbSDimitry Andric "DW_OP_entry_value)", 6558bcb0991SDimitry Andric GlobalStats.ScopeEntryValueBytesCovered); 6565ffd83dbSDimitry Andric 657*e8d8bef9SDimitry Andric printDatum(J, "sum_all_params(#bytes in parent scope)", 658480093f4SDimitry Andric GlobalStats.ParamScopeBytes); 659*e8d8bef9SDimitry Andric printDatum(J, 6605ffd83dbSDimitry Andric "sum_all_params(#bytes in parent scope covered by DW_AT_location)", 6618bcb0991SDimitry Andric GlobalStats.ParamScopeBytesCovered); 662*e8d8bef9SDimitry Andric printDatum(J, 6635ffd83dbSDimitry Andric "sum_all_params(#bytes in parent scope covered by " 6645ffd83dbSDimitry Andric "DW_OP_entry_value)", 6658bcb0991SDimitry Andric GlobalStats.ParamScopeEntryValueBytesCovered); 6665ffd83dbSDimitry Andric 667*e8d8bef9SDimitry Andric printDatum(J, "sum_all_local_vars(#bytes in parent scope)", 6685ffd83dbSDimitry Andric GlobalStats.LocalVarScopeBytes); 669*e8d8bef9SDimitry Andric printDatum(J, 6705ffd83dbSDimitry Andric "sum_all_local_vars(#bytes in parent scope covered by " 6715ffd83dbSDimitry Andric "DW_AT_location)", 6725ffd83dbSDimitry Andric GlobalStats.LocalVarScopeBytesCovered); 673*e8d8bef9SDimitry Andric printDatum(J, 6745ffd83dbSDimitry Andric "sum_all_local_vars(#bytes in parent scope covered by " 6755ffd83dbSDimitry Andric "DW_OP_entry_value)", 6765ffd83dbSDimitry Andric GlobalStats.LocalVarScopeEntryValueBytesCovered); 6775ffd83dbSDimitry Andric 678*e8d8bef9SDimitry Andric printDatum(J, "#bytes within functions", GlobalStats.FunctionSize); 679*e8d8bef9SDimitry Andric printDatum(J, "#bytes within inlined functions", 6805ffd83dbSDimitry Andric GlobalStats.InlineFunctionSize); 6815ffd83dbSDimitry Andric 6825ffd83dbSDimitry Andric // Print the summary for formal parameters. 683*e8d8bef9SDimitry Andric printDatum(J, "#params", ParamTotal); 684*e8d8bef9SDimitry Andric printDatum(J, "#params with source location", ParamWithSrcLoc); 685*e8d8bef9SDimitry Andric printDatum(J, "#params with type", ParamWithType); 686*e8d8bef9SDimitry Andric printDatum(J, "#params with binary location", ParamWithLoc); 6875ffd83dbSDimitry Andric 6885ffd83dbSDimitry Andric // Print the summary for local variables. 689*e8d8bef9SDimitry Andric printDatum(J, "#local vars", LocalVarTotal); 690*e8d8bef9SDimitry Andric printDatum(J, "#local vars with source location", LocalVarWithSrcLoc); 691*e8d8bef9SDimitry Andric printDatum(J, "#local vars with type", LocalVarWithType); 692*e8d8bef9SDimitry Andric printDatum(J, "#local vars with binary location", LocalVarWithLoc); 6935ffd83dbSDimitry Andric 6945ffd83dbSDimitry Andric // Print the debug section sizes. 695*e8d8bef9SDimitry Andric printSectionSizes(J, Sizes); 6965ffd83dbSDimitry Andric 6975ffd83dbSDimitry Andric // Print the location statistics for variables (includes local variables 6985ffd83dbSDimitry Andric // and formal parameters). 699*e8d8bef9SDimitry Andric printDatum(J, "#variables processed by location statistics", 7008bcb0991SDimitry Andric LocStats.NumVarParam); 701*e8d8bef9SDimitry Andric printLocationStats(J, "#variables", LocStats.VarParamLocStats); 702*e8d8bef9SDimitry Andric printLocationStats(J, "#variables - entry values", 7038bcb0991SDimitry Andric LocStats.VarParamNonEntryValLocStats); 7045ffd83dbSDimitry Andric 7055ffd83dbSDimitry Andric // Print the location statistics for formal parameters. 706*e8d8bef9SDimitry Andric printDatum(J, "#params processed by location statistics", LocStats.NumParam); 707*e8d8bef9SDimitry Andric printLocationStats(J, "#params", LocStats.ParamLocStats); 708*e8d8bef9SDimitry Andric printLocationStats(J, "#params - entry values", 7098bcb0991SDimitry Andric LocStats.ParamNonEntryValLocStats); 7105ffd83dbSDimitry Andric 7115ffd83dbSDimitry Andric // Print the location statistics for local variables. 712*e8d8bef9SDimitry Andric printDatum(J, "#local vars processed by location statistics", 7135ffd83dbSDimitry Andric LocStats.NumVar); 714*e8d8bef9SDimitry Andric printLocationStats(J, "#local vars", LocStats.LocalVarLocStats); 715*e8d8bef9SDimitry Andric printLocationStats(J, "#local vars - entry values", 7165ffd83dbSDimitry Andric LocStats.LocalVarNonEntryValLocStats); 717*e8d8bef9SDimitry Andric J.objectEnd(); 718*e8d8bef9SDimitry Andric OS << '\n'; 7190b57cec5SDimitry Andric LLVM_DEBUG( 7200b57cec5SDimitry Andric llvm::dbgs() << "Total Availability: " 7210b57cec5SDimitry Andric << (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal) 7220b57cec5SDimitry Andric << "%\n"; 7230b57cec5SDimitry Andric llvm::dbgs() << "PC Ranges covered: " 7240b57cec5SDimitry Andric << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) / 725480093f4SDimitry Andric GlobalStats.ScopeBytes) 7260b57cec5SDimitry Andric << "%\n"); 7270b57cec5SDimitry Andric return true; 7280b57cec5SDimitry Andric } 729