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" |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 5 | |
| 6 | using namespace llvm; |
| 7 | |
Benjamin Kramer | debb3c3 | 2017-05-26 20:09:00 +0000 | [diff] [blame] | 8 | namespace { |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 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 | }; |
Benjamin Kramer | debb3c3 | 2017-05-26 20:09:00 +0000 | [diff] [blame] | 43 | } // namespace |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 44 | |
| 45 | // Create our command line option. |
| 46 | static DebugCounterList DebugCounterOption( |
Craig Topper | 8a1787a | 2018-04-01 22:16:52 +0000 | [diff] [blame] | 47 | "debug-counter", cl::Hidden, |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 48 | cl::desc("Comma separated list of debug counter skip and count"), |
| 49 | cl::CommaSeparated, cl::ZeroOrMore, cl::location(DebugCounter::instance())); |
| 50 | |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 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 | |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 55 | static ManagedStatic<DebugCounter> DC; |
| 56 | |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 57 | // Print information when destroyed, iff command line option is specified. |
| 58 | DebugCounter::~DebugCounter() { |
| 59 | if (isCountingEnabled() && PrintDebugCounter) |
| 60 | print(dbgs()); |
| 61 | } |
| 62 | |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 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. |
George Burgess IV | b00fb46 | 2018-07-23 21:49:36 +0000 | [diff] [blame] | 78 | int64_t CounterVal; |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 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); |
Benjamin Kramer | adcd026 | 2020-01-28 20:23:46 +0100 | [diff] [blame] | 88 | unsigned CounterID = getCounterId(std::string(CounterName)); |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 89 | if (!CounterID) { |
| 90 | errs() << "DebugCounter Error: " << CounterName |
| 91 | << " is not a registered counter\n"; |
| 92 | return; |
| 93 | } |
George Burgess IV | 31da130 | 2018-08-02 19:50:27 +0000 | [diff] [blame] | 94 | enableAllCounters(); |
George Burgess IV | 04df67e | 2018-08-17 22:34:04 +0000 | [diff] [blame] | 95 | |
| 96 | CounterInfo &Counter = Counters[CounterID]; |
| 97 | Counter.Skip = CounterVal; |
| 98 | Counter.IsSet = true; |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 99 | } else if (CounterPair.first.endswith("-count")) { |
| 100 | auto CounterName = CounterPair.first.drop_back(6); |
Benjamin Kramer | adcd026 | 2020-01-28 20:23:46 +0100 | [diff] [blame] | 101 | unsigned CounterID = getCounterId(std::string(CounterName)); |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 102 | if (!CounterID) { |
| 103 | errs() << "DebugCounter Error: " << CounterName |
| 104 | << " is not a registered counter\n"; |
| 105 | return; |
| 106 | } |
George Burgess IV | 31da130 | 2018-08-02 19:50:27 +0000 | [diff] [blame] | 107 | enableAllCounters(); |
George Burgess IV | 04df67e | 2018-08-17 22:34:04 +0000 | [diff] [blame] | 108 | |
| 109 | CounterInfo &Counter = Counters[CounterID]; |
| 110 | Counter.StopAfter = CounterVal; |
| 111 | Counter.IsSet = true; |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 112 | } else { |
| 113 | errs() << "DebugCounter Error: " << CounterPair.first |
| 114 | << " does not end with -skip or -count\n"; |
| 115 | } |
| 116 | } |
| 117 | |
Frederich Munch | dceb612 | 2017-06-14 19:16:22 +0000 | [diff] [blame] | 118 | void DebugCounter::print(raw_ostream &OS) const { |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 119 | SmallVector<StringRef, 16> CounterNames(RegisteredCounters.begin(), |
| 120 | RegisteredCounters.end()); |
| 121 | sort(CounterNames.begin(), CounterNames.end()); |
| 122 | |
| 123 | auto &Us = instance(); |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 124 | OS << "Counters and values:\n"; |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 125 | for (auto &CounterName : CounterNames) { |
Benjamin Kramer | adcd026 | 2020-01-28 20:23:46 +0100 | [diff] [blame] | 126 | unsigned CounterID = getCounterId(std::string(CounterName)); |
Zhizhou Yang | 13f76f8 | 2018-10-23 21:51:56 +0000 | [diff] [blame] | 127 | OS << left_justify(RegisteredCounters[CounterID], 32) << ": {" |
| 128 | << Us.Counters[CounterID].Count << "," << Us.Counters[CounterID].Skip |
| 129 | << "," << Us.Counters[CounterID].StopAfter << "}\n"; |
| 130 | } |
Daniel Berlin | ce3d348a | 2017-02-19 04:29:50 +0000 | [diff] [blame] | 131 | } |
Frederich Munch | dceb612 | 2017-06-14 19:16:22 +0000 | [diff] [blame] | 132 | |
| 133 | LLVM_DUMP_METHOD void DebugCounter::dump() const { |
| 134 | print(dbgs()); |
| 135 | } |