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