1 #include "llvm/Support/DebugCounter.h" 2 #include "llvm/Support/CommandLine.h" 3 #include "llvm/Support/Format.h" 4 #include "llvm/Support/ManagedStatic.h" 5 #include "llvm/Support/Options.h" 6 7 using namespace llvm; 8 9 // This class overrides the default list implementation of printing so we 10 // can pretty print the list of debug counter options. This type of 11 // dynamic option is pretty rare (basically this and pass lists). 12 class DebugCounterList : public cl::list<std::string, DebugCounter> { 13 private: 14 using Base = cl::list<std::string, DebugCounter>; 15 16 public: 17 template <class... Mods> 18 explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {} 19 20 private: 21 void printOptionInfo(size_t GlobalWidth) const override { 22 // This is a variant of from generic_parser_base::printOptionInfo. Sadly, 23 // it's not easy to make it more usable. We could get it to print these as 24 // options if we were a cl::opt and registered them, but lists don't have 25 // options, nor does the parser for std::string. The other mechanisms for 26 // options are global and would pollute the global namespace with our 27 // counters. Rather than go that route, we have just overridden the 28 // printing, which only a few things call anyway. 29 outs() << " -" << ArgStr; 30 // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for 31 // width, so we do the same. 32 Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6); 33 const auto &CounterInstance = DebugCounter::instance(); 34 for (auto Name : CounterInstance) { 35 const auto Info = 36 CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name)); 37 size_t NumSpaces = GlobalWidth - Info.first.size() - 8; 38 outs() << " =" << Info.first; 39 outs().indent(NumSpaces) << " - " << Info.second << '\n'; 40 } 41 } 42 }; 43 44 // Create our command line option. 45 static DebugCounterList DebugCounterOption( 46 "debug-counter", 47 cl::desc("Comma separated list of debug counter skip and count"), 48 cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance())); 49 50 static ManagedStatic<DebugCounter> DC; 51 52 DebugCounter &DebugCounter::instance() { return *DC; } 53 54 // This is called by the command line parser when it sees a value for the 55 // debug-counter option defined above. 56 void DebugCounter::push_back(const std::string &Val) { 57 if (Val.empty()) 58 return; 59 // The strings should come in as counter=value 60 auto CounterPair = StringRef(Val).split('='); 61 if (CounterPair.second.empty()) { 62 errs() << "DebugCounter Error: " << Val << " does not have an = in it\n"; 63 return; 64 } 65 // Now we have counter=value. 66 // First, process value. 67 long CounterVal; 68 if (CounterPair.second.getAsInteger(0, CounterVal)) { 69 errs() << "DebugCounter Error: " << CounterPair.second 70 << " is not a number\n"; 71 return; 72 } 73 // Now we need to see if this is the skip or the count, remove the suffix, and 74 // add it to the counter values. 75 if (CounterPair.first.endswith("-skip")) { 76 auto CounterName = CounterPair.first.drop_back(5); 77 unsigned CounterID = RegisteredCounters.idFor(CounterName); 78 if (!CounterID) { 79 errs() << "DebugCounter Error: " << CounterName 80 << " is not a registered counter\n"; 81 return; 82 } 83 84 auto Res = Counters.insert({CounterID, {0, -1}}); 85 Res.first->second.first = CounterVal; 86 } else if (CounterPair.first.endswith("-count")) { 87 auto CounterName = CounterPair.first.drop_back(6); 88 unsigned CounterID = RegisteredCounters.idFor(CounterName); 89 if (!CounterID) { 90 errs() << "DebugCounter Error: " << CounterName 91 << " is not a registered counter\n"; 92 return; 93 } 94 95 auto Res = Counters.insert({CounterID, {0, -1}}); 96 Res.first->second.second = CounterVal; 97 } else { 98 errs() << "DebugCounter Error: " << CounterPair.first 99 << " does not end with -skip or -count\n"; 100 } 101 } 102 103 void DebugCounter::print(raw_ostream &OS) { 104 OS << "Counters and values:\n"; 105 for (const auto &KV : Counters) 106 OS << left_justify(RegisteredCounters[KV.first], 32) << ": {" 107 << KV.second.first << "," << KV.second.second << "}\n"; 108 } 109