| //===- DebugCounter.cpp - Debug Counter Facilities ------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "mlir/Support/DebugCounter.h" |
| #include "llvm/Support/CommandLine.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/Format.h" |
| #include "llvm/Support/ManagedStatic.h" |
| |
| using namespace mlir; |
| |
| //===----------------------------------------------------------------------===// |
| // DebugCounter CommandLine Options |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| /// This struct contains command line options that can be used to initialize |
| /// various bits of a DebugCounter. This uses a struct wrapper to avoid the need |
| /// for global command line options. |
| struct DebugCounterOptions { |
| llvm::cl::list<std::string> counters{ |
| "mlir-debug-counter", |
| llvm::cl::desc( |
| "Comma separated list of debug counter skip and count arguments"), |
| llvm::cl::CommaSeparated, llvm::cl::ZeroOrMore}; |
| |
| llvm::cl::opt<bool> printCounterInfo{ |
| "mlir-print-debug-counter", llvm::cl::init(false), llvm::cl::Optional, |
| llvm::cl::desc("Print out debug counter information after all counters " |
| "have been accumulated")}; |
| }; |
| } // end anonymous namespace |
| |
| static llvm::ManagedStatic<DebugCounterOptions> clOptions; |
| |
| //===----------------------------------------------------------------------===// |
| // DebugCounter |
| //===----------------------------------------------------------------------===// |
| |
| DebugCounter::DebugCounter() { applyCLOptions(); } |
| |
| DebugCounter::~DebugCounter() { |
| // Print information when destroyed, iff command line option is specified. |
| if (clOptions.isConstructed() && clOptions->printCounterInfo) |
| print(llvm::dbgs()); |
| } |
| |
| /// Add a counter for the given debug action tag. `countToSkip` is the number |
| /// of counter executions to skip before enabling execution of the action. |
| /// `countToStopAfter` is the number of executions of the counter to allow |
| /// before preventing the action from executing any more. |
| void DebugCounter::addCounter(StringRef actionTag, int64_t countToSkip, |
| int64_t countToStopAfter) { |
| assert(!counters.count(actionTag) && |
| "a counter for the given action was already registered"); |
| counters.try_emplace(actionTag, countToSkip, countToStopAfter); |
| } |
| |
| // Register a counter with the specified name. |
| FailureOr<bool> DebugCounter::shouldExecute(StringRef tag, |
| StringRef description) { |
| auto counterIt = counters.find(tag); |
| if (counterIt == counters.end()) |
| return true; |
| |
| ++counterIt->second.count; |
| |
| // We only execute while the `countToSkip` is not smaller than `count`, and |
| // `countToStopAfter + countToSkip` is larger than `count`. Negative counters |
| // always execute. |
| if (counterIt->second.countToSkip < 0) |
| return true; |
| if (counterIt->second.countToSkip >= counterIt->second.count) |
| return false; |
| if (counterIt->second.countToStopAfter < 0) |
| return true; |
| return counterIt->second.countToStopAfter + counterIt->second.countToSkip >= |
| counterIt->second.count; |
| } |
| |
| void DebugCounter::print(raw_ostream &os) const { |
| // Order the registered counters by name. |
| SmallVector<const llvm::StringMapEntry<Counter> *, 16> sortedCounters( |
| llvm::make_pointer_range(counters)); |
| llvm::sort(sortedCounters, [](const llvm::StringMapEntry<Counter> *lhs, |
| const llvm::StringMapEntry<Counter> *rhs) { |
| return lhs->getKey() < rhs->getKey(); |
| }); |
| |
| os << "DebugCounter counters:\n"; |
| for (const llvm::StringMapEntry<Counter> *counter : sortedCounters) { |
| os << llvm::left_justify(counter->getKey(), 32) << ": {" |
| << counter->second.count << "," << counter->second.countToSkip << "," |
| << counter->second.countToStopAfter << "}\n"; |
| } |
| } |
| |
| /// Register a set of useful command-line options that can be used to configure |
| /// various flags within the DebugCounter. These flags are used when |
| /// constructing a DebugCounter for initialization. |
| void DebugCounter::registerCLOptions() { |
| #ifndef NDEBUG |
| // Make sure that the options struct has been initialized. |
| *clOptions; |
| #endif |
| } |
| |
| // This is called by the command line parser when it sees a value for the |
| // debug-counter option defined above. |
| void DebugCounter::applyCLOptions() { |
| if (!clOptions.isConstructed()) |
| return; |
| |
| for (StringRef arg : clOptions->counters) { |
| if (arg.empty()) |
| continue; |
| |
| // Debug counter arguments are expected to be in the form: `counter=value`. |
| StringRef counterName, counterValueStr; |
| std::tie(counterName, counterValueStr) = arg.split('='); |
| if (counterValueStr.empty()) { |
| llvm::errs() << "error: expected DebugCounter argument to have an `=` " |
| "separating the counter name and value, but the provided " |
| "argument was: `" |
| << arg << "`\n"; |
| llvm::report_fatal_error( |
| "Invalid DebugCounter command-line configuration"); |
| } |
| |
| // Extract the counter value. |
| int64_t counterValue; |
| if (counterValueStr.getAsInteger(0, counterValue)) { |
| llvm::errs() << "error: expected DebugCounter counter value to be " |
| "numeric, but got `" |
| << counterValueStr << "`\n"; |
| llvm::report_fatal_error( |
| "Invalid DebugCounter command-line configuration"); |
| } |
| |
| // Now we need to see if this is the skip or the count, remove the suffix, |
| // and add it to the counter values. |
| if (counterName.consume_back("-skip")) { |
| counters[counterName].countToSkip = counterValue; |
| |
| } else if (counterName.consume_back("-count")) { |
| counters[counterName].countToStopAfter = counterValue; |
| |
| } else { |
| llvm::errs() << "error: expected DebugCounter counter name to end with " |
| "either `-skip` or `-count`, but got`" |
| << counterName << "`\n"; |
| llvm::report_fatal_error( |
| "Invalid DebugCounter command-line configuration"); |
| } |
| } |
| } |