//===- 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 counters{ "mlir-debug-counter", llvm::cl::desc( "Comma separated list of debug counter skip and count arguments"), llvm::cl::CommaSeparated}; llvm::cl::opt 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")}; }; } // namespace static llvm::ManagedStatic 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 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 *, 16> sortedCounters( llvm::make_pointer_range(counters)); llvm::array_pod_sort(sortedCounters.begin(), sortedCounters.end(), [](const decltype(sortedCounters)::value_type *lhs, const decltype(sortedCounters)::value_type *rhs) { return (*lhs)->getKey().compare((*rhs)->getKey()); }); os << "DebugCounter counters:\n"; for (const llvm::StringMapEntry *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`. auto [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"); } } }