Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 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 | |
Daniel Berlin | f0236fd | 2017-03-04 14:08:47 +0000 | [diff] [blame^] | 84 | auto Res = Counters.insert({CounterID, {0, -1}}); |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 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 | |
Daniel Berlin | f0236fd | 2017-03-04 14:08:47 +0000 | [diff] [blame^] | 95 | auto Res = Counters.insert({CounterID, {0, -1}}); |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 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 | } |