1 | //===- llvm/Support/DebugCounter.h - Debug counter support ------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// \file |
9 | /// This file provides an implementation of debug counters. Debug |
10 | /// counters are a tool that let you narrow down a miscompilation to a specific |
11 | /// thing happening. |
12 | /// |
13 | /// To give a use case: Imagine you have a file, very large, and you |
14 | /// are trying to understand the minimal transformation that breaks it. Bugpoint |
15 | /// and bisection is often helpful here in narrowing it down to a specific pass, |
16 | /// but it's still a very large file, and a very complicated pass to try to |
17 | /// debug. That is where debug counting steps in. You can instrument the pass |
18 | /// with a debug counter before it does a certain thing, and depending on the |
19 | /// counts, it will either execute that thing or not. The debug counter itself |
20 | /// consists of a skip and a count. Skip is the number of times shouldExecute |
21 | /// needs to be called before it returns true. Count is the number of times to |
22 | /// return true once Skip is 0. So a skip=47, count=2 ,would skip the first 47 |
23 | /// executions by returning false from shouldExecute, then execute twice, and |
24 | /// then return false again. |
25 | /// Note that a counter set to a negative number will always execute. |
26 | /// For a concrete example, during predicateinfo creation, the renaming pass |
27 | /// replaces each use with a renamed use. |
28 | //// |
29 | /// If I use DEBUG_COUNTER to create a counter called "predicateinfo", and |
30 | /// variable name RenameCounter, and then instrument this renaming with a debug |
31 | /// counter, like so: |
32 | /// |
33 | /// if (!DebugCounter::shouldExecute(RenameCounter) |
34 | /// <continue or return or whatever not executing looks like> |
35 | /// |
36 | /// Now I can, from the command line, make it rename or not rename certain uses |
37 | /// by setting the skip and count. |
38 | /// So for example |
39 | /// bin/opt -debug-counter=predicateinfo-skip=47,predicateinfo-count=1 |
40 | /// will skip renaming the first 47 uses, then rename one, then skip the rest. |
41 | //===----------------------------------------------------------------------===// |
42 | |
43 | #ifndef LLVM_SUPPORT_DEBUGCOUNTER_H |
44 | #define LLVM_SUPPORT_DEBUGCOUNTER_H |
45 | |
46 | #include "llvm/ADT/DenseMap.h" |
47 | #include "llvm/ADT/StringRef.h" |
48 | #include "llvm/ADT/UniqueVector.h" |
49 | #include "llvm/Support/Debug.h" |
50 | #include <string> |
51 | |
52 | namespace llvm { |
53 | |
54 | class raw_ostream; |
55 | |
56 | class DebugCounter { |
57 | public: |
58 | /// Returns a reference to the singleton instance. |
59 | static DebugCounter &instance(); |
60 | |
61 | // Used by the command line option parser to push a new value it parsed. |
62 | void push_back(const std::string &); |
63 | |
64 | // Register a counter with the specified name. |
65 | // |
66 | // FIXME: Currently, counter registration is required to happen before command |
67 | // line option parsing. The main reason to register counters is to produce a |
68 | // nice list of them on the command line, but i'm not sure this is worth it. |
69 | static unsigned registerCounter(StringRef Name, StringRef Desc) { |
70 | return instance().addCounter(Name: std::string(Name), Desc: std::string(Desc)); |
71 | } |
72 | inline static bool shouldExecute(unsigned CounterName) { |
73 | if (!isCountingEnabled()) |
74 | return true; |
75 | |
76 | auto &Us = instance(); |
77 | auto Result = Us.Counters.find(Val: CounterName); |
78 | if (Result != Us.Counters.end()) { |
79 | auto &CounterInfo = Result->second; |
80 | ++CounterInfo.Count; |
81 | |
82 | // We only execute while the Skip is not smaller than Count, |
83 | // and the StopAfter + Skip is larger than Count. |
84 | // Negative counters always execute. |
85 | if (CounterInfo.Skip < 0) |
86 | return true; |
87 | if (CounterInfo.Skip >= CounterInfo.Count) |
88 | return false; |
89 | if (CounterInfo.StopAfter < 0) |
90 | return true; |
91 | return CounterInfo.StopAfter + CounterInfo.Skip >= CounterInfo.Count; |
92 | } |
93 | // Didn't find the counter, should we warn? |
94 | return true; |
95 | } |
96 | |
97 | // Return true if a given counter had values set (either programatically or on |
98 | // the command line). This will return true even if those values are |
99 | // currently in a state where the counter will always execute. |
100 | static bool isCounterSet(unsigned ID) { |
101 | return instance().Counters[ID].IsSet; |
102 | } |
103 | |
104 | // Return the Count for a counter. This only works for set counters. |
105 | static int64_t getCounterValue(unsigned ID) { |
106 | auto &Us = instance(); |
107 | auto Result = Us.Counters.find(Val: ID); |
108 | assert(Result != Us.Counters.end() && "Asking about a non-set counter" ); |
109 | return Result->second.Count; |
110 | } |
111 | |
112 | // Set a registered counter to a given Count value. |
113 | static void setCounterValue(unsigned ID, int64_t Count) { |
114 | auto &Us = instance(); |
115 | Us.Counters[ID].Count = Count; |
116 | } |
117 | |
118 | // Dump or print the current counter set into llvm::dbgs(). |
119 | LLVM_DUMP_METHOD void dump() const; |
120 | |
121 | void print(raw_ostream &OS) const; |
122 | |
123 | // Get the counter ID for a given named counter, or return 0 if none is found. |
124 | unsigned getCounterId(const std::string &Name) const { |
125 | return RegisteredCounters.idFor(Entry: Name); |
126 | } |
127 | |
128 | // Return the number of registered counters. |
129 | unsigned int getNumCounters() const { return RegisteredCounters.size(); } |
130 | |
131 | // Return the name and description of the counter with the given ID. |
132 | std::pair<std::string, std::string> getCounterInfo(unsigned ID) const { |
133 | return std::make_pair(x: RegisteredCounters[ID], y: Counters.lookup(Val: ID).Desc); |
134 | } |
135 | |
136 | // Iterate through the registered counters |
137 | typedef UniqueVector<std::string> CounterVector; |
138 | CounterVector::const_iterator begin() const { |
139 | return RegisteredCounters.begin(); |
140 | } |
141 | CounterVector::const_iterator end() const { return RegisteredCounters.end(); } |
142 | |
143 | // Force-enables counting all DebugCounters. |
144 | // |
145 | // Since DebugCounters are incompatible with threading (not only do they not |
146 | // make sense, but we'll also see data races), this should only be used in |
147 | // contexts where we're certain we won't spawn threads. |
148 | static void enableAllCounters() { instance().Enabled = true; } |
149 | |
150 | static bool isCountingEnabled() { |
151 | // Compile to nothing when debugging is off |
152 | #ifdef NDEBUG |
153 | return false; |
154 | #else |
155 | return instance().Enabled; |
156 | #endif |
157 | } |
158 | |
159 | private: |
160 | unsigned addCounter(const std::string &Name, const std::string &Desc) { |
161 | unsigned Result = RegisteredCounters.insert(Entry: Name); |
162 | Counters[Result] = {}; |
163 | Counters[Result].Desc = Desc; |
164 | return Result; |
165 | } |
166 | // Struct to store counter info. |
167 | struct CounterInfo { |
168 | int64_t Count = 0; |
169 | int64_t Skip = 0; |
170 | int64_t StopAfter = -1; |
171 | bool IsSet = false; |
172 | std::string Desc; |
173 | }; |
174 | DenseMap<unsigned, CounterInfo> Counters; |
175 | CounterVector RegisteredCounters; |
176 | |
177 | // Whether we should do DebugCounting at all. DebugCounters aren't |
178 | // thread-safe, so this should always be false in multithreaded scenarios. |
179 | bool Enabled = false; |
180 | }; |
181 | |
182 | #define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC) \ |
183 | static const unsigned VARNAME = \ |
184 | DebugCounter::registerCounter(COUNTERNAME, DESC) |
185 | |
186 | } // namespace llvm |
187 | #endif |
188 | |