1 | #include "llvm/Support/DebugCounter.h" |
2 | |
3 | #include "DebugOptions.h" |
4 | |
5 | #include "llvm/Support/CommandLine.h" |
6 | #include "llvm/Support/Format.h" |
7 | |
8 | using namespace llvm; |
9 | |
10 | namespace { |
11 | // This class overrides the default list implementation of printing so we |
12 | // can pretty print the list of debug counter options. This type of |
13 | // dynamic option is pretty rare (basically this and pass lists). |
14 | class DebugCounterList : public cl::list<std::string, DebugCounter> { |
15 | private: |
16 | using Base = cl::list<std::string, DebugCounter>; |
17 | |
18 | public: |
19 | template <class... Mods> |
20 | explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {} |
21 | |
22 | private: |
23 | void printOptionInfo(size_t GlobalWidth) const override { |
24 | // This is a variant of from generic_parser_base::printOptionInfo. Sadly, |
25 | // it's not easy to make it more usable. We could get it to print these as |
26 | // options if we were a cl::opt and registered them, but lists don't have |
27 | // options, nor does the parser for std::string. The other mechanisms for |
28 | // options are global and would pollute the global namespace with our |
29 | // counters. Rather than go that route, we have just overridden the |
30 | // printing, which only a few things call anyway. |
31 | outs() << " -" << ArgStr; |
32 | // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for |
33 | // width, so we do the same. |
34 | Option::printHelpStr(HelpStr, Indent: GlobalWidth, FirstLineIndentedBy: ArgStr.size() + 6); |
35 | const auto &CounterInstance = DebugCounter::instance(); |
36 | for (const auto &Name : CounterInstance) { |
37 | const auto Info = |
38 | CounterInstance.getCounterInfo(ID: CounterInstance.getCounterId(Name)); |
39 | size_t NumSpaces = GlobalWidth - Info.first.size() - 8; |
40 | outs() << " =" << Info.first; |
41 | outs().indent(NumSpaces) << " - " << Info.second << '\n'; |
42 | } |
43 | } |
44 | }; |
45 | |
46 | // All global objects associated to the DebugCounter, including the DebugCounter |
47 | // itself, are owned by a single global instance of the DebugCounterOwner |
48 | // struct. This makes it easier to control the order in which constructors and |
49 | // destructors are run. |
50 | struct DebugCounterOwner { |
51 | DebugCounter DC; |
52 | DebugCounterList DebugCounterOption{ |
53 | "debug-counter" , cl::Hidden, |
54 | cl::desc("Comma separated list of debug counter skip and count" ), |
55 | cl::CommaSeparated, cl::location(L&: DC)}; |
56 | cl::opt<bool> PrintDebugCounter{ |
57 | "print-debug-counter" , cl::Hidden, cl::init(Val: false), cl::Optional, |
58 | cl::desc("Print out debug counter info after all counters accumulated" )}; |
59 | |
60 | DebugCounterOwner() { |
61 | // Our destructor uses the debug stream. By referencing it here, we |
62 | // ensure that its destructor runs after our destructor. |
63 | (void)dbgs(); |
64 | } |
65 | |
66 | // Print information when destroyed, iff command line option is specified. |
67 | ~DebugCounterOwner() { |
68 | if (DC.isCountingEnabled() && PrintDebugCounter) |
69 | DC.print(OS&: dbgs()); |
70 | } |
71 | }; |
72 | |
73 | } // anonymous namespace |
74 | |
75 | void llvm::initDebugCounterOptions() { (void)DebugCounter::instance(); } |
76 | |
77 | DebugCounter &DebugCounter::instance() { |
78 | static DebugCounterOwner O; |
79 | return O.DC; |
80 | } |
81 | |
82 | // This is called by the command line parser when it sees a value for the |
83 | // debug-counter option defined above. |
84 | void DebugCounter::push_back(const std::string &Val) { |
85 | if (Val.empty()) |
86 | return; |
87 | // The strings should come in as counter=value |
88 | auto CounterPair = StringRef(Val).split(Separator: '='); |
89 | if (CounterPair.second.empty()) { |
90 | errs() << "DebugCounter Error: " << Val << " does not have an = in it\n" ; |
91 | return; |
92 | } |
93 | // Now we have counter=value. |
94 | // First, process value. |
95 | int64_t CounterVal; |
96 | if (CounterPair.second.getAsInteger(Radix: 0, Result&: CounterVal)) { |
97 | errs() << "DebugCounter Error: " << CounterPair.second |
98 | << " is not a number\n" ; |
99 | return; |
100 | } |
101 | // Now we need to see if this is the skip or the count, remove the suffix, and |
102 | // add it to the counter values. |
103 | if (CounterPair.first.ends_with(Suffix: "-skip" )) { |
104 | auto CounterName = CounterPair.first.drop_back(N: 5); |
105 | unsigned CounterID = getCounterId(Name: std::string(CounterName)); |
106 | if (!CounterID) { |
107 | errs() << "DebugCounter Error: " << CounterName |
108 | << " is not a registered counter\n" ; |
109 | return; |
110 | } |
111 | enableAllCounters(); |
112 | |
113 | CounterInfo &Counter = Counters[CounterID]; |
114 | Counter.Skip = CounterVal; |
115 | Counter.IsSet = true; |
116 | } else if (CounterPair.first.ends_with(Suffix: "-count" )) { |
117 | auto CounterName = CounterPair.first.drop_back(N: 6); |
118 | unsigned CounterID = getCounterId(Name: std::string(CounterName)); |
119 | if (!CounterID) { |
120 | errs() << "DebugCounter Error: " << CounterName |
121 | << " is not a registered counter\n" ; |
122 | return; |
123 | } |
124 | enableAllCounters(); |
125 | |
126 | CounterInfo &Counter = Counters[CounterID]; |
127 | Counter.StopAfter = CounterVal; |
128 | Counter.IsSet = true; |
129 | } else { |
130 | errs() << "DebugCounter Error: " << CounterPair.first |
131 | << " does not end with -skip or -count\n" ; |
132 | } |
133 | } |
134 | |
135 | void DebugCounter::print(raw_ostream &OS) const { |
136 | SmallVector<StringRef, 16> CounterNames(RegisteredCounters.begin(), |
137 | RegisteredCounters.end()); |
138 | sort(C&: CounterNames); |
139 | |
140 | auto &Us = instance(); |
141 | OS << "Counters and values:\n" ; |
142 | for (auto &CounterName : CounterNames) { |
143 | unsigned CounterID = getCounterId(Name: std::string(CounterName)); |
144 | OS << left_justify(Str: RegisteredCounters[CounterID], Width: 32) << ": {" |
145 | << Us.Counters[CounterID].Count << "," << Us.Counters[CounterID].Skip |
146 | << "," << Us.Counters[CounterID].StopAfter << "}\n" ; |
147 | } |
148 | } |
149 | |
150 | LLVM_DUMP_METHOD void DebugCounter::dump() const { |
151 | print(OS&: dbgs()); |
152 | } |
153 | |