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