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