From 4b0a7fe008e6a61997f622b7993d6316d898deae Mon Sep 17 00:00:00 2001 From: Kristina Bessonova Date: Tue, 14 Jan 2020 20:39:04 +0200 Subject: [PATCH] [llvm-dwarfdump][Statistics] Make calculations of vars in global scope more accurate It isn't known how many times we've seen the same variable or member in the global scope (unlike in functions), but there still can be some duplicates among different CUs. So, this patch proposes to count variables in the global scope just as a sum of the number of vars, constant members and artificial entities. Reviewed by: aprantl Differential Revision: https://reviews.llvm.org/D73004 --- .../X86/stats-multiple-cu-members.ll | 61 ++++++++++++++++++++ llvm/tools/llvm-dwarfdump/Statistics.cpp | 66 +++++++++++----------- 2 files changed, 95 insertions(+), 32 deletions(-) create mode 100644 llvm/test/tools/llvm-dwarfdump/X86/stats-multiple-cu-members.ll diff --git a/llvm/test/tools/llvm-dwarfdump/X86/stats-multiple-cu-members.ll b/llvm/test/tools/llvm-dwarfdump/X86/stats-multiple-cu-members.ll new file mode 100644 index 0000000..5cc529e --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/stats-multiple-cu-members.ll @@ -0,0 +1,61 @@ +; RUN: llc -O0 %s -o - -filetype=obj \ +; RUN: | llvm-dwarfdump -statistics - | FileCheck %s + +; This checks that if DW_TAG_structure_type duplicates in multiple CU, +; the number of total vars ("source variables") will include every copy, +; so the number of "variables with location" doesn't exceed the number of total vars. + +; $ cat test.h +; struct s { static const int ss = 42; }; +; +; $ cat test1.cpp +; #include "test.h" +; s S1; +; +; $ cat test2.cpp +; #include "test.h" +; s S2; + +; CHECK: "source variables":4 +; CHECK-SAME: "variables with location":4 + +source_filename = "llvm-link" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +%struct.s = type { i8 } +%struct.s.1 = type { i8 } + +@S1 = dso_local global %struct.s zeroinitializer, align 1, !dbg !0 +@S2 = dso_local global %struct.s.1 zeroinitializer, align 1, !dbg !13 + +!llvm.dbg.cu = !{!2, !15} +!llvm.ident = !{!18, !18} +!llvm.module.flags = !{!19, !20, !21} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "S1", scope: !2, file: !3, line: 2, type: !6, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 10.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !5, globals: !12, splitDebugInlining: false, nameTableKind: None) +!3 = !DIFile(filename: "test1.cpp", directory: "/") +!4 = !{} +!5 = !{!6} +!6 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !7, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !8, identifier: "_ZTS1s") +!7 = !DIFile(filename: "./test.h", directory: "/") +!8 = !{!9} +!9 = !DIDerivedType(tag: DW_TAG_member, name: "ss", scope: !6, file: !7, line: 1, baseType: !10, flags: DIFlagStaticMember, extraData: i32 42) +!10 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !11) +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !{!0} +!13 = !DIGlobalVariableExpression(var: !14, expr: !DIExpression()) +!14 = distinct !DIGlobalVariable(name: "S2", scope: !15, file: !16, line: 2, type: !6, isLocal: false, isDefinition: true) +!15 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !16, producer: "clang version 10.0.0", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, retainedTypes: !22, globals: !17, splitDebugInlining: false, nameTableKind: None) +!16 = !DIFile(filename: "test2.cpp", directory: "/") +!17 = !{!13} +!18 = !{!"clang version 10.0.0"} +!19 = !{i32 7, !"Dwarf Version", i32 4} +!20 = !{i32 2, !"Debug Info Version", i32 3} +!21 = !{i32 1, !"wchar_size", i32 4} +!22 = !{!23} +!23 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !7, line: 1, size: 8, flags: DIFlagTypePassByValue, elements: !24, identifier: "_ZTS1s") +!24 = !{!25} +!25 = !DIDerivedType(tag: DW_TAG_member, name: "ss", scope: !23, file: !7, line: 1, baseType: !10, flags: DIFlagStaticMember, extraData: i32 42) diff --git a/llvm/tools/llvm-dwarfdump/Statistics.cpp b/llvm/tools/llvm-dwarfdump/Statistics.cpp index 92d17c3..f0656c1 100644 --- a/llvm/tools/llvm-dwarfdump/Statistics.cpp +++ b/llvm/tools/llvm-dwarfdump/Statistics.cpp @@ -31,6 +31,8 @@ struct PerFunctionStats { unsigned TotalVarWithLoc = 0; /// Number of constants with location across all inlined instances. unsigned ConstantMembers = 0; + /// Number of arificial variables, parameters or members across all instances. + unsigned NumArtificial = 0; /// List of all Variables and parameters in this function. StringSet<> VarsInFunction; /// Compile units also cover a PC range, but have this flag set to false. @@ -196,12 +198,13 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, bool HasLoc = false; bool HasSrcLoc = false; bool HasType = false; - bool IsArtificial = false; uint64_t BytesCovered = 0; uint64_t BytesEntryValuesCovered = 0; auto &FnStats = FnStatMap[FnPrefix]; bool IsParam = Die.getTag() == dwarf::DW_TAG_formal_parameter; bool IsVariable = Die.getTag() == dwarf::DW_TAG_variable; + bool IsConstantMember = Die.getTag() == dwarf::DW_TAG_member && + Die.find(dwarf::DW_AT_const_value); if (Die.getTag() == dwarf::DW_TAG_call_site || Die.getTag() == dwarf::DW_TAG_GNU_call_site) { @@ -215,7 +218,7 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, return; } - if (!IsParam && !IsVariable && Die.getTag() != dwarf::DW_TAG_member) { + if (!IsParam && !IsVariable && !IsConstantMember) { // Not a variable or constant member. return; } @@ -231,9 +234,6 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, if (Die.findRecursively(dwarf::DW_AT_type)) HasType = true; - if (Die.find(dwarf::DW_AT_artificial)) - IsArtificial = true; - auto IsEntryValue = [&](ArrayRef D) -> bool { DWARFUnit *U = Die.getDwarfUnit(); DataExtractor Data(toStringRef(D), @@ -252,10 +252,6 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, HasLoc = true; BytesCovered = BytesInScope; } else { - if (Die.getTag() == dwarf::DW_TAG_member) { - // Non-const member. - return; - } // Handle variables and function arguments. Expected> Loc = Die.getLocations(dwarf::DW_AT_location); @@ -307,7 +303,6 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, FnStats.VarsInFunction.insert(VarID); if (BytesInScope) { - FnStats.TotalVarWithLoc += (unsigned)HasLoc; // Turns out we have a lot of ranges that extend past the lexical scope. GlobalStats.ScopeBytesCovered += std::min(BytesInScope, BytesCovered); GlobalStats.ScopeBytes += BytesInScope; @@ -323,29 +318,36 @@ static void collectStatsForDie(DWARFDie Die, std::string FnPrefix, GlobalStats.VarScopeEntryValueBytesCovered += BytesEntryValuesCovered; } assert(GlobalStats.ScopeBytesCovered <= GlobalStats.ScopeBytes); - } else if (Die.getTag() == dwarf::DW_TAG_member) { + } + + if (IsConstantMember) { FnStats.ConstantMembers++; - } else { - FnStats.TotalVarWithLoc += (unsigned)HasLoc; + return; } - if (!IsArtificial) { - 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++; - } + + 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++; } } @@ -527,7 +529,7 @@ bool collectStatsForObjectFile(ObjectFile &Obj, DWARFContext &DICtx, (Stats.NumFnInlined + Stats.NumFnOutOfLine); // Count variables in global scope. if (!Stats.IsFunction) - TotalVars += Stats.VarsInFunction.size(); + TotalVars = Stats.NumVars + Stats.ConstantMembers + Stats.NumArtificial; unsigned Constants = Stats.ConstantMembers; VarParamWithLoc += Stats.TotalVarWithLoc + Constants; VarParamTotal += TotalVars; -- 2.7.4