1 //===- DebugCounter.cpp - Debug Counter Facilities ------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "mlir/Support/DebugCounter.h" 10 #include "llvm/Support/CommandLine.h" 11 #include "llvm/Support/Debug.h" 12 #include "llvm/Support/Format.h" 13 #include "llvm/Support/ManagedStatic.h" 14 15 using namespace mlir; 16 17 //===----------------------------------------------------------------------===// 18 // DebugCounter CommandLine Options 19 //===----------------------------------------------------------------------===// 20 21 namespace { 22 /// This struct contains command line options that can be used to initialize 23 /// various bits of a DebugCounter. This uses a struct wrapper to avoid the need 24 /// for global command line options. 25 struct DebugCounterOptions { 26 llvm::cl::list<std::string> counters{ 27 "mlir-debug-counter", 28 llvm::cl::desc( 29 "Comma separated list of debug counter skip and count arguments"), 30 llvm::cl::CommaSeparated}; 31 32 llvm::cl::opt<bool> printCounterInfo{ 33 "mlir-print-debug-counter", llvm::cl::init(false), llvm::cl::Optional, 34 llvm::cl::desc("Print out debug counter information after all counters " 35 "have been accumulated")}; 36 }; 37 } // namespace 38 39 static llvm::ManagedStatic<DebugCounterOptions> clOptions; 40 41 //===----------------------------------------------------------------------===// 42 // DebugCounter 43 //===----------------------------------------------------------------------===// 44 45 DebugCounter::DebugCounter() { applyCLOptions(); } 46 47 DebugCounter::~DebugCounter() { 48 // Print information when destroyed, iff command line option is specified. 49 if (clOptions.isConstructed() && clOptions->printCounterInfo) 50 print(llvm::dbgs()); 51 } 52 53 /// Add a counter for the given debug action tag. `countToSkip` is the number 54 /// of counter executions to skip before enabling execution of the action. 55 /// `countToStopAfter` is the number of executions of the counter to allow 56 /// before preventing the action from executing any more. 57 void DebugCounter::addCounter(StringRef actionTag, int64_t countToSkip, 58 int64_t countToStopAfter) { 59 assert(!counters.count(actionTag) && 60 "a counter for the given action was already registered"); 61 counters.try_emplace(actionTag, countToSkip, countToStopAfter); 62 } 63 64 // Register a counter with the specified name. 65 FailureOr<bool> DebugCounter::shouldExecute(StringRef tag, 66 StringRef description) { 67 auto counterIt = counters.find(tag); 68 if (counterIt == counters.end()) 69 return true; 70 71 ++counterIt->second.count; 72 73 // We only execute while the `countToSkip` is not smaller than `count`, and 74 // `countToStopAfter + countToSkip` is larger than `count`. Negative counters 75 // always execute. 76 if (counterIt->second.countToSkip < 0) 77 return true; 78 if (counterIt->second.countToSkip >= counterIt->second.count) 79 return false; 80 if (counterIt->second.countToStopAfter < 0) 81 return true; 82 return counterIt->second.countToStopAfter + counterIt->second.countToSkip >= 83 counterIt->second.count; 84 } 85 86 void DebugCounter::print(raw_ostream &os) const { 87 // Order the registered counters by name. 88 SmallVector<const llvm::StringMapEntry<Counter> *, 16> sortedCounters( 89 llvm::make_pointer_range(counters)); 90 llvm::array_pod_sort(sortedCounters.begin(), sortedCounters.end(), 91 [](const decltype(sortedCounters)::value_type *lhs, 92 const decltype(sortedCounters)::value_type *rhs) { 93 return (*lhs)->getKey().compare((*rhs)->getKey()); 94 }); 95 96 os << "DebugCounter counters:\n"; 97 for (const llvm::StringMapEntry<Counter> *counter : sortedCounters) { 98 os << llvm::left_justify(counter->getKey(), 32) << ": {" 99 << counter->second.count << "," << counter->second.countToSkip << "," 100 << counter->second.countToStopAfter << "}\n"; 101 } 102 } 103 104 /// Register a set of useful command-line options that can be used to configure 105 /// various flags within the DebugCounter. These flags are used when 106 /// constructing a DebugCounter for initialization. 107 void DebugCounter::registerCLOptions() { 108 #ifndef NDEBUG 109 // Make sure that the options struct has been initialized. 110 *clOptions; 111 #endif 112 } 113 114 // This is called by the command line parser when it sees a value for the 115 // debug-counter option defined above. 116 void DebugCounter::applyCLOptions() { 117 if (!clOptions.isConstructed()) 118 return; 119 120 for (StringRef arg : clOptions->counters) { 121 if (arg.empty()) 122 continue; 123 124 // Debug counter arguments are expected to be in the form: `counter=value`. 125 StringRef counterName, counterValueStr; 126 std::tie(counterName, counterValueStr) = arg.split('='); 127 if (counterValueStr.empty()) { 128 llvm::errs() << "error: expected DebugCounter argument to have an `=` " 129 "separating the counter name and value, but the provided " 130 "argument was: `" 131 << arg << "`\n"; 132 llvm::report_fatal_error( 133 "Invalid DebugCounter command-line configuration"); 134 } 135 136 // Extract the counter value. 137 int64_t counterValue; 138 if (counterValueStr.getAsInteger(0, counterValue)) { 139 llvm::errs() << "error: expected DebugCounter counter value to be " 140 "numeric, but got `" 141 << counterValueStr << "`\n"; 142 llvm::report_fatal_error( 143 "Invalid DebugCounter command-line configuration"); 144 } 145 146 // Now we need to see if this is the skip or the count, remove the suffix, 147 // and add it to the counter values. 148 if (counterName.consume_back("-skip")) { 149 counters[counterName].countToSkip = counterValue; 150 151 } else if (counterName.consume_back("-count")) { 152 counters[counterName].countToStopAfter = counterValue; 153 154 } else { 155 llvm::errs() << "error: expected DebugCounter counter name to end with " 156 "either `-skip` or `-count`, but got`" 157 << counterName << "`\n"; 158 llvm::report_fatal_error( 159 "Invalid DebugCounter command-line configuration"); 160 } 161 } 162 } 163