1317017Sdim//===- llvm/Support/DebugCounter.h - Debug counter support ------*- C++ -*-===//
2317017Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6317017Sdim//
7317017Sdim//===----------------------------------------------------------------------===//
8317017Sdim/// \file
9341825Sdim/// This file provides an implementation of debug counters.  Debug
10317017Sdim/// counters are a tool that let you narrow down a miscompilation to a specific
11317017Sdim/// thing happening.
12317017Sdim///
13317017Sdim/// To give a use case: Imagine you have a file, very large, and you
14317017Sdim/// are trying to understand the minimal transformation that breaks it. Bugpoint
15317017Sdim/// and bisection is often helpful here in narrowing it down to a specific pass,
16317017Sdim/// but it's still a very large file, and a very complicated pass to try to
17317017Sdim/// debug.  That is where debug counting steps in.  You can instrument the pass
18317017Sdim/// with a debug counter before it does a certain thing, and depending on the
19317017Sdim/// counts, it will either execute that thing or not.  The debug counter itself
20317017Sdim/// consists of a skip and a count.  Skip is the number of times shouldExecute
21317017Sdim/// needs to be called before it returns true.  Count is the number of times to
22317017Sdim/// return true once Skip is 0.  So a skip=47, count=2 ,would skip the first 47
23317017Sdim/// executions by returning false from shouldExecute, then execute twice, and
24317017Sdim/// then return false again.
25317017Sdim/// Note that a counter set to a negative number will always execute.
26317017Sdim/// For a concrete example, during predicateinfo creation, the renaming pass
27317017Sdim/// replaces each use with a renamed use.
28317017Sdim////
29317017Sdim/// If I use DEBUG_COUNTER to create a counter called "predicateinfo", and
30317017Sdim/// variable name RenameCounter, and then instrument this renaming with a debug
31317017Sdim/// counter, like so:
32317017Sdim///
33317017Sdim/// if (!DebugCounter::shouldExecute(RenameCounter)
34317017Sdim/// <continue or return or whatever not executing looks like>
35317017Sdim///
36317017Sdim/// Now I can, from the command line, make it rename or not rename certain uses
37317017Sdim/// by setting the skip and count.
38317017Sdim/// So for example
39317017Sdim/// bin/opt -debug-counter=predicateinfo-skip=47,predicateinfo-count=1
40317017Sdim/// will skip renaming the first 47 uses, then rename one, then skip the rest.
41317017Sdim//===----------------------------------------------------------------------===//
42317017Sdim
43317017Sdim#ifndef LLVM_SUPPORT_DEBUGCOUNTER_H
44317017Sdim#define LLVM_SUPPORT_DEBUGCOUNTER_H
45317017Sdim
46317017Sdim#include "llvm/ADT/DenseMap.h"
47317017Sdim#include "llvm/ADT/UniqueVector.h"
48317017Sdim#include "llvm/Support/CommandLine.h"
49317017Sdim#include "llvm/Support/Debug.h"
50317017Sdim#include "llvm/Support/raw_ostream.h"
51317017Sdim#include <string>
52317017Sdim
53317017Sdimnamespace llvm {
54317017Sdim
55317017Sdimclass DebugCounter {
56317017Sdimpublic:
57344779Sdim  ~DebugCounter();
58344779Sdim
59341825Sdim  /// Returns a reference to the singleton instance.
60317017Sdim  static DebugCounter &instance();
61317017Sdim
62317017Sdim  // Used by the command line option parser to push a new value it parsed.
63317017Sdim  void push_back(const std::string &);
64317017Sdim
65317017Sdim  // Register a counter with the specified name.
66317017Sdim  //
67317017Sdim  // FIXME: Currently, counter registration is required to happen before command
68317017Sdim  // line option parsing. The main reason to register counters is to produce a
69317017Sdim  // nice list of them on the command line, but i'm not sure this is worth it.
70317017Sdim  static unsigned registerCounter(StringRef Name, StringRef Desc) {
71317017Sdim    return instance().addCounter(Name, Desc);
72317017Sdim  }
73317017Sdim  inline static bool shouldExecute(unsigned CounterName) {
74341825Sdim    if (!isCountingEnabled())
75341825Sdim      return true;
76341825Sdim
77317017Sdim    auto &Us = instance();
78317017Sdim    auto Result = Us.Counters.find(CounterName);
79317017Sdim    if (Result != Us.Counters.end()) {
80341825Sdim      auto &CounterInfo = Result->second;
81341825Sdim      ++CounterInfo.Count;
82341825Sdim
83341825Sdim      // We only execute while the Skip is not smaller than Count,
84341825Sdim      // and the StopAfter + Skip is larger than Count.
85317017Sdim      // Negative counters always execute.
86341825Sdim      if (CounterInfo.Skip < 0)
87317017Sdim        return true;
88341825Sdim      if (CounterInfo.Skip >= CounterInfo.Count)
89317017Sdim        return false;
90341825Sdim      if (CounterInfo.StopAfter < 0)
91317017Sdim        return true;
92341825Sdim      return CounterInfo.StopAfter + CounterInfo.Skip >= CounterInfo.Count;
93317017Sdim    }
94317017Sdim    // Didn't find the counter, should we warn?
95317017Sdim    return true;
96317017Sdim  }
97317017Sdim
98317017Sdim  // Return true if a given counter had values set (either programatically or on
99317017Sdim  // the command line).  This will return true even if those values are
100317017Sdim  // currently in a state where the counter will always execute.
101317017Sdim  static bool isCounterSet(unsigned ID) {
102341825Sdim    return instance().Counters[ID].IsSet;
103317017Sdim  }
104317017Sdim
105341825Sdim  // Return the Count for a counter. This only works for set counters.
106341825Sdim  static int64_t getCounterValue(unsigned ID) {
107317017Sdim    auto &Us = instance();
108317017Sdim    auto Result = Us.Counters.find(ID);
109317017Sdim    assert(Result != Us.Counters.end() && "Asking about a non-set counter");
110341825Sdim    return Result->second.Count;
111317017Sdim  }
112317017Sdim
113341825Sdim  // Set a registered counter to a given Count value.
114341825Sdim  static void setCounterValue(unsigned ID, int64_t Count) {
115317017Sdim    auto &Us = instance();
116341825Sdim    Us.Counters[ID].Count = Count;
117317017Sdim  }
118317017Sdim
119320041Sdim  // Dump or print the current counter set into llvm::dbgs().
120320041Sdim  LLVM_DUMP_METHOD void dump() const;
121317017Sdim
122320041Sdim  void print(raw_ostream &OS) const;
123317017Sdim
124317017Sdim  // Get the counter ID for a given named counter, or return 0 if none is found.
125317017Sdim  unsigned getCounterId(const std::string &Name) const {
126317017Sdim    return RegisteredCounters.idFor(Name);
127317017Sdim  }
128317017Sdim
129317017Sdim  // Return the number of registered counters.
130317017Sdim  unsigned int getNumCounters() const { return RegisteredCounters.size(); }
131317017Sdim
132317017Sdim  // Return the name and description of the counter with the given ID.
133317017Sdim  std::pair<std::string, std::string> getCounterInfo(unsigned ID) const {
134341825Sdim    return std::make_pair(RegisteredCounters[ID], Counters.lookup(ID).Desc);
135317017Sdim  }
136317017Sdim
137317017Sdim  // Iterate through the registered counters
138317017Sdim  typedef UniqueVector<std::string> CounterVector;
139317017Sdim  CounterVector::const_iterator begin() const {
140317017Sdim    return RegisteredCounters.begin();
141317017Sdim  }
142317017Sdim  CounterVector::const_iterator end() const { return RegisteredCounters.end(); }
143317017Sdim
144341825Sdim  // Force-enables counting all DebugCounters.
145341825Sdim  //
146341825Sdim  // Since DebugCounters are incompatible with threading (not only do they not
147341825Sdim  // make sense, but we'll also see data races), this should only be used in
148341825Sdim  // contexts where we're certain we won't spawn threads.
149341825Sdim  static void enableAllCounters() { instance().Enabled = true; }
150341825Sdim
151317017Sdimprivate:
152341825Sdim  static bool isCountingEnabled() {
153341825Sdim// Compile to nothing when debugging is off
154341825Sdim#ifdef NDEBUG
155341825Sdim    return false;
156341825Sdim#else
157341825Sdim    return instance().Enabled;
158341825Sdim#endif
159341825Sdim  }
160341825Sdim
161317017Sdim  unsigned addCounter(const std::string &Name, const std::string &Desc) {
162317017Sdim    unsigned Result = RegisteredCounters.insert(Name);
163341825Sdim    Counters[Result] = {};
164341825Sdim    Counters[Result].Desc = Desc;
165317017Sdim    return Result;
166317017Sdim  }
167341825Sdim  // Struct to store counter info.
168341825Sdim  struct CounterInfo {
169341825Sdim    int64_t Count = 0;
170341825Sdim    int64_t Skip = 0;
171341825Sdim    int64_t StopAfter = -1;
172341825Sdim    bool IsSet = false;
173341825Sdim    std::string Desc;
174341825Sdim  };
175341825Sdim  DenseMap<unsigned, CounterInfo> Counters;
176317017Sdim  CounterVector RegisteredCounters;
177341825Sdim
178341825Sdim  // Whether we should do DebugCounting at all. DebugCounters aren't
179341825Sdim  // thread-safe, so this should always be false in multithreaded scenarios.
180341825Sdim  bool Enabled = false;
181317017Sdim};
182317017Sdim
183317017Sdim#define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC)                              \
184317017Sdim  static const unsigned VARNAME =                                              \
185327952Sdim      DebugCounter::registerCounter(COUNTERNAME, DESC)
186317017Sdim
187317017Sdim} // namespace llvm
188317017Sdim#endif
189