2020-02-07 18:15:04 +01:00
|
|
|
//===-- Statistics.cpp - Debug Info quality metrics -----------------------===//
|
2020-02-07 12:37:29 +01:00
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2018-09-21 23:59:34 +02:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
#include "llvm/ADT/StringSet.h"
|
2017-10-06 22:24:34 +02:00
|
|
|
#include "llvm/DebugInfo/DIContext.h"
|
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
|
|
|
|
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
|
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2019-09-20 11:25:11 +02:00
|
|
|
#include "llvm/Support/JSON.h"
|
2017-10-06 22:24:34 +02:00
|
|
|
|
2020-04-02 10:58:27 +02:00
|
|
|
#include "SectionSizes.h"
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
#define DEBUG_TYPE "dwarfdump"
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace object;
|
|
|
|
|
2019-09-10 12:37:28 +02:00
|
|
|
/// This represents the number of categories of debug location coverage being
|
|
|
|
/// calculated. The first category is the number of variables with 0% location
|
|
|
|
/// coverage, but the last category is the number of variables with 100%
|
|
|
|
/// location coverage.
|
|
|
|
constexpr int NumOfCoverageCategories = 12;
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
/// Holds statistics for one function (or other entity that has a PC range and
|
|
|
|
/// contains variables, such as a compile unit).
|
|
|
|
struct PerFunctionStats {
|
|
|
|
/// Number of inlined instances of this function.
|
|
|
|
unsigned NumFnInlined = 0;
|
2020-01-08 16:33:51 +01:00
|
|
|
/// Number of out-of-line instances of this function.
|
|
|
|
unsigned NumFnOutOfLine = 0;
|
2019-03-02 00:51:54 +01:00
|
|
|
/// Number of inlined instances that have abstract origins.
|
|
|
|
unsigned NumAbstractOrigins = 0;
|
|
|
|
/// Number of variables and parameters with location across all inlined
|
|
|
|
/// instances.
|
2017-10-06 22:24:34 +02:00
|
|
|
unsigned TotalVarWithLoc = 0;
|
|
|
|
/// Number of constants with location across all inlined instances.
|
|
|
|
unsigned ConstantMembers = 0;
|
2020-01-14 19:39:04 +01:00
|
|
|
/// Number of arificial variables, parameters or members across all instances.
|
|
|
|
unsigned NumArtificial = 0;
|
2019-03-02 00:51:54 +01:00
|
|
|
/// List of all Variables and parameters in this function.
|
2018-09-21 23:59:34 +02:00
|
|
|
StringSet<> VarsInFunction;
|
2017-10-06 22:24:34 +02:00
|
|
|
/// Compile units also cover a PC range, but have this flag set to false.
|
|
|
|
bool IsFunction = false;
|
2019-03-02 00:51:54 +01:00
|
|
|
/// Function has source location information.
|
|
|
|
bool HasSourceLocation = false;
|
|
|
|
/// Number of function parameters.
|
|
|
|
unsigned NumParams = 0;
|
|
|
|
/// Number of function parameters with source location.
|
|
|
|
unsigned NumParamSourceLocations = 0;
|
|
|
|
/// Number of function parameters with type.
|
|
|
|
unsigned NumParamTypes = 0;
|
|
|
|
/// Number of function parameters with a DW_AT_location.
|
|
|
|
unsigned NumParamLocations = 0;
|
|
|
|
/// Number of variables.
|
|
|
|
unsigned NumVars = 0;
|
|
|
|
/// Number of variables with source location.
|
|
|
|
unsigned NumVarSourceLocations = 0;
|
2019-09-04 11:44:09 +02:00
|
|
|
/// Number of variables with type.
|
2019-03-02 00:51:54 +01:00
|
|
|
unsigned NumVarTypes = 0;
|
2019-09-04 11:44:09 +02:00
|
|
|
/// Number of variables with DW_AT_location.
|
2019-03-02 00:51:54 +01:00
|
|
|
unsigned NumVarLocations = 0;
|
2017-10-06 22:24:34 +02:00
|
|
|
};
|
|
|
|
|
2018-11-09 19:10:02 +01:00
|
|
|
/// Holds accumulated global statistics about DIEs.
|
2017-10-06 22:24:34 +02:00
|
|
|
struct GlobalStats {
|
|
|
|
/// Total number of PC range bytes covered by DW_AT_locations.
|
|
|
|
unsigned ScopeBytesCovered = 0;
|
2019-11-19 11:28:21 +01:00
|
|
|
/// Total number of PC range bytes in each variable's enclosing scope.
|
|
|
|
unsigned ScopeBytes = 0;
|
2019-09-10 12:37:28 +02:00
|
|
|
/// Total number of PC range bytes covered by DW_AT_locations with
|
|
|
|
/// the debug entry values (DW_OP_entry_value).
|
|
|
|
unsigned ScopeEntryValueBytesCovered = 0;
|
|
|
|
/// Total number of PC range bytes covered by DW_AT_locations of
|
|
|
|
/// formal parameters.
|
|
|
|
unsigned ParamScopeBytesCovered = 0;
|
2019-11-19 11:28:21 +01:00
|
|
|
/// Total number of PC range bytes in each variable's enclosing scope
|
|
|
|
/// (only for parameters).
|
|
|
|
unsigned ParamScopeBytes = 0;
|
2019-09-10 12:37:28 +02:00
|
|
|
/// Total number of PC range bytes covered by DW_AT_locations with
|
|
|
|
/// the debug entry values (DW_OP_entry_value) (only for parameters).
|
|
|
|
unsigned ParamScopeEntryValueBytesCovered = 0;
|
|
|
|
/// Total number of PC range bytes covered by DW_AT_locations (only for local
|
|
|
|
/// variables).
|
|
|
|
unsigned VarScopeBytesCovered = 0;
|
2019-11-19 11:28:21 +01:00
|
|
|
/// Total number of PC range bytes in each variable's enclosing scope
|
|
|
|
/// (only for local variables).
|
|
|
|
unsigned VarScopeBytes = 0;
|
2019-09-10 12:37:28 +02:00
|
|
|
/// Total number of PC range bytes covered by DW_AT_locations with
|
|
|
|
/// the debug entry values (DW_OP_entry_value) (only for local variables).
|
|
|
|
unsigned VarScopeEntryValueBytesCovered = 0;
|
2019-07-31 18:51:28 +02:00
|
|
|
/// Total number of call site entries (DW_AT_call_file & DW_AT_call_line).
|
2018-10-05 22:37:17 +02:00
|
|
|
unsigned CallSiteEntries = 0;
|
2019-07-31 18:51:28 +02:00
|
|
|
/// Total number of call site DIEs (DW_TAG_call_site).
|
|
|
|
unsigned CallSiteDIEs = 0;
|
|
|
|
/// Total number of call site parameter DIEs (DW_TAG_call_site_parameter).
|
|
|
|
unsigned CallSiteParamDIEs = 0;
|
2018-11-09 19:10:02 +01:00
|
|
|
/// Total byte size of concrete functions. This byte size includes
|
|
|
|
/// inline functions contained in the concrete functions.
|
2019-09-20 11:25:11 +02:00
|
|
|
unsigned FunctionSize = 0;
|
2018-11-09 19:10:02 +01:00
|
|
|
/// Total byte size of inlined functions. This is the total number of bytes
|
|
|
|
/// for the top inline functions within concrete functions. This can help
|
|
|
|
/// tune the inline settings when compiling to match user expectations.
|
2019-09-20 11:25:11 +02:00
|
|
|
unsigned InlineFunctionSize = 0;
|
2017-10-06 22:24:34 +02:00
|
|
|
};
|
|
|
|
|
2019-09-10 12:37:28 +02:00
|
|
|
/// Holds accumulated debug location statistics about local variables and
|
|
|
|
/// formal parameters.
|
|
|
|
struct LocationStats {
|
|
|
|
/// Map the scope coverage decile to the number of variables in the decile.
|
|
|
|
/// The first element of the array (at the index zero) represents the number
|
|
|
|
/// of variables with the no debug location at all, but the last element
|
|
|
|
/// in the vector represents the number of fully covered variables within
|
|
|
|
/// its scope.
|
|
|
|
std::vector<unsigned> VarParamLocStats{
|
|
|
|
std::vector<unsigned>(NumOfCoverageCategories, 0)};
|
|
|
|
/// Map non debug entry values coverage.
|
|
|
|
std::vector<unsigned> VarParamNonEntryValLocStats{
|
|
|
|
std::vector<unsigned>(NumOfCoverageCategories, 0)};
|
|
|
|
/// The debug location statistics for formal parameters.
|
|
|
|
std::vector<unsigned> ParamLocStats{
|
|
|
|
std::vector<unsigned>(NumOfCoverageCategories, 0)};
|
|
|
|
/// Map non debug entry values coverage for formal parameters.
|
|
|
|
std::vector<unsigned> ParamNonEntryValLocStats{
|
|
|
|
std::vector<unsigned>(NumOfCoverageCategories, 0)};
|
|
|
|
/// The debug location statistics for local variables.
|
|
|
|
std::vector<unsigned> VarLocStats{
|
|
|
|
std::vector<unsigned>(NumOfCoverageCategories, 0)};
|
|
|
|
/// Map non debug entry values coverage for local variables.
|
|
|
|
std::vector<unsigned> VarNonEntryValLocStats{
|
|
|
|
std::vector<unsigned>(NumOfCoverageCategories, 0)};
|
|
|
|
/// Total number of local variables and function parameters processed.
|
|
|
|
unsigned NumVarParam = 0;
|
|
|
|
/// Total number of formal parameters processed.
|
|
|
|
unsigned NumParam = 0;
|
|
|
|
/// Total number of local variables processed.
|
|
|
|
unsigned NumVar = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/// Collect debug location statistics for one DIE.
|
|
|
|
static void collectLocStats(uint64_t BytesCovered, uint64_t BytesInScope,
|
|
|
|
std::vector<unsigned> &VarParamLocStats,
|
|
|
|
std::vector<unsigned> &ParamLocStats,
|
|
|
|
std::vector<unsigned> &VarLocStats, bool IsParam,
|
|
|
|
bool IsLocalVar) {
|
|
|
|
auto getCoverageBucket = [BytesCovered, BytesInScope]() -> unsigned {
|
2019-12-05 14:45:57 +01:00
|
|
|
// No debug location at all for the variable.
|
|
|
|
if (BytesCovered == 0)
|
2019-09-10 12:37:28 +02:00
|
|
|
return 0;
|
2019-12-05 14:45:57 +01:00
|
|
|
// Fully covered variable within its scope.
|
|
|
|
if (BytesCovered >= BytesInScope)
|
2019-09-10 12:37:28 +02:00
|
|
|
return NumOfCoverageCategories - 1;
|
2019-12-05 14:45:57 +01:00
|
|
|
// Get covered range (e.g. 20%-29%).
|
|
|
|
unsigned LocBucket = 100 * (double)BytesCovered / BytesInScope;
|
|
|
|
LocBucket /= 10;
|
|
|
|
return LocBucket + 1;
|
2019-09-10 12:37:28 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
unsigned CoverageBucket = getCoverageBucket();
|
|
|
|
VarParamLocStats[CoverageBucket]++;
|
|
|
|
if (IsParam)
|
|
|
|
ParamLocStats[CoverageBucket]++;
|
|
|
|
else if (IsLocalVar)
|
|
|
|
VarLocStats[CoverageBucket]++;
|
|
|
|
}
|
2020-01-14 19:36:30 +01:00
|
|
|
/// Construct an identifier for a given DIE from its Prefix, Name, DeclFileName
|
|
|
|
/// and DeclLine. The identifier aims to be unique for any unique entities,
|
|
|
|
/// but keeping the same among different instances of the same entity.
|
|
|
|
static std::string constructDieID(DWARFDie Die,
|
|
|
|
StringRef Prefix = StringRef()) {
|
|
|
|
std::string IDStr;
|
|
|
|
llvm::raw_string_ostream ID(IDStr);
|
|
|
|
ID << Prefix
|
|
|
|
<< Die.getName(DINameKind::LinkageName);
|
|
|
|
|
|
|
|
// Prefix + Name is enough for local variables and parameters.
|
|
|
|
if (!Prefix.empty() && !Prefix.equals("g"))
|
|
|
|
return ID.str();
|
|
|
|
|
|
|
|
auto DeclFile = Die.findRecursively(dwarf::DW_AT_decl_file);
|
|
|
|
std::string File;
|
|
|
|
if (DeclFile) {
|
|
|
|
DWARFUnit *U = Die.getDwarfUnit();
|
|
|
|
if (const auto *LT = U->getContext().getLineTableForUnit(U))
|
|
|
|
if (LT->getFileNameByIndex(
|
|
|
|
dwarf::toUnsigned(DeclFile, 0), U->getCompilationDir(),
|
|
|
|
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File))
|
2020-01-28 20:23:46 +01:00
|
|
|
File = std::string(sys::path::filename(File));
|
2020-01-14 19:36:30 +01:00
|
|
|
}
|
|
|
|
ID << ":" << (File.empty() ? "/" : File);
|
|
|
|
ID << ":"
|
|
|
|
<< dwarf::toUnsigned(Die.findRecursively(dwarf::DW_AT_decl_line), 0);
|
|
|
|
return ID.str();
|
|
|
|
}
|
2019-09-10 12:37:28 +02:00
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
/// Collect debug info quality metrics for one DIE.
|
dwarfdump --statistics: Use new location list api
Summary:
This patch removes manual location list handling in the statistics code
and replaces it with the new DWARFDie api, which provides access to a
"cooked" location list. This has the following effects:
- the code now properly handles split-dwarf location lists
- it will automatically support dwarf5 location lists once support for
those is added
- it properly handles location lists with base address selection entries
- it fixes a bug where the location list code was using the first
DW_AT_ranges range as a "base address" of the compile unit (it should
have used DW_AT_low_pc instead. The effect of this was that the
computation of the start address of a variable in its scope was broken
for these kinds of compile units. This only manifested itself on
linked files, since in object files the first DW_AT_ranges range
normally starts at 0.
Since pretty much every kind of location list was broken in some way,
it's hard to verify that the new implementation is correct -- the output
will be different in all non-trivial cases, and mostly with good reason.
Most of the existing statistics tests continue to pass though, and a
visual inspection of the statistics for non-trivial inputs shows that
the data is more "reasonable" now. I have updated the "dwo statistics"
test to include the new numbers, as the previous ones were completely
bogus, and I have added a targeted test for the "base address" bug.
Reviewers: dblaikie, cmtice, vsk
Subscribers: aprantl, SouraVX, JDevlieghere, djtodoro, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70444
2019-11-19 15:14:59 +01:00
|
|
|
static void collectStatsForDie(DWARFDie Die, std::string FnPrefix,
|
2019-11-19 11:28:21 +01:00
|
|
|
std::string VarPrefix, uint64_t BytesInScope,
|
|
|
|
uint32_t InlineDepth,
|
2017-10-06 22:24:34 +02:00
|
|
|
StringMap<PerFunctionStats> &FnStatMap,
|
2019-09-10 12:37:28 +02:00
|
|
|
GlobalStats &GlobalStats,
|
|
|
|
LocationStats &LocStats) {
|
2017-10-06 22:24:34 +02:00
|
|
|
bool HasLoc = false;
|
2019-03-02 00:51:54 +01:00
|
|
|
bool HasSrcLoc = false;
|
|
|
|
bool HasType = false;
|
2017-10-06 22:24:34 +02:00
|
|
|
uint64_t BytesCovered = 0;
|
2019-09-10 12:37:28 +02:00
|
|
|
uint64_t BytesEntryValuesCovered = 0;
|
|
|
|
auto &FnStats = FnStatMap[FnPrefix];
|
|
|
|
bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter;
|
2020-01-19 15:28:35 +01:00
|
|
|
bool IsVariable = Die.getTag() == dwarf::DW_TAG_variable;
|
2020-01-14 19:39:04 +01:00
|
|
|
bool IsConstantMember = Die.getTag() == dwarf::DW_TAG_member &&
|
|
|
|
Die.find(dwarf::DW_AT_const_value);
|
2018-09-21 23:59:34 +02:00
|
|
|
|
2019-07-31 18:51:28 +02:00
|
|
|
if (Die.getTag() == dwarf::DW_TAG_call_site ||
|
|
|
|
Die.getTag() == dwarf::DW_TAG_GNU_call_site) {
|
|
|
|
GlobalStats.CallSiteDIEs++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Die.getTag() == dwarf::DW_TAG_call_site_parameter ||
|
|
|
|
Die.getTag() == dwarf::DW_TAG_GNU_call_site_parameter) {
|
|
|
|
GlobalStats.CallSiteParamDIEs++;
|
2018-10-05 22:37:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-14 19:39:04 +01:00
|
|
|
if (!IsParam && !IsVariable && !IsConstantMember) {
|
2018-09-21 23:59:34 +02:00
|
|
|
// Not a variable or constant member.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-19 15:28:35 +01:00
|
|
|
// Ignore declarations of global variables.
|
|
|
|
if (IsVariable && Die.find(dwarf::DW_AT_declaration))
|
|
|
|
return;
|
|
|
|
|
2019-03-02 00:51:54 +01:00
|
|
|
if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
|
|
|
|
Die.findRecursively(dwarf::DW_AT_decl_line))
|
|
|
|
HasSrcLoc = true;
|
|
|
|
|
|
|
|
if (Die.findRecursively(dwarf::DW_AT_type))
|
|
|
|
HasType = true;
|
|
|
|
|
2019-09-10 12:37:28 +02:00
|
|
|
auto IsEntryValue = [&](ArrayRef<uint8_t> D) -> bool {
|
|
|
|
DWARFUnit *U = Die.getDwarfUnit();
|
|
|
|
DataExtractor Data(toStringRef(D),
|
|
|
|
Die.getDwarfUnit()->getContext().isLittleEndian(), 0);
|
2020-01-23 03:24:00 +01:00
|
|
|
DWARFExpression Expression(Data, U->getAddressByteSize());
|
2019-09-10 12:37:28 +02:00
|
|
|
// Consider the expression containing the DW_OP_entry_value as
|
|
|
|
// an entry value.
|
|
|
|
return llvm::any_of(Expression, [](DWARFExpression::Operation &Op) {
|
|
|
|
return Op.getCode() == dwarf::DW_OP_entry_value ||
|
|
|
|
Op.getCode() == dwarf::DW_OP_GNU_entry_value;
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
if (Die.find(dwarf::DW_AT_const_value)) {
|
|
|
|
// This catches constant members *and* variables.
|
|
|
|
HasLoc = true;
|
|
|
|
BytesCovered = BytesInScope;
|
2018-09-21 23:59:34 +02:00
|
|
|
} else {
|
2017-10-06 22:24:34 +02:00
|
|
|
// Handle variables and function arguments.
|
dwarfdump --statistics: Use new location list api
Summary:
This patch removes manual location list handling in the statistics code
and replaces it with the new DWARFDie api, which provides access to a
"cooked" location list. This has the following effects:
- the code now properly handles split-dwarf location lists
- it will automatically support dwarf5 location lists once support for
those is added
- it properly handles location lists with base address selection entries
- it fixes a bug where the location list code was using the first
DW_AT_ranges range as a "base address" of the compile unit (it should
have used DW_AT_low_pc instead. The effect of this was that the
computation of the start address of a variable in its scope was broken
for these kinds of compile units. This only manifested itself on
linked files, since in object files the first DW_AT_ranges range
normally starts at 0.
Since pretty much every kind of location list was broken in some way,
it's hard to verify that the new implementation is correct -- the output
will be different in all non-trivial cases, and mostly with good reason.
Most of the existing statistics tests continue to pass though, and a
visual inspection of the statistics for non-trivial inputs shows that
the data is more "reasonable" now. I have updated the "dwo statistics"
test to include the new numbers, as the previous ones were completely
bogus, and I have added a targeted test for the "base address" bug.
Reviewers: dblaikie, cmtice, vsk
Subscribers: aprantl, SouraVX, JDevlieghere, djtodoro, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70444
2019-11-19 15:14:59 +01:00
|
|
|
Expected<std::vector<DWARFLocationExpression>> Loc =
|
|
|
|
Die.getLocations(dwarf::DW_AT_location);
|
|
|
|
if (!Loc) {
|
|
|
|
consumeError(Loc.takeError());
|
|
|
|
} else {
|
|
|
|
HasLoc = true;
|
2017-10-06 22:24:34 +02:00
|
|
|
// Get PC coverage.
|
dwarfdump --statistics: Use new location list api
Summary:
This patch removes manual location list handling in the statistics code
and replaces it with the new DWARFDie api, which provides access to a
"cooked" location list. This has the following effects:
- the code now properly handles split-dwarf location lists
- it will automatically support dwarf5 location lists once support for
those is added
- it properly handles location lists with base address selection entries
- it fixes a bug where the location list code was using the first
DW_AT_ranges range as a "base address" of the compile unit (it should
have used DW_AT_low_pc instead. The effect of this was that the
computation of the start address of a variable in its scope was broken
for these kinds of compile units. This only manifested itself on
linked files, since in object files the first DW_AT_ranges range
normally starts at 0.
Since pretty much every kind of location list was broken in some way,
it's hard to verify that the new implementation is correct -- the output
will be different in all non-trivial cases, and mostly with good reason.
Most of the existing statistics tests continue to pass though, and a
visual inspection of the statistics for non-trivial inputs shows that
the data is more "reasonable" now. I have updated the "dwo statistics"
test to include the new numbers, as the previous ones were completely
bogus, and I have added a targeted test for the "base address" bug.
Reviewers: dblaikie, cmtice, vsk
Subscribers: aprantl, SouraVX, JDevlieghere, djtodoro, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70444
2019-11-19 15:14:59 +01:00
|
|
|
auto Default = find_if(
|
|
|
|
*Loc, [](const DWARFLocationExpression &L) { return !L.Range; });
|
|
|
|
if (Default != Loc->end()) {
|
2017-10-06 22:24:34 +02:00
|
|
|
// Assume the entire range is covered by a single location.
|
|
|
|
BytesCovered = BytesInScope;
|
dwarfdump --statistics: Use new location list api
Summary:
This patch removes manual location list handling in the statistics code
and replaces it with the new DWARFDie api, which provides access to a
"cooked" location list. This has the following effects:
- the code now properly handles split-dwarf location lists
- it will automatically support dwarf5 location lists once support for
those is added
- it properly handles location lists with base address selection entries
- it fixes a bug where the location list code was using the first
DW_AT_ranges range as a "base address" of the compile unit (it should
have used DW_AT_low_pc instead. The effect of this was that the
computation of the start address of a variable in its scope was broken
for these kinds of compile units. This only manifested itself on
linked files, since in object files the first DW_AT_ranges range
normally starts at 0.
Since pretty much every kind of location list was broken in some way,
it's hard to verify that the new implementation is correct -- the output
will be different in all non-trivial cases, and mostly with good reason.
Most of the existing statistics tests continue to pass though, and a
visual inspection of the statistics for non-trivial inputs shows that
the data is more "reasonable" now. I have updated the "dwo statistics"
test to include the new numbers, as the previous ones were completely
bogus, and I have added a targeted test for the "base address" bug.
Reviewers: dblaikie, cmtice, vsk
Subscribers: aprantl, SouraVX, JDevlieghere, djtodoro, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70444
2019-11-19 15:14:59 +01:00
|
|
|
} else {
|
|
|
|
for (auto Entry : *Loc) {
|
|
|
|
uint64_t BytesEntryCovered = Entry.Range->HighPC - Entry.Range->LowPC;
|
|
|
|
BytesCovered += BytesEntryCovered;
|
|
|
|
if (IsEntryValue(Entry.Expr))
|
|
|
|
BytesEntryValuesCovered += BytesEntryCovered;
|
|
|
|
}
|
2017-10-06 22:24:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-10 12:37:28 +02:00
|
|
|
// Calculate the debug location statistics.
|
|
|
|
if (BytesInScope) {
|
|
|
|
LocStats.NumVarParam++;
|
|
|
|
if (IsParam)
|
|
|
|
LocStats.NumParam++;
|
2020-01-19 15:28:35 +01:00
|
|
|
else if (IsVariable)
|
2019-09-10 12:37:28 +02:00
|
|
|
LocStats.NumVar++;
|
|
|
|
|
|
|
|
collectLocStats(BytesCovered, BytesInScope, LocStats.VarParamLocStats,
|
|
|
|
LocStats.ParamLocStats, LocStats.VarLocStats, IsParam,
|
2020-01-19 15:28:35 +01:00
|
|
|
IsVariable);
|
2019-09-10 12:37:28 +02:00
|
|
|
// Non debug entry values coverage statistics.
|
|
|
|
collectLocStats(BytesCovered - BytesEntryValuesCovered, BytesInScope,
|
|
|
|
LocStats.VarParamNonEntryValLocStats,
|
|
|
|
LocStats.ParamNonEntryValLocStats,
|
2020-01-19 15:28:35 +01:00
|
|
|
LocStats.VarNonEntryValLocStats, IsParam, IsVariable);
|
2019-09-10 12:37:28 +02:00
|
|
|
}
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
// Collect PC range coverage data.
|
|
|
|
if (DWARFDie D =
|
|
|
|
Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin))
|
|
|
|
Die = D;
|
2020-01-14 19:36:30 +01:00
|
|
|
|
|
|
|
std::string VarID = constructDieID(Die, VarPrefix);
|
|
|
|
FnStats.VarsInFunction.insert(VarID);
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
if (BytesInScope) {
|
|
|
|
// Turns out we have a lot of ranges that extend past the lexical scope.
|
|
|
|
GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered);
|
2019-11-19 11:28:21 +01:00
|
|
|
GlobalStats.ScopeBytes += BytesInScope;
|
2019-09-10 12:37:28 +02:00
|
|
|
GlobalStats.ScopeEntryValueBytesCovered += BytesEntryValuesCovered;
|
|
|
|
if (IsParam) {
|
|
|
|
GlobalStats.ParamScopeBytesCovered +=
|
|
|
|
std::min(BytesInScope, BytesCovered);
|
2019-11-19 11:28:21 +01:00
|
|
|
GlobalStats.ParamScopeBytes += BytesInScope;
|
2019-09-10 12:37:28 +02:00
|
|
|
GlobalStats.ParamScopeEntryValueBytesCovered += BytesEntryValuesCovered;
|
2020-01-19 15:28:35 +01:00
|
|
|
} else if (IsVariable) {
|
2019-09-10 12:37:28 +02:00
|
|
|
GlobalStats.VarScopeBytesCovered += std::min(BytesInScope, BytesCovered);
|
2019-11-19 11:28:21 +01:00
|
|
|
GlobalStats.VarScopeBytes += BytesInScope;
|
2019-09-10 12:37:28 +02:00
|
|
|
GlobalStats.VarScopeEntryValueBytesCovered += BytesEntryValuesCovered;
|
|
|
|
}
|
2019-11-19 11:28:21 +01:00
|
|
|
assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes);
|
2020-01-14 19:39:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (IsConstantMember) {
|
2017-10-06 22:24:34 +02:00
|
|
|
FnStats.ConstantMembers++;
|
2020-01-14 19:39:04 +01:00
|
|
|
return;
|
2017-10-06 22:24:34 +02:00
|
|
|
}
|
2020-01-14 19:39:04 +01:00
|
|
|
|
|
|
|
FnStats.TotalVarWithLoc += (unsigned)HasLoc;
|
|
|
|
|
|
|
|
if (Die.find(dwarf::DW_AT_artificial)) {
|
|
|
|
FnStats.NumArtificial++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsParam) {
|
|
|
|
FnStats.NumParams++;
|
|
|
|
if (HasType)
|
|
|
|
FnStats.NumParamTypes++;
|
|
|
|
if (HasSrcLoc)
|
|
|
|
FnStats.NumParamSourceLocations++;
|
|
|
|
if (HasLoc)
|
|
|
|
FnStats.NumParamLocations++;
|
|
|
|
} else if (IsVariable) {
|
|
|
|
FnStats.NumVars++;
|
|
|
|
if (HasType)
|
|
|
|
FnStats.NumVarTypes++;
|
|
|
|
if (HasSrcLoc)
|
|
|
|
FnStats.NumVarSourceLocations++;
|
|
|
|
if (HasLoc)
|
|
|
|
FnStats.NumVarLocations++;
|
2019-03-02 00:51:54 +01:00
|
|
|
}
|
2017-10-06 22:24:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Recursively collect debug info quality metrics.
|
dwarfdump --statistics: Use new location list api
Summary:
This patch removes manual location list handling in the statistics code
and replaces it with the new DWARFDie api, which provides access to a
"cooked" location list. This has the following effects:
- the code now properly handles split-dwarf location lists
- it will automatically support dwarf5 location lists once support for
those is added
- it properly handles location lists with base address selection entries
- it fixes a bug where the location list code was using the first
DW_AT_ranges range as a "base address" of the compile unit (it should
have used DW_AT_low_pc instead. The effect of this was that the
computation of the start address of a variable in its scope was broken
for these kinds of compile units. This only manifested itself on
linked files, since in object files the first DW_AT_ranges range
normally starts at 0.
Since pretty much every kind of location list was broken in some way,
it's hard to verify that the new implementation is correct -- the output
will be different in all non-trivial cases, and mostly with good reason.
Most of the existing statistics tests continue to pass though, and a
visual inspection of the statistics for non-trivial inputs shows that
the data is more "reasonable" now. I have updated the "dwo statistics"
test to include the new numbers, as the previous ones were completely
bogus, and I have added a targeted test for the "base address" bug.
Reviewers: dblaikie, cmtice, vsk
Subscribers: aprantl, SouraVX, JDevlieghere, djtodoro, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70444
2019-11-19 15:14:59 +01:00
|
|
|
static void collectStatsRecursive(DWARFDie Die, std::string FnPrefix,
|
2019-11-19 11:28:21 +01:00
|
|
|
std::string VarPrefix, uint64_t BytesInScope,
|
|
|
|
uint32_t InlineDepth,
|
2017-10-06 22:24:34 +02:00
|
|
|
StringMap<PerFunctionStats> &FnStatMap,
|
2019-09-10 12:37:28 +02:00
|
|
|
GlobalStats &GlobalStats,
|
|
|
|
LocationStats &LocStats) {
|
2018-11-09 19:10:02 +01:00
|
|
|
const dwarf::Tag Tag = Die.getTag();
|
2020-01-09 21:21:17 +01:00
|
|
|
// Skip function types.
|
|
|
|
if (Tag == dwarf::DW_TAG_subroutine_type)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Handle any kind of lexical scope.
|
2018-11-09 19:10:02 +01:00
|
|
|
const bool IsFunction = Tag == dwarf::DW_TAG_subprogram;
|
|
|
|
const bool IsBlock = Tag == dwarf::DW_TAG_lexical_block;
|
|
|
|
const bool IsInlinedFunction = Tag == dwarf::DW_TAG_inlined_subroutine;
|
|
|
|
if (IsFunction || IsInlinedFunction || IsBlock) {
|
2018-09-21 23:59:34 +02:00
|
|
|
|
|
|
|
// Reset VarPrefix when entering a new function.
|
|
|
|
if (Die.getTag() == dwarf::DW_TAG_subprogram ||
|
|
|
|
Die.getTag() == dwarf::DW_TAG_inlined_subroutine)
|
|
|
|
VarPrefix = "v";
|
2018-11-09 19:10:02 +01:00
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
// Ignore forward declarations.
|
|
|
|
if (Die.find(dwarf::DW_AT_declaration))
|
|
|
|
return;
|
|
|
|
|
2019-03-02 00:51:54 +01:00
|
|
|
// Check for call sites.
|
|
|
|
if (Die.find(dwarf::DW_AT_call_file) && Die.find(dwarf::DW_AT_call_line))
|
|
|
|
GlobalStats.CallSiteEntries++;
|
|
|
|
|
2019-02-08 01:51:33 +01:00
|
|
|
// PC Ranges.
|
|
|
|
auto RangesOrError = Die.getAddressRanges();
|
|
|
|
if (!RangesOrError) {
|
|
|
|
llvm::consumeError(RangesOrError.takeError());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto Ranges = RangesOrError.get();
|
|
|
|
uint64_t BytesInThisScope = 0;
|
|
|
|
for (auto Range : Ranges)
|
|
|
|
BytesInThisScope += Range.HighPC - Range.LowPC;
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
// Count the function.
|
2018-11-09 19:10:02 +01:00
|
|
|
if (!IsBlock) {
|
2017-10-06 22:24:34 +02:00
|
|
|
// Skip over abstract origins.
|
|
|
|
if (Die.find(dwarf::DW_AT_inline))
|
|
|
|
return;
|
2020-01-14 19:36:30 +01:00
|
|
|
std::string FnID = constructDieID(Die);
|
2020-01-08 16:33:51 +01:00
|
|
|
// We've seen an instance of this function.
|
2020-01-14 19:36:30 +01:00
|
|
|
auto &FnStats = FnStatMap[FnID];
|
|
|
|
FnStats.IsFunction = true;
|
2019-03-02 00:51:54 +01:00
|
|
|
if (IsInlinedFunction) {
|
2019-02-08 01:51:33 +01:00
|
|
|
FnStats.NumFnInlined++;
|
2019-03-02 00:51:54 +01:00
|
|
|
if (Die.findRecursively(dwarf::DW_AT_abstract_origin))
|
|
|
|
FnStats.NumAbstractOrigins++;
|
2020-01-08 16:33:51 +01:00
|
|
|
} else {
|
|
|
|
FnStats.NumFnOutOfLine++;
|
2019-03-02 00:51:54 +01:00
|
|
|
}
|
|
|
|
if (Die.findRecursively(dwarf::DW_AT_decl_file) &&
|
|
|
|
Die.findRecursively(dwarf::DW_AT_decl_line))
|
|
|
|
FnStats.HasSourceLocation = true;
|
2020-01-14 19:36:30 +01:00
|
|
|
// Update function prefix.
|
|
|
|
FnPrefix = FnID;
|
2017-10-06 22:24:34 +02:00
|
|
|
}
|
|
|
|
|
2018-11-09 19:10:02 +01:00
|
|
|
if (BytesInThisScope) {
|
2017-10-06 22:24:34 +02:00
|
|
|
BytesInScope = BytesInThisScope;
|
2018-11-09 19:10:02 +01:00
|
|
|
if (IsFunction)
|
|
|
|
GlobalStats.FunctionSize += BytesInThisScope;
|
|
|
|
else if (IsInlinedFunction && InlineDepth == 0)
|
|
|
|
GlobalStats.InlineFunctionSize += BytesInThisScope;
|
|
|
|
}
|
2017-10-06 22:24:34 +02:00
|
|
|
} else {
|
|
|
|
// Not a scope, visit the Die itself. It could be a variable.
|
2019-11-19 11:28:21 +01:00
|
|
|
collectStatsForDie(Die, FnPrefix, VarPrefix, BytesInScope, InlineDepth,
|
|
|
|
FnStatMap, GlobalStats, LocStats);
|
2017-10-06 22:24:34 +02:00
|
|
|
}
|
|
|
|
|
2018-11-09 19:10:02 +01:00
|
|
|
// Set InlineDepth correctly for child recursion
|
|
|
|
if (IsFunction)
|
|
|
|
InlineDepth = 0;
|
|
|
|
else if (IsInlinedFunction)
|
|
|
|
++InlineDepth;
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
// Traverse children.
|
2018-09-21 23:59:34 +02:00
|
|
|
unsigned LexicalBlockIndex = 0;
|
2020-01-14 19:37:47 +01:00
|
|
|
unsigned FormalParameterIndex = 0;
|
2017-10-06 22:24:34 +02:00
|
|
|
DWARFDie Child = Die.getFirstChild();
|
|
|
|
while (Child) {
|
2018-09-21 23:59:34 +02:00
|
|
|
std::string ChildVarPrefix = VarPrefix;
|
|
|
|
if (Child.getTag() == dwarf::DW_TAG_lexical_block)
|
|
|
|
ChildVarPrefix += toHex(LexicalBlockIndex++) + '.';
|
2020-01-14 19:37:47 +01:00
|
|
|
if (Child.getTag() == dwarf::DW_TAG_formal_parameter)
|
|
|
|
ChildVarPrefix += 'p' + toHex(FormalParameterIndex++) + '.';
|
2018-09-21 23:59:34 +02:00
|
|
|
|
2019-11-19 11:28:21 +01:00
|
|
|
collectStatsRecursive(Child, FnPrefix, ChildVarPrefix, BytesInScope,
|
|
|
|
InlineDepth, FnStatMap, GlobalStats, LocStats);
|
2017-10-06 22:24:34 +02:00
|
|
|
Child = Child.getSibling();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Print machine-readable output.
|
|
|
|
/// The machine-readable format is single-line JSON output.
|
|
|
|
/// \{
|
2019-09-20 11:25:11 +02:00
|
|
|
static void printDatum(raw_ostream &OS, const char *Key, json::Value Value) {
|
2017-10-06 22:24:34 +02:00
|
|
|
OS << ",\"" << Key << "\":" << Value;
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << Key << ": " << Value << '\n');
|
2017-10-06 22:24:34 +02:00
|
|
|
}
|
2020-04-02 10:58:27 +02:00
|
|
|
|
2019-09-10 12:37:28 +02:00
|
|
|
static void printLocationStats(raw_ostream &OS,
|
|
|
|
const char *Key,
|
|
|
|
std::vector<unsigned> &LocationStats) {
|
|
|
|
OS << ",\"" << Key << " with 0% of its scope covered\":"
|
|
|
|
<< LocationStats[0];
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << Key << " with 0% of its scope covered: "
|
|
|
|
<< LocationStats[0] << '\n');
|
2019-12-05 14:45:57 +01:00
|
|
|
OS << ",\"" << Key << " with (0%,10%) of its scope covered\":"
|
2019-09-10 12:37:28 +02:00
|
|
|
<< LocationStats[1];
|
2019-12-05 14:45:57 +01:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << Key << " with (0%,10%) of its scope covered: "
|
2019-09-10 12:37:28 +02:00
|
|
|
<< LocationStats[1] << '\n');
|
|
|
|
for (unsigned i = 2; i < NumOfCoverageCategories - 1; ++i) {
|
2019-12-11 18:52:49 +01:00
|
|
|
OS << ",\"" << Key << " with [" << (i - 1) * 10 << "%," << i * 10
|
|
|
|
<< "%) of its scope covered\":" << LocationStats[i];
|
2019-09-10 12:37:28 +02:00
|
|
|
LLVM_DEBUG(llvm::dbgs()
|
2019-12-11 18:52:49 +01:00
|
|
|
<< Key << " with [" << (i - 1) * 10 << "%," << i * 10
|
|
|
|
<< "%) of its scope covered: " << LocationStats[i]);
|
2019-09-10 12:37:28 +02:00
|
|
|
}
|
|
|
|
OS << ",\"" << Key << " with 100% of its scope covered\":"
|
|
|
|
<< LocationStats[NumOfCoverageCategories - 1];
|
|
|
|
LLVM_DEBUG(llvm::dbgs() << Key << " with 100% of its scope covered: "
|
|
|
|
<< LocationStats[NumOfCoverageCategories - 1]);
|
|
|
|
}
|
2020-04-02 10:58:27 +02:00
|
|
|
|
|
|
|
static void printSectionSizes(raw_ostream &OS, const SectionSizes &Sizes) {
|
|
|
|
for (const auto &DebugSec : Sizes.DebugSectionSizes)
|
|
|
|
OS << ",\"size of " << DebugSec.getKey() << "\":" << DebugSec.getValue();
|
|
|
|
}
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
/// \}
|
|
|
|
|
|
|
|
/// Collect debug info quality metrics for an entire DIContext.
|
|
|
|
///
|
|
|
|
/// Do the impossible and reduce the quality of the debug info down to a few
|
|
|
|
/// numbers. The idea is to condense the data into numbers that can be tracked
|
|
|
|
/// over time to identify trends in newer compiler versions and gauge the effect
|
|
|
|
/// of particular optimizations. The raw numbers themselves are not particularly
|
|
|
|
/// useful, only the delta between compiling the same program with different
|
|
|
|
/// compilers is.
|
|
|
|
bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
|
2020-03-10 12:06:08 +01:00
|
|
|
const Twine &Filename, raw_ostream &OS) {
|
2017-10-06 22:24:34 +02:00
|
|
|
StringRef FormatName = Obj.getFileFormatName();
|
|
|
|
GlobalStats GlobalStats;
|
2019-09-10 12:37:28 +02:00
|
|
|
LocationStats LocStats;
|
2017-10-06 22:24:34 +02:00
|
|
|
StringMap<PerFunctionStats> Statistics;
|
|
|
|
for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units())
|
2019-05-09 23:53:33 +02:00
|
|
|
if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false))
|
2019-11-19 11:28:21 +01:00
|
|
|
collectStatsRecursive(CUDie, "/", "g", 0, 0, Statistics, GlobalStats,
|
dwarfdump --statistics: Use new location list api
Summary:
This patch removes manual location list handling in the statistics code
and replaces it with the new DWARFDie api, which provides access to a
"cooked" location list. This has the following effects:
- the code now properly handles split-dwarf location lists
- it will automatically support dwarf5 location lists once support for
those is added
- it properly handles location lists with base address selection entries
- it fixes a bug where the location list code was using the first
DW_AT_ranges range as a "base address" of the compile unit (it should
have used DW_AT_low_pc instead. The effect of this was that the
computation of the start address of a variable in its scope was broken
for these kinds of compile units. This only manifested itself on
linked files, since in object files the first DW_AT_ranges range
normally starts at 0.
Since pretty much every kind of location list was broken in some way,
it's hard to verify that the new implementation is correct -- the output
will be different in all non-trivial cases, and mostly with good reason.
Most of the existing statistics tests continue to pass though, and a
visual inspection of the statistics for non-trivial inputs shows that
the data is more "reasonable" now. I have updated the "dwo statistics"
test to include the new numbers, as the previous ones were completely
bogus, and I have added a targeted test for the "base address" bug.
Reviewers: dblaikie, cmtice, vsk
Subscribers: aprantl, SouraVX, JDevlieghere, djtodoro, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D70444
2019-11-19 15:14:59 +01:00
|
|
|
LocStats);
|
2017-10-06 22:24:34 +02:00
|
|
|
|
2020-04-02 10:58:27 +02:00
|
|
|
/// Collect the sizes of debug sections.
|
|
|
|
SectionSizes Sizes;
|
|
|
|
calculateSectionSizes(Obj, Sizes, Filename);
|
|
|
|
|
2017-10-06 22:24:34 +02:00
|
|
|
/// The version number should be increased every time the algorithm is changed
|
|
|
|
/// (including bug fixes). New metrics may be added without increasing the
|
|
|
|
/// version.
|
2019-11-19 11:28:21 +01:00
|
|
|
unsigned Version = 4;
|
2019-03-02 00:51:54 +01:00
|
|
|
unsigned VarParamTotal = 0;
|
|
|
|
unsigned VarParamUnique = 0;
|
|
|
|
unsigned VarParamWithLoc = 0;
|
2017-10-06 22:24:34 +02:00
|
|
|
unsigned NumFunctions = 0;
|
|
|
|
unsigned NumInlinedFunctions = 0;
|
2019-03-02 00:51:54 +01:00
|
|
|
unsigned NumFuncsWithSrcLoc = 0;
|
|
|
|
unsigned NumAbstractOrigins = 0;
|
|
|
|
unsigned ParamTotal = 0;
|
|
|
|
unsigned ParamWithType = 0;
|
|
|
|
unsigned ParamWithLoc = 0;
|
|
|
|
unsigned ParamWithSrcLoc = 0;
|
|
|
|
unsigned VarTotal = 0;
|
|
|
|
unsigned VarWithType = 0;
|
|
|
|
unsigned VarWithSrcLoc = 0;
|
|
|
|
unsigned VarWithLoc = 0;
|
2017-10-06 22:24:34 +02:00
|
|
|
for (auto &Entry : Statistics) {
|
|
|
|
PerFunctionStats &Stats = Entry.getValue();
|
2020-01-08 16:33:51 +01:00
|
|
|
unsigned TotalVars = Stats.VarsInFunction.size() *
|
|
|
|
(Stats.NumFnInlined + Stats.NumFnOutOfLine);
|
|
|
|
// Count variables in global scope.
|
|
|
|
if (!Stats.IsFunction)
|
2020-01-14 19:39:04 +01:00
|
|
|
TotalVars = Stats.NumVars + Stats.ConstantMembers + Stats.NumArtificial;
|
2017-10-06 22:24:34 +02:00
|
|
|
unsigned Constants = Stats.ConstantMembers;
|
2019-03-02 00:51:54 +01:00
|
|
|
VarParamWithLoc += Stats.TotalVarWithLoc + Constants;
|
|
|
|
VarParamTotal += TotalVars;
|
|
|
|
VarParamUnique += Stats.VarsInFunction.size();
|
|
|
|
LLVM_DEBUG(for (auto &V
|
|
|
|
: Stats.VarsInFunction) llvm::dbgs()
|
2018-09-21 23:59:34 +02:00
|
|
|
<< Entry.getKey() << ": " << V.getKey() << "\n");
|
2017-10-06 22:24:34 +02:00
|
|
|
NumFunctions += Stats.IsFunction;
|
2019-03-02 00:51:54 +01:00
|
|
|
NumFuncsWithSrcLoc += Stats.HasSourceLocation;
|
2017-10-06 22:24:34 +02:00
|
|
|
NumInlinedFunctions += Stats.IsFunction * Stats.NumFnInlined;
|
2019-03-02 00:51:54 +01:00
|
|
|
NumAbstractOrigins += Stats.IsFunction * Stats.NumAbstractOrigins;
|
|
|
|
ParamTotal += Stats.NumParams;
|
|
|
|
ParamWithType += Stats.NumParamTypes;
|
|
|
|
ParamWithLoc += Stats.NumParamLocations;
|
|
|
|
ParamWithSrcLoc += Stats.NumParamSourceLocations;
|
|
|
|
VarTotal += Stats.NumVars;
|
|
|
|
VarWithType += Stats.NumVarTypes;
|
|
|
|
VarWithLoc += Stats.NumVarLocations;
|
|
|
|
VarWithSrcLoc += Stats.NumVarSourceLocations;
|
2017-10-06 22:24:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Print summary.
|
|
|
|
OS.SetBufferSize(1024);
|
2018-10-05 19:41:30 +02:00
|
|
|
OS << "{\"version\":" << Version;
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "Variable location quality metrics\n";
|
|
|
|
llvm::dbgs() << "---------------------------------\n");
|
2017-10-06 22:24:34 +02:00
|
|
|
printDatum(OS, "file", Filename.str());
|
|
|
|
printDatum(OS, "format", FormatName);
|
|
|
|
printDatum(OS, "source functions", NumFunctions);
|
2019-03-02 00:51:54 +01:00
|
|
|
printDatum(OS, "source functions with location", NumFuncsWithSrcLoc);
|
2017-10-06 22:24:34 +02:00
|
|
|
printDatum(OS, "inlined functions", NumInlinedFunctions);
|
2019-03-02 00:51:54 +01:00
|
|
|
printDatum(OS, "inlined funcs with abstract origins", NumAbstractOrigins);
|
|
|
|
printDatum(OS, "unique source variables", VarParamUnique);
|
|
|
|
printDatum(OS, "source variables", VarParamTotal);
|
|
|
|
printDatum(OS, "variables with location", VarParamWithLoc);
|
2018-10-05 22:37:17 +02:00
|
|
|
printDatum(OS, "call site entries", GlobalStats.CallSiteEntries);
|
2019-07-31 18:51:28 +02:00
|
|
|
printDatum(OS, "call site DIEs", GlobalStats.CallSiteDIEs);
|
|
|
|
printDatum(OS, "call site parameter DIEs", GlobalStats.CallSiteParamDIEs);
|
2019-11-19 11:28:21 +01:00
|
|
|
printDatum(OS, "scope bytes total", GlobalStats.ScopeBytes);
|
2017-10-06 22:24:34 +02:00
|
|
|
printDatum(OS, "scope bytes covered", GlobalStats.ScopeBytesCovered);
|
2019-09-10 12:37:28 +02:00
|
|
|
printDatum(OS, "entry value scope bytes covered",
|
|
|
|
GlobalStats.ScopeEntryValueBytesCovered);
|
|
|
|
printDatum(OS, "formal params scope bytes total",
|
2019-11-19 11:28:21 +01:00
|
|
|
GlobalStats.ParamScopeBytes);
|
2019-09-10 12:37:28 +02:00
|
|
|
printDatum(OS, "formal params scope bytes covered",
|
|
|
|
GlobalStats.ParamScopeBytesCovered);
|
|
|
|
printDatum(OS, "formal params entry value scope bytes covered",
|
|
|
|
GlobalStats.ParamScopeEntryValueBytesCovered);
|
2019-11-19 11:28:21 +01:00
|
|
|
printDatum(OS, "vars scope bytes total", GlobalStats.VarScopeBytes);
|
2019-09-10 12:37:28 +02:00
|
|
|
printDatum(OS, "vars scope bytes covered", GlobalStats.VarScopeBytesCovered);
|
|
|
|
printDatum(OS, "vars entry value scope bytes covered",
|
|
|
|
GlobalStats.VarScopeEntryValueBytesCovered);
|
2018-11-09 19:10:02 +01:00
|
|
|
printDatum(OS, "total function size", GlobalStats.FunctionSize);
|
|
|
|
printDatum(OS, "total inlined function size", GlobalStats.InlineFunctionSize);
|
2019-03-02 00:51:54 +01:00
|
|
|
printDatum(OS, "total formal params", ParamTotal);
|
|
|
|
printDatum(OS, "formal params with source location", ParamWithSrcLoc);
|
|
|
|
printDatum(OS, "formal params with type", ParamWithType);
|
|
|
|
printDatum(OS, "formal params with binary location", ParamWithLoc);
|
|
|
|
printDatum(OS, "total vars", VarTotal);
|
|
|
|
printDatum(OS, "vars with source location", VarWithSrcLoc);
|
|
|
|
printDatum(OS, "vars with type", VarWithType);
|
|
|
|
printDatum(OS, "vars with binary location", VarWithLoc);
|
2019-09-10 12:37:28 +02:00
|
|
|
printDatum(OS, "total variables procesed by location statistics",
|
|
|
|
LocStats.NumVarParam);
|
2020-04-02 10:58:27 +02:00
|
|
|
printSectionSizes(OS, Sizes);
|
2019-09-10 12:37:28 +02:00
|
|
|
printLocationStats(OS, "variables", LocStats.VarParamLocStats);
|
|
|
|
printLocationStats(OS, "variables (excluding the debug entry values)",
|
|
|
|
LocStats.VarParamNonEntryValLocStats);
|
|
|
|
printDatum(OS, "total params procesed by location statistics",
|
|
|
|
LocStats.NumParam);
|
|
|
|
printLocationStats(OS, "params", LocStats.ParamLocStats);
|
|
|
|
printLocationStats(OS, "params (excluding the debug entry values)",
|
|
|
|
LocStats.ParamNonEntryValLocStats);
|
|
|
|
printDatum(OS, "total vars procesed by location statistics", LocStats.NumVar);
|
|
|
|
printLocationStats(OS, "vars", LocStats.VarLocStats);
|
|
|
|
printLocationStats(OS, "vars (excluding the debug entry values)",
|
2019-10-02 15:24:45 +02:00
|
|
|
LocStats.VarNonEntryValLocStats);
|
2017-10-06 22:24:34 +02:00
|
|
|
OS << "}\n";
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(
|
2017-10-06 22:24:34 +02:00
|
|
|
llvm::dbgs() << "Total Availability: "
|
2019-03-02 00:51:54 +01:00
|
|
|
<< (int)std::round((VarParamWithLoc * 100.0) / VarParamTotal)
|
|
|
|
<< "%\n";
|
2017-10-06 22:24:34 +02:00
|
|
|
llvm::dbgs() << "PC Ranges covered: "
|
|
|
|
<< (int)std::round((GlobalStats.ScopeBytesCovered * 100.0) /
|
2019-11-19 11:28:21 +01:00
|
|
|
GlobalStats.ScopeBytes)
|
2017-10-06 22:24:34 +02:00
|
|
|
<< "%\n");
|
|
|
|
return true;
|
|
|
|
}
|