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