DebugCounters allow for selectively enabling the execution of a debug action based upon a "counter". This counter is comprised of two components that are used in the control of execution of an action, a "skip" value and a "count" value. The "skip" value is used to skip a certain number of initial executions of a debug action. The "count" value is used to prevent a debug action from executing after it has executed for a set number of times (not including any executions that have been skipped). For example, a counter for a debug action with `skip=47` and `count=2`, would skip the first 47 executions, then execute twice, and finally prevent any further executions. This is effectively the same as the DebugCounter infrastructure in LLVM, but using the DebugAction infrastructure in MLIR. We can't simply reuse the DebugCounter support already present in LLVM due to its heavy reliance on global constructors (which are not allowed in MLIR). The DebugAction infrastructure already nicely supports the debug counter use case, and promotes the separation of policy and mechanism design philosophy. Differential Revision: https://reviews.llvm.org/D96395
161 lines
6.1 KiB
C++
161 lines
6.1 KiB
C++
//===- 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/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");
|
|
}
|
|
}
|
|
}
|