Skip to content

Commit 451f3fc

Browse files
authored
[DwarfDump] Add new set of line-table-related statistics to llvm-dwarfdump (llvm#93289)
This patch adds a new set of statistics to llvm-dwarfdump that provide additional information about .debug_line regarding the number of bytes covered by the line table (and how many of those are covered by line 0 entries), and the number of entries within the table and how many of those are is_stmt, unique, or unique and non-line-0 (where "uniqueness" is based on file, line, and column only). Collectively these give a little more insight into the state of debug line information, rather than variables (as most of the dwarfdump statistics are currently oriented towards). I've added all of the stats that were useful to some degree, but I think the most generally useful stat is "unique line entries", since it gives the most straightforward indication of regressions, i.e. when the number goes down it means that fewer source lines are reachable in the program.
1 parent 9f70cd8 commit 451f3fc

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

llvm/test/tools/llvm-dwarfdump/X86/locstats.ll

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
; RUN: llc -debug-entry-values %s -o - -filetype=obj \
22
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
3+
; RUN: llc -debug-entry-values --dwarf-version=4 %s -o - -filetype=obj \
4+
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
5+
; RUN: llc -debug-entry-values --dwarf-version=3 %s -o - -filetype=obj \
6+
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
7+
; RUN: llc -debug-entry-values --dwarf-version=2 %s -o - -filetype=obj \
8+
; RUN: | llvm-dwarfdump -statistics - | FileCheck %s
39

410
; CHECK: "sum_all_variables(#bytes in parent scope covered by DW_OP_entry_value)": 5,
511
; CHECK-NEXT: "sum_all_params(#bytes in parent scope)": 20,
@@ -89,6 +95,12 @@
8995
; CHECK-NEXT: "#local vars - entry values with [80%,90%) of parent scope covered by DW_AT_location": 1,
9096
; CHECK-NEXT: "#local vars - entry values with [90%,100%) of parent scope covered by DW_AT_location": 0,
9197
; CHECK-NEXT: "#local vars - entry values with 100% of parent scope covered by DW_AT_location": 1
98+
; CHECK-NEXT: "#bytes with line information": 51,
99+
; CHECK-NEXT: "#bytes with line-0 locations": 3,
100+
; CHECK-NEXT: "#line entries": 7,
101+
; CHECK-NEXT: "#line entries (is_stmt)": 5,
102+
; CHECK-NEXT: "#line entries (unique)": 6,
103+
; CHECK-NEXT: "#line entries (unique non-0)": 5
92104

93105
; The source code of the test case:
94106
; extern void fn3(int *);

llvm/tools/llvm-dwarfdump/Statistics.cpp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "llvm-dwarfdump.h"
1010
#include "llvm/ADT/DenseMap.h"
11+
#include "llvm/ADT/DenseSet.h"
1112
#include "llvm/ADT/StringSet.h"
1213
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
1314
#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
@@ -188,6 +189,16 @@ struct LocationStats {
188189
/// Total number of local variables processed.
189190
SaturatingUINT64 NumVar = 0;
190191
};
192+
193+
/// Holds accumulated debug line statistics across all CUs.
194+
struct LineStats {
195+
SaturatingUINT64 NumBytes = 0;
196+
SaturatingUINT64 NumLineZeroBytes = 0;
197+
SaturatingUINT64 NumEntries = 0;
198+
SaturatingUINT64 NumIsStmtEntries = 0;
199+
SaturatingUINT64 NumUniqueEntries = 0;
200+
SaturatingUINT64 NumUniqueNonZeroEntries = 0;
201+
};
191202
} // namespace
192203

193204
/// Collect debug location statistics for one DIE.
@@ -848,6 +859,7 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
848859
StringRef FormatName = Obj.getFileFormatName();
849860
GlobalStats GlobalStats;
850861
LocationStats LocStats;
862+
LineStats LnStats;
851863
StringMap<PerFunctionStats> Statistics;
852864
// This variable holds variable information for functions with
853865
// abstract_origin globally, across all CUs.
@@ -856,6 +868,14 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
856868
// abstract_origin.
857869
FunctionDIECUTyMap AbstractOriginFnCUs;
858870
CrossCUReferencingDIELocationTy CrossCUReferencesToBeResolved;
871+
// Tuple representing a single source code position in the line table. Fields
872+
// are respectively: Line, Col, File, where 'File' is an index into the Files
873+
// vector below.
874+
using LineTuple = std::tuple<uint32_t, uint16_t, uint16_t>;
875+
SmallVector<std::string> Files;
876+
DenseSet<LineTuple> UniqueLines;
877+
DenseSet<LineTuple> UniqueNonZeroLines;
878+
859879
for (const auto &CU : static_cast<DWARFContext *>(&DICtx)->compile_units()) {
860880
if (DWARFDie CUDie = CU->getNonSkeletonUnitDIE(false)) {
861881
// This variable holds variable information for functions with
@@ -882,8 +902,58 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
882902
CrossCUReferencesToBeResolved.push_back(
883903
DIELocation(CUDie.getDwarfUnit(), CrossCUReferencingDIEOffset));
884904
}
905+
const auto *LineTable = DICtx.getLineTableForUnit(CU.get());
906+
std::optional<uint64_t> LastFileIdxOpt;
907+
if (LineTable)
908+
LastFileIdxOpt = LineTable->getLastValidFileIndex();
909+
if (LastFileIdxOpt) {
910+
// Each CU has its own file index; in order to track unique line entries
911+
// across CUs, we therefore need to map each CU file index to a global
912+
// file index, which we store here.
913+
DenseMap<uint64_t, uint16_t> CUFileMapping;
914+
for (uint64_t FileIdx = 0; FileIdx <= *LastFileIdxOpt; ++FileIdx) {
915+
std::string File;
916+
if (LineTable->getFileNameByIndex(
917+
FileIdx, CU->getCompilationDir(),
918+
DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
919+
File)) {
920+
auto ExistingFile = llvm::find(Files, File);
921+
if (ExistingFile != Files.end()) {
922+
CUFileMapping[FileIdx] = std::distance(Files.begin(), ExistingFile);
923+
} else {
924+
CUFileMapping[FileIdx] = Files.size();
925+
Files.push_back(File);
926+
}
927+
}
928+
}
929+
for (const auto &Seq : LineTable->Sequences) {
930+
LnStats.NumBytes += Seq.HighPC - Seq.LowPC;
931+
// Ignore the `end_sequence` entry, since it's not interesting for us.
932+
LnStats.NumEntries += Seq.LastRowIndex - Seq.FirstRowIndex - 1;
933+
for (size_t RowIdx = Seq.FirstRowIndex; RowIdx < Seq.LastRowIndex - 1;
934+
++RowIdx) {
935+
auto Entry = LineTable->Rows[RowIdx];
936+
if (Entry.IsStmt)
937+
LnStats.NumIsStmtEntries += 1;
938+
assert(CUFileMapping.contains(Entry.File) &&
939+
"Should have been collected earlier!");
940+
uint16_t MappedFile = CUFileMapping[Entry.File];
941+
UniqueLines.insert({Entry.Line, Entry.Column, MappedFile});
942+
if (Entry.Line != 0) {
943+
UniqueNonZeroLines.insert({Entry.Line, Entry.Column, MappedFile});
944+
} else {
945+
auto EntryStartAddress = Entry.Address.Address;
946+
auto EntryEndAddress = LineTable->Rows[RowIdx + 1].Address.Address;
947+
LnStats.NumLineZeroBytes += EntryEndAddress - EntryStartAddress;
948+
}
949+
}
950+
}
951+
}
885952
}
886953

954+
LnStats.NumUniqueEntries = UniqueLines.size();
955+
LnStats.NumUniqueNonZeroEntries = UniqueNonZeroLines.size();
956+
887957
/// Resolve CrossCU references.
888958
collectZeroLocCovForVarsWithCrossCUReferencingAbstractOrigin(
889959
LocStats, AbstractOriginFnCUs, GlobalAbstractOriginFnInfo,
@@ -1043,6 +1113,16 @@ bool dwarfdump::collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx,
10431113
printLocationStats(J, "#local vars", LocStats.LocalVarLocStats);
10441114
printLocationStats(J, "#local vars - entry values",
10451115
LocStats.LocalVarNonEntryValLocStats);
1116+
1117+
// Print line statistics for the object file.
1118+
printDatum(J, "#bytes with line information", LnStats.NumBytes.Value);
1119+
printDatum(J, "#bytes with line-0 locations", LnStats.NumLineZeroBytes.Value);
1120+
printDatum(J, "#line entries", LnStats.NumEntries.Value);
1121+
printDatum(J, "#line entries (is_stmt)", LnStats.NumIsStmtEntries.Value);
1122+
printDatum(J, "#line entries (unique)", LnStats.NumUniqueEntries.Value);
1123+
printDatum(J, "#line entries (unique non-0)",
1124+
LnStats.NumUniqueNonZeroEntries.Value);
1125+
10461126
J.objectEnd();
10471127
OS << '\n';
10481128
LLVM_DEBUG(

0 commit comments

Comments
 (0)