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 6 using namespace llvm; 7 8 namespace { 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 (const 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 } // namespace 44 45 // Create our command line option. 46 static DebugCounterList DebugCounterOption( 47 "debug-counter", cl::Hidden, 48 cl::desc("Comma separated list of debug counter skip and count"), 49 cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance())); 50 51 static cl::opt<bool> PrintDebugCounter( 52 "print-debug-counter", cl::Hidden, cl::init(false), cl::Optional, 53 cl::desc("Print out debug counter info after all counters accumulated")); 54 55 static ManagedStatic<DebugCounter> DC; 56 57 // Print information when destroyed, iff command line option is specified. 58 DebugCounter::~DebugCounter() { 59 if (isCountingEnabled() && PrintDebugCounter) 60 print(dbgs()); 61 } 62 63 DebugCounter &DebugCounter::instance() { return *DC; } 64 65 // This is called by the command line parser when it sees a value for the 66 // debug-counter option defined above. 67 void DebugCounter::push_back(const std::string &Val) { 68 if (Val.empty()) 69 return; 70 // The strings should come in as counter=value 71 auto CounterPair = StringRef(Val).split('='); 72 if (CounterPair.second.empty()) { 73 errs() << "DebugCounter Error: " << Val << " does not have an = in it\n"; 74 return; 75 } 76 // Now we have counter=value. 77 // First, process value. 78 int64_t CounterVal; 79 if (CounterPair.second.getAsInteger(0, CounterVal)) { 80 errs() << "DebugCounter Error: " << CounterPair.second 81 << " is not a number\n"; 82 return; 83 } 84 // Now we need to see if this is the skip or the count, remove the suffix, and 85 // add it to the counter values. 86 if (CounterPair.first.endswith("-skip")) { 87 auto CounterName = CounterPair.first.drop_back(5); 88 unsigned CounterID = getCounterId(std::string(CounterName)); 89 if (!CounterID) { 90 errs() << "DebugCounter Error: " << CounterName 91 << " is not a registered counter\n"; 92 return; 93 } 94 enableAllCounters(); 95 96 CounterInfo &Counter = Counters[CounterID]; 97 Counter.Skip = CounterVal; 98 Counter.IsSet = true; 99 } else if (CounterPair.first.endswith("-count")) { 100 auto CounterName = CounterPair.first.drop_back(6); 101 unsigned CounterID = getCounterId(std::string(CounterName)); 102 if (!CounterID) { 103 errs() << "DebugCounter Error: " << CounterName 104 << " is not a registered counter\n"; 105 return; 106 } 107 enableAllCounters(); 108 109 CounterInfo &Counter = Counters[CounterID]; 110 Counter.StopAfter = CounterVal; 111 Counter.IsSet = true; 112 } else { 113 errs() << "DebugCounter Error: " << CounterPair.first 114 << " does not end with -skip or -count\n"; 115 } 116 } 117 118 void DebugCounter::print(raw_ostream &OS) const { 119 SmallVector<StringRef, 16> CounterNames(RegisteredCounters.begin(), 120 RegisteredCounters.end()); 121 sort(CounterNames.begin(), CounterNames.end()); 122 123 auto &Us = instance(); 124 OS << "Counters and values:\n"; 125 for (auto &CounterName : CounterNames) { 126 unsigned CounterID = getCounterId(std::string(CounterName)); 127 OS << left_justify(RegisteredCounters[CounterID], 32) << ": {" 128 << Us.Counters[CounterID].Count << "," << Us.Counters[CounterID].Skip 129 << "," << Us.Counters[CounterID].StopAfter << "}\n"; 130 } 131 } 132 133 LLVM_DUMP_METHOD void DebugCounter::dump() const { 134 print(dbgs()); 135 } 136