|
| 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 | +} |
0 commit comments