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-dwarfdump.h" 10 #include "llvm/ADT/DenseMap.h" 11 #include "llvm/ADT/StringSet.h" 12 #include "llvm/DebugInfo/DWARF/DWARFContext.h" 13 #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" 14 #include "llvm/DebugInfo/DWARF/DWARFExpression.h" 15 #include "llvm/Object/ObjectFile.h" 16 #include "llvm/Support/JSON.h" 17 18 #define DEBUG_TYPE "dwarfdump" 19 using namespace llvm; 20 using namespace llvm::dwarfdump; 21 using namespace llvm::object; 22 23 namespace { 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 /// This is used for zero location coverage bucket. 31 constexpr unsigned ZeroCoverageBucket = 0; 32 33 /// The UINT64_MAX is used as an indication of the overflow. 34 constexpr uint64_t OverflowValue = std::numeric_limits<uint64_t>::max(); 35 36 /// This represents variables DIE offsets. 37 using AbstractOriginVarsTy = llvm::SmallVector<uint64_t>; 38 /// This maps function DIE offset to its variables. 39 using AbstractOriginVarsTyMap = llvm::DenseMap<uint64_t, AbstractOriginVarsTy>; 40 /// This represents function DIE offsets containing an abstract_origin. 41 using FunctionsWithAbstractOriginTy = llvm::SmallVector<uint64_t>; 42 43 /// This represents a data type for the stats and it helps us to 44 /// detect an overflow. 45 /// NOTE: This can be implemented as a template if there is an another type 46 /// needing this. 47 struct SaturatingUINT64 { 48 /// Number that represents the stats. 49 uint64_t Value; 50 51 SaturatingUINT64(uint64_t Value_) : Value(Value_) {} 52 53 void operator++(int) { return *this += 1; } 54 void operator+=(uint64_t Value_) { 55 if (Value != OverflowValue) { 56 if (Value < OverflowValue - Value_) 57 Value += Value_; 58 else 59 Value = OverflowValue; 60 } 61 } 62 }; 63 64 /// Utility struct to store the full location of a DIE - its CU and offset. 65 struct DIELocation { 66 DWARFUnit *DwUnit; 67 uint64_t DIEOffset; 68 DIELocation(DWARFUnit *_DwUnit, uint64_t _DIEOffset) 69 : DwUnit(_DwUnit), DIEOffset(_DIEOffset) {} 70 }; 71 /// This represents DWARF locations of CrossCU referencing DIEs. 72 using CrossCUReferencingDIELocationTy = llvm::SmallVector<DIELocation>; 73 74 /// This maps function DIE offset to its DWARF CU. 75 using FunctionDIECUTyMap = llvm::DenseMap<uint64_t, DWARFUnit *>; 76 77 /// Holds statistics for one function (or other entity that has a PC range and 78 /// contains variables, such as a compile unit). 79 struct PerFunctionStats { 80 /// Number of inlined instances of this function. 81 uint64_t NumFnInlined = 0; 82 /// Number of out-of-line instances of this function. 83 uint64_t NumFnOutOfLine = 0; 84 /// Number of inlined instances that have abstract origins. 85 uint64_t NumAbstractOrigins = 0; 86 /// Number of variables and parameters with location across all inlined 87 /// instances. 88 uint64_t TotalVarWithLoc = 0; 89 /// Number of constants with location across all inlined instances. 90 uint64_t ConstantMembers = 0; 91 /// Number of arificial variables, parameters or members across all instances. 92 uint64_t NumArtificial = 0; 93 /// List of all Variables and parameters in this function. 94 StringSet<> VarsInFunction; 95 /// Compile units also cover a PC range, but have this flag set to false. 96 bool IsFunction = false; 97 /// Function has source location information. 98 bool HasSourceLocation = false; 99 /// Number of function parameters. 100 uint64_t NumParams = 0; 101 /// Number of function parameters with source location. 102 uint64_t NumParamSourceLocations = 0; 103 /// Number of function parameters with type. 104 uint64_t NumParamTypes = 0; 105 /// Number of function parameters with a DW_AT_location. 106 uint64_t NumParamLocations = 0; 107 /// Number of local variables. 108 uint64_t NumLocalVars = 0; 109 /// Number of local variables with source location. 110 uint64_t NumLocalVarSourceLocations = 0; 111 /// Number of local variables with type. 112 uint64_t NumLocalVarTypes = 0; 113 /// Number of local variables with DW_AT_location. 114 uint64_t NumLocalVarLocations = 0; 115 }; 116 117 /// Holds accumulated global statistics about DIEs. 118 struct GlobalStats { 119 /// Total number of PC range bytes covered by DW_AT_locations. 120 SaturatingUINT64 TotalBytesCovered = 0; 121 /// Total number of parent DIE PC range bytes covered by DW_AT_Locations. 122 SaturatingUINT64 ScopeBytesCovered = 0; 123 /// Total number of PC range bytes in each variable's enclosing scope. 124 SaturatingUINT64 ScopeBytes = 0; 125 /// Total number of PC range bytes covered by DW_AT_locations with 126 /// the debug entry values (DW_OP_entry_value). 127 SaturatingUINT64 ScopeEntryValueBytesCovered = 0; 128 /// Total number of PC range bytes covered by DW_AT_locations of 129 /// formal parameters. 130 SaturatingUINT64 ParamScopeBytesCovered = 0; 131 /// Total number of PC range bytes in each parameter's enclosing scope. 132 SaturatingUINT64 ParamScopeBytes = 0; 133 /// Total number of PC range bytes covered by DW_AT_locations with 134 /// the debug entry values (DW_OP_entry_value) (only for parameters). 135 SaturatingUINT64 ParamScopeEntryValueBytesCovered = 0; 136 /// Total number of PC range bytes covered by DW_AT_locations (only for local 137 /// variables). 138 SaturatingUINT64 LocalVarScopeBytesCovered = 0; 139 /// Total number of PC range bytes in each local variable's enclosing scope. 140 SaturatingUINT64 LocalVarScopeBytes = 0; 141 /// Total number of PC range bytes covered by DW_AT_locations with 142 /// the debug entry values (DW_OP_entry_value) (only for local variables). 143 SaturatingUINT64 LocalVarScopeEntryValueBytesCovered = 0; 144 /// Total number of call site entries (DW_AT_call_file & DW_AT_call_line). 145 SaturatingUINT64 CallSiteEntries = 0; 146 /// Total number of call site DIEs (DW_TAG_call_site). 147 SaturatingUINT64 CallSiteDIEs = 0; 148 /// Total number of call site parameter DIEs (DW_TAG_call_site_parameter). 149 SaturatingUINT64 CallSiteParamDIEs = 0; 150 /// Total byte size of concrete functions. This byte size includes 151 /// inline functions contained in the concrete functions. 152 SaturatingUINT64 FunctionSize = 0; 153 /// Total byte size of inlined functions. This is the total number of bytes 154 /// for the top inline functions within concrete functions. This can help 155 /// tune the inline settings when compiling to match user expectations. 156 SaturatingUINT64 InlineFunctionSize = 0; 157 }; 158 159 /// Holds accumulated debug location statistics about local variables and 160 /// formal parameters. 161 struct LocationStats { 162 /// Map the scope coverage decile to the number of variables in the decile. 163 /// The first element of the array (at the index zero) represents the number 164 /// of variables with the no debug location at all, but the last element 165 /// in the vector represents the number of fully covered variables within 166 /// its scope. 167 std::vector<SaturatingUINT64> VarParamLocStats{ 168 std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)}; 169 /// Map non debug entry values coverage. 170 std::vector<SaturatingUINT64> VarParamNonEntryValLocStats{ 171 std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)}; 172 /// The debug location statistics for formal parameters. 173 std::vector<SaturatingUINT64> ParamLocStats{ 174 std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)}; 175 /// Map non debug entry values coverage for formal parameters. 176 std::vector<SaturatingUINT64> ParamNonEntryValLocStats{ 177 std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)}; 178 /// The debug location statistics for local variables. 179 std::vector<SaturatingUINT64> LocalVarLocStats{ 180 std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)}; 181 /// Map non debug entry values coverage for local variables. 182 std::vector<SaturatingUINT64> LocalVarNonEntryValLocStats{ 183 std::vector<SaturatingUINT64>(NumOfCoverageCategories, 0)}; 184 /// Total number of local variables and function parameters processed. 185 SaturatingUINT64 NumVarParam = 0; 186 /// Total number of formal parameters processed. 187 SaturatingUINT64 NumParam = 0; 188 /// Total number of local variables processed. 189 SaturatingUINT64 NumVar = 0; 190 }; 191 } // namespace 192 193 /// Collect debug location statistics for one DIE. 194 static void collectLocStats(uint64_t ScopeBytesCovered, uint64_t BytesInScope, 195 std::vector<SaturatingUINT64> &VarParamLocStats, 196 std::vector<SaturatingUINT64> &ParamLocStats, 197 std::vector<SaturatingUINT64> &LocalVarLocStats, 198 bool IsParam, bool IsLocalVar) { 199 auto getCoverageBucket = [ScopeBytesCovered, BytesInScope]() -> unsigned { 200 // No debug location at all for the variable. 201 if (ScopeBytesCovered == 0) 202 return 0; 203 // Fully covered variable within its scope. 204 if (ScopeBytesCovered >= BytesInScope) 205 return NumOfCoverageCategories - 1; 206 // Get covered range (e.g. 20%-29%). 207 unsigned LocBucket = 100 * (double)ScopeBytesCovered / BytesInScope; 208 LocBucket /= 10; 209 return LocBucket + 1; 210 }; 211 212 unsigned CoverageBucket = getCoverageBucket(); 213 214 VarParamLocStats[CoverageBucket].Value++; 215 if (IsParam) 216 ParamLocStats[CoverageBucket].Value++; 217 else if (IsLocalVar) 218 LocalVarLocStats[CoverageBucket].Value++; 219 } 220 221 /// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName 222 /// and DeclLine. The identifier aims to be unique for any unique entities, 223 /// but keeping the same among different instances of the same entity. 224 static std::string constructDieID(DWARFDie Die, 225 StringRef Prefix = StringRef()) { 226 std::string IDStr; 227 llvm::raw_string_ostream ID(IDStr); 228 ID << Prefix 229 << Die.getName(DINameKind::LinkageName); 230 231 // Prefix + Name is enough for local variables and parameters. 232 if (!Prefix.empty() && !Prefix.equals("g")) 233 return ID.str(); 234 235 auto DeclFile = Die.findRecursively(dwarf::DW_AT_decl_file); 236 std::string File; 237 if (DeclFile) { 238 DWARFUnit *U = Die.getDwarfUnit(); 239 if (const auto *LT = U->getContext().getLineTableForUnit(U)) 240 if (LT->getFileNameByIndex( 241 dwarf::toUnsigned(DeclFile, 0), U->getCompilationDir(), 242 DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) 243 File = std::string(sys::path::filename(File)); 244 } 245 ID << ":" << (File.empty() ? "/" : File); 246 ID << ":" 247 << dwarf::toUnsigned(Die.findRecursively(dwarf::DW_AT_decl_line), 0); 248 return ID.str(); 249 } 250 251 /// Return the number of bytes in the overlap of ranges A and B. 252 static uint64_t calculateOverlap(DWARFAddressRange A, DWARFAddressRange B) { 253 uint64_t Lower = std::max(A.LowPC, B.LowPC); 254 uint64_t Upper = std::min(A.HighPC, B.HighPC); 255 if (Lower >= Upper) 256 return 0; 257 return Upper - Lower; 258 } 259 260 /// Collect debug info quality metrics for one DIE. 261 static void collectStatsForDie(DWARFDie Die, const std::string &FnPrefix, 262 const std::string &VarPrefix, 263 uint64_t BytesInScope, uint32_t InlineDepth, 264 StringMap<PerFunctionStats> &FnStatMap, 265 GlobalStats &GlobalStats, 266 LocationStats &LocStats, 267 AbstractOriginVarsTy *AbstractOriginVariables) { 268 const dwarf::Tag Tag = Die.getTag(); 269 // Skip CU node. 270 if (Tag == dwarf::DW_TAG_compile_unit) 271 return; 272 273 bool HasLoc = false; 274 bool HasSrcLoc = false; 275 bool HasType = false; 276 uint64_t TotalBytesCovered = 0; 277 uint64_t ScopeBytesCovered = 0; 278 uint64_t BytesEntryValuesCovered = 0; 279 auto &FnStats = FnStatMap[FnPrefix]; 280 bool IsParam = Tag == dwarf::DW_TAG_formal_parameter; 281 bool IsLocalVar = Tag == dwarf::DW_TAG_variable; 282 bool IsConstantMember = Tag == dwarf::DW_TAG_member && 283 Die.find(dwarf::DW_AT_const_value); 284 285 // For zero covered inlined variables the locstats will be 286 // calculated later. 287 bool DeferLocStats = false; 288 289 if (Tag == dwarf::DW_TAG_call_site || Tag == dwarf::DW_TAG_GNU_call_site) { 290 GlobalStats.CallSiteDIEs++; 291 return; 292 } 293 294 if (Tag == dwarf::DW_TAG_call_site_parameter || 295 Tag == dwarf::DW_TAG_GNU_call_site_parameter) { 296 GlobalStats.CallSiteParamDIEs++; 297 return; 298 } 299 300 if (!IsParam && !IsLocalVar && !IsConstantMember) { 301 // Not a variable or constant member. 302 return; 303 } 304 305 // Ignore declarations of global variables. 306 if (IsLocalVar && Die.find(dwarf::DW_AT_declaration)) 307 return; 308 309 if (Die.findRecursively(dwarf::DW_AT_decl_file) && 310 Die.findRecursively(dwarf::DW_AT_decl_line)) 311 HasSrcLoc = true; 312 313 if (Die.findRecursively(dwarf::DW_AT_type)) 314 HasType = true; 315 316 if (Die.find(dwarf::DW_AT_abstract_origin)) { 317 if (Die.find(dwarf::DW_AT_location) || Die.find(dwarf::DW_AT_const_value)) { 318 if (AbstractOriginVariables) { 319 auto Offset = Die.find(dwarf::DW_AT_abstract_origin); 320 // Do not track this variable any more, since it has location 321 // coverage. 322 llvm::erase_value(*AbstractOriginVariables, (*Offset).getRawUValue()); 323 } 324 } else { 325 // The locstats will be handled at the end of 326 // the collectStatsRecursive(). 327 DeferLocStats = true; 328 } 329 } 330 331 auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool { 332 DWARFUnit *U = Die.getDwarfUnit(); 333 DataExtractor Data(toStringRef(D), 334 Die.getDwarfUnit()->getContext().isLittleEndian(), 0); 335 DWARFExpression Expression(Data, U->getAddressByteSize(), 336 U->getFormParams().Format); 337 // Consider the expression containing the DW_OP_entry_value as 338 // an entry value. 339 return llvm::any_of(Expression, [](const DWARFExpression::Operation &Op) { 340 return Op.getCode() == dwarf::DW_OP_entry_value || 341 Op.getCode() == dwarf::DW_OP_GNU_entry_value; 342 }); 343 }; 344 345 if (Die.find(dwarf::DW_AT_const_value)) { 346 // This catches constant members *and* variables. 347 HasLoc = true; 348 ScopeBytesCovered = BytesInScope; 349 TotalBytesCovered = BytesInScope; 350 } else { 351 // Handle variables and function arguments. 352 Expected<std::vector<DWARFLocationExpression>> Loc = 353 Die.getLocations(dwarf::DW_AT_location); 354 if (!Loc) { 355 consumeError(Loc.takeError()); 356 } else { 357 HasLoc = true; 358 // Get PC coverage. 359 auto Default = find_if( 360 *Loc, [](const DWARFLocationExpression &L) { return !L.Range; }); 361 if (Default != Loc->end()) { 362 // Assume the entire range is covered by a single location. 363 ScopeBytesCovered = BytesInScope; 364 TotalBytesCovered = BytesInScope; 365 } else { 366 // Caller checks this Expected result already, it cannot fail. 367 auto ScopeRanges = cantFail(Die.getParent().getAddressRanges()); 368 for (auto Entry : *Loc) { 369 TotalBytesCovered += Entry.Range->HighPC - Entry.Range->LowPC; 370 uint64_t ScopeBytesCoveredByEntry = 0; 371 // Calculate how many bytes of the parent scope this entry covers. 372 // FIXME: In section 2.6.2 of the DWARFv5 spec it says that "The 373 // address ranges defined by the bounded location descriptions of a 374 // location list may overlap". So in theory a variable can have 375 // multiple simultaneous locations, which would make this calculation 376 // misleading because we will count the overlapped areas 377 // twice. However, clang does not currently emit DWARF like this. 378 for (DWARFAddressRange R : ScopeRanges) { 379 ScopeBytesCoveredByEntry += calculateOverlap(*Entry.Range, R); 380 } 381 ScopeBytesCovered += ScopeBytesCoveredByEntry; 382 if (IsEntryValue(Entry.Expr)) 383 BytesEntryValuesCovered += ScopeBytesCoveredByEntry; 384 } 385 } 386 } 387 } 388 389 // Calculate the debug location statistics. 390 if (BytesInScope && !DeferLocStats) { 391 LocStats.NumVarParam.Value++; 392 if (IsParam) 393 LocStats.NumParam.Value++; 394 else if (IsLocalVar) 395 LocStats.NumVar.Value++; 396 397 collectLocStats(ScopeBytesCovered, BytesInScope, LocStats.VarParamLocStats, 398 LocStats.ParamLocStats, LocStats.LocalVarLocStats, IsParam, 399 IsLocalVar); 400 // Non debug entry values coverage statistics. 401 collectLocStats(ScopeBytesCovered - BytesEntryValuesCovered, BytesInScope, 402 LocStats.VarParamNonEntryValLocStats, 403 LocStats.ParamNonEntryValLocStats, 404 LocStats.LocalVarNonEntryValLocStats, IsParam, IsLocalVar); 405 } 406 407 // Collect PC range coverage data. 408 if (DWARFDie D = 409 Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin)) 410 Die = D; 411 412 std::string VarID = constructDieID(Die, VarPrefix); 413 FnStats.VarsInFunction.insert(VarID); 414 415 GlobalStats.TotalBytesCovered += TotalBytesCovered; 416 if (BytesInScope) { 417 GlobalStats.ScopeBytesCovered += ScopeBytesCovered; 418 GlobalStats.ScopeBytes += BytesInScope; 419 GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered; 420 if (IsParam) { 421 GlobalStats.ParamScopeBytesCovered += ScopeBytesCovered; 422 GlobalStats.ParamScopeBytes += BytesInScope; 423 GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered; 424 } else if (IsLocalVar) { 425 GlobalStats.LocalVarScopeBytesCovered += ScopeBytesCovered; 426 GlobalStats.LocalVarScopeBytes += BytesInScope; 427 GlobalStats.LocalVarScopeEntryValueBytesCovered += 428 BytesEntryValuesCovered; 429 } 430 assert(GlobalStats.ScopeBytesCovered.Value <= GlobalStats.ScopeBytes.Value); 431 } 432 433 if (IsConstantMember) { 434 FnStats.ConstantMembers++; 435 return; 436 } 437 438 FnStats.TotalVarWithLoc += (unsigned)HasLoc; 439 440 if (Die.find(dwarf::DW_AT_artificial)) { 441 FnStats.NumArtificial++; 442 return; 443 } 444 445 if (IsParam) { 446 FnStats.NumParams++; 447 if (HasType) 448 FnStats.NumParamTypes++; 449 if (HasSrcLoc) 450 FnStats.NumParamSourceLocations++; 451 if (HasLoc) 452 FnStats.NumParamLocations++; 453 } else if (IsLocalVar) { 454 FnStats.NumLocalVars++; 455 if (HasType) 456 FnStats.NumLocalVarTypes++; 457 if (HasSrcLoc) 458 FnStats.NumLocalVarSourceLocations++; 459 if (HasLoc) 460 FnStats.NumLocalVarLocations++; 461 } 462 } 463 464 /// Recursively collect variables from subprogram with DW_AT_inline attribute. 465 static void collectAbstractOriginFnInfo( 466 DWARFDie Die, uint64_t SPOffset, 467 AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo, 468 AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo) { 469 DWARFDie Child = Die.getFirstChild(); 470 while (Child) { 471 const dwarf::Tag ChildTag = Child.getTag(); 472 if (ChildTag == dwarf::DW_TAG_formal_parameter || 473 ChildTag == dwarf::DW_TAG_variable) { 474 GlobalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset()); 475 LocalAbstractOriginFnInfo[SPOffset].push_back(Child.getOffset()); 476 } else if (ChildTag == dwarf::DW_TAG_lexical_block) 477 collectAbstractOriginFnInfo(Child, SPOffset, GlobalAbstractOriginFnInfo, 478 LocalAbstractOriginFnInfo); 479 Child = Child.getSibling(); 480 } 481 } 482 483 /// Recursively collect debug info quality metrics. 484 static void collectStatsRecursive( 485 DWARFDie Die, std::string FnPrefix, std::string VarPrefix, 486 uint64_t BytesInScope, uint32_t InlineDepth, 487 StringMap<PerFunctionStats> &FnStatMap, GlobalStats &GlobalStats, 488 LocationStats &LocStats, FunctionDIECUTyMap &AbstractOriginFnCUs, 489 AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo, 490 AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo, 491 FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed, 492 AbstractOriginVarsTy *AbstractOriginVarsPtr = nullptr) { 493 // Skip NULL nodes. 494 if (Die.isNULL()) 495 return; 496 497 const dwarf::Tag Tag = Die.getTag(); 498 // Skip function types. 499 if (Tag == dwarf::DW_TAG_subroutine_type) 500 return; 501 502 // Handle any kind of lexical scope. 503 const bool HasAbstractOrigin = 504 Die.find(dwarf::DW_AT_abstract_origin) != std::nullopt; 505 const bool IsFunction = Tag == dwarf::DW_TAG_subprogram; 506 const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block; 507 const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine; 508 // We want to know how many variables (with abstract_origin) don't have 509 // location info. 510 const bool IsCandidateForZeroLocCovTracking = 511 (IsInlinedFunction || (IsFunction && HasAbstractOrigin)); 512 513 AbstractOriginVarsTy AbstractOriginVars; 514 515 // Get the vars of the inlined fn, so the locstats 516 // reports the missing vars (with coverage 0%). 517 if (IsCandidateForZeroLocCovTracking) { 518 auto OffsetFn = Die.find(dwarf::DW_AT_abstract_origin); 519 if (OffsetFn) { 520 uint64_t OffsetOfInlineFnCopy = (*OffsetFn).getRawUValue(); 521 if (LocalAbstractOriginFnInfo.count(OffsetOfInlineFnCopy)) { 522 AbstractOriginVars = LocalAbstractOriginFnInfo[OffsetOfInlineFnCopy]; 523 AbstractOriginVarsPtr = &AbstractOriginVars; 524 } else { 525 // This means that the DW_AT_inline fn copy is out of order 526 // or that the abstract_origin references another CU, 527 // so this abstract origin instance will be processed later. 528 FnsWithAbstractOriginToBeProcessed.push_back(Die.getOffset()); 529 AbstractOriginVarsPtr = nullptr; 530 } 531 } 532 } 533 534 if (IsFunction || IsInlinedFunction || IsBlock) { 535 // Reset VarPrefix when entering a new function. 536 if (IsFunction || IsInlinedFunction) 537 VarPrefix = "v"; 538 539 // Ignore forward declarations. 540 if (Die.find(dwarf::DW_AT_declaration)) 541 return; 542 543 // Check for call sites. 544 if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line)) 545 GlobalStats.CallSiteEntries++; 546 547 // PC Ranges. 548 auto RangesOrError = Die.getAddressRanges(); 549 if (!RangesOrError) { 550 llvm::consumeError(RangesOrError.takeError()); 551 return; 552 } 553 554 auto Ranges = RangesOrError.get(); 555 uint64_t BytesInThisScope = 0; 556 for (auto Range : Ranges) 557 BytesInThisScope += Range.HighPC - Range.LowPC; 558 559 // Count the function. 560 if (!IsBlock) { 561 // Skip over abstract origins, but collect variables 562 // from it so it can be used for location statistics 563 // for inlined instancies. 564 if (Die.find(dwarf::DW_AT_inline)) { 565 uint64_t SPOffset = Die.getOffset(); 566 AbstractOriginFnCUs[SPOffset] = Die.getDwarfUnit(); 567 collectAbstractOriginFnInfo(Die, SPOffset, GlobalAbstractOriginFnInfo, 568 LocalAbstractOriginFnInfo); 569 return; 570 } 571 572 std::string FnID = constructDieID(Die); 573 // We've seen an instance of this function. 574 auto &FnStats = FnStatMap[FnID]; 575 FnStats.IsFunction = true; 576 if (IsInlinedFunction) { 577 FnStats.NumFnInlined++; 578 if (Die.findRecursively(dwarf::DW_AT_abstract_origin)) 579 FnStats.NumAbstractOrigins++; 580 } else { 581 FnStats.NumFnOutOfLine++; 582 } 583 if (Die.findRecursively(dwarf::DW_AT_decl_file) && 584 Die.findRecursively(dwarf::DW_AT_decl_line)) 585 FnStats.HasSourceLocation = true; 586 // Update function prefix. 587 FnPrefix = FnID; 588 } 589 590 if (BytesInThisScope) { 591 BytesInScope = BytesInThisScope; 592 if (IsFunction) 593 GlobalStats.FunctionSize += BytesInThisScope; 594 else if (IsInlinedFunction && InlineDepth == 0) 595 GlobalStats.InlineFunctionSize += BytesInThisScope; 596 } 597 } else { 598 // Not a scope, visit the Die itself. It could be a variable. 599 collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth, 600 FnStatMap, GlobalStats, LocStats, AbstractOriginVarsPtr); 601 } 602 603 // Set InlineDepth correctly for child recursion 604 if (IsFunction) 605 InlineDepth = 0; 606 else if (IsInlinedFunction) 607 ++InlineDepth; 608 609 // Traverse children. 610 unsigned LexicalBlockIndex = 0; 611 unsigned FormalParameterIndex = 0; 612 DWARFDie Child = Die.getFirstChild(); 613 while (Child) { 614 std::string ChildVarPrefix = VarPrefix; 615 if (Child.getTag() == dwarf::DW_TAG_lexical_block) 616 ChildVarPrefix += toHex(LexicalBlockIndex++) + '.'; 617 if (Child.getTag() == dwarf::DW_TAG_formal_parameter) 618 ChildVarPrefix += 'p' + toHex(FormalParameterIndex++) + '.'; 619 620 collectStatsRecursive( 621 Child, FnPrefix, ChildVarPrefix, BytesInScope, InlineDepth, FnStatMap, 622 GlobalStats, LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo, 623 LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed, 624 AbstractOriginVarsPtr); 625 Child = Child.getSibling(); 626 } 627 628 if (!IsCandidateForZeroLocCovTracking) 629 return; 630 631 // After we have processed all vars of the inlined function (or function with 632 // an abstract_origin), we want to know how many variables have no location. 633 for (auto Offset : AbstractOriginVars) { 634 LocStats.NumVarParam++; 635 LocStats.VarParamLocStats[ZeroCoverageBucket]++; 636 auto FnDie = Die.getDwarfUnit()->getDIEForOffset(Offset); 637 if (!FnDie) 638 continue; 639 auto Tag = FnDie.getTag(); 640 if (Tag == dwarf::DW_TAG_formal_parameter) { 641 LocStats.NumParam++; 642 LocStats.ParamLocStats[ZeroCoverageBucket]++; 643 } else if (Tag == dwarf::DW_TAG_variable) { 644 LocStats.NumVar++; 645 LocStats.LocalVarLocStats[ZeroCoverageBucket]++; 646 } 647 } 648 } 649 650 /// Print human-readable output. 651 /// \{ 652 static void printDatum(json::OStream &J, const char *Key, json::Value Value) { 653 if (Value == OverflowValue) 654 J.attribute(Key, "overflowed"); 655 else 656 J.attribute(Key, Value); 657 658 LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n'); 659 } 660 661 static void printLocationStats(json::OStream &J, const char *Key, 662 std::vector<SaturatingUINT64> &LocationStats) { 663 if (LocationStats[0].Value == OverflowValue) 664 J.attribute((Twine(Key) + 665 " with (0%,10%) of parent scope covered by DW_AT_location") 666 .str(), 667 "overflowed"); 668 else 669 J.attribute( 670 (Twine(Key) + " with 0% of parent scope covered by DW_AT_location") 671 .str(), 672 LocationStats[0].Value); 673 LLVM_DEBUG( 674 llvm::dbgs() << Key 675 << " with 0% of parent scope covered by DW_AT_location: \\" 676 << LocationStats[0].Value << '\n'); 677 678 if (LocationStats[1].Value == OverflowValue) 679 J.attribute((Twine(Key) + 680 " with (0%,10%) of parent scope covered by DW_AT_location") 681 .str(), 682 "overflowed"); 683 else 684 J.attribute((Twine(Key) + 685 " with (0%,10%) of parent scope covered by DW_AT_location") 686 .str(), 687 LocationStats[1].Value); 688 LLVM_DEBUG(llvm::dbgs() 689 << Key 690 << " with (0%,10%) of parent scope covered by DW_AT_location: " 691 << LocationStats[1].Value << '\n'); 692 693 for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) { 694 if (LocationStats[i].Value == OverflowValue) 695 J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," + 696 Twine(i * 10) + 697 "%) of parent scope covered by DW_AT_location") 698 .str(), 699 "overflowed"); 700 else 701 J.attribute((Twine(Key) + " with [" + Twine((i - 1) * 10) + "%," + 702 Twine(i * 10) + 703 "%) of parent scope covered by DW_AT_location") 704 .str(), 705 LocationStats[i].Value); 706 LLVM_DEBUG(llvm::dbgs() 707 << Key << " with [" << (i - 1) * 10 << "%," << i * 10 708 << "%) of parent scope covered by DW_AT_location: " 709 << LocationStats[i].Value); 710 } 711 if (LocationStats[NumOfCoverageCategories - 1].Value == OverflowValue) 712 J.attribute( 713 (Twine(Key) + " with 100% of parent scope covered by DW_AT_location") 714 .str(), 715 "overflowed"); 716 else 717 J.attribute( 718 (Twine(Key) + " with 100% of parent scope covered by DW_AT_location") 719 .str(), 720 LocationStats[NumOfCoverageCategories - 1].Value); 721 LLVM_DEBUG( 722 llvm::dbgs() << Key 723 << " with 100% of parent scope covered by DW_AT_location: " 724 << LocationStats[NumOfCoverageCategories - 1].Value); 725 } 726 727 static void printSectionSizes(json::OStream &J, const SectionSizes &Sizes) { 728 for (const auto &It : Sizes.DebugSectionSizes) 729 J.attribute((Twine("#bytes in ") + It.first).str(), int64_t(It.second)); 730 } 731 732 /// Stop tracking variables that contain abstract_origin with a location. 733 /// This is used for out-of-order DW_AT_inline subprograms only. 734 static void updateVarsWithAbstractOriginLocCovInfo( 735 DWARFDie FnDieWithAbstractOrigin, 736 AbstractOriginVarsTy &AbstractOriginVars) { 737 DWARFDie Child = FnDieWithAbstractOrigin.getFirstChild(); 738 while (Child) { 739 const dwarf::Tag ChildTag = Child.getTag(); 740 if ((ChildTag == dwarf::DW_TAG_formal_parameter || 741 ChildTag == dwarf::DW_TAG_variable) && 742 (Child.find(dwarf::DW_AT_location) || 743 Child.find(dwarf::DW_AT_const_value))) { 744 auto OffsetVar = Child.find(dwarf::DW_AT_abstract_origin); 745 if (OffsetVar) 746 llvm::erase_value(AbstractOriginVars, (*OffsetVar).getRawUValue()); 747 } else if (ChildTag == dwarf::DW_TAG_lexical_block) 748 updateVarsWithAbstractOriginLocCovInfo(Child, AbstractOriginVars); 749 Child = Child.getSibling(); 750 } 751 } 752 753 /// Collect zero location coverage for inlined variables which refer to 754 /// a DW_AT_inline copy of subprogram that is out of order in the DWARF. 755 /// Also cover the variables of a concrete function (represented with 756 /// the DW_TAG_subprogram) with an abstract_origin attribute. 757 static void collectZeroLocCovForVarsWithAbstractOrigin( 758 DWARFUnit *DwUnit, GlobalStats &GlobalStats, LocationStats &LocStats, 759 AbstractOriginVarsTyMap &LocalAbstractOriginFnInfo, 760 FunctionsWithAbstractOriginTy &FnsWithAbstractOriginToBeProcessed) { 761 // The next variable is used to filter out functions that have been processed, 762 // leaving FnsWithAbstractOriginToBeProcessed with just CrossCU references. 763 FunctionsWithAbstractOriginTy ProcessedFns; 764 for (auto FnOffset : FnsWithAbstractOriginToBeProcessed) { 765 DWARFDie FnDieWithAbstractOrigin = DwUnit->getDIEForOffset(FnOffset); 766 auto FnCopy = FnDieWithAbstractOrigin.find(dwarf::DW_AT_abstract_origin); 767 AbstractOriginVarsTy AbstractOriginVars; 768 if (!FnCopy) 769 continue; 770 uint64_t FnCopyRawUValue = (*FnCopy).getRawUValue(); 771 // If there is no entry within LocalAbstractOriginFnInfo for the given 772 // FnCopyRawUValue, function isn't out-of-order in DWARF. Rather, we have 773 // CrossCU referencing. 774 if (!LocalAbstractOriginFnInfo.count(FnCopyRawUValue)) 775 continue; 776 AbstractOriginVars = LocalAbstractOriginFnInfo[FnCopyRawUValue]; 777 updateVarsWithAbstractOriginLocCovInfo(FnDieWithAbstractOrigin, 778 AbstractOriginVars); 779 780 for (auto Offset : AbstractOriginVars) { 781 LocStats.NumVarParam++; 782 LocStats.VarParamLocStats[ZeroCoverageBucket]++; 783 auto Tag = DwUnit->getDIEForOffset(Offset).getTag(); 784 if (Tag == dwarf::DW_TAG_formal_parameter) { 785 LocStats.NumParam++; 786 LocStats.ParamLocStats[ZeroCoverageBucket]++; 787 } else if (Tag == dwarf::DW_TAG_variable) { 788 LocStats.NumVar++; 789 LocStats.LocalVarLocStats[ZeroCoverageBucket]++; 790 } 791 } 792 ProcessedFns.push_back(FnOffset); 793 } 794 for (auto ProcessedFn : ProcessedFns) 795 llvm::erase_value(FnsWithAbstractOriginToBeProcessed, ProcessedFn); 796 } 797 798 /// Collect zero location coverage for inlined variables which refer to 799 /// a DW_AT_inline copy of subprogram that is in a different CU. 800 static void collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin( 801 LocationStats &LocStats, FunctionDIECUTyMap AbstractOriginFnCUs, 802 AbstractOriginVarsTyMap &GlobalAbstractOriginFnInfo, 803 CrossCUReferencingDIELocationTy &CrossCUReferencesToBeResolved) { 804 for (const auto &CrossCUReferenceToBeResolved : 805 CrossCUReferencesToBeResolved) { 806 DWARFUnit *DwUnit = CrossCUReferenceToBeResolved.DwUnit; 807 DWARFDie FnDIEWithCrossCUReferencing = 808 DwUnit->getDIEForOffset(CrossCUReferenceToBeResolved.DIEOffset); 809 auto FnCopy = 810 FnDIEWithCrossCUReferencing.find(dwarf::DW_AT_abstract_origin); 811 if (!FnCopy) 812 continue; 813 uint64_t FnCopyRawUValue = (*FnCopy).getRawUValue(); 814 AbstractOriginVarsTy AbstractOriginVars = 815 GlobalAbstractOriginFnInfo[FnCopyRawUValue]; 816 updateVarsWithAbstractOriginLocCovInfo(FnDIEWithCrossCUReferencing, 817 AbstractOriginVars); 818 for (auto Offset : AbstractOriginVars) { 819 LocStats.NumVarParam++; 820 LocStats.VarParamLocStats[ZeroCoverageBucket]++; 821 auto Tag = (AbstractOriginFnCUs[FnCopyRawUValue]) 822 ->getDIEForOffset(Offset) 823 .getTag(); 824 if (Tag == dwarf::DW_TAG_formal_parameter) { 825 LocStats.NumParam++; 826 LocStats.ParamLocStats[ZeroCoverageBucket]++; 827 } else if (Tag == dwarf::DW_TAG_variable) { 828 LocStats.NumVar++; 829 LocStats.LocalVarLocStats[ZeroCoverageBucket]++; 830 } 831 } 832 } 833 } 834 835 /// \} 836 837 /// Collect debug info quality metrics for an entire DIContext. 838 /// 839 /// Do the impossible and reduce the quality of the debug info down to a few 840 /// numbers. The idea is to condense the data into numbers that can be tracked 841 /// over time to identify trends in newer compiler versions and gauge the effect 842 /// of particular optimizations. The raw numbers themselves are not particularly 843 /// useful, only the delta between compiling the same program with different 844 /// compilers is. 845 bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, 846 const Twine &Filename, 847 raw_ostream &OS) { 848 StringRef FormatName = Obj.getFileFormatName(); 849 GlobalStats GlobalStats; 850 LocationStats LocStats; 851 StringMap<PerFunctionStats> Statistics; 852 // This variable holds variable information for functions with 853 // abstract_origin globally, across all CUs. 854 AbstractOriginVarsTyMap GlobalAbstractOriginFnInfo; 855 // This variable holds information about the CU of a function with 856 // abstract_origin. 857 FunctionDIECUTyMap AbstractOriginFnCUs; 858 CrossCUReferencingDIELocationTy CrossCUReferencesToBeResolved; 859 for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) { 860 if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) { 861 // This variable holds variable information for functions with 862 // abstract_origin, but just for the current CU. 863 AbstractOriginVarsTyMap LocalAbstractOriginFnInfo; 864 FunctionsWithAbstractOriginTy FnsWithAbstractOriginToBeProcessed; 865 866 collectStatsRecursive( 867 CUDie, "/", "g", 0, 0, Statistics, GlobalStats, LocStats, 868 AbstractOriginFnCUs, GlobalAbstractOriginFnInfo, 869 LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed); 870 871 // collectZeroLocCovForVarsWithAbstractOrigin will filter out all 872 // out-of-order DWARF functions that have been processed within it, 873 // leaving FnsWithAbstractOriginToBeProcessed with only CrossCU 874 // references. 875 collectZeroLocCovForVarsWithAbstractOrigin( 876 CUDie.getDwarfUnit(), GlobalStats, LocStats, 877 LocalAbstractOriginFnInfo, FnsWithAbstractOriginToBeProcessed); 878 879 // Collect all CrossCU references into CrossCUReferencesToBeResolved. 880 for (auto CrossCUReferencingDIEOffset : 881 FnsWithAbstractOriginToBeProcessed) 882 CrossCUReferencesToBeResolved.push_back( 883 DIELocation(CUDie.getDwarfUnit(), CrossCUReferencingDIEOffset)); 884 } 885 } 886 887 /// Resolve CrossCU references. 888 collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin( 889 LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo, 890 CrossCUReferencesToBeResolved); 891 892 /// Collect the sizes of debug sections. 893 SectionSizes Sizes; 894 calculateSectionSizes(Obj, Sizes, Filename); 895 896 /// The version number should be increased every time the algorithm is changed 897 /// (including bug fixes). New metrics may be added without increasing the 898 /// version. 899 unsigned Version = 9; 900 SaturatingUINT64 VarParamTotal = 0; 901 SaturatingUINT64 VarParamUnique = 0; 902 SaturatingUINT64 VarParamWithLoc = 0; 903 SaturatingUINT64 NumFunctions = 0; 904 SaturatingUINT64 NumInlinedFunctions = 0; 905 SaturatingUINT64 NumFuncsWithSrcLoc = 0; 906 SaturatingUINT64 NumAbstractOrigins = 0; 907 SaturatingUINT64 ParamTotal = 0; 908 SaturatingUINT64 ParamWithType = 0; 909 SaturatingUINT64 ParamWithLoc = 0; 910 SaturatingUINT64 ParamWithSrcLoc = 0; 911 SaturatingUINT64 LocalVarTotal = 0; 912 SaturatingUINT64 LocalVarWithType = 0; 913 SaturatingUINT64 LocalVarWithSrcLoc = 0; 914 SaturatingUINT64 LocalVarWithLoc = 0; 915 for (auto &Entry : Statistics) { 916 PerFunctionStats &Stats = Entry.getValue(); 917 uint64_t TotalVars = Stats.VarsInFunction.size() * 918 (Stats.NumFnInlined + Stats.NumFnOutOfLine); 919 // Count variables in global scope. 920 if (!Stats.IsFunction) 921 TotalVars = 922 Stats.NumLocalVars + Stats.ConstantMembers + Stats.NumArtificial; 923 uint64_t Constants = Stats.ConstantMembers; 924 VarParamWithLoc += Stats.TotalVarWithLoc + Constants; 925 VarParamTotal += TotalVars; 926 VarParamUnique += Stats.VarsInFunction.size(); 927 LLVM_DEBUG(for (auto &V 928 : Stats.VarsInFunction) llvm::dbgs() 929 << Entry.getKey() << ": " << V.getKey() << "\n"); 930 NumFunctions += Stats.IsFunction; 931 NumFuncsWithSrcLoc += Stats.HasSourceLocation; 932 NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined; 933 NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins; 934 ParamTotal += Stats.NumParams; 935 ParamWithType += Stats.NumParamTypes; 936 ParamWithLoc += Stats.NumParamLocations; 937 ParamWithSrcLoc += Stats.NumParamSourceLocations; 938 LocalVarTotal += Stats.NumLocalVars; 939 LocalVarWithType += Stats.NumLocalVarTypes; 940 LocalVarWithLoc += Stats.NumLocalVarLocations; 941 LocalVarWithSrcLoc += Stats.NumLocalVarSourceLocations; 942 } 943 944 // Print summary. 945 OS.SetBufferSize(1024); 946 json::OStream J(OS, 2); 947 J.objectBegin(); 948 J.attribute("version", Version); 949 LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n"; 950 llvm::dbgs() << "---------------------------------\n"); 951 952 printDatum(J, "file", Filename.str()); 953 printDatum(J, "format", FormatName); 954 955 printDatum(J, "#functions", NumFunctions.Value); 956 printDatum(J, "#functions with location", NumFuncsWithSrcLoc.Value); 957 printDatum(J, "#inlined functions", NumInlinedFunctions.Value); 958 printDatum(J, "#inlined functions with abstract origins", 959 NumAbstractOrigins.Value); 960 961 // This includes local variables and formal parameters. 962 printDatum(J, "#unique source variables", VarParamUnique.Value); 963 printDatum(J, "#source variables", VarParamTotal.Value); 964 printDatum(J, "#source variables with location", VarParamWithLoc.Value); 965 966 printDatum(J, "#call site entries", GlobalStats.CallSiteEntries.Value); 967 printDatum(J, "#call site DIEs", GlobalStats.CallSiteDIEs.Value); 968 printDatum(J, "#call site parameter DIEs", 969 GlobalStats.CallSiteParamDIEs.Value); 970 971 printDatum(J, "sum_all_variables(#bytes in parent scope)", 972 GlobalStats.ScopeBytes.Value); 973 printDatum(J, 974 "sum_all_variables(#bytes in any scope covered by DW_AT_location)", 975 GlobalStats.TotalBytesCovered.Value); 976 printDatum(J, 977 "sum_all_variables(#bytes in parent scope covered by " 978 "DW_AT_location)", 979 GlobalStats.ScopeBytesCovered.Value); 980 printDatum(J, 981 "sum_all_variables(#bytes in parent scope covered by " 982 "DW_OP_entry_value)", 983 GlobalStats.ScopeEntryValueBytesCovered.Value); 984 985 printDatum(J, "sum_all_params(#bytes in parent scope)", 986 GlobalStats.ParamScopeBytes.Value); 987 printDatum(J, 988 "sum_all_params(#bytes in parent scope covered by DW_AT_location)", 989 GlobalStats.ParamScopeBytesCovered.Value); 990 printDatum(J, 991 "sum_all_params(#bytes in parent scope covered by " 992 "DW_OP_entry_value)", 993 GlobalStats.ParamScopeEntryValueBytesCovered.Value); 994 995 printDatum(J, "sum_all_local_vars(#bytes in parent scope)", 996 GlobalStats.LocalVarScopeBytes.Value); 997 printDatum(J, 998 "sum_all_local_vars(#bytes in parent scope covered by " 999 "DW_AT_location)", 1000 GlobalStats.LocalVarScopeBytesCovered.Value); 1001 printDatum(J, 1002 "sum_all_local_vars(#bytes in parent scope covered by " 1003 "DW_OP_entry_value)", 1004 GlobalStats.LocalVarScopeEntryValueBytesCovered.Value); 1005 1006 printDatum(J, "#bytes within functions", GlobalStats.FunctionSize.Value); 1007 printDatum(J, "#bytes within inlined functions", 1008 GlobalStats.InlineFunctionSize.Value); 1009 1010 // Print the summary for formal parameters. 1011 printDatum(J, "#params", ParamTotal.Value); 1012 printDatum(J, "#params with source location", ParamWithSrcLoc.Value); 1013 printDatum(J, "#params with type", ParamWithType.Value); 1014 printDatum(J, "#params with binary location", ParamWithLoc.Value); 1015 1016 // Print the summary for local variables. 1017 printDatum(J, "#local vars", LocalVarTotal.Value); 1018 printDatum(J, "#local vars with source location", LocalVarWithSrcLoc.Value); 1019 printDatum(J, "#local vars with type", LocalVarWithType.Value); 1020 printDatum(J, "#local vars with binary location", LocalVarWithLoc.Value); 1021 1022 // Print the debug section sizes. 1023 printSectionSizes(J, Sizes); 1024 1025 // Print the location statistics for variables (includes local variables 1026 // and formal parameters). 1027 printDatum(J, "#variables processed by location statistics", 1028 LocStats.NumVarParam.Value); 1029 printLocationStats(J, "#variables", LocStats.VarParamLocStats); 1030 printLocationStats(J, "#variables - entry values", 1031 LocStats.VarParamNonEntryValLocStats); 1032 1033 // Print the location statistics for formal parameters. 1034 printDatum(J, "#params processed by location statistics", 1035 LocStats.NumParam.Value); 1036 printLocationStats(J, "#params", LocStats.ParamLocStats); 1037 printLocationStats(J, "#params - entry values", 1038 LocStats.ParamNonEntryValLocStats); 1039 1040 // Print the location statistics for local variables. 1041 printDatum(J, "#local vars processed by location statistics", 1042 LocStats.NumVar.Value); 1043 printLocationStats(J, "#local vars", LocStats.LocalVarLocStats); 1044 printLocationStats(J, "#local vars - entry values", 1045 LocStats.LocalVarNonEntryValLocStats); 1046 J.objectEnd(); 1047 OS << '\n'; 1048 LLVM_DEBUG( 1049 llvm::dbgs() << "Total Availability: " 1050 << (VarParamTotal.Value 1051 ? (int)std::round((VarParamWithLoc.Value * 100.0) / 1052 VarParamTotal.Value) 1053 : 0) 1054 << "%\n"; 1055 llvm::dbgs() << "PC Ranges covered: " 1056 << (GlobalStats.ScopeBytes.Value 1057 ? (int)std::round( 1058 (GlobalStats.ScopeBytesCovered.Value * 100.0) / 1059 GlobalStats.ScopeBytes.Value) 1060 : 0) 1061 << "%\n"); 1062 return true; 1063 } 1064