1 #include "llvm/Support/DebugCounter.h"
3 #include "DebugOptions.h"
5 #include "llvm/Support/CommandLine.h"
6 #include "llvm/Support/Format.h"
12 void DebugCounter::Chunk::print(llvm::raw_ostream
&OS
) {
16 OS
<< Begin
<< "-" << End
;
19 void DebugCounter::printChunks(raw_ostream
&OS
, ArrayRef
<Chunk
> Chunks
) {
24 for (auto E
: Chunks
) {
34 bool DebugCounter::parseChunks(StringRef Str
, SmallVector
<Chunk
> &Chunks
) {
35 StringRef Remaining
= Str
;
37 auto ConsumeInt
= [&]() -> int64_t {
39 Remaining
.take_until([](char c
) { return c
< '0' || c
> '9'; });
41 if (Number
.getAsInteger(10, Res
)) {
42 errs() << "Failed to parse int at : " << Remaining
<< "\n";
45 Remaining
= Remaining
.drop_front(Number
.size());
50 int64_t Num
= ConsumeInt();
53 if (!Chunks
.empty() && Num
<= Chunks
[Chunks
.size() - 1].End
) {
54 errs() << "Expected Chunks to be in increasing order " << Num
55 << " <= " << Chunks
[Chunks
.size() - 1].End
<< "\n";
58 if (Remaining
.starts_with("-")) {
59 Remaining
= Remaining
.drop_front();
60 int64_t Num2
= ConsumeInt();
64 errs() << "Expected " << Num
<< " < " << Num2
<< " in " << Num
<< "-"
69 Chunks
.push_back({Num
, Num2
});
71 Chunks
.push_back({Num
, Num
});
73 if (Remaining
.starts_with(":")) {
74 Remaining
= Remaining
.drop_front();
77 if (Remaining
.empty())
79 errs() << "Failed to parse at : " << Remaining
;
88 // This class overrides the default list implementation of printing so we
89 // can pretty print the list of debug counter options. This type of
90 // dynamic option is pretty rare (basically this and pass lists).
91 class DebugCounterList
: public cl::list
<std::string
, DebugCounter
> {
93 using Base
= cl::list
<std::string
, DebugCounter
>;
96 template <class... Mods
>
97 explicit DebugCounterList(Mods
&&... Ms
) : Base(std::forward
<Mods
>(Ms
)...) {}
100 void printOptionInfo(size_t GlobalWidth
) const override
{
101 // This is a variant of from generic_parser_base::printOptionInfo. Sadly,
102 // it's not easy to make it more usable. We could get it to print these as
103 // options if we were a cl::opt and registered them, but lists don't have
104 // options, nor does the parser for std::string. The other mechanisms for
105 // options are global and would pollute the global namespace with our
106 // counters. Rather than go that route, we have just overridden the
107 // printing, which only a few things call anyway.
108 outs() << " -" << ArgStr
;
109 // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for
110 // width, so we do the same.
111 Option::printHelpStr(HelpStr
, GlobalWidth
, ArgStr
.size() + 6);
112 const auto &CounterInstance
= DebugCounter::instance();
113 for (const auto &Name
: CounterInstance
) {
115 CounterInstance
.getCounterInfo(CounterInstance
.getCounterId(Name
));
116 size_t NumSpaces
= GlobalWidth
- Info
.first
.size() - 8;
117 outs() << " =" << Info
.first
;
118 outs().indent(NumSpaces
) << " - " << Info
.second
<< '\n';
123 // All global objects associated to the DebugCounter, including the DebugCounter
124 // itself, are owned by a single global instance of the DebugCounterOwner
125 // struct. This makes it easier to control the order in which constructors and
126 // destructors are run.
127 struct DebugCounterOwner
: DebugCounter
{
128 DebugCounterList DebugCounterOption
{
129 "debug-counter", cl::Hidden
,
130 cl::desc("Comma separated list of debug counter skip and count"),
131 cl::CommaSeparated
, cl::location
<DebugCounter
>(*this)};
132 cl::opt
<bool, true> PrintDebugCounter
{
133 "print-debug-counter",
136 cl::location(this->ShouldPrintCounter
),
138 cl::desc("Print out debug counter info after all counters accumulated")};
139 cl::opt
<bool, true> BreakOnLastCount
{
140 "debug-counter-break-on-last",
143 cl::location(this->BreakOnLast
),
145 cl::desc("Insert a break point on the last enabled count of a "
148 DebugCounterOwner() {
149 // Our destructor uses the debug stream. By referencing it here, we
150 // ensure that its destructor runs after our destructor.
154 // Print information when destroyed, iff command line option is specified.
155 ~DebugCounterOwner() {
156 if (ShouldPrintCounter
)
161 } // anonymous namespace
163 void llvm::initDebugCounterOptions() { (void)DebugCounter::instance(); }
165 DebugCounter
&DebugCounter::instance() {
166 static DebugCounterOwner O
;
170 // This is called by the command line parser when it sees a value for the
171 // debug-counter option defined above.
172 void DebugCounter::push_back(const std::string
&Val
) {
176 // The strings should come in as counter=chunk_list
177 auto CounterPair
= StringRef(Val
).split('=');
178 if (CounterPair
.second
.empty()) {
179 errs() << "DebugCounter Error: " << Val
<< " does not have an = in it\n";
182 StringRef CounterName
= CounterPair
.first
;
183 SmallVector
<Chunk
> Chunks
;
185 if (parseChunks(CounterPair
.second
, Chunks
)) {
189 unsigned CounterID
= getCounterId(std::string(CounterName
));
191 errs() << "DebugCounter Error: " << CounterName
192 << " is not a registered counter\n";
197 CounterInfo
&Counter
= Counters
[CounterID
];
198 Counter
.IsSet
= true;
199 Counter
.Chunks
= std::move(Chunks
);
202 void DebugCounter::print(raw_ostream
&OS
) const {
203 SmallVector
<StringRef
, 16> CounterNames(RegisteredCounters
.begin(),
204 RegisteredCounters
.end());
207 auto &Us
= instance();
208 OS
<< "Counters and values:\n";
209 for (auto &CounterName
: CounterNames
) {
210 unsigned CounterID
= getCounterId(std::string(CounterName
));
211 OS
<< left_justify(RegisteredCounters
[CounterID
], 32) << ": {"
212 << Us
.Counters
[CounterID
].Count
<< ",";
213 printChunks(OS
, Us
.Counters
[CounterID
].Chunks
);
218 bool DebugCounter::shouldExecuteImpl(unsigned CounterName
) {
219 auto &Us
= instance();
220 auto Result
= Us
.Counters
.find(CounterName
);
221 if (Result
!= Us
.Counters
.end()) {
222 auto &CounterInfo
= Result
->second
;
223 int64_t CurrCount
= CounterInfo
.Count
++;
224 uint64_t CurrIdx
= CounterInfo
.CurrChunkIdx
;
226 if (CounterInfo
.Chunks
.empty())
228 if (CurrIdx
>= CounterInfo
.Chunks
.size())
231 bool Res
= CounterInfo
.Chunks
[CurrIdx
].contains(CurrCount
);
232 if (Us
.BreakOnLast
&& CurrIdx
== (CounterInfo
.Chunks
.size() - 1) &&
233 CurrCount
== CounterInfo
.Chunks
[CurrIdx
].End
) {
234 LLVM_BUILTIN_DEBUGTRAP
;
236 if (CurrCount
> CounterInfo
.Chunks
[CurrIdx
].End
) {
237 CounterInfo
.CurrChunkIdx
++;
239 /// Handle consecutive blocks.
240 if (CounterInfo
.CurrChunkIdx
< CounterInfo
.Chunks
.size() &&
241 CurrCount
== CounterInfo
.Chunks
[CounterInfo
.CurrChunkIdx
].Begin
)
246 // Didn't find the counter, should we warn?
250 LLVM_DUMP_METHOD
void DebugCounter::dump() const {