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 | |
Benjamin Kramer | debb3c3 | 2017-05-26 20:09:00 +0000 | [diff] [blame] | 9 | namespace { |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 10 | // This class overrides the default list implementation of printing so we |
| 11 | // can pretty print the list of debug counter options. This type of |
| 12 | // dynamic option is pretty rare (basically this and pass lists). |
| 13 | class DebugCounterList : public cl::list<std::string, DebugCounter> { |
| 14 | private: |
| 15 | using Base = cl::list<std::string, DebugCounter>; |
| 16 | |
| 17 | public: |
| 18 | template <class... Mods> |
| 19 | explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {} |
| 20 | |
| 21 | private: |
| 22 | void printOptionInfo(size_t GlobalWidth) const override { |
| 23 | // This is a variant of from generic_parser_base::printOptionInfo. Sadly, |
| 24 | // it's not easy to make it more usable. We could get it to print these as |
| 25 | // options if we were a cl::opt and registered them, but lists don't have |
| 26 | // options, nor does the parser for std::string. The other mechanisms for |
| 27 | // options are global and would pollute the global namespace with our |
| 28 | // counters. Rather than go that route, we have just overridden the |
| 29 | // printing, which only a few things call anyway. |
| 30 | outs() << " -" << ArgStr; |
| 31 | // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for |
| 32 | // width, so we do the same. |
| 33 | Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6); |
| 34 | const auto &CounterInstance = DebugCounter::instance(); |
| 35 | for (auto Name : CounterInstance) { |
| 36 | const auto Info = |
| 37 | CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name)); |
| 38 | size_t NumSpaces = GlobalWidth - Info.first.size() - 8; |
| 39 | outs() << " =" << Info.first; |
| 40 | outs().indent(NumSpaces) << " - " << Info.second << '\n'; |
| 41 | } |
| 42 | } |
| 43 | }; |
Benjamin Kramer | debb3c3 | 2017-05-26 20:09:00 +0000 | [diff] [blame] | 44 | } // namespace |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 45 | |
| 46 | // Create our command line option. |
| 47 | static DebugCounterList DebugCounterOption( |
Craig Topper | 8a1787a | 2018-04-01 22:16:52 +0000 | [diff] [blame] | 48 | "debug-counter", cl::Hidden, |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 49 | cl::desc("Comma separated list of debug counter skip and count"), |
| 50 | cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance())); |
| 51 | |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 52 | static cl::opt<bool> PrintDebugCounter( |
| 53 | "print-debug-counter", cl::Hidden, cl::init(false), cl::Optional, |
| 54 | cl::desc("Print out debug counter info after all counters accumulated")); |
| 55 | |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 56 | static ManagedStatic<DebugCounter> DC; |
| 57 | |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 58 | // Print information when destroyed, iff command line option is specified. |
| 59 | DebugCounter::~DebugCounter() { |
| 60 | if (isCountingEnabled() && PrintDebugCounter) |
| 61 | print(dbgs()); |
| 62 | } |
| 63 | |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 64 | DebugCounter &DebugCounter::instance() { return *DC; } |
| 65 | |
| 66 | // This is called by the command line parser when it sees a value for the |
| 67 | // debug-counter option defined above. |
| 68 | void DebugCounter::push_back(const std::string &Val) { |
| 69 | if (Val.empty()) |
| 70 | return; |
| 71 | // The strings should come in as counter=value |
| 72 | auto CounterPair = StringRef(Val).split('='); |
| 73 | if (CounterPair.second.empty()) { |
| 74 | errs() << "DebugCounter Error: " << Val << " does not have an = in it\n"; |
| 75 | return; |
| 76 | } |
| 77 | // Now we have counter=value. |
| 78 | // First, process value. |
George Burgess IV | b00fb46 | 2018-07-23 21:49:36 +0000 | [diff] [blame] | 79 | int64_t CounterVal; |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 80 | if (CounterPair.second.getAsInteger(0, CounterVal)) { |
| 81 | errs() << "DebugCounter Error: " << CounterPair.second |
| 82 | << " is not a number\n"; |
| 83 | return; |
| 84 | } |
| 85 | // Now we need to see if this is the skip or the count, remove the suffix, and |
| 86 | // add it to the counter values. |
| 87 | if (CounterPair.first.endswith("-skip")) { |
| 88 | auto CounterName = CounterPair.first.drop_back(5); |
George Burgess IV | b00fb46 | 2018-07-23 21:49:36 +0000 | [diff] [blame] | 89 | unsigned CounterID = getCounterId(CounterName); |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 90 | if (!CounterID) { |
| 91 | errs() << "DebugCounter Error: " << CounterName |
| 92 | << " is not a registered counter\n"; |
| 93 | return; |
| 94 | } |
George Burgess IV | 31da130 | 2018-08-02 19:50:27 +0000 | [diff] [blame] | 95 | enableAllCounters(); |
George Burgess IV | 04df67e | 2018-08-17 22:34:04 +0000 | [diff] [blame] | 96 | |
| 97 | CounterInfo &Counter = Counters[CounterID]; |
| 98 | Counter.Skip = CounterVal; |
| 99 | Counter.IsSet = true; |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 100 | } else if (CounterPair.first.endswith("-count")) { |
| 101 | auto CounterName = CounterPair.first.drop_back(6); |
George Burgess IV | b00fb46 | 2018-07-23 21:49:36 +0000 | [diff] [blame] | 102 | unsigned CounterID = getCounterId(CounterName); |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 103 | if (!CounterID) { |
| 104 | errs() << "DebugCounter Error: " << CounterName |
| 105 | << " is not a registered counter\n"; |
| 106 | return; |
| 107 | } |
George Burgess IV | 31da130 | 2018-08-02 19:50:27 +0000 | [diff] [blame] | 108 | enableAllCounters(); |
George Burgess IV | 04df67e | 2018-08-17 22:34:04 +0000 | [diff] [blame] | 109 | |
| 110 | CounterInfo &Counter = Counters[CounterID]; |
| 111 | Counter.StopAfter = CounterVal; |
| 112 | Counter.IsSet = true; |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 113 | } else { |
| 114 | errs() << "DebugCounter Error: " << CounterPair.first |
| 115 | << " does not end with -skip or -count\n"; |
| 116 | } |
| 117 | } |
| 118 | |
Frederich Munch | dceb612 | 2017-06-14 19:16:22 +0000 | [diff] [blame] | 119 | void DebugCounter::print(raw_ostream &OS) const { |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 120 | SmallVector<StringRef, 16> CounterNames(RegisteredCounters.begin(), |
| 121 | RegisteredCounters.end()); |
| 122 | sort(CounterNames.begin(), CounterNames.end()); |
| 123 | |
| 124 | auto &Us = instance(); |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 125 | OS << "Counters and values:\n"; |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 126 | for (auto &CounterName : CounterNames) { |
| 127 | unsigned CounterID = getCounterId(CounterName); |
| 128 | OS << left_justify(RegisteredCounters[CounterID], 32) << ": {" |
| 129 | << Us.Counters[CounterID].Count << "," << Us.Counters[CounterID].Skip |
| 130 | << "," << Us.Counters[CounterID].StopAfter << "}\n"; |
| 131 | } |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 132 | } |
Frederich Munch | dceb612 | 2017-06-14 19:16:22 +0000 | [diff] [blame] | 133 | |
| 134 | LLVM_DUMP_METHOD void DebugCounter::dump() const { |
| 135 | print(dbgs()); |
| 136 | } |