17a7e6055SDimitry Andric #include "llvm/Support/DebugCounter.h"
27a7e6055SDimitry Andric #include "llvm/Support/CommandLine.h"
37a7e6055SDimitry Andric #include "llvm/Support/Format.h"
47a7e6055SDimitry Andric #include "llvm/Support/ManagedStatic.h"
57a7e6055SDimitry Andric #include "llvm/Support/Options.h"
67a7e6055SDimitry Andric
77a7e6055SDimitry Andric using namespace llvm;
87a7e6055SDimitry Andric
9302affcbSDimitry Andric namespace {
107a7e6055SDimitry Andric // This class overrides the default list implementation of printing so we
117a7e6055SDimitry Andric // can pretty print the list of debug counter options. This type of
127a7e6055SDimitry Andric // dynamic option is pretty rare (basically this and pass lists).
137a7e6055SDimitry Andric class DebugCounterList : public cl::list<std::string, DebugCounter> {
147a7e6055SDimitry Andric private:
157a7e6055SDimitry Andric using Base = cl::list<std::string, DebugCounter>;
167a7e6055SDimitry Andric
177a7e6055SDimitry Andric public:
187a7e6055SDimitry Andric template <class... Mods>
DebugCounterList(Mods &&...Ms)197a7e6055SDimitry Andric explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {}
207a7e6055SDimitry Andric
217a7e6055SDimitry Andric private:
printOptionInfo(size_t GlobalWidth) const227a7e6055SDimitry Andric void printOptionInfo(size_t GlobalWidth) const override {
237a7e6055SDimitry Andric // This is a variant of from generic_parser_base::printOptionInfo. Sadly,
247a7e6055SDimitry Andric // it's not easy to make it more usable. We could get it to print these as
257a7e6055SDimitry Andric // options if we were a cl::opt and registered them, but lists don't have
267a7e6055SDimitry Andric // options, nor does the parser for std::string. The other mechanisms for
277a7e6055SDimitry Andric // options are global and would pollute the global namespace with our
287a7e6055SDimitry Andric // counters. Rather than go that route, we have just overridden the
297a7e6055SDimitry Andric // printing, which only a few things call anyway.
307a7e6055SDimitry Andric outs() << " -" << ArgStr;
317a7e6055SDimitry Andric // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for
327a7e6055SDimitry Andric // width, so we do the same.
337a7e6055SDimitry Andric Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6);
347a7e6055SDimitry Andric const auto &CounterInstance = DebugCounter::instance();
357a7e6055SDimitry Andric for (auto Name : CounterInstance) {
367a7e6055SDimitry Andric const auto Info =
377a7e6055SDimitry Andric CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name));
387a7e6055SDimitry Andric size_t NumSpaces = GlobalWidth - Info.first.size() - 8;
397a7e6055SDimitry Andric outs() << " =" << Info.first;
407a7e6055SDimitry Andric outs().indent(NumSpaces) << " - " << Info.second << '\n';
417a7e6055SDimitry Andric }
427a7e6055SDimitry Andric }
437a7e6055SDimitry Andric };
44302affcbSDimitry Andric } // namespace
457a7e6055SDimitry Andric
467a7e6055SDimitry Andric // Create our command line option.
477a7e6055SDimitry Andric static DebugCounterList DebugCounterOption(
484ba319b5SDimitry Andric "debug-counter", cl::Hidden,
497a7e6055SDimitry Andric cl::desc("Comma separated list of debug counter skip and count"),
507a7e6055SDimitry Andric cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance()));
517a7e6055SDimitry Andric
52*b5893f02SDimitry Andric static cl::opt<bool> PrintDebugCounter(
53*b5893f02SDimitry Andric "print-debug-counter", cl::Hidden, cl::init(false), cl::Optional,
54*b5893f02SDimitry Andric cl::desc("Print out debug counter info after all counters accumulated"));
55*b5893f02SDimitry Andric
567a7e6055SDimitry Andric static ManagedStatic<DebugCounter> DC;
577a7e6055SDimitry Andric
58*b5893f02SDimitry Andric // Print information when destroyed, iff command line option is specified.
~DebugCounter()59*b5893f02SDimitry Andric DebugCounter::~DebugCounter() {
60*b5893f02SDimitry Andric if (isCountingEnabled() && PrintDebugCounter)
61*b5893f02SDimitry Andric print(dbgs());
62*b5893f02SDimitry Andric }
63*b5893f02SDimitry Andric
instance()647a7e6055SDimitry Andric DebugCounter &DebugCounter::instance() { return *DC; }
657a7e6055SDimitry Andric
667a7e6055SDimitry Andric // This is called by the command line parser when it sees a value for the
677a7e6055SDimitry Andric // debug-counter option defined above.
push_back(const std::string & Val)687a7e6055SDimitry Andric void DebugCounter::push_back(const std::string &Val) {
697a7e6055SDimitry Andric if (Val.empty())
707a7e6055SDimitry Andric return;
717a7e6055SDimitry Andric // The strings should come in as counter=value
727a7e6055SDimitry Andric auto CounterPair = StringRef(Val).split('=');
737a7e6055SDimitry Andric if (CounterPair.second.empty()) {
747a7e6055SDimitry Andric errs() << "DebugCounter Error: " << Val << " does not have an = in it\n";
757a7e6055SDimitry Andric return;
767a7e6055SDimitry Andric }
777a7e6055SDimitry Andric // Now we have counter=value.
787a7e6055SDimitry Andric // First, process value.
794ba319b5SDimitry Andric int64_t CounterVal;
807a7e6055SDimitry Andric if (CounterPair.second.getAsInteger(0, CounterVal)) {
817a7e6055SDimitry Andric errs() << "DebugCounter Error: " << CounterPair.second
827a7e6055SDimitry Andric << " is not a number\n";
837a7e6055SDimitry Andric return;
847a7e6055SDimitry Andric }
857a7e6055SDimitry Andric // Now we need to see if this is the skip or the count, remove the suffix, and
867a7e6055SDimitry Andric // add it to the counter values.
877a7e6055SDimitry Andric if (CounterPair.first.endswith("-skip")) {
887a7e6055SDimitry Andric auto CounterName = CounterPair.first.drop_back(5);
894ba319b5SDimitry Andric unsigned CounterID = getCounterId(CounterName);
907a7e6055SDimitry Andric if (!CounterID) {
917a7e6055SDimitry Andric errs() << "DebugCounter Error: " << CounterName
927a7e6055SDimitry Andric << " is not a registered counter\n";
937a7e6055SDimitry Andric return;
947a7e6055SDimitry Andric }
954ba319b5SDimitry Andric enableAllCounters();
96*b5893f02SDimitry Andric
97*b5893f02SDimitry Andric CounterInfo &Counter = Counters[CounterID];
98*b5893f02SDimitry Andric Counter.Skip = CounterVal;
99*b5893f02SDimitry Andric Counter.IsSet = true;
1007a7e6055SDimitry Andric } else if (CounterPair.first.endswith("-count")) {
1017a7e6055SDimitry Andric auto CounterName = CounterPair.first.drop_back(6);
1024ba319b5SDimitry Andric unsigned CounterID = getCounterId(CounterName);
1037a7e6055SDimitry Andric if (!CounterID) {
1047a7e6055SDimitry Andric errs() << "DebugCounter Error: " << CounterName
1057a7e6055SDimitry Andric << " is not a registered counter\n";
1067a7e6055SDimitry Andric return;
1077a7e6055SDimitry Andric }
1084ba319b5SDimitry Andric enableAllCounters();
109*b5893f02SDimitry Andric
110*b5893f02SDimitry Andric CounterInfo &Counter = Counters[CounterID];
111*b5893f02SDimitry Andric Counter.StopAfter = CounterVal;
112*b5893f02SDimitry Andric Counter.IsSet = true;
1137a7e6055SDimitry Andric } else {
1147a7e6055SDimitry Andric errs() << "DebugCounter Error: " << CounterPair.first
1157a7e6055SDimitry Andric << " does not end with -skip or -count\n";
1167a7e6055SDimitry Andric }
1177a7e6055SDimitry Andric }
1187a7e6055SDimitry Andric
print(raw_ostream & OS) const11924d58133SDimitry Andric void DebugCounter::print(raw_ostream &OS) const {
120*b5893f02SDimitry Andric SmallVector<StringRef, 16> CounterNames(RegisteredCounters.begin(),
121*b5893f02SDimitry Andric RegisteredCounters.end());
122*b5893f02SDimitry Andric sort(CounterNames.begin(), CounterNames.end());
123*b5893f02SDimitry Andric
124*b5893f02SDimitry Andric auto &Us = instance();
1257a7e6055SDimitry Andric OS << "Counters and values:\n";
126*b5893f02SDimitry Andric for (auto &CounterName : CounterNames) {
127*b5893f02SDimitry Andric unsigned CounterID = getCounterId(CounterName);
128*b5893f02SDimitry Andric OS << left_justify(RegisteredCounters[CounterID], 32) << ": {"
129*b5893f02SDimitry Andric << Us.Counters[CounterID].Count << "," << Us.Counters[CounterID].Skip
130*b5893f02SDimitry Andric << "," << Us.Counters[CounterID].StopAfter << "}\n";
131*b5893f02SDimitry Andric }
1327a7e6055SDimitry Andric }
13324d58133SDimitry Andric
dump() const13424d58133SDimitry Andric LLVM_DUMP_METHOD void DebugCounter::dump() const {
13524d58133SDimitry Andric print(dbgs());
13624d58133SDimitry Andric }
137