Skip to content

[DwarfDump] Add new set of line-table-related statistics to llvm-dwarfdump #93289

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions llvm/test/tools/llvm-dwarfdump/X86/locstats.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
; RUN: llc -debug-entry-values %s -o - -filetype=obj \
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
; RUN: llc -debug-entry-values --dwarf-version=4 %s -o - -filetype=obj \
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
; RUN: llc -debug-entry-values --dwarf-version=3 %s -o - -filetype=obj \
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
; RUN: llc -debug-entry-values --dwarf-version=2 %s -o - -filetype=obj \
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s

; CHECK: "sum_all_variables(#bytes in parent scope covered by DW_OP_entry_value)": 5,
; CHECK-NEXT: "sum_all_params(#bytes in parent scope)": 20,
Expand Down Expand Up @@ -89,6 +95,12 @@
; CHECK-NEXT: "#local vars - entry values with [80%,90%) of parent scope covered by DW_AT_location": 1,
; CHECK-NEXT: "#local vars - entry values with [90%,100%) of parent scope covered by DW_AT_location": 0,
; CHECK-NEXT: "#local vars - entry values with 100% of parent scope covered by DW_AT_location": 1
; CHECK-NEXT: "#bytes with line information": 51,
; CHECK-NEXT: "#bytes with line-0 locations": 3,
; CHECK-NEXT: "#line entries": 7,
; CHECK-NEXT: "#line entries (is_stmt)": 5,
; CHECK-NEXT: "#line entries (unique)": 6,
; CHECK-NEXT: "#line entries (unique non-0)": 5

; The source code of the test case:
; extern void fn3(int *);
Expand Down
80 changes: 80 additions & 0 deletions llvm/tools/llvm-dwarfdump/Statistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "llvm-dwarfdump.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
Expand Down Expand Up @@ -188,6 +189,16 @@ struct LocationStats {
/// Total number of local variables processed.
SaturatingUINT64 NumVar = 0;
};

/// Holds accumulated debug line statistics across all CUs.
struct LineStats {
SaturatingUINT64 NumBytes = 0;
SaturatingUINT64 NumLineZeroBytes = 0;
SaturatingUINT64 NumEntries = 0;
SaturatingUINT64 NumIsStmtEntries = 0;
SaturatingUINT64 NumUniqueEntries = 0;
SaturatingUINT64 NumUniqueNonZeroEntries = 0;
};
} // namespace

/// Collect debug location statistics for one DIE.
Expand Down Expand Up @@ -848,6 +859,7 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
StringRef FormatName = Obj.getFileFormatName();
GlobalStats GlobalStats;
LocationStats LocStats;
LineStats LnStats;
StringMap<PerFunctionStats> Statistics;
// This variable holds variable information for functions with
// abstract_origin globally, across all CUs.
Expand All @@ -856,6 +868,14 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
// abstract_origin.
FunctionDIECUTyMap AbstractOriginFnCUs;
CrossCUReferencingDIELocationTy CrossCUReferencesToBeResolved;
// Tuple representing a single source code position in the line table. Fields
// are respectively: Line, Col, File, where 'File' is an index into the Files
// vector below.
using LineTuple = std::tuple<uint32_t, uint16_t, uint16_t>;
SmallVector<std::string> Files;
DenseSet<LineTuple> UniqueLines;
DenseSet<LineTuple> UniqueNonZeroLines;

for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) {
if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) {
// This variable holds variable information for functions with
Expand All @@ -882,8 +902,58 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
CrossCUReferencesToBeResolved.push_back(
DIELocation(CUDie.getDwarfUnit(), CrossCUReferencingDIEOffset));
}
const auto *LineTable = DICtx.getLineTableForUnit(CU.get());
std::optional<uint64_t> LastFileIdxOpt;
if (LineTable)
LastFileIdxOpt = LineTable->getLastValidFileIndex();
if (LastFileIdxOpt) {
// Each CU has its own file index; in order to track unique line entries
// across CUs, we therefore need to map each CU file index to a global
// file index, which we store here.
DenseMap<uint64_t, uint16_t> CUFileMapping;
for (uint64_t FileIdx = 0; FileIdx <= *LastFileIdxOpt; ++FileIdx) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't dwarf 4 indices 1-based and 0-based in dwarf 5?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are - but the method getFileNameByIndex will return std::nullopt if you fetch index 0 for DWARFv4 and earlier, and we have the correct final index for the for-loop from getLastValidFileIndex, so in this case this loop still does the right thing.

std::string File;
if (LineTable->getFileNameByIndex(
FileIdx, CU->getCompilationDir(),
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
File)) {
auto ExistingFile = llvm::find(Files, File);
if (ExistingFile != Files.end()) {
CUFileMapping[FileIdx] = std::distance(Files.begin(), ExistingFile);
} else {
CUFileMapping[FileIdx] = Files.size();
Files.push_back(File);
}
}
}
for (const auto &Seq : LineTable->Sequences) {
LnStats.NumBytes += Seq.HighPC - Seq.LowPC;
// Ignore the `end_sequence` entry, since it's not interesting for us.
LnStats.NumEntries += Seq.LastRowIndex - Seq.FirstRowIndex - 1;
for (size_t RowIdx = Seq.FirstRowIndex; RowIdx < Seq.LastRowIndex - 1;
++RowIdx) {
auto Entry = LineTable->Rows[RowIdx];
if (Entry.IsStmt)
LnStats.NumIsStmtEntries += 1;
assert(CUFileMapping.contains(Entry.File) &&
"Should have been collected earlier!");
uint16_t MappedFile = CUFileMapping[Entry.File];
UniqueLines.insert({Entry.Line, Entry.Column, MappedFile});
if (Entry.Line != 0) {
UniqueNonZeroLines.insert({Entry.Line, Entry.Column, MappedFile});
} else {
auto EntryStartAddress = Entry.Address.Address;
auto EntryEndAddress = LineTable->Rows[RowIdx + 1].Address.Address;
LnStats.NumLineZeroBytes += EntryEndAddress - EntryStartAddress;
}
}
}
}
}

LnStats.NumUniqueEntries = UniqueLines.size();
LnStats.NumUniqueNonZeroEntries = UniqueNonZeroLines.size();

/// Resolve CrossCU references.
collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin(
LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
Expand Down Expand Up @@ -1043,6 +1113,16 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
printLocationStats(J, "#local vars", LocStats.LocalVarLocStats);
printLocationStats(J, "#local vars - entry values",
LocStats.LocalVarNonEntryValLocStats);

// Print line statistics for the object file.
printDatum(J, "#bytes with line information", LnStats.NumBytes.Value);
printDatum(J, "#bytes with line-0 locations", LnStats.NumLineZeroBytes.Value);
printDatum(J, "#line entries", LnStats.NumEntries.Value);
printDatum(J, "#line entries (is_stmt)", LnStats.NumIsStmtEntries.Value);
printDatum(J, "#line entries (unique)", LnStats.NumUniqueEntries.Value);
printDatum(J, "#line entries (unique non-0)",
LnStats.NumUniqueNonZeroEntries.Value);

J.objectEnd();
OS << '\n';
LLVM_DEBUG(
Expand Down
Loading