Statistics.cpp 42 KB

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