1 #include "llvm/ADT/DenseMap.h" 2 #include "llvm/ADT/StringExtras.h" 3 #include "llvm/ADT/StringSet.h" 4 #include "llvm/DebugInfo/DIContext.h" 5 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 6 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" 7 #include "llvm/Object/ObjectFile.h" 8 #include "llvm/Support/JSON.h" 9 10 #define DEBUG_TYPE "dwarfdump" 11 using namespace llvm; 12 using namespace object; 13 14 /// This represents the number of categories of debug location coverage being 15 /// calculated. The first category is the number of variables with 0% location 16 /// coverage, but the last category is the number of variables with 100% 17 /// location coverage. 18 constexpr int NumOfCoverageCategories = 12; 19 20 /// Holds statistics for one function (or other entity that has a PC range and 21 /// contains variables, such as a compile unit). 22 struct PerFunctionStats { 23 /// Number of inlined instances of this function. 24 unsigned NumFnInlined = 0; 25 /// Number of inlined instances that have abstract origins. 26 unsigned NumAbstractOrigins = 0; 27 /// Number of variables and parameters with location across all inlined 28 /// instances. 29 unsigned TotalVarWithLoc = 0; 30 /// Number of constants with location across all inlined instances. 31 unsigned ConstantMembers = 0; 32 /// List of all Variables and parameters in this function. 33 StringSet<> VarsInFunction; 34 /// Compile units also cover a PC range, but have this flag set to false. 35 bool IsFunction = false; 36 /// Verify function definition has PC addresses (for detecting when 37 /// a function has been inlined everywhere). 38 bool HasPCAddresses = false; 39 /// Function has source location information. 40 bool HasSourceLocation = false; 41 /// Number of function parameters. 42 unsigned NumParams = 0; 43 /// Number of function parameters with source location. 44 unsigned NumParamSourceLocations = 0; 45 /// Number of function parameters with type. 46 unsigned NumParamTypes = 0; 47 /// Number of function parameters with a DW_AT_location. 48 unsigned NumParamLocations = 0; 49 /// Number of variables. 50 unsigned NumVars = 0; 51 /// Number of variables with source location. 52 unsigned NumVarSourceLocations = 0; 53 /// Number of variables with type. 54 unsigned NumVarTypes = 0; 55 /// Number of variables with DW_AT_location. 56 unsigned NumVarLocations = 0; 57 }; 58 59 /// Holds accumulated global statistics about DIEs. 60 struct GlobalStats { 61 /// Total number of PC range bytes covered by DW_AT_locations. 62 unsigned ScopeBytesCovered = 0; 63 /// Total number of PC range bytes in each variable's enclosing scope, 64 /// starting from the first definition of the variable. 65 unsigned ScopeBytesFromFirstDefinition = 0; 66 /// Total number of PC range bytes covered by DW_AT_locations with 67 /// the debug entry values (DW_OP_entry_value). 68 unsigned ScopeEntryValueBytesCovered = 0; 69 /// Total number of PC range bytes covered by DW_AT_locations of 70 /// formal parameters. 71 unsigned ParamScopeBytesCovered = 0; 72 /// Total number of PC range bytes in each variable's enclosing scope, 73 /// starting from the first definition of the variable (only for parameters). 74 unsigned ParamScopeBytesFromFirstDefinition = 0; 75 /// Total number of PC range bytes covered by DW_AT_locations with 76 /// the debug entry values (DW_OP_entry_value) (only for parameters). 77 unsigned ParamScopeEntryValueBytesCovered = 0; 78 /// Total number of PC range bytes covered by DW_AT_locations (only for local 79 /// variables). 80 unsigned VarScopeBytesCovered = 0; 81 /// Total number of PC range bytes in each variable's enclosing scope, 82 /// starting from the first definition of the variable (only for local 83 /// variables). 84 unsigned VarScopeBytesFromFirstDefinition = 0; 85 /// Total number of PC range bytes covered by DW_AT_locations with 86 /// the debug entry values (DW_OP_entry_value) (only for local variables). 87 unsigned VarScopeEntryValueBytesCovered = 0; 88 /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line). 89 unsigned CallSiteEntries = 0; 90 /// Total number of call site DIEs (DW_TAG_call_site). 91 unsigned CallSiteDIEs = 0; 92 /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter). 93 unsigned CallSiteParamDIEs = 0; 94 /// Total byte size of concrete functions. This byte size includes 95 /// inline functions contained in the concrete functions. 96 unsigned FunctionSize = 0; 97 /// Total byte size of inlined functions. This is the total number of bytes 98 /// for the top inline functions within concrete functions. This can help 99 /// tune the inline settings when compiling to match user expectations. 100 unsigned InlineFunctionSize = 0; 101 }; 102 103 /// Holds accumulated debug location statistics about local variables and 104 /// formal parameters. 105 struct LocationStats { 106 /// Map the scope coverage decile to the number of variables in the decile. 107 /// The first element of the array (at the index zero) represents the number 108 /// of variables with the no debug location at all, but the last element 109 /// in the vector represents the number of fully covered variables within 110 /// its scope. 111 std::vector<unsigned> VarParamLocStats{ 112 std::vector<unsigned>(NumOfCoverageCategories, 0)}; 113 /// Map non debug entry values coverage. 114 std::vector<unsigned> VarParamNonEntryValLocStats{ 115 std::vector<unsigned>(NumOfCoverageCategories, 0)}; 116 /// The debug location statistics for formal parameters. 117 std::vector<unsigned> ParamLocStats{ 118 std::vector<unsigned>(NumOfCoverageCategories, 0)}; 119 /// Map non debug entry values coverage for formal parameters. 120 std::vector<unsigned> ParamNonEntryValLocStats{ 121 std::vector<unsigned>(NumOfCoverageCategories, 0)}; 122 /// The debug location statistics for local variables. 123 std::vector<unsigned> VarLocStats{ 124 std::vector<unsigned>(NumOfCoverageCategories, 0)}; 125 /// Map non debug entry values coverage for local variables. 126 std::vector<unsigned> VarNonEntryValLocStats{ 127 std::vector<unsigned>(NumOfCoverageCategories, 0)}; 128 /// Total number of local variables and function parameters processed. 129 unsigned NumVarParam = 0; 130 /// Total number of formal parameters processed. 131 unsigned NumParam = 0; 132 /// Total number of local variables processed. 133 unsigned NumVar = 0; 134 }; 135 136 /// Extract the low pc from a Die. 137 static uint64_t getLowPC(DWARFDie Die) { 138 auto RangesOrError = Die.getAddressRanges(); 139 DWARFAddressRangesVector Ranges; 140 if (RangesOrError) 141 Ranges = RangesOrError.get(); 142 else 143 llvm::consumeError(RangesOrError.takeError()); 144 if (Ranges.size()) 145 return Ranges[0].LowPC; 146 return dwarf::toAddress(Die.find(dwarf::DW_AT_low_pc), 0); 147 } 148 149 /// Collect debug location statistics for one DIE. 150 static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope, 151 std::vector<unsigned> &VarParamLocStats, 152 std::vector<unsigned> &ParamLocStats, 153 std::vector<unsigned> &VarLocStats, bool IsParam, 154 bool IsLocalVar) { 155 auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned { 156 unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope; 157 if (LocBucket == 0) { 158 // No debug location at all for the variable. 159 return 0; 160 } else if (LocBucket == 100 || BytesCovered > BytesInScope) { 161 // Fully covered variable within its scope. 162 return NumOfCoverageCategories - 1; 163 } else { 164 // Get covered range (e.g. 20%-29%). 165 LocBucket /= 10; 166 return LocBucket + 1; 167 } 168 }; 169 170 unsigned CoverageBucket = getCoverageBucket(); 171 VarParamLocStats[CoverageBucket]++; 172 if (IsParam) 173 ParamLocStats[CoverageBucket]++; 174 else if (IsLocalVar) 175 VarLocStats[CoverageBucket]++; 176 } 177 178 /// Collect debug info quality metrics for one DIE. 179 static void collectStatsForDie(DWARFDie Die, uint64_t UnitLowPC, std::string FnPrefix, 180 std::string VarPrefix, uint64_t ScopeLowPC, 181 uint64_t BytesInScope, uint32_t InlineDepth, 182 StringMap<PerFunctionStats> &FnStatMap, 183 GlobalStats &GlobalStats, 184 LocationStats &LocStats) { 185 bool HasLoc = false; 186 bool HasSrcLoc = false; 187 bool HasType = false; 188 bool IsArtificial = false; 189 uint64_t BytesCovered = 0; 190 uint64_t BytesEntryValuesCovered = 0; 191 uint64_t OffsetToFirstDefinition = 0; 192 auto &FnStats = FnStatMap[FnPrefix]; 193 bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter; 194 bool IsLocalVar = Die.getTag() == dwarf::DW_TAG_variable; 195 196 if (Die.getTag() == dwarf::DW_TAG_call_site || 197 Die.getTag() == dwarf::DW_TAG_GNU_call_site) { 198 GlobalStats.CallSiteDIEs++; 199 return; 200 } 201 202 if (Die.getTag() == dwarf::DW_TAG_call_site_parameter || 203 Die.getTag() == dwarf::DW_TAG_GNU_call_site_parameter) { 204 GlobalStats.CallSiteParamDIEs++; 205 return; 206 } 207 208 if (!IsParam && !IsLocalVar && Die.getTag() != dwarf::DW_TAG_member) { 209 // Not a variable or constant member. 210 return; 211 } 212 213 if (Die.findRecursively(dwarf::DW_AT_decl_file) && 214 Die.findRecursively(dwarf::DW_AT_decl_line)) 215 HasSrcLoc = true; 216 217 if (Die.findRecursively(dwarf::DW_AT_type)) 218 HasType = true; 219 220 if (Die.find(dwarf::DW_AT_artificial)) 221 IsArtificial = true; 222 223 auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool { 224 DWARFUnit *U = Die.getDwarfUnit(); 225 DataExtractor Data(toStringRef(D), 226 Die.getDwarfUnit()->getContext().isLittleEndian(), 0); 227 DWARFExpression Expression(Data, U->getVersion(), U->getAddressByteSize()); 228 // Consider the expression containing the DW_OP_entry_value as 229 // an entry value. 230 return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) { 231 return Op.getCode() == dwarf::DW_OP_entry_value || 232 Op.getCode() == dwarf::DW_OP_GNU_entry_value; 233 }); 234 }; 235 236 if (Die.find(dwarf::DW_AT_const_value)) { 237 // This catches constant members *and* variables. 238 HasLoc = true; 239 BytesCovered = BytesInScope; 240 } else { 241 if (Die.getTag() == dwarf::DW_TAG_member) { 242 // Non-const member. 243 return; 244 } 245 // Handle variables and function arguments. 246 auto FormValue = Die.find(dwarf::DW_AT_location); 247 HasLoc = FormValue.hasValue(); 248 if (HasLoc) { 249 // Get PC coverage. 250 if (auto DebugLocOffset = FormValue->getAsSectionOffset()) { 251 auto *DebugLoc = Die.getDwarfUnit()->getContext().getDebugLoc(); 252 if (auto List = DebugLoc->getLocationListAtOffset(*DebugLocOffset)) { 253 for (auto Entry : List->Entries) { 254 uint64_t BytesEntryCovered = Entry.End - Entry.Begin; 255 BytesCovered += BytesEntryCovered; 256 if (IsEntryValue(Entry.Loc)) 257 BytesEntryValuesCovered += BytesEntryCovered; 258 } 259 if (List->Entries.size()) { 260 uint64_t FirstDef = List->Entries[0].Begin; 261 uint64_t UnitOfs = UnitLowPC; 262 // Ranges sometimes start before the lexical scope. 263 if (UnitOfs + FirstDef >= ScopeLowPC) 264 OffsetToFirstDefinition = UnitOfs + FirstDef - ScopeLowPC; 265 // Or even after it. Count that as a failure. 266 if (OffsetToFirstDefinition > BytesInScope) 267 OffsetToFirstDefinition = 0; 268 } 269 } 270 assert(BytesInScope); 271 } else { 272 // Assume the entire range is covered by a single location. 273 BytesCovered = BytesInScope; 274 } 275 } 276 } 277 278 // Calculate the debug location statistics. 279 if (BytesInScope) { 280 LocStats.NumVarParam++; 281 if (IsParam) 282 LocStats.NumParam++; 283 else if (IsLocalVar) 284 LocStats.NumVar++; 285 286 collectLocStats(BytesCovered, BytesInScope, LocStats.VarParamLocStats, 287 LocStats.ParamLocStats, LocStats.VarLocStats, IsParam, 288 IsLocalVar); 289 // Non debug entry values coverage statistics. 290 collectLocStats(BytesCovered - BytesEntryValuesCovered, BytesInScope, 291 LocStats.VarParamNonEntryValLocStats, 292 LocStats.ParamNonEntryValLocStats, 293 LocStats.VarNonEntryValLocStats, IsParam, IsLocalVar); 294 } 295 296 // Collect PC range coverage data. 297 if (DWARFDie D = 298 Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin)) 299 Die = D; 300 // By using the variable name + the path through the lexical block tree, the 301 // keys are consistent across duplicate abstract origins in different CUs. 302 std::string VarName = StringRef(Die.getName(DINameKind::ShortName)); 303 FnStats.VarsInFunction.insert(VarPrefix + VarName); 304 if (BytesInScope) { 305 FnStats.TotalVarWithLoc += (unsigned)HasLoc; 306 // Adjust for the fact the variables often start their lifetime in the 307 // middle of the scope. 308 BytesInScope -= OffsetToFirstDefinition; 309 // Turns out we have a lot of ranges that extend past the lexical scope. 310 GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered); 311 GlobalStats.ScopeBytesFromFirstDefinition += BytesInScope; 312 GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered; 313 if (IsParam) { 314 GlobalStats.ParamScopeBytesCovered += 315 std::min(BytesInScope, BytesCovered); 316 GlobalStats.ParamScopeBytesFromFirstDefinition += BytesInScope; 317 GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered; 318 } else if (IsLocalVar) { 319 GlobalStats.VarScopeBytesCovered += std::min(BytesInScope, BytesCovered); 320 GlobalStats.VarScopeBytesFromFirstDefinition += BytesInScope; 321 GlobalStats.VarScopeEntryValueBytesCovered += BytesEntryValuesCovered; 322 } 323 assert(GlobalStats.ScopeBytesCovered <= 324 GlobalStats.ScopeBytesFromFirstDefinition); 325 } else if (Die.getTag() == dwarf::DW_TAG_member) { 326 FnStats.ConstantMembers++; 327 } else { 328 FnStats.TotalVarWithLoc += (unsigned)HasLoc; 329 } 330 if (!IsArtificial) { 331 if (IsParam) { 332 FnStats.NumParams++; 333 if (HasType) 334 FnStats.NumParamTypes++; 335 if (HasSrcLoc) 336 FnStats.NumParamSourceLocations++; 337 if (HasLoc) 338 FnStats.NumParamLocations++; 339 } else if (IsLocalVar) { 340 FnStats.NumVars++; 341 if (HasType) 342 FnStats.NumVarTypes++; 343 if (HasSrcLoc) 344 FnStats.NumVarSourceLocations++; 345 if (HasLoc) 346 FnStats.NumVarLocations++; 347 } 348 } 349 } 350 351 /// Recursively collect debug info quality metrics. 352 static void collectStatsRecursive(DWARFDie Die, uint64_t UnitLowPC, std::string FnPrefix, 353 std::string VarPrefix, uint64_t ScopeLowPC, 354 uint64_t BytesInScope, uint32_t InlineDepth, 355 StringMap<PerFunctionStats> &FnStatMap, 356 GlobalStats &GlobalStats, 357 LocationStats &LocStats) { 358 // Handle any kind of lexical scope. 359 const dwarf::Tag Tag = Die.getTag(); 360 const bool IsFunction = Tag == dwarf::DW_TAG_subprogram; 361 const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block; 362 const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine; 363 if (IsFunction || IsInlinedFunction || IsBlock) { 364 365 // Reset VarPrefix when entering a new function. 366 if (Die.getTag() == dwarf::DW_TAG_subprogram || 367 Die.getTag() == dwarf::DW_TAG_inlined_subroutine) 368 VarPrefix = "v"; 369 370 // Ignore forward declarations. 371 if (Die.find(dwarf::DW_AT_declaration)) 372 return; 373 374 // Check for call sites. 375 if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line)) 376 GlobalStats.CallSiteEntries++; 377 378 // PC Ranges. 379 auto RangesOrError = Die.getAddressRanges(); 380 if (!RangesOrError) { 381 llvm::consumeError(RangesOrError.takeError()); 382 return; 383 } 384 385 auto Ranges = RangesOrError.get(); 386 uint64_t BytesInThisScope = 0; 387 for (auto Range : Ranges) 388 BytesInThisScope += Range.HighPC - Range.LowPC; 389 ScopeLowPC = getLowPC(Die); 390 391 // Count the function. 392 if (!IsBlock) { 393 StringRef Name = Die.getName(DINameKind::LinkageName); 394 if (Name.empty()) 395 Name = Die.getName(DINameKind::ShortName); 396 FnPrefix = Name; 397 // Skip over abstract origins. 398 if (Die.find(dwarf::DW_AT_inline)) 399 return; 400 // We've seen an (inlined) instance of this function. 401 auto &FnStats = FnStatMap[Name]; 402 if (IsInlinedFunction) { 403 FnStats.NumFnInlined++; 404 if (Die.findRecursively(dwarf::DW_AT_abstract_origin)) 405 FnStats.NumAbstractOrigins++; 406 } 407 FnStats.IsFunction = true; 408 if (BytesInThisScope && !IsInlinedFunction) 409 FnStats.HasPCAddresses = true; 410 std::string FnName = StringRef(Die.getName(DINameKind::ShortName)); 411 if (Die.findRecursively(dwarf::DW_AT_decl_file) && 412 Die.findRecursively(dwarf::DW_AT_decl_line)) 413 FnStats.HasSourceLocation = true; 414 } 415 416 if (BytesInThisScope) { 417 BytesInScope = BytesInThisScope; 418 if (IsFunction) 419 GlobalStats.FunctionSize += BytesInThisScope; 420 else if (IsInlinedFunction && InlineDepth == 0) 421 GlobalStats.InlineFunctionSize += BytesInThisScope; 422 } 423 } else { 424 // Not a scope, visit the Die itself. It could be a variable. 425 collectStatsForDie(Die, UnitLowPC, FnPrefix, VarPrefix, ScopeLowPC, BytesInScope, 426 InlineDepth, FnStatMap, GlobalStats, LocStats); 427 } 428 429 // Set InlineDepth correctly for child recursion 430 if (IsFunction) 431 InlineDepth = 0; 432 else if (IsInlinedFunction) 433 ++InlineDepth; 434 435 // Traverse children. 436 unsigned LexicalBlockIndex = 0; 437 DWARFDie Child = Die.getFirstChild(); 438 while (Child) { 439 std::string ChildVarPrefix = VarPrefix; 440 if (Child.getTag() == dwarf::DW_TAG_lexical_block) 441 ChildVarPrefix += toHex(LexicalBlockIndex++) + '.'; 442 443 collectStatsRecursive(Child, UnitLowPC, FnPrefix, ChildVarPrefix, ScopeLowPC, 444 BytesInScope, InlineDepth, FnStatMap, GlobalStats, 445 LocStats); 446 Child = Child.getSibling(); 447 } 448 } 449 450 /// Print machine-readable output. 451 /// The machine-readable format is single-line JSON output. 452 /// \{ 453 static void printDatum(raw_ostream &OS, const char *Key, json::Value Value) { 454 OS << ",\"" << Key << "\":" << Value; 455 LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n'); 456 } 457 static void printLocationStats(raw_ostream &OS, 458 const char *Key, 459 std::vector<unsigned> &LocationStats) { 460 OS << ",\"" << Key << " with 0% of its scope covered\":" 461 << LocationStats[0]; 462 LLVM_DEBUG(llvm::dbgs() << Key << " with 0% of its scope covered: " 463 << LocationStats[0] << '\n'); 464 OS << ",\"" << Key << " with 1-9% of its scope covered\":" 465 << LocationStats[1]; 466 LLVM_DEBUG(llvm::dbgs() << Key << " with 1-9% of its scope covered: " 467 << LocationStats[1] << '\n'); 468 for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) { 469 OS << ",\"" << Key << " with " << (i - 1) * 10 << "-" << i * 10 - 1 470 << "% of its scope covered\":" << LocationStats[i]; 471 LLVM_DEBUG(llvm::dbgs() 472 << Key << " with " << (i - 1) * 10 << "-" << i * 10 - 1 473 << "% of its scope covered: " << LocationStats[i]); 474 } 475 OS << ",\"" << Key << " with 100% of its scope covered\":" 476 << LocationStats[NumOfCoverageCategories - 1]; 477 LLVM_DEBUG(llvm::dbgs() << Key << " with 100% of its scope covered: " 478 << LocationStats[NumOfCoverageCategories - 1]); 479 } 480 /// \} 481 482 /// Collect debug info quality metrics for an entire DIContext. 483 /// 484 /// Do the impossible and reduce the quality of the debug info down to a few 485 /// numbers. The idea is to condense the data into numbers that can be tracked 486 /// over time to identify trends in newer compiler versions and gauge the effect 487 /// of particular optimizations. The raw numbers themselves are not particularly 488 /// useful, only the delta between compiling the same program with different 489 /// compilers is. 490 bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, 491 Twine Filename, raw_ostream &OS) { 492 StringRef FormatName = Obj.getFileFormatName(); 493 GlobalStats GlobalStats; 494 LocationStats LocStats; 495 StringMap<PerFunctionStats> Statistics; 496 for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) 497 if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) 498 collectStatsRecursive(CUDie, getLowPC(CUDie), "/", "g", 0, 0, 0, 499 Statistics, GlobalStats, LocStats); 500 501 /// The version number should be increased every time the algorithm is changed 502 /// (including bug fixes). New metrics may be added without increasing the 503 /// version. 504 unsigned Version = 3; 505 unsigned VarParamTotal = 0; 506 unsigned VarParamUnique = 0; 507 unsigned VarParamWithLoc = 0; 508 unsigned NumFunctions = 0; 509 unsigned NumInlinedFunctions = 0; 510 unsigned NumFuncsWithSrcLoc = 0; 511 unsigned NumAbstractOrigins = 0; 512 unsigned ParamTotal = 0; 513 unsigned ParamWithType = 0; 514 unsigned ParamWithLoc = 0; 515 unsigned ParamWithSrcLoc = 0; 516 unsigned VarTotal = 0; 517 unsigned VarWithType = 0; 518 unsigned VarWithSrcLoc = 0; 519 unsigned VarWithLoc = 0; 520 for (auto &Entry : Statistics) { 521 PerFunctionStats &Stats = Entry.getValue(); 522 unsigned TotalVars = Stats.VarsInFunction.size() * Stats.NumFnInlined; 523 // Count variables in concrete out-of-line functions and in global scope. 524 if (Stats.HasPCAddresses || !Stats.IsFunction) 525 TotalVars += Stats.VarsInFunction.size(); 526 unsigned Constants = Stats.ConstantMembers; 527 VarParamWithLoc += Stats.TotalVarWithLoc + Constants; 528 VarParamTotal += TotalVars; 529 VarParamUnique += Stats.VarsInFunction.size(); 530 LLVM_DEBUG(for (auto &V 531 : Stats.VarsInFunction) llvm::dbgs() 532 << Entry.getKey() << ": " << V.getKey() << "\n"); 533 NumFunctions += Stats.IsFunction; 534 NumFuncsWithSrcLoc += Stats.HasSourceLocation; 535 NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined; 536 NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins; 537 ParamTotal += Stats.NumParams; 538 ParamWithType += Stats.NumParamTypes; 539 ParamWithLoc += Stats.NumParamLocations; 540 ParamWithSrcLoc += Stats.NumParamSourceLocations; 541 VarTotal += Stats.NumVars; 542 VarWithType += Stats.NumVarTypes; 543 VarWithLoc += Stats.NumVarLocations; 544 VarWithSrcLoc += Stats.NumVarSourceLocations; 545 } 546 547 // Print summary. 548 OS.SetBufferSize(1024); 549 OS << "{\"version\":" << Version; 550 LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n"; 551 llvm::dbgs() << "---------------------------------\n"); 552 printDatum(OS, "file", Filename.str()); 553 printDatum(OS, "format", FormatName); 554 printDatum(OS, "source functions", NumFunctions); 555 printDatum(OS, "source functions with location", NumFuncsWithSrcLoc); 556 printDatum(OS, "inlined functions", NumInlinedFunctions); 557 printDatum(OS, "inlined funcs with abstract origins", NumAbstractOrigins); 558 printDatum(OS, "unique source variables", VarParamUnique); 559 printDatum(OS, "source variables", VarParamTotal); 560 printDatum(OS, "variables with location", VarParamWithLoc); 561 printDatum(OS, "call site entries", GlobalStats.CallSiteEntries); 562 printDatum(OS, "call site DIEs", GlobalStats.CallSiteDIEs); 563 printDatum(OS, "call site parameter DIEs", GlobalStats.CallSiteParamDIEs); 564 printDatum(OS, "scope bytes total", 565 GlobalStats.ScopeBytesFromFirstDefinition); 566 printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered); 567 printDatum(OS, "entry value scope bytes covered", 568 GlobalStats.ScopeEntryValueBytesCovered); 569 printDatum(OS, "formal params scope bytes total", 570 GlobalStats.ParamScopeBytesFromFirstDefinition); 571 printDatum(OS, "formal params scope bytes covered", 572 GlobalStats.ParamScopeBytesCovered); 573 printDatum(OS, "formal params entry value scope bytes covered", 574 GlobalStats.ParamScopeEntryValueBytesCovered); 575 printDatum(OS, "vars scope bytes total", 576 GlobalStats.VarScopeBytesFromFirstDefinition); 577 printDatum(OS, "vars scope bytes covered", GlobalStats.VarScopeBytesCovered); 578 printDatum(OS, "vars entry value scope bytes covered", 579 GlobalStats.VarScopeEntryValueBytesCovered); 580 printDatum(OS, "total function size", GlobalStats.FunctionSize); 581 printDatum(OS, "total inlined function size", GlobalStats.InlineFunctionSize); 582 printDatum(OS, "total formal params", ParamTotal); 583 printDatum(OS, "formal params with source location", ParamWithSrcLoc); 584 printDatum(OS, "formal params with type", ParamWithType); 585 printDatum(OS, "formal params with binary location", ParamWithLoc); 586 printDatum(OS, "total vars", VarTotal); 587 printDatum(OS, "vars with source location", VarWithSrcLoc); 588 printDatum(OS, "vars with type", VarWithType); 589 printDatum(OS, "vars with binary location", VarWithLoc); 590 printDatum(OS, "total variables procesed by location statistics", 591 LocStats.NumVarParam); 592 printLocationStats(OS, "variables", LocStats.VarParamLocStats); 593 printLocationStats(OS, "variables (excluding the debug entry values)", 594 LocStats.VarParamNonEntryValLocStats); 595 printDatum(OS, "total params procesed by location statistics", 596 LocStats.NumParam); 597 printLocationStats(OS, "params", LocStats.ParamLocStats); 598 printLocationStats(OS, "params (excluding the debug entry values)", 599 LocStats.ParamNonEntryValLocStats); 600 printDatum(OS, "total vars procesed by location statistics", LocStats.NumVar); 601 printLocationStats(OS, "vars", LocStats.VarLocStats); 602 printLocationStats(OS, "vars (excluding the debug entry values)", 603 LocStats.VarNonEntryValLocStats); 604 OS << "}\n"; 605 LLVM_DEBUG( 606 llvm::dbgs() << "Total Availability: " 607 << (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal) 608 << "%\n"; 609 llvm::dbgs() << "PC Ranges covered: " 610 << (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) / 611 GlobalStats.ScopeBytesFromFirstDefinition) 612 << "%\n"); 613 return true; 614 } 615