128d04c56SMehdi Amini //===- DebugCounter.cpp - Debug Counter Facilities ------------------------===//
228d04c56SMehdi Amini //
328d04c56SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
428d04c56SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
528d04c56SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
628d04c56SMehdi Amini //
728d04c56SMehdi Amini //===----------------------------------------------------------------------===//
828d04c56SMehdi Amini
928d04c56SMehdi Amini #include "mlir/Debug/Counter.h"
1028d04c56SMehdi Amini #include "llvm/Support/CommandLine.h"
1128d04c56SMehdi Amini #include "llvm/Support/Debug.h"
1228d04c56SMehdi Amini #include "llvm/Support/Format.h"
1328d04c56SMehdi Amini #include "llvm/Support/ManagedStatic.h"
1428d04c56SMehdi Amini
1528d04c56SMehdi Amini using namespace mlir;
1628d04c56SMehdi Amini using namespace mlir::tracing;
1728d04c56SMehdi Amini
1828d04c56SMehdi Amini //===----------------------------------------------------------------------===//
1928d04c56SMehdi Amini // DebugCounter CommandLine Options
2028d04c56SMehdi Amini //===----------------------------------------------------------------------===//
2128d04c56SMehdi Amini
2228d04c56SMehdi Amini namespace {
2328d04c56SMehdi Amini /// This struct contains command line options that can be used to initialize
2428d04c56SMehdi Amini /// various bits of a DebugCounter. This uses a struct wrapper to avoid the need
2528d04c56SMehdi Amini /// for global command line options.
2628d04c56SMehdi Amini struct DebugCounterOptions {
2728d04c56SMehdi Amini llvm::cl::list<std::string> counters{
2828d04c56SMehdi Amini "mlir-debug-counter",
2928d04c56SMehdi Amini llvm::cl::desc(
3028d04c56SMehdi Amini "Comma separated list of debug counter skip and count arguments"),
3128d04c56SMehdi Amini llvm::cl::CommaSeparated};
3228d04c56SMehdi Amini
3328d04c56SMehdi Amini llvm::cl::opt<bool> printCounterInfo{
3428d04c56SMehdi Amini "mlir-print-debug-counter", llvm::cl::init(false), llvm::cl::Optional,
3528d04c56SMehdi Amini llvm::cl::desc("Print out debug counter information after all counters "
3628d04c56SMehdi Amini "have been accumulated")};
3728d04c56SMehdi Amini };
3828d04c56SMehdi Amini } // namespace
3928d04c56SMehdi Amini
4028d04c56SMehdi Amini static llvm::ManagedStatic<DebugCounterOptions> clOptions;
4128d04c56SMehdi Amini
4228d04c56SMehdi Amini //===----------------------------------------------------------------------===//
4328d04c56SMehdi Amini // DebugCounter
4428d04c56SMehdi Amini //===----------------------------------------------------------------------===//
4528d04c56SMehdi Amini
DebugCounter()4628d04c56SMehdi Amini DebugCounter::DebugCounter() { applyCLOptions(); }
4728d04c56SMehdi Amini
~DebugCounter()4828d04c56SMehdi Amini DebugCounter::~DebugCounter() {
4928d04c56SMehdi Amini // Print information when destroyed, iff command line option is specified.
5028d04c56SMehdi Amini if (clOptions.isConstructed() && clOptions->printCounterInfo)
5128d04c56SMehdi Amini print(llvm::dbgs());
5228d04c56SMehdi Amini }
5328d04c56SMehdi Amini
5428d04c56SMehdi Amini /// Add a counter for the given debug action tag. `countToSkip` is the number
5528d04c56SMehdi Amini /// of counter executions to skip before enabling execution of the action.
5628d04c56SMehdi Amini /// `countToStopAfter` is the number of executions of the counter to allow
5728d04c56SMehdi Amini /// before preventing the action from executing any more.
addCounter(StringRef actionTag,int64_t countToSkip,int64_t countToStopAfter)5828d04c56SMehdi Amini void DebugCounter::addCounter(StringRef actionTag, int64_t countToSkip,
5928d04c56SMehdi Amini int64_t countToStopAfter) {
6028d04c56SMehdi Amini assert(!counters.count(actionTag) &&
6128d04c56SMehdi Amini "a counter for the given action was already registered");
6228d04c56SMehdi Amini counters.try_emplace(actionTag, countToSkip, countToStopAfter);
6328d04c56SMehdi Amini }
6428d04c56SMehdi Amini
operator ()(llvm::function_ref<void ()> transform,const Action & action)659b1fe564SMehdi Amini void DebugCounter::operator()(llvm::function_ref<void()> transform,
6628d04c56SMehdi Amini const Action &action) {
679b1fe564SMehdi Amini if (shouldExecute(action.getTag()))
689b1fe564SMehdi Amini transform();
699b1fe564SMehdi Amini }
709b1fe564SMehdi Amini
shouldExecute(StringRef tag)719b1fe564SMehdi Amini bool DebugCounter::shouldExecute(StringRef tag) {
729b1fe564SMehdi Amini auto counterIt = counters.find(tag);
7328d04c56SMehdi Amini if (counterIt == counters.end())
7428d04c56SMehdi Amini return true;
7528d04c56SMehdi Amini
7628d04c56SMehdi Amini ++counterIt->second.count;
7728d04c56SMehdi Amini
7828d04c56SMehdi Amini // We only execute while the `countToSkip` is not smaller than `count`, and
7928d04c56SMehdi Amini // `countToStopAfter + countToSkip` is larger than `count`. Negative counters
8028d04c56SMehdi Amini // always execute.
8128d04c56SMehdi Amini if (counterIt->second.countToSkip < 0)
8228d04c56SMehdi Amini return true;
8328d04c56SMehdi Amini if (counterIt->second.countToSkip >= counterIt->second.count)
8428d04c56SMehdi Amini return false;
8528d04c56SMehdi Amini if (counterIt->second.countToStopAfter < 0)
8628d04c56SMehdi Amini return true;
8728d04c56SMehdi Amini return counterIt->second.countToStopAfter + counterIt->second.countToSkip >=
8828d04c56SMehdi Amini counterIt->second.count;
8928d04c56SMehdi Amini }
9028d04c56SMehdi Amini
print(raw_ostream & os) const9128d04c56SMehdi Amini void DebugCounter::print(raw_ostream &os) const {
9228d04c56SMehdi Amini // Order the registered counters by name.
9328d04c56SMehdi Amini SmallVector<const llvm::StringMapEntry<Counter> *, 16> sortedCounters(
9428d04c56SMehdi Amini llvm::make_pointer_range(counters));
9528d04c56SMehdi Amini llvm::array_pod_sort(sortedCounters.begin(), sortedCounters.end(),
9628d04c56SMehdi Amini [](const decltype(sortedCounters)::value_type *lhs,
9728d04c56SMehdi Amini const decltype(sortedCounters)::value_type *rhs) {
9828d04c56SMehdi Amini return (*lhs)->getKey().compare((*rhs)->getKey());
9928d04c56SMehdi Amini });
10028d04c56SMehdi Amini
10128d04c56SMehdi Amini os << "DebugCounter counters:\n";
10228d04c56SMehdi Amini for (const llvm::StringMapEntry<Counter> *counter : sortedCounters) {
10328d04c56SMehdi Amini os << llvm::left_justify(counter->getKey(), 32) << ": {"
10428d04c56SMehdi Amini << counter->second.count << "," << counter->second.countToSkip << ","
10528d04c56SMehdi Amini << counter->second.countToStopAfter << "}\n";
10628d04c56SMehdi Amini }
10728d04c56SMehdi Amini }
10828d04c56SMehdi Amini
10928d04c56SMehdi Amini /// Register a set of useful command-line options that can be used to configure
11028d04c56SMehdi Amini /// various flags within the DebugCounter. These flags are used when
11128d04c56SMehdi Amini /// constructing a DebugCounter for initialization.
registerCLOptions()11228d04c56SMehdi Amini void DebugCounter::registerCLOptions() {
11328d04c56SMehdi Amini // Make sure that the options struct has been initialized.
11428d04c56SMehdi Amini *clOptions;
11528d04c56SMehdi Amini }
11628d04c56SMehdi Amini
isActivated()117*930744fcSMehdi Amini bool DebugCounter::isActivated() {
118*930744fcSMehdi Amini return clOptions->counters.getNumOccurrences() ||
119*930744fcSMehdi Amini clOptions->printCounterInfo.getNumOccurrences();
120*930744fcSMehdi Amini }
121*930744fcSMehdi Amini
12228d04c56SMehdi Amini // This is called by the command line parser when it sees a value for the
12328d04c56SMehdi Amini // debug-counter option defined above.
applyCLOptions()12428d04c56SMehdi Amini void DebugCounter::applyCLOptions() {
12528d04c56SMehdi Amini if (!clOptions.isConstructed())
12628d04c56SMehdi Amini return;
12728d04c56SMehdi Amini
12828d04c56SMehdi Amini for (StringRef arg : clOptions->counters) {
12928d04c56SMehdi Amini if (arg.empty())
13028d04c56SMehdi Amini continue;
13128d04c56SMehdi Amini
13228d04c56SMehdi Amini // Debug counter arguments are expected to be in the form: `counter=value`.
13328d04c56SMehdi Amini auto [counterName, counterValueStr] = arg.split('=');
13428d04c56SMehdi Amini if (counterValueStr.empty()) {
13528d04c56SMehdi Amini llvm::errs() << "error: expected DebugCounter argument to have an `=` "
13628d04c56SMehdi Amini "separating the counter name and value, but the provided "
13728d04c56SMehdi Amini "argument was: `"
13828d04c56SMehdi Amini << arg << "`\n";
13928d04c56SMehdi Amini llvm::report_fatal_error(
14028d04c56SMehdi Amini "Invalid DebugCounter command-line configuration");
14128d04c56SMehdi Amini }
14228d04c56SMehdi Amini
14328d04c56SMehdi Amini // Extract the counter value.
14428d04c56SMehdi Amini int64_t counterValue;
14528d04c56SMehdi Amini if (counterValueStr.getAsInteger(0, counterValue)) {
14628d04c56SMehdi Amini llvm::errs() << "error: expected DebugCounter counter value to be "
14728d04c56SMehdi Amini "numeric, but got `"
14828d04c56SMehdi Amini << counterValueStr << "`\n";
14928d04c56SMehdi Amini llvm::report_fatal_error(
15028d04c56SMehdi Amini "Invalid DebugCounter command-line configuration");
15128d04c56SMehdi Amini }
15228d04c56SMehdi Amini
15328d04c56SMehdi Amini // Now we need to see if this is the skip or the count, remove the suffix,
15428d04c56SMehdi Amini // and add it to the counter values.
15528d04c56SMehdi Amini if (counterName.consume_back("-skip")) {
15628d04c56SMehdi Amini counters[counterName].countToSkip = counterValue;
15728d04c56SMehdi Amini
15828d04c56SMehdi Amini } else if (counterName.consume_back("-count")) {
15928d04c56SMehdi Amini counters[counterName].countToStopAfter = counterValue;
16028d04c56SMehdi Amini
16128d04c56SMehdi Amini } else {
16228d04c56SMehdi Amini llvm::errs() << "error: expected DebugCounter counter name to end with "
16328d04c56SMehdi Amini "either `-skip` or `-count`, but got`"
16428d04c56SMehdi Amini << counterName << "`\n";
16528d04c56SMehdi Amini llvm::report_fatal_error(
16628d04c56SMehdi Amini "Invalid DebugCounter command-line configuration");
16728d04c56SMehdi Amini }
16828d04c56SMehdi Amini }
16928d04c56SMehdi Amini }
170