brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.4 KiB · 5ab1def Raw
277 lines · cpp
1#include "llvm/Support/DebugCounter.h"2 3#include "DebugOptions.h"4 5#include "llvm/Support/CommandLine.h"6#include "llvm/Support/Format.h"7 8using namespace llvm;9 10namespace llvm {11 12void DebugCounter::Chunk::print(llvm::raw_ostream &OS) {13  if (Begin == End)14    OS << Begin;15  else16    OS << Begin << "-" << End;17}18 19void DebugCounter::printChunks(raw_ostream &OS, ArrayRef<Chunk> Chunks) {20  if (Chunks.empty()) {21    OS << "empty";22  } else {23    bool IsFirst = true;24    for (auto E : Chunks) {25      if (!IsFirst)26        OS << ':';27      else28        IsFirst = false;29      E.print(OS);30    }31  }32}33 34bool DebugCounter::parseChunks(StringRef Str, SmallVector<Chunk> &Chunks) {35  StringRef Remaining = Str;36 37  auto ConsumeInt = [&]() -> int64_t {38    StringRef Number =39        Remaining.take_until([](char c) { return c < '0' || c > '9'; });40    int64_t Res;41    if (Number.getAsInteger(10, Res)) {42      errs() << "Failed to parse int at : " << Remaining << "\n";43      return -1;44    }45    Remaining = Remaining.drop_front(Number.size());46    return Res;47  };48 49  while (1) {50    int64_t Num = ConsumeInt();51    if (Num == -1)52      return true;53    if (!Chunks.empty() && Num <= Chunks[Chunks.size() - 1].End) {54      errs() << "Expected Chunks to be in increasing order " << Num55             << " <= " << Chunks[Chunks.size() - 1].End << "\n";56      return true;57    }58    if (Remaining.starts_with("-")) {59      Remaining = Remaining.drop_front();60      int64_t Num2 = ConsumeInt();61      if (Num2 == -1)62        return true;63      if (Num >= Num2) {64        errs() << "Expected " << Num << " < " << Num2 << " in " << Num << "-"65               << Num2 << "\n";66        return true;67      }68 69      Chunks.push_back({Num, Num2});70    } else {71      Chunks.push_back({Num, Num});72    }73    if (Remaining.starts_with(":")) {74      Remaining = Remaining.drop_front();75      continue;76    }77    if (Remaining.empty())78      break;79    errs() << "Failed to parse at : " << Remaining;80    return true;81  }82  return false;83}84 85} // namespace llvm86 87namespace {88// This class overrides the default list implementation of printing so we89// can pretty print the list of debug counter options.  This type of90// dynamic option is pretty rare (basically this and pass lists).91class DebugCounterList : public cl::list<std::string, DebugCounter> {92private:93  using Base = cl::list<std::string, DebugCounter>;94 95public:96  template <class... Mods>97  explicit DebugCounterList(Mods &&... Ms) : Base(std::forward<Mods>(Ms)...) {}98 99private:100  void printOptionInfo(size_t GlobalWidth) const override {101    // This is a variant of from generic_parser_base::printOptionInfo.  Sadly,102    // it's not easy to make it more usable.  We could get it to print these as103    // options if we were a cl::opt and registered them, but lists don't have104    // options, nor does the parser for std::string.  The other mechanisms for105    // options are global and would pollute the global namespace with our106    // counters.  Rather than go that route, we have just overridden the107    // printing, which only a few things call anyway.108    outs() << "  -" << ArgStr;109    // All of the other options in CommandLine.cpp use ArgStr.size() + 6 for110    // width, so we do the same.111    Option::printHelpStr(HelpStr, GlobalWidth, ArgStr.size() + 6);112    const auto &CounterInstance = DebugCounter::instance();113    for (const auto &Name : CounterInstance) {114      const auto Info =115          CounterInstance.getCounterInfo(CounterInstance.getCounterId(Name));116      size_t NumSpaces = GlobalWidth - Info.first.size() - 8;117      outs() << "    =" << Info.first;118      outs().indent(NumSpaces) << " -   " << Info.second << '\n';119    }120  }121};122 123// All global objects associated to the DebugCounter, including the DebugCounter124// itself, are owned by a single global instance of the DebugCounterOwner125// struct. This makes it easier to control the order in which constructors and126// destructors are run.127struct DebugCounterOwner : DebugCounter {128  DebugCounterList DebugCounterOption{129      "debug-counter", cl::Hidden,130      cl::desc("Comma separated list of debug counter skip and count"),131      cl::CommaSeparated, cl::location<DebugCounter>(*this)};132  cl::opt<bool, true> PrintDebugCounter{133      "print-debug-counter",134      cl::Hidden,135      cl::Optional,136      cl::location(this->ShouldPrintCounter),137      cl::init(false),138      cl::desc("Print out debug counter info after all counters accumulated")};139  cl::opt<bool, true> PrintDebugCounterQueries{140      "print-debug-counter-queries",141      cl::Hidden,142      cl::Optional,143      cl::location(this->ShouldPrintCounterQueries),144      cl::init(false),145      cl::desc("Print out each query of an enabled debug counter")};146  cl::opt<bool, true> BreakOnLastCount{147      "debug-counter-break-on-last",148      cl::Hidden,149      cl::Optional,150      cl::location(this->BreakOnLast),151      cl::init(false),152      cl::desc("Insert a break point on the last enabled count of a "153               "chunks list")};154 155  DebugCounterOwner() {156    // Our destructor uses the debug stream. By referencing it here, we157    // ensure that its destructor runs after our destructor.158    (void)dbgs();159  }160 161  // Print information when destroyed, iff command line option is specified.162  ~DebugCounterOwner() {163    if (ShouldPrintCounter)164      print(dbgs());165  }166};167 168} // anonymous namespace169 170void llvm::initDebugCounterOptions() { (void)DebugCounter::instance(); }171 172DebugCounter &DebugCounter::instance() {173  static DebugCounterOwner O;174  return O;175}176 177// This is called by the command line parser when it sees a value for the178// debug-counter option defined above.179void DebugCounter::push_back(const std::string &Val) {180  if (Val.empty())181    return;182#ifdef NDEBUG183  // isCountingEnabled is hardcoded to false in NDEBUG.184  errs() << "Requested --debug-counter in LLVM build without assertions. This "185            "is a no-op.\n";186#endif187 188  // The strings should come in as counter=chunk_list189  auto CounterPair = StringRef(Val).split('=');190  if (CounterPair.second.empty()) {191    errs() << "DebugCounter Error: " << Val << " does not have an = in it\n";192    return;193  }194  StringRef CounterName = CounterPair.first;195  SmallVector<Chunk> Chunks;196 197  if (parseChunks(CounterPair.second, Chunks)) {198    return;199  }200 201  unsigned CounterID = getCounterId(std::string(CounterName));202  if (!CounterID) {203    errs() << "DebugCounter Error: " << CounterName204           << " is not a registered counter\n";205    return;206  }207  enableAllCounters();208 209  CounterInfo &Counter = Counters[CounterID];210  Counter.IsSet = true;211  Counter.Chunks = std::move(Chunks);212}213 214void DebugCounter::print(raw_ostream &OS) const {215  SmallVector<StringRef, 16> CounterNames(RegisteredCounters.begin(),216                                          RegisteredCounters.end());217  sort(CounterNames);218 219  auto &Us = instance();220  OS << "Counters and values:\n";221  for (auto &CounterName : CounterNames) {222    unsigned CounterID = getCounterId(std::string(CounterName));223    const CounterInfo &C = Us.Counters[CounterID];224    OS << left_justify(RegisteredCounters[CounterID], 32) << ": {" << C.Count225       << ",";226    printChunks(OS, C.Chunks);227    OS << "}\n";228  }229}230 231bool DebugCounter::handleCounterIncrement(CounterInfo &Info) {232  int64_t CurrCount = Info.Count++;233  uint64_t CurrIdx = Info.CurrChunkIdx;234 235  if (Info.Chunks.empty())236    return true;237  if (CurrIdx >= Info.Chunks.size())238    return false;239 240  bool Res = Info.Chunks[CurrIdx].contains(CurrCount);241  if (BreakOnLast && CurrIdx == (Info.Chunks.size() - 1) &&242      CurrCount == Info.Chunks[CurrIdx].End) {243    LLVM_BUILTIN_DEBUGTRAP;244  }245  if (CurrCount > Info.Chunks[CurrIdx].End) {246    Info.CurrChunkIdx++;247 248    /// Handle consecutive blocks.249    if (Info.CurrChunkIdx < Info.Chunks.size() &&250        CurrCount == Info.Chunks[Info.CurrChunkIdx].Begin)251      return true;252  }253  return Res;254}255 256bool DebugCounter::shouldExecuteImpl(unsigned CounterName) {257  auto &Us = instance();258  auto Result = Us.Counters.find(CounterName);259  if (Result != Us.Counters.end()) {260    auto &CounterInfo = Result->second;261    bool Res = Us.handleCounterIncrement(CounterInfo);262    if (Us.ShouldPrintCounterQueries && CounterInfo.IsSet) {263      dbgs() << "DebugCounter " << Us.RegisteredCounters[CounterName] << "="264             << (CounterInfo.Count - 1) << (Res ? " execute" : " skip") << "\n";265    }266    return Res;267  }268  // Didn't find the counter, should we warn?269  return true;270}271 272#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)273LLVM_DUMP_METHOD void DebugCounter::dump() const {274  print(dbgs());275}276#endif277