1*5ffd83dbSDimitry Andric //===-- Statistics.cpp - Debug Info quality metrics -----------------------===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric 9*5ffd83dbSDimitry 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; 21*5ffd83dbSDimitry Andric using namespace llvm::dwarfdump; 22*5ffd83dbSDimitry 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 30*5ffd83dbSDimitry 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; 36*5ffd83dbSDimitry Andric /// Number of out-of-line instances of this function. 37*5ffd83dbSDimitry 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; 45*5ffd83dbSDimitry Andric /// Number of arificial variables, parameters or members across all instances. 46*5ffd83dbSDimitry 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; 61*5ffd83dbSDimitry Andric /// Number of local variables. 62*5ffd83dbSDimitry Andric unsigned NumLocalVars = 0; 63*5ffd83dbSDimitry Andric /// Number of local variables with source location. 64*5ffd83dbSDimitry Andric unsigned NumLocalVarSourceLocations = 0; 65*5ffd83dbSDimitry Andric /// Number of local variables with type. 66*5ffd83dbSDimitry Andric unsigned NumLocalVarTypes = 0; 67*5ffd83dbSDimitry Andric /// Number of local variables with DW_AT_location. 68*5ffd83dbSDimitry 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. 740b57cec5SDimitry Andric unsigned ScopeBytesCovered = 0; 75480093f4SDimitry Andric /// Total number of PC range bytes in each variable's enclosing scope. 76480093f4SDimitry Andric unsigned ScopeBytes = 0; 778bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations with 788bcb0991SDimitry Andric /// the debug entry values (DW_OP_entry_value). 798bcb0991SDimitry Andric unsigned ScopeEntryValueBytesCovered = 0; 808bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations of 818bcb0991SDimitry Andric /// formal parameters. 828bcb0991SDimitry Andric unsigned ParamScopeBytesCovered = 0; 83*5ffd83dbSDimitry Andric /// Total number of PC range bytes in each parameter's enclosing scope. 84480093f4SDimitry Andric unsigned ParamScopeBytes = 0; 858bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations with 868bcb0991SDimitry Andric /// the debug entry values (DW_OP_entry_value) (only for parameters). 878bcb0991SDimitry Andric unsigned ParamScopeEntryValueBytesCovered = 0; 888bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations (only for local 898bcb0991SDimitry Andric /// variables). 90*5ffd83dbSDimitry Andric unsigned LocalVarScopeBytesCovered = 0; 91*5ffd83dbSDimitry Andric /// Total number of PC range bytes in each local variable's enclosing scope. 92*5ffd83dbSDimitry Andric unsigned LocalVarScopeBytes = 0; 938bcb0991SDimitry Andric /// Total number of PC range bytes covered by DW_AT_locations with 948bcb0991SDimitry Andric /// the debug entry values (DW_OP_entry_value) (only for local variables). 95*5ffd83dbSDimitry Andric unsigned LocalVarScopeEntryValueBytesCovered = 0; 968bcb0991SDimitry Andric /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line). 970b57cec5SDimitry Andric unsigned CallSiteEntries = 0; 988bcb0991SDimitry Andric /// Total number of call site DIEs (DW_TAG_call_site). 998bcb0991SDimitry Andric unsigned CallSiteDIEs = 0; 1008bcb0991SDimitry Andric /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter). 1018bcb0991SDimitry Andric unsigned CallSiteParamDIEs = 0; 1020b57cec5SDimitry Andric /// Total byte size of concrete functions. This byte size includes 1030b57cec5SDimitry Andric /// inline functions contained in the concrete functions. 1048bcb0991SDimitry Andric unsigned FunctionSize = 0; 1050b57cec5SDimitry Andric /// Total byte size of inlined functions. This is the total number of bytes 1060b57cec5SDimitry Andric /// for the top inline functions within concrete functions. This can help 1070b57cec5SDimitry Andric /// tune the inline settings when compiling to match user expectations. 1088bcb0991SDimitry Andric unsigned InlineFunctionSize = 0; 1098bcb0991SDimitry Andric }; 1108bcb0991SDimitry Andric 1118bcb0991SDimitry Andric /// Holds accumulated debug location statistics about local variables and 1128bcb0991SDimitry Andric /// formal parameters. 1138bcb0991SDimitry Andric struct LocationStats { 1148bcb0991SDimitry Andric /// Map the scope coverage decile to the number of variables in the decile. 1158bcb0991SDimitry Andric /// The first element of the array (at the index zero) represents the number 1168bcb0991SDimitry Andric /// of variables with the no debug location at all, but the last element 1178bcb0991SDimitry Andric /// in the vector represents the number of fully covered variables within 1188bcb0991SDimitry Andric /// its scope. 1198bcb0991SDimitry Andric std::vector<unsigned> VarParamLocStats{ 1208bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1218bcb0991SDimitry Andric /// Map non debug entry values coverage. 1228bcb0991SDimitry Andric std::vector<unsigned> VarParamNonEntryValLocStats{ 1238bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1248bcb0991SDimitry Andric /// The debug location statistics for formal parameters. 1258bcb0991SDimitry Andric std::vector<unsigned> ParamLocStats{ 1268bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1278bcb0991SDimitry Andric /// Map non debug entry values coverage for formal parameters. 1288bcb0991SDimitry Andric std::vector<unsigned> ParamNonEntryValLocStats{ 1298bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1308bcb0991SDimitry Andric /// The debug location statistics for local variables. 131*5ffd83dbSDimitry Andric std::vector<unsigned> LocalVarLocStats{ 1328bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1338bcb0991SDimitry Andric /// Map non debug entry values coverage for local variables. 134*5ffd83dbSDimitry Andric std::vector<unsigned> LocalVarNonEntryValLocStats{ 1358bcb0991SDimitry Andric std::vector<unsigned>(NumOfCoverageCategories, 0)}; 1368bcb0991SDimitry Andric /// Total number of local variables and function parameters processed. 1378bcb0991SDimitry Andric unsigned NumVarParam = 0; 1388bcb0991SDimitry Andric /// Total number of formal parameters processed. 1398bcb0991SDimitry Andric unsigned NumParam = 0; 1408bcb0991SDimitry Andric /// Total number of local variables processed. 1418bcb0991SDimitry Andric unsigned NumVar = 0; 1420b57cec5SDimitry Andric }; 143*5ffd83dbSDimitry Andric } // namespace 1440b57cec5SDimitry Andric 1458bcb0991SDimitry Andric /// Collect debug location statistics for one DIE. 1468bcb0991SDimitry Andric static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope, 1478bcb0991SDimitry Andric std::vector<unsigned> &VarParamLocStats, 1488bcb0991SDimitry Andric std::vector<unsigned> &ParamLocStats, 149*5ffd83dbSDimitry Andric std::vector<unsigned> &LocalVarLocStats, 150*5ffd83dbSDimitry Andric bool IsParam, bool IsLocalVar) { 1518bcb0991SDimitry Andric auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned { 1528bcb0991SDimitry Andric // No debug location at all for the variable. 153480093f4SDimitry Andric if (BytesCovered == 0) 1548bcb0991SDimitry Andric return 0; 1558bcb0991SDimitry Andric // Fully covered variable within its scope. 156480093f4SDimitry Andric if (BytesCovered >= BytesInScope) 1578bcb0991SDimitry Andric return NumOfCoverageCategories - 1; 1588bcb0991SDimitry Andric // Get covered range (e.g. 20%-29%). 159480093f4SDimitry Andric unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope; 1608bcb0991SDimitry Andric LocBucket /= 10; 1618bcb0991SDimitry Andric return LocBucket + 1; 1628bcb0991SDimitry Andric }; 1638bcb0991SDimitry Andric 1648bcb0991SDimitry Andric unsigned CoverageBucket = getCoverageBucket(); 1658bcb0991SDimitry Andric VarParamLocStats[CoverageBucket]++; 1668bcb0991SDimitry Andric if (IsParam) 1678bcb0991SDimitry Andric ParamLocStats[CoverageBucket]++; 1688bcb0991SDimitry Andric else if (IsLocalVar) 169*5ffd83dbSDimitry Andric LocalVarLocStats[CoverageBucket]++; 170*5ffd83dbSDimitry Andric } 171*5ffd83dbSDimitry Andric /// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName 172*5ffd83dbSDimitry Andric /// and DeclLine. The identifier aims to be unique for any unique entities, 173*5ffd83dbSDimitry Andric /// but keeping the same among different instances of the same entity. 174*5ffd83dbSDimitry Andric static std::string constructDieID(DWARFDie Die, 175*5ffd83dbSDimitry Andric StringRef Prefix = StringRef()) { 176*5ffd83dbSDimitry Andric std::string IDStr; 177*5ffd83dbSDimitry Andric llvm::raw_string_ostream ID(IDStr); 178*5ffd83dbSDimitry Andric ID << Prefix 179*5ffd83dbSDimitry Andric << Die.getName(DINameKind::LinkageName); 180*5ffd83dbSDimitry Andric 181*5ffd83dbSDimitry Andric // Prefix + Name is enough for local variables and parameters. 182*5ffd83dbSDimitry Andric if (!Prefix.empty() && !Prefix.equals("g")) 183*5ffd83dbSDimitry Andric return ID.str(); 184*5ffd83dbSDimitry Andric 185*5ffd83dbSDimitry Andric auto DeclFile = Die.findRecursively(dwarf::DW_AT_decl_file); 186*5ffd83dbSDimitry Andric std::string File; 187*5ffd83dbSDimitry Andric if (DeclFile) { 188*5ffd83dbSDimitry Andric DWARFUnit *U = Die.getDwarfUnit(); 189*5ffd83dbSDimitry Andric if (const auto *LT = U->getContext().getLineTableForUnit(U)) 190*5ffd83dbSDimitry Andric if (LT->getFileNameByIndex( 191*5ffd83dbSDimitry Andric dwarf::toUnsigned(DeclFile, 0), U->getCompilationDir(), 192*5ffd83dbSDimitry Andric DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) 193*5ffd83dbSDimitry Andric File = std::string(sys::path::filename(File)); 194*5ffd83dbSDimitry Andric } 195*5ffd83dbSDimitry Andric ID << ":" << (File.empty() ? "/" : File); 196*5ffd83dbSDimitry Andric ID << ":" 197*5ffd83dbSDimitry Andric << dwarf::toUnsigned(Die.findRecursively(dwarf::DW_AT_decl_line), 0); 198*5ffd83dbSDimitry Andric return ID.str(); 1998bcb0991SDimitry Andric } 2008bcb0991SDimitry Andric 2010b57cec5SDimitry Andric /// Collect debug info quality metrics for one DIE. 202480093f4SDimitry Andric static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, 203480093f4SDimitry Andric std::string VarPrefix, uint64_t BytesInScope, 204480093f4SDimitry Andric uint32_t InlineDepth, 2050b57cec5SDimitry Andric StringMap<PerFunctionStats> &FnStatMap, 2068bcb0991SDimitry Andric GlobalStats &GlobalStats, 2078bcb0991SDimitry Andric LocationStats &LocStats) { 2080b57cec5SDimitry Andric bool HasLoc = false; 2090b57cec5SDimitry Andric bool HasSrcLoc = false; 2100b57cec5SDimitry Andric bool HasType = false; 2110b57cec5SDimitry Andric uint64_t BytesCovered = 0; 2128bcb0991SDimitry Andric uint64_t BytesEntryValuesCovered = 0; 2138bcb0991SDimitry Andric auto &FnStats = FnStatMap[FnPrefix]; 2148bcb0991SDimitry Andric bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter; 2158bcb0991SDimitry Andric bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable; 216*5ffd83dbSDimitry Andric bool IsConstantMember = Die.getTag() == dwarf::DW_TAG_member && 217*5ffd83dbSDimitry Andric Die.find(dwarf::DW_AT_const_value); 2180b57cec5SDimitry Andric 2198bcb0991SDimitry Andric if (Die.getTag() == dwarf::DW_TAG_call_site || 2208bcb0991SDimitry Andric Die.getTag() == dwarf::DW_TAG_GNU_call_site) { 2218bcb0991SDimitry Andric GlobalStats.CallSiteDIEs++; 2220b57cec5SDimitry Andric return; 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2258bcb0991SDimitry Andric if (Die.getTag() == dwarf::DW_TAG_call_site_parameter || 2268bcb0991SDimitry Andric Die.getTag() == dwarf::DW_TAG_GNU_call_site_parameter) { 2278bcb0991SDimitry Andric GlobalStats.CallSiteParamDIEs++; 2288bcb0991SDimitry Andric return; 2298bcb0991SDimitry Andric } 2308bcb0991SDimitry Andric 231*5ffd83dbSDimitry Andric if (!IsParam && !IsLocalVar && !IsConstantMember) { 2320b57cec5SDimitry Andric // Not a variable or constant member. 2330b57cec5SDimitry Andric return; 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 236*5ffd83dbSDimitry Andric // Ignore declarations of global variables. 237*5ffd83dbSDimitry Andric if (IsLocalVar && Die.find(dwarf::DW_AT_declaration)) 238*5ffd83dbSDimitry Andric return; 239*5ffd83dbSDimitry Andric 2400b57cec5SDimitry Andric if (Die.findRecursively(dwarf::DW_AT_decl_file) && 2410b57cec5SDimitry Andric Die.findRecursively(dwarf::DW_AT_decl_line)) 2420b57cec5SDimitry Andric HasSrcLoc = true; 2430b57cec5SDimitry Andric 2440b57cec5SDimitry Andric if (Die.findRecursively(dwarf::DW_AT_type)) 2450b57cec5SDimitry Andric HasType = true; 2460b57cec5SDimitry Andric 2478bcb0991SDimitry Andric auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool { 2488bcb0991SDimitry Andric DWARFUnit *U = Die.getDwarfUnit(); 2498bcb0991SDimitry Andric DataExtractor Data(toStringRef(D), 2508bcb0991SDimitry Andric Die.getDwarfUnit()->getContext().isLittleEndian(), 0); 251*5ffd83dbSDimitry Andric DWARFExpression Expression(Data, U->getAddressByteSize(), 252*5ffd83dbSDimitry Andric U->getFormParams().Format); 2538bcb0991SDimitry Andric // Consider the expression containing the DW_OP_entry_value as 2548bcb0991SDimitry Andric // an entry value. 2558bcb0991SDimitry Andric return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { 2568bcb0991SDimitry Andric return Op.getCode() == dwarf::DW_OP_entry_value || 2578bcb0991SDimitry Andric Op.getCode() == dwarf::DW_OP_GNU_entry_value; 2588bcb0991SDimitry Andric }); 2598bcb0991SDimitry Andric }; 2608bcb0991SDimitry Andric 2610b57cec5SDimitry Andric if (Die.find(dwarf::DW_AT_const_value)) { 2620b57cec5SDimitry Andric // This catches constant members *and* variables. 2630b57cec5SDimitry Andric HasLoc = true; 2640b57cec5SDimitry Andric BytesCovered = BytesInScope; 2650b57cec5SDimitry Andric } else { 2660b57cec5SDimitry Andric // Handle variables and function arguments. 267480093f4SDimitry Andric Expected<std::vector<DWARFLocationExpression>> Loc = 268480093f4SDimitry Andric Die.getLocations(dwarf::DW_AT_location); 269480093f4SDimitry Andric if (!Loc) { 270480093f4SDimitry Andric consumeError(Loc.takeError()); 2710b57cec5SDimitry Andric } else { 272480093f4SDimitry Andric HasLoc = true; 273480093f4SDimitry Andric // Get PC coverage. 274480093f4SDimitry Andric auto Default = find_if( 275480093f4SDimitry Andric *Loc, [](const DWARFLocationExpression &L) { return !L.Range; }); 276480093f4SDimitry Andric if (Default != Loc->end()) { 2770b57cec5SDimitry Andric // Assume the entire range is covered by a single location. 2780b57cec5SDimitry Andric BytesCovered = BytesInScope; 279480093f4SDimitry Andric } else { 280480093f4SDimitry Andric for (auto Entry : *Loc) { 281480093f4SDimitry Andric uint64_t BytesEntryCovered = Entry.Range->HighPC - Entry.Range->LowPC; 282480093f4SDimitry Andric BytesCovered += BytesEntryCovered; 283480093f4SDimitry Andric if (IsEntryValue(Entry.Expr)) 284480093f4SDimitry Andric BytesEntryValuesCovered += BytesEntryCovered; 285480093f4SDimitry Andric } 2860b57cec5SDimitry Andric } 2870b57cec5SDimitry Andric } 2880b57cec5SDimitry Andric } 2890b57cec5SDimitry Andric 2908bcb0991SDimitry Andric // Calculate the debug location statistics. 2918bcb0991SDimitry Andric if (BytesInScope) { 2928bcb0991SDimitry Andric LocStats.NumVarParam++; 2938bcb0991SDimitry Andric if (IsParam) 2948bcb0991SDimitry Andric LocStats.NumParam++; 2958bcb0991SDimitry Andric else if (IsLocalVar) 2968bcb0991SDimitry Andric LocStats.NumVar++; 2978bcb0991SDimitry Andric 2988bcb0991SDimitry Andric collectLocStats(BytesCovered, BytesInScope, LocStats.VarParamLocStats, 299*5ffd83dbSDimitry Andric LocStats.ParamLocStats, LocStats.LocalVarLocStats, IsParam, 3008bcb0991SDimitry Andric IsLocalVar); 3018bcb0991SDimitry Andric // Non debug entry values coverage statistics. 3028bcb0991SDimitry Andric collectLocStats(BytesCovered - BytesEntryValuesCovered, BytesInScope, 3038bcb0991SDimitry Andric LocStats.VarParamNonEntryValLocStats, 3048bcb0991SDimitry Andric LocStats.ParamNonEntryValLocStats, 305*5ffd83dbSDimitry Andric LocStats.LocalVarNonEntryValLocStats, IsParam, IsLocalVar); 3068bcb0991SDimitry Andric } 3078bcb0991SDimitry Andric 3080b57cec5SDimitry Andric // Collect PC range coverage data. 3090b57cec5SDimitry Andric if (DWARFDie D = 3100b57cec5SDimitry Andric Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin)) 3110b57cec5SDimitry Andric Die = D; 312*5ffd83dbSDimitry Andric 313*5ffd83dbSDimitry Andric std::string VarID = constructDieID(Die, VarPrefix); 314*5ffd83dbSDimitry Andric FnStats.VarsInFunction.insert(VarID); 315*5ffd83dbSDimitry Andric 3160b57cec5SDimitry Andric if (BytesInScope) { 3170b57cec5SDimitry Andric // Turns out we have a lot of ranges that extend past the lexical scope. 3180b57cec5SDimitry Andric GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered); 319480093f4SDimitry Andric GlobalStats.ScopeBytes += BytesInScope; 3208bcb0991SDimitry Andric GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered; 3218bcb0991SDimitry Andric if (IsParam) { 3228bcb0991SDimitry Andric GlobalStats.ParamScopeBytesCovered += 3238bcb0991SDimitry Andric std::min(BytesInScope, BytesCovered); 324480093f4SDimitry Andric GlobalStats.ParamScopeBytes += BytesInScope; 3258bcb0991SDimitry Andric GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered; 3268bcb0991SDimitry Andric } else if (IsLocalVar) { 327*5ffd83dbSDimitry Andric GlobalStats.LocalVarScopeBytesCovered += 328*5ffd83dbSDimitry Andric std::min(BytesInScope, BytesCovered); 329*5ffd83dbSDimitry Andric GlobalStats.LocalVarScopeBytes += BytesInScope; 330*5ffd83dbSDimitry Andric GlobalStats.LocalVarScopeEntryValueBytesCovered += 331*5ffd83dbSDimitry Andric BytesEntryValuesCovered; 3328bcb0991SDimitry Andric } 333480093f4SDimitry Andric assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes); 3340b57cec5SDimitry Andric } 335*5ffd83dbSDimitry Andric 336*5ffd83dbSDimitry Andric if (IsConstantMember) { 337*5ffd83dbSDimitry Andric FnStats.ConstantMembers++; 338*5ffd83dbSDimitry Andric return; 339*5ffd83dbSDimitry Andric } 340*5ffd83dbSDimitry Andric 341*5ffd83dbSDimitry Andric FnStats.TotalVarWithLoc += (unsigned)HasLoc; 342*5ffd83dbSDimitry Andric 343*5ffd83dbSDimitry Andric if (Die.find(dwarf::DW_AT_artificial)) { 344*5ffd83dbSDimitry Andric FnStats.NumArtificial++; 345*5ffd83dbSDimitry Andric return; 346*5ffd83dbSDimitry Andric } 347*5ffd83dbSDimitry Andric 3488bcb0991SDimitry Andric if (IsParam) { 3490b57cec5SDimitry Andric FnStats.NumParams++; 3500b57cec5SDimitry Andric if (HasType) 3510b57cec5SDimitry Andric FnStats.NumParamTypes++; 3520b57cec5SDimitry Andric if (HasSrcLoc) 3530b57cec5SDimitry Andric FnStats.NumParamSourceLocations++; 3540b57cec5SDimitry Andric if (HasLoc) 3550b57cec5SDimitry Andric FnStats.NumParamLocations++; 3568bcb0991SDimitry Andric } else if (IsLocalVar) { 357*5ffd83dbSDimitry Andric FnStats.NumLocalVars++; 3580b57cec5SDimitry Andric if (HasType) 359*5ffd83dbSDimitry Andric FnStats.NumLocalVarTypes++; 3600b57cec5SDimitry Andric if (HasSrcLoc) 361*5ffd83dbSDimitry Andric FnStats.NumLocalVarSourceLocations++; 3620b57cec5SDimitry Andric if (HasLoc) 363*5ffd83dbSDimitry Andric FnStats.NumLocalVarLocations++; 3640b57cec5SDimitry Andric } 3650b57cec5SDimitry Andric } 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric /// Recursively collect debug info quality metrics. 368480093f4SDimitry Andric static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix, 369480093f4SDimitry Andric std::string VarPrefix, uint64_t BytesInScope, 370480093f4SDimitry Andric uint32_t InlineDepth, 3710b57cec5SDimitry Andric StringMap<PerFunctionStats> &FnStatMap, 3728bcb0991SDimitry Andric GlobalStats &GlobalStats, 3738bcb0991SDimitry Andric LocationStats &LocStats) { 3740b57cec5SDimitry Andric const dwarf::Tag Tag = Die.getTag(); 375*5ffd83dbSDimitry Andric // Skip function types. 376*5ffd83dbSDimitry Andric if (Tag == dwarf::DW_TAG_subroutine_type) 377*5ffd83dbSDimitry Andric return; 378*5ffd83dbSDimitry Andric 379*5ffd83dbSDimitry Andric // Handle any kind of lexical scope. 3800b57cec5SDimitry Andric const bool IsFunction = Tag == dwarf::DW_TAG_subprogram; 3810b57cec5SDimitry Andric const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block; 3820b57cec5SDimitry Andric const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine; 3830b57cec5SDimitry Andric if (IsFunction || IsInlinedFunction || IsBlock) { 3840b57cec5SDimitry Andric 3850b57cec5SDimitry Andric // Reset VarPrefix when entering a new function. 3860b57cec5SDimitry Andric if (Die.getTag() == dwarf::DW_TAG_subprogram || 3870b57cec5SDimitry Andric Die.getTag() == dwarf::DW_TAG_inlined_subroutine) 3880b57cec5SDimitry Andric VarPrefix = "v"; 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric // Ignore forward declarations. 3910b57cec5SDimitry Andric if (Die.find(dwarf::DW_AT_declaration)) 3920b57cec5SDimitry Andric return; 3930b57cec5SDimitry Andric 3940b57cec5SDimitry Andric // Check for call sites. 3950b57cec5SDimitry Andric if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line)) 3960b57cec5SDimitry Andric GlobalStats.CallSiteEntries++; 3970b57cec5SDimitry Andric 3980b57cec5SDimitry Andric // PC Ranges. 3990b57cec5SDimitry Andric auto RangesOrError = Die.getAddressRanges(); 4000b57cec5SDimitry Andric if (!RangesOrError) { 4010b57cec5SDimitry Andric llvm::consumeError(RangesOrError.takeError()); 4020b57cec5SDimitry Andric return; 4030b57cec5SDimitry Andric } 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric auto Ranges = RangesOrError.get(); 4060b57cec5SDimitry Andric uint64_t BytesInThisScope = 0; 4070b57cec5SDimitry Andric for (auto Range : Ranges) 4080b57cec5SDimitry Andric BytesInThisScope += Range.HighPC - Range.LowPC; 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric // Count the function. 4110b57cec5SDimitry Andric if (!IsBlock) { 4120b57cec5SDimitry Andric // Skip over abstract origins. 4130b57cec5SDimitry Andric if (Die.find(dwarf::DW_AT_inline)) 4140b57cec5SDimitry Andric return; 415*5ffd83dbSDimitry Andric std::string FnID = constructDieID(Die); 416*5ffd83dbSDimitry Andric // We've seen an instance of this function. 417*5ffd83dbSDimitry Andric auto &FnStats = FnStatMap[FnID]; 418*5ffd83dbSDimitry Andric FnStats.IsFunction = true; 4190b57cec5SDimitry Andric if (IsInlinedFunction) { 4200b57cec5SDimitry Andric FnStats.NumFnInlined++; 4210b57cec5SDimitry Andric if (Die.findRecursively(dwarf::DW_AT_abstract_origin)) 4220b57cec5SDimitry Andric FnStats.NumAbstractOrigins++; 423*5ffd83dbSDimitry Andric } else { 424*5ffd83dbSDimitry Andric FnStats.NumFnOutOfLine++; 4250b57cec5SDimitry Andric } 4260b57cec5SDimitry Andric if (Die.findRecursively(dwarf::DW_AT_decl_file) && 4270b57cec5SDimitry Andric Die.findRecursively(dwarf::DW_AT_decl_line)) 4280b57cec5SDimitry Andric FnStats.HasSourceLocation = true; 429*5ffd83dbSDimitry Andric // Update function prefix. 430*5ffd83dbSDimitry Andric FnPrefix = FnID; 4310b57cec5SDimitry Andric } 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric if (BytesInThisScope) { 4340b57cec5SDimitry Andric BytesInScope = BytesInThisScope; 4350b57cec5SDimitry Andric if (IsFunction) 4360b57cec5SDimitry Andric GlobalStats.FunctionSize += BytesInThisScope; 4370b57cec5SDimitry Andric else if (IsInlinedFunction && InlineDepth == 0) 4380b57cec5SDimitry Andric GlobalStats.InlineFunctionSize += BytesInThisScope; 4390b57cec5SDimitry Andric } 4400b57cec5SDimitry Andric } else { 4410b57cec5SDimitry Andric // Not a scope, visit the Die itself. It could be a variable. 442480093f4SDimitry Andric collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth, 443480093f4SDimitry Andric FnStatMap, GlobalStats, LocStats); 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric 4460b57cec5SDimitry Andric // Set InlineDepth correctly for child recursion 4470b57cec5SDimitry Andric if (IsFunction) 4480b57cec5SDimitry Andric InlineDepth = 0; 4490b57cec5SDimitry Andric else if (IsInlinedFunction) 4500b57cec5SDimitry Andric ++InlineDepth; 4510b57cec5SDimitry Andric 4520b57cec5SDimitry Andric // Traverse children. 4530b57cec5SDimitry Andric unsigned LexicalBlockIndex = 0; 454*5ffd83dbSDimitry Andric unsigned FormalParameterIndex = 0; 4550b57cec5SDimitry Andric DWARFDie Child = Die.getFirstChild(); 4560b57cec5SDimitry Andric while (Child) { 4570b57cec5SDimitry Andric std::string ChildVarPrefix = VarPrefix; 4580b57cec5SDimitry Andric if (Child.getTag() == dwarf::DW_TAG_lexical_block) 4590b57cec5SDimitry Andric ChildVarPrefix += toHex(LexicalBlockIndex++) + '.'; 460*5ffd83dbSDimitry Andric if (Child.getTag() == dwarf::DW_TAG_formal_parameter) 461*5ffd83dbSDimitry Andric ChildVarPrefix += 'p' + toHex(FormalParameterIndex++) + '.'; 4620b57cec5SDimitry Andric 463480093f4SDimitry Andric collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, BytesInScope, 464480093f4SDimitry Andric InlineDepth, FnStatMap, GlobalStats, LocStats); 4650b57cec5SDimitry Andric Child = Child.getSibling(); 4660b57cec5SDimitry Andric } 4670b57cec5SDimitry Andric } 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric /// Print machine-readable output. 4700b57cec5SDimitry Andric /// The machine-readable format is single-line JSON output. 4710b57cec5SDimitry Andric /// \{ 4728bcb0991SDimitry Andric static void printDatum(raw_ostream &OS, const char *Key, json::Value Value) { 4730b57cec5SDimitry Andric OS << ",\"" << Key << "\":" << Value; 4740b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n'); 4750b57cec5SDimitry Andric } 476*5ffd83dbSDimitry Andric 477*5ffd83dbSDimitry Andric static void printLocationStats(raw_ostream &OS, const char *Key, 4788bcb0991SDimitry Andric std::vector<unsigned> &LocationStats) { 479*5ffd83dbSDimitry Andric OS << ",\"" << Key << " with 0% of parent scope covered by DW_AT_location\":" 4808bcb0991SDimitry Andric << LocationStats[0]; 481*5ffd83dbSDimitry Andric LLVM_DEBUG( 482*5ffd83dbSDimitry Andric llvm::dbgs() << Key 483*5ffd83dbSDimitry Andric << " with 0% of parent scope covered by DW_AT_location: \\" 4848bcb0991SDimitry Andric << LocationStats[0] << '\n'); 485*5ffd83dbSDimitry Andric OS << ",\"" << Key 486*5ffd83dbSDimitry Andric << " with (0%,10%) of parent scope covered by DW_AT_location\":" 4878bcb0991SDimitry Andric << LocationStats[1]; 488*5ffd83dbSDimitry Andric LLVM_DEBUG(llvm::dbgs() 489*5ffd83dbSDimitry Andric << Key 490*5ffd83dbSDimitry Andric << " with (0%,10%) of parent scope covered by DW_AT_location: " 4918bcb0991SDimitry Andric << LocationStats[1] << '\n'); 4928bcb0991SDimitry Andric for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) { 493480093f4SDimitry Andric OS << ",\"" << Key << " with [" << (i - 1) * 10 << "%," << i * 10 494*5ffd83dbSDimitry Andric << "%) of parent scope covered by DW_AT_location\":" << LocationStats[i]; 4958bcb0991SDimitry Andric LLVM_DEBUG(llvm::dbgs() 496480093f4SDimitry Andric << Key << " with [" << (i - 1) * 10 << "%," << i * 10 497*5ffd83dbSDimitry Andric << "%) of parent scope covered by DW_AT_location: " 498*5ffd83dbSDimitry Andric << LocationStats[i]); 4998bcb0991SDimitry Andric } 500*5ffd83dbSDimitry Andric OS << ",\"" << Key 501*5ffd83dbSDimitry Andric << " with 100% of parent scope covered by DW_AT_location\":" 5028bcb0991SDimitry Andric << LocationStats[NumOfCoverageCategories - 1]; 503*5ffd83dbSDimitry Andric LLVM_DEBUG( 504*5ffd83dbSDimitry Andric llvm::dbgs() << Key 505*5ffd83dbSDimitry Andric << " with 100% of parent scope covered by DW_AT_location: " 5068bcb0991SDimitry Andric << LocationStats[NumOfCoverageCategories - 1]); 5078bcb0991SDimitry Andric } 508*5ffd83dbSDimitry Andric 509*5ffd83dbSDimitry Andric static void printSectionSizes(raw_ostream &OS, const SectionSizes &Sizes) { 510*5ffd83dbSDimitry Andric for (const auto &DebugSec : Sizes.DebugSectionSizes) 511*5ffd83dbSDimitry Andric OS << ",\"#bytes in " << DebugSec.getKey() << "\":" << DebugSec.getValue(); 512*5ffd83dbSDimitry Andric } 513*5ffd83dbSDimitry Andric 5140b57cec5SDimitry Andric /// \} 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric /// Collect debug info quality metrics for an entire DIContext. 5170b57cec5SDimitry Andric /// 5180b57cec5SDimitry Andric /// Do the impossible and reduce the quality of the debug info down to a few 5190b57cec5SDimitry Andric /// numbers. The idea is to condense the data into numbers that can be tracked 5200b57cec5SDimitry Andric /// over time to identify trends in newer compiler versions and gauge the effect 5210b57cec5SDimitry Andric /// of particular optimizations. The raw numbers themselves are not particularly 5220b57cec5SDimitry Andric /// useful, only the delta between compiling the same program with different 5230b57cec5SDimitry Andric /// compilers is. 524*5ffd83dbSDimitry Andric bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, 525*5ffd83dbSDimitry Andric const Twine &Filename, 526*5ffd83dbSDimitry Andric raw_ostream &OS) { 5270b57cec5SDimitry Andric StringRef FormatName = Obj.getFileFormatName(); 5280b57cec5SDimitry Andric GlobalStats GlobalStats; 5298bcb0991SDimitry Andric LocationStats LocStats; 5300b57cec5SDimitry Andric StringMap<PerFunctionStats> Statistics; 5310b57cec5SDimitry Andric for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) 5320b57cec5SDimitry Andric if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) 533480093f4SDimitry Andric collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats, 534480093f4SDimitry Andric LocStats); 5350b57cec5SDimitry Andric 536*5ffd83dbSDimitry Andric /// Collect the sizes of debug sections. 537*5ffd83dbSDimitry Andric SectionSizes Sizes; 538*5ffd83dbSDimitry Andric calculateSectionSizes(Obj, Sizes, Filename); 539*5ffd83dbSDimitry Andric 5400b57cec5SDimitry Andric /// The version number should be increased every time the algorithm is changed 5410b57cec5SDimitry Andric /// (including bug fixes). New metrics may be added without increasing the 5420b57cec5SDimitry Andric /// version. 543*5ffd83dbSDimitry Andric unsigned Version = 5; 5440b57cec5SDimitry Andric unsigned VarParamTotal = 0; 5450b57cec5SDimitry Andric unsigned VarParamUnique = 0; 5460b57cec5SDimitry Andric unsigned VarParamWithLoc = 0; 5470b57cec5SDimitry Andric unsigned NumFunctions = 0; 5480b57cec5SDimitry Andric unsigned NumInlinedFunctions = 0; 5490b57cec5SDimitry Andric unsigned NumFuncsWithSrcLoc = 0; 5500b57cec5SDimitry Andric unsigned NumAbstractOrigins = 0; 5510b57cec5SDimitry Andric unsigned ParamTotal = 0; 5520b57cec5SDimitry Andric unsigned ParamWithType = 0; 5530b57cec5SDimitry Andric unsigned ParamWithLoc = 0; 5540b57cec5SDimitry Andric unsigned ParamWithSrcLoc = 0; 555*5ffd83dbSDimitry Andric unsigned LocalVarTotal = 0; 556*5ffd83dbSDimitry Andric unsigned LocalVarWithType = 0; 557*5ffd83dbSDimitry Andric unsigned LocalVarWithSrcLoc = 0; 558*5ffd83dbSDimitry Andric unsigned LocalVarWithLoc = 0; 5590b57cec5SDimitry Andric for (auto &Entry : Statistics) { 5600b57cec5SDimitry Andric PerFunctionStats &Stats = Entry.getValue(); 561*5ffd83dbSDimitry Andric unsigned TotalVars = Stats.VarsInFunction.size() * 562*5ffd83dbSDimitry Andric (Stats.NumFnInlined + Stats.NumFnOutOfLine); 563*5ffd83dbSDimitry Andric // Count variables in global scope. 564*5ffd83dbSDimitry Andric if (!Stats.IsFunction) 565*5ffd83dbSDimitry Andric TotalVars = 566*5ffd83dbSDimitry Andric Stats.NumLocalVars + Stats.ConstantMembers + Stats.NumArtificial; 5670b57cec5SDimitry Andric unsigned Constants = Stats.ConstantMembers; 5680b57cec5SDimitry Andric VarParamWithLoc += Stats.TotalVarWithLoc + Constants; 5690b57cec5SDimitry Andric VarParamTotal += TotalVars; 5700b57cec5SDimitry Andric VarParamUnique += Stats.VarsInFunction.size(); 5710b57cec5SDimitry Andric LLVM_DEBUG(for (auto &V 5720b57cec5SDimitry Andric : Stats.VarsInFunction) llvm::dbgs() 5730b57cec5SDimitry Andric << Entry.getKey() << ": " << V.getKey() << "\n"); 5740b57cec5SDimitry Andric NumFunctions += Stats.IsFunction; 5750b57cec5SDimitry Andric NumFuncsWithSrcLoc += Stats.HasSourceLocation; 5760b57cec5SDimitry Andric NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined; 5770b57cec5SDimitry Andric NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins; 5780b57cec5SDimitry Andric ParamTotal += Stats.NumParams; 5790b57cec5SDimitry Andric ParamWithType += Stats.NumParamTypes; 5800b57cec5SDimitry Andric ParamWithLoc += Stats.NumParamLocations; 5810b57cec5SDimitry Andric ParamWithSrcLoc += Stats.NumParamSourceLocations; 582*5ffd83dbSDimitry Andric LocalVarTotal += Stats.NumLocalVars; 583*5ffd83dbSDimitry Andric LocalVarWithType += Stats.NumLocalVarTypes; 584*5ffd83dbSDimitry Andric LocalVarWithLoc += Stats.NumLocalVarLocations; 585*5ffd83dbSDimitry Andric LocalVarWithSrcLoc += Stats.NumLocalVarSourceLocations; 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric 5880b57cec5SDimitry Andric // Print summary. 5890b57cec5SDimitry Andric OS.SetBufferSize(1024); 5900b57cec5SDimitry Andric OS << "{\"version\":" << Version; 5910b57cec5SDimitry Andric LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n"; 5920b57cec5SDimitry Andric llvm::dbgs() << "---------------------------------\n"); 593*5ffd83dbSDimitry Andric 5940b57cec5SDimitry Andric printDatum(OS, "file", Filename.str()); 5950b57cec5SDimitry Andric printDatum(OS, "format", FormatName); 596*5ffd83dbSDimitry Andric 597*5ffd83dbSDimitry Andric printDatum(OS, "#functions", NumFunctions); 598*5ffd83dbSDimitry Andric printDatum(OS, "#functions with location", NumFuncsWithSrcLoc); 599*5ffd83dbSDimitry Andric printDatum(OS, "#inlined functions", NumInlinedFunctions); 600*5ffd83dbSDimitry Andric printDatum(OS, "#inlined functions with abstract origins", 601*5ffd83dbSDimitry Andric NumAbstractOrigins); 602*5ffd83dbSDimitry Andric 603*5ffd83dbSDimitry Andric // This includes local variables and formal parameters. 604*5ffd83dbSDimitry Andric printDatum(OS, "#unique source variables", VarParamUnique); 605*5ffd83dbSDimitry Andric printDatum(OS, "#source variables", VarParamTotal); 606*5ffd83dbSDimitry Andric printDatum(OS, "#source variables with location", VarParamWithLoc); 607*5ffd83dbSDimitry Andric 608*5ffd83dbSDimitry Andric printDatum(OS, "#call site entries", GlobalStats.CallSiteEntries); 609*5ffd83dbSDimitry Andric printDatum(OS, "#call site DIEs", GlobalStats.CallSiteDIEs); 610*5ffd83dbSDimitry Andric printDatum(OS, "#call site parameter DIEs", GlobalStats.CallSiteParamDIEs); 611*5ffd83dbSDimitry Andric 612*5ffd83dbSDimitry Andric printDatum(OS, "sum_all_variables(#bytes in parent scope)", 613*5ffd83dbSDimitry Andric GlobalStats.ScopeBytes); 614*5ffd83dbSDimitry Andric printDatum(OS, 615*5ffd83dbSDimitry Andric "sum_all_variables(#bytes in parent scope covered by " 616*5ffd83dbSDimitry Andric "DW_AT_location)", 617*5ffd83dbSDimitry Andric GlobalStats.ScopeBytesCovered); 618*5ffd83dbSDimitry Andric printDatum(OS, 619*5ffd83dbSDimitry Andric "sum_all_variables(#bytes in parent scope covered by " 620*5ffd83dbSDimitry Andric "DW_OP_entry_value)", 6218bcb0991SDimitry Andric GlobalStats.ScopeEntryValueBytesCovered); 622*5ffd83dbSDimitry Andric 623*5ffd83dbSDimitry Andric printDatum(OS, "sum_all_params(#bytes in parent scope)", 624480093f4SDimitry Andric GlobalStats.ParamScopeBytes); 625*5ffd83dbSDimitry Andric printDatum( 626*5ffd83dbSDimitry Andric OS, 627*5ffd83dbSDimitry Andric "sum_all_params(#bytes in parent scope covered by DW_AT_location)", 6288bcb0991SDimitry Andric GlobalStats.ParamScopeBytesCovered); 629*5ffd83dbSDimitry Andric printDatum(OS, 630*5ffd83dbSDimitry Andric "sum_all_params(#bytes in parent scope covered by " 631*5ffd83dbSDimitry Andric "DW_OP_entry_value)", 6328bcb0991SDimitry Andric GlobalStats.ParamScopeEntryValueBytesCovered); 633*5ffd83dbSDimitry Andric 634*5ffd83dbSDimitry Andric printDatum(OS, "sum_all_local_vars(#bytes in parent scope)", 635*5ffd83dbSDimitry Andric GlobalStats.LocalVarScopeBytes); 636*5ffd83dbSDimitry Andric printDatum(OS, 637*5ffd83dbSDimitry Andric "sum_all_local_vars(#bytes in parent scope covered by " 638*5ffd83dbSDimitry Andric "DW_AT_location)", 639*5ffd83dbSDimitry Andric GlobalStats.LocalVarScopeBytesCovered); 640*5ffd83dbSDimitry Andric printDatum(OS, 641*5ffd83dbSDimitry Andric "sum_all_local_vars(#bytes in parent scope covered by " 642*5ffd83dbSDimitry Andric "DW_OP_entry_value)", 643*5ffd83dbSDimitry Andric GlobalStats.LocalVarScopeEntryValueBytesCovered); 644*5ffd83dbSDimitry Andric 645*5ffd83dbSDimitry Andric printDatum(OS, "#bytes witin functions", GlobalStats.FunctionSize); 646*5ffd83dbSDimitry Andric printDatum(OS, "#bytes witin inlined functions", 647*5ffd83dbSDimitry Andric GlobalStats.InlineFunctionSize); 648*5ffd83dbSDimitry Andric 649*5ffd83dbSDimitry Andric // Print the summary for formal parameters. 650*5ffd83dbSDimitry Andric printDatum(OS, "#params", ParamTotal); 651*5ffd83dbSDimitry Andric printDatum(OS, "#params with source location", ParamWithSrcLoc); 652*5ffd83dbSDimitry Andric printDatum(OS, "#params with type", ParamWithType); 653*5ffd83dbSDimitry Andric printDatum(OS, "#params with binary location", ParamWithLoc); 654*5ffd83dbSDimitry Andric 655*5ffd83dbSDimitry Andric // Print the summary for local variables. 656*5ffd83dbSDimitry Andric printDatum(OS, "#local vars", LocalVarTotal); 657*5ffd83dbSDimitry Andric printDatum(OS, "#local vars with source location", LocalVarWithSrcLoc); 658*5ffd83dbSDimitry Andric printDatum(OS, "#local vars with type", LocalVarWithType); 659*5ffd83dbSDimitry Andric printDatum(OS, "#local vars with binary location", LocalVarWithLoc); 660*5ffd83dbSDimitry Andric 661*5ffd83dbSDimitry Andric // Print the debug section sizes. 662*5ffd83dbSDimitry Andric printSectionSizes(OS, Sizes); 663*5ffd83dbSDimitry Andric 664*5ffd83dbSDimitry Andric // Print the location statistics for variables (includes local variables 665*5ffd83dbSDimitry Andric // and formal parameters). 666*5ffd83dbSDimitry Andric printDatum(OS, "#variables processed by location statistics", 6678bcb0991SDimitry Andric LocStats.NumVarParam); 668*5ffd83dbSDimitry Andric printLocationStats(OS, "#variables", LocStats.VarParamLocStats); 669*5ffd83dbSDimitry Andric printLocationStats(OS, "#variables - entry values", 6708bcb0991SDimitry Andric LocStats.VarParamNonEntryValLocStats); 671*5ffd83dbSDimitry Andric 672*5ffd83dbSDimitry Andric // Print the location statistics for formal parameters. 673*5ffd83dbSDimitry Andric printDatum(OS, "#params processed by location statistics", LocStats.NumParam); 674*5ffd83dbSDimitry Andric printLocationStats(OS, "#params", LocStats.ParamLocStats); 675*5ffd83dbSDimitry Andric printLocationStats(OS, "#params - entry values", 6768bcb0991SDimitry Andric LocStats.ParamNonEntryValLocStats); 677*5ffd83dbSDimitry Andric 678*5ffd83dbSDimitry Andric // Print the location statistics for local variables. 679*5ffd83dbSDimitry Andric printDatum(OS, "#local vars processed by location statistics", 680*5ffd83dbSDimitry Andric LocStats.NumVar); 681*5ffd83dbSDimitry Andric printLocationStats(OS, "#local vars", LocStats.LocalVarLocStats); 682*5ffd83dbSDimitry Andric printLocationStats(OS, "#local vars - entry values", 683*5ffd83dbSDimitry Andric LocStats.LocalVarNonEntryValLocStats); 6840b57cec5SDimitry Andric OS << "}\n"; 6850b57cec5SDimitry Andric LLVM_DEBUG( 6860b57cec5SDimitry Andric llvm::dbgs() << "Total Availability: " 6870b57cec5SDimitry Andric << (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal) 6880b57cec5SDimitry Andric << "%\n"; 6890b57cec5SDimitry Andric llvm::dbgs() << "PC Ranges covered: " 6900b57cec5SDimitry Andric << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) / 691480093f4SDimitry Andric GlobalStats.ScopeBytes) 6920b57cec5SDimitry Andric << "%\n"); 6930b57cec5SDimitry Andric return true; 6940b57cec5SDimitry Andric } 695