10b57cec5SDimitry Andric //===- llvm/Support/DebugCounter.h - Debug counter support ------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric /// \file 90b57cec5SDimitry Andric /// This file provides an implementation of debug counters. Debug 100b57cec5SDimitry Andric /// counters are a tool that let you narrow down a miscompilation to a specific 110b57cec5SDimitry Andric /// thing happening. 120b57cec5SDimitry Andric /// 130b57cec5SDimitry Andric /// To give a use case: Imagine you have a file, very large, and you 140b57cec5SDimitry Andric /// are trying to understand the minimal transformation that breaks it. Bugpoint 150b57cec5SDimitry Andric /// and bisection is often helpful here in narrowing it down to a specific pass, 160b57cec5SDimitry Andric /// but it's still a very large file, and a very complicated pass to try to 170b57cec5SDimitry Andric /// debug. That is where debug counting steps in. You can instrument the pass 180b57cec5SDimitry Andric /// with a debug counter before it does a certain thing, and depending on the 190b57cec5SDimitry Andric /// counts, it will either execute that thing or not. The debug counter itself 20*0fca6ea1SDimitry Andric /// consists of a list of chunks (inclusive numeric ranges). `shouldExecute` 21*0fca6ea1SDimitry Andric /// returns true iff the list is empty or the current count is in one of the 22*0fca6ea1SDimitry Andric /// chunks. 23*0fca6ea1SDimitry Andric /// 24*0fca6ea1SDimitry Andric /// Note that a counter set to a negative number will always execute. For a 25*0fca6ea1SDimitry Andric /// concrete example, during predicateinfo creation, the renaming pass replaces 26*0fca6ea1SDimitry Andric /// each use with a renamed use. 270b57cec5SDimitry Andric //// 280b57cec5SDimitry Andric /// If I use DEBUG_COUNTER to create a counter called "predicateinfo", and 290b57cec5SDimitry Andric /// variable name RenameCounter, and then instrument this renaming with a debug 300b57cec5SDimitry Andric /// counter, like so: 310b57cec5SDimitry Andric /// 320b57cec5SDimitry Andric /// if (!DebugCounter::shouldExecute(RenameCounter) 330b57cec5SDimitry Andric /// <continue or return or whatever not executing looks like> 340b57cec5SDimitry Andric /// 350b57cec5SDimitry Andric /// Now I can, from the command line, make it rename or not rename certain uses 36*0fca6ea1SDimitry Andric /// by setting the chunk list. 370b57cec5SDimitry Andric /// So for example 38*0fca6ea1SDimitry Andric /// bin/opt -debug-counter=predicateinfo=47 390b57cec5SDimitry Andric /// will skip renaming the first 47 uses, then rename one, then skip the rest. 400b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_DEBUGCOUNTER_H 430b57cec5SDimitry Andric #define LLVM_SUPPORT_DEBUGCOUNTER_H 440b57cec5SDimitry Andric 45*0fca6ea1SDimitry Andric #include "llvm/ADT/ArrayRef.h" 460b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h" 475ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h" 480b57cec5SDimitry Andric #include "llvm/ADT/UniqueVector.h" 490b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 500b57cec5SDimitry Andric #include <string> 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric namespace llvm { 530b57cec5SDimitry Andric 545ffd83dbSDimitry Andric class raw_ostream; 555ffd83dbSDimitry Andric 560b57cec5SDimitry Andric class DebugCounter { 570b57cec5SDimitry Andric public: 58*0fca6ea1SDimitry Andric struct Chunk { 59*0fca6ea1SDimitry Andric int64_t Begin; 60*0fca6ea1SDimitry Andric int64_t End; 61*0fca6ea1SDimitry Andric void print(llvm::raw_ostream &OS); containsChunk62*0fca6ea1SDimitry Andric bool contains(int64_t Idx) { return Idx >= Begin && Idx <= End; } 63*0fca6ea1SDimitry Andric }; 64*0fca6ea1SDimitry Andric 65*0fca6ea1SDimitry Andric static void printChunks(raw_ostream &OS, ArrayRef<Chunk>); 66*0fca6ea1SDimitry Andric 67*0fca6ea1SDimitry Andric /// Return true on parsing error and print the error message on the 68*0fca6ea1SDimitry Andric /// llvm::errs() 69*0fca6ea1SDimitry Andric static bool parseChunks(StringRef Str, SmallVector<Chunk> &Res); 70*0fca6ea1SDimitry Andric 710b57cec5SDimitry Andric /// Returns a reference to the singleton instance. 720b57cec5SDimitry Andric static DebugCounter &instance(); 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric // Used by the command line option parser to push a new value it parsed. 750b57cec5SDimitry Andric void push_back(const std::string &); 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric // Register a counter with the specified name. 780b57cec5SDimitry Andric // 790b57cec5SDimitry Andric // FIXME: Currently, counter registration is required to happen before command 800b57cec5SDimitry Andric // line option parsing. The main reason to register counters is to produce a 810b57cec5SDimitry Andric // nice list of them on the command line, but i'm not sure this is worth it. registerCounter(StringRef Name,StringRef Desc)820b57cec5SDimitry Andric static unsigned registerCounter(StringRef Name, StringRef Desc) { 835ffd83dbSDimitry Andric return instance().addCounter(std::string(Name), std::string(Desc)); 840b57cec5SDimitry Andric } 85*0fca6ea1SDimitry Andric static bool shouldExecuteImpl(unsigned CounterName); 86*0fca6ea1SDimitry Andric shouldExecute(unsigned CounterName)870b57cec5SDimitry Andric inline static bool shouldExecute(unsigned CounterName) { 880b57cec5SDimitry Andric if (!isCountingEnabled()) 890b57cec5SDimitry Andric return true; 90*0fca6ea1SDimitry Andric return shouldExecuteImpl(CounterName); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric // Return true if a given counter had values set (either programatically or on 940b57cec5SDimitry Andric // the command line). This will return true even if those values are 950b57cec5SDimitry Andric // currently in a state where the counter will always execute. isCounterSet(unsigned ID)960b57cec5SDimitry Andric static bool isCounterSet(unsigned ID) { 970b57cec5SDimitry Andric return instance().Counters[ID].IsSet; 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 100*0fca6ea1SDimitry Andric struct CounterState { 101*0fca6ea1SDimitry Andric int64_t Count; 102*0fca6ea1SDimitry Andric uint64_t ChunkIdx; 103*0fca6ea1SDimitry Andric }; 104*0fca6ea1SDimitry Andric 105*0fca6ea1SDimitry Andric // Return the state of a counter. This only works for set counters. getCounterState(unsigned ID)106*0fca6ea1SDimitry Andric static CounterState getCounterState(unsigned ID) { 1070b57cec5SDimitry Andric auto &Us = instance(); 1080b57cec5SDimitry Andric auto Result = Us.Counters.find(ID); 1090b57cec5SDimitry Andric assert(Result != Us.Counters.end() && "Asking about a non-set counter"); 110*0fca6ea1SDimitry Andric return {Result->second.Count, Result->second.CurrChunkIdx}; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 113*0fca6ea1SDimitry Andric // Set a registered counter to a given state. setCounterState(unsigned ID,CounterState State)114*0fca6ea1SDimitry Andric static void setCounterState(unsigned ID, CounterState State) { 1150b57cec5SDimitry Andric auto &Us = instance(); 116*0fca6ea1SDimitry Andric auto &Counter = Us.Counters[ID]; 117*0fca6ea1SDimitry Andric Counter.Count = State.Count; 118*0fca6ea1SDimitry Andric Counter.CurrChunkIdx = State.ChunkIdx; 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric // Dump or print the current counter set into llvm::dbgs(). 1220b57cec5SDimitry Andric LLVM_DUMP_METHOD void dump() const; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric void print(raw_ostream &OS) const; 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric // Get the counter ID for a given named counter, or return 0 if none is found. getCounterId(const std::string & Name)1270b57cec5SDimitry Andric unsigned getCounterId(const std::string &Name) const { 1280b57cec5SDimitry Andric return RegisteredCounters.idFor(Name); 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // Return the number of registered counters. getNumCounters()1320b57cec5SDimitry Andric unsigned int getNumCounters() const { return RegisteredCounters.size(); } 1330b57cec5SDimitry Andric 1340b57cec5SDimitry Andric // Return the name and description of the counter with the given ID. getCounterInfo(unsigned ID)1350b57cec5SDimitry Andric std::pair<std::string, std::string> getCounterInfo(unsigned ID) const { 1360b57cec5SDimitry Andric return std::make_pair(RegisteredCounters[ID], Counters.lookup(ID).Desc); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // Iterate through the registered counters 1400b57cec5SDimitry Andric typedef UniqueVector<std::string> CounterVector; begin()1410b57cec5SDimitry Andric CounterVector::const_iterator begin() const { 1420b57cec5SDimitry Andric return RegisteredCounters.begin(); 1430b57cec5SDimitry Andric } end()1440b57cec5SDimitry Andric CounterVector::const_iterator end() const { return RegisteredCounters.end(); } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric // Force-enables counting all DebugCounters. 1470b57cec5SDimitry Andric // 1480b57cec5SDimitry Andric // Since DebugCounters are incompatible with threading (not only do they not 1490b57cec5SDimitry Andric // make sense, but we'll also see data races), this should only be used in 1500b57cec5SDimitry Andric // contexts where we're certain we won't spawn threads. enableAllCounters()1510b57cec5SDimitry Andric static void enableAllCounters() { instance().Enabled = true; } 1520b57cec5SDimitry Andric isCountingEnabled()1530b57cec5SDimitry Andric static bool isCountingEnabled() { 1540b57cec5SDimitry Andric // Compile to nothing when debugging is off 1550b57cec5SDimitry Andric #ifdef NDEBUG 1560b57cec5SDimitry Andric return false; 1570b57cec5SDimitry Andric #else 158*0fca6ea1SDimitry Andric return instance().Enabled || instance().ShouldPrintCounter; 1590b57cec5SDimitry Andric #endif 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 162*0fca6ea1SDimitry Andric protected: addCounter(const std::string & Name,const std::string & Desc)1630b57cec5SDimitry Andric unsigned addCounter(const std::string &Name, const std::string &Desc) { 1640b57cec5SDimitry Andric unsigned Result = RegisteredCounters.insert(Name); 1650b57cec5SDimitry Andric Counters[Result] = {}; 1660b57cec5SDimitry Andric Counters[Result].Desc = Desc; 1670b57cec5SDimitry Andric return Result; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric // Struct to store counter info. 1700b57cec5SDimitry Andric struct CounterInfo { 1710b57cec5SDimitry Andric int64_t Count = 0; 172*0fca6ea1SDimitry Andric uint64_t CurrChunkIdx = 0; 1730b57cec5SDimitry Andric bool IsSet = false; 1740b57cec5SDimitry Andric std::string Desc; 175*0fca6ea1SDimitry Andric SmallVector<Chunk> Chunks; 1760b57cec5SDimitry Andric }; 177*0fca6ea1SDimitry Andric 1780b57cec5SDimitry Andric DenseMap<unsigned, CounterInfo> Counters; 1790b57cec5SDimitry Andric CounterVector RegisteredCounters; 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric // Whether we should do DebugCounting at all. DebugCounters aren't 1820b57cec5SDimitry Andric // thread-safe, so this should always be false in multithreaded scenarios. 1830b57cec5SDimitry Andric bool Enabled = false; 184*0fca6ea1SDimitry Andric 185*0fca6ea1SDimitry Andric bool ShouldPrintCounter = false; 186*0fca6ea1SDimitry Andric 187*0fca6ea1SDimitry Andric bool BreakOnLast = false; 1880b57cec5SDimitry Andric }; 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric #define DEBUG_COUNTER(VARNAME, COUNTERNAME, DESC) \ 1910b57cec5SDimitry Andric static const unsigned VARNAME = \ 1920b57cec5SDimitry Andric DebugCounter::registerCounter(COUNTERNAME, DESC) 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric } // namespace llvm 1950b57cec5SDimitry Andric #endif 196