Home | History | Annotate | Line # | Download | only in Support
      1 //===-- Statistic.cpp - Easy way to expose stats information --------------===//
      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 //
      9 // This file implements the 'Statistic' class, which is designed to be an easy
     10 // way to expose various success metrics from passes.  These statistics are
     11 // printed at the end of a run, when the -stats command line option is enabled
     12 // on the command line.
     13 //
     14 // This is useful for reporting information like the number of instructions
     15 // simplified, optimized or removed by various transformations, like this:
     16 //
     17 // static Statistic NumInstEliminated("GCSE", "Number of instructions killed");
     18 //
     19 // Later, in the code: ++NumInstEliminated;
     20 //
     21 //===----------------------------------------------------------------------===//
     22 
     23 #include "llvm/ADT/Statistic.h"
     24 #include "llvm/ADT/StringExtras.h"
     25 #include "llvm/Support/CommandLine.h"
     26 #include "llvm/Support/Compiler.h"
     27 #include "llvm/Support/Debug.h"
     28 #include "llvm/Support/Format.h"
     29 #include "llvm/Support/ManagedStatic.h"
     30 #include "llvm/Support/Mutex.h"
     31 #include "llvm/Support/Timer.h"
     32 #include "llvm/Support/YAMLTraits.h"
     33 #include "llvm/Support/raw_ostream.h"
     34 #include <algorithm>
     35 #include <cstring>
     36 using namespace llvm;
     37 
     38 /// -stats - Command line option to cause transformations to emit stats about
     39 /// what they did.
     40 ///
     41 static cl::opt<bool> EnableStats(
     42     "stats",
     43     cl::desc("Enable statistics output from program (available with Asserts)"),
     44     cl::Hidden);
     45 
     46 static cl::opt<bool> StatsAsJSON("stats-json",
     47                                  cl::desc("Display statistics as json data"),
     48                                  cl::Hidden);
     49 
     50 static bool Enabled;
     51 static bool PrintOnExit;
     52 
     53 namespace {
     54 /// This class is used in a ManagedStatic so that it is created on demand (when
     55 /// the first statistic is bumped) and destroyed only when llvm_shutdown is
     56 /// called. We print statistics from the destructor.
     57 /// This class is also used to look up statistic values from applications that
     58 /// use LLVM.
     59 class StatisticInfo {
     60   std::vector<TrackingStatistic *> Stats;
     61 
     62   friend void llvm::PrintStatistics();
     63   friend void llvm::PrintStatistics(raw_ostream &OS);
     64   friend void llvm::PrintStatisticsJSON(raw_ostream &OS);
     65 
     66   /// Sort statistics by debugtype,name,description.
     67   void sort();
     68 public:
     69   using const_iterator = std::vector<TrackingStatistic *>::const_iterator;
     70 
     71   StatisticInfo();
     72   ~StatisticInfo();
     73 
     74   void addStatistic(TrackingStatistic *S) { Stats.push_back(S); }
     75 
     76   const_iterator begin() const { return Stats.begin(); }
     77   const_iterator end() const { return Stats.end(); }
     78   iterator_range<const_iterator> statistics() const {
     79     return {begin(), end()};
     80   }
     81 
     82   void reset();
     83 };
     84 } // end anonymous namespace
     85 
     86 static ManagedStatic<StatisticInfo> StatInfo;
     87 static ManagedStatic<sys::SmartMutex<true> > StatLock;
     88 
     89 /// RegisterStatistic - The first time a statistic is bumped, this method is
     90 /// called.
     91 void TrackingStatistic::RegisterStatistic() {
     92   // If stats are enabled, inform StatInfo that this statistic should be
     93   // printed.
     94   // llvm_shutdown calls destructors while holding the ManagedStatic mutex.
     95   // These destructors end up calling PrintStatistics, which takes StatLock.
     96   // Since dereferencing StatInfo and StatLock can require taking the
     97   // ManagedStatic mutex, doing so with StatLock held would lead to a lock
     98   // order inversion. To avoid that, we dereference the ManagedStatics first,
     99   // and only take StatLock afterwards.
    100   if (!Initialized.load(std::memory_order_relaxed)) {
    101     sys::SmartMutex<true> &Lock = *StatLock;
    102     StatisticInfo &SI = *StatInfo;
    103     sys::SmartScopedLock<true> Writer(Lock);
    104     // Check Initialized again after acquiring the lock.
    105     if (Initialized.load(std::memory_order_relaxed))
    106       return;
    107     if (EnableStats || Enabled)
    108       SI.addStatistic(this);
    109 
    110     // Remember we have been registered.
    111     Initialized.store(true, std::memory_order_release);
    112   }
    113 }
    114 
    115 StatisticInfo::StatisticInfo() {
    116   // Ensure timergroup lists are created first so they are destructed after us.
    117   TimerGroup::ConstructTimerLists();
    118 }
    119 
    120 // Print information when destroyed, iff command line option is specified.
    121 StatisticInfo::~StatisticInfo() {
    122   if (EnableStats || PrintOnExit)
    123     llvm::PrintStatistics();
    124 }
    125 
    126 void llvm::EnableStatistics(bool DoPrintOnExit) {
    127   Enabled = true;
    128   PrintOnExit = DoPrintOnExit;
    129 }
    130 
    131 bool llvm::AreStatisticsEnabled() {
    132   return Enabled || EnableStats;
    133 }
    134 
    135 void StatisticInfo::sort() {
    136   llvm::stable_sort(
    137       Stats, [](const TrackingStatistic *LHS, const TrackingStatistic *RHS) {
    138         if (int Cmp = std::strcmp(LHS->getDebugType(), RHS->getDebugType()))
    139           return Cmp < 0;
    140 
    141         if (int Cmp = std::strcmp(LHS->getName(), RHS->getName()))
    142           return Cmp < 0;
    143 
    144         return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0;
    145       });
    146 }
    147 
    148 void StatisticInfo::reset() {
    149   sys::SmartScopedLock<true> Writer(*StatLock);
    150 
    151   // Tell each statistic that it isn't registered so it has to register
    152   // again. We're holding the lock so it won't be able to do so until we're
    153   // finished. Once we've forced it to re-register (after we return), then zero
    154   // the value.
    155   for (auto *Stat : Stats) {
    156     // Value updates to a statistic that complete before this statement in the
    157     // iteration for that statistic will be lost as intended.
    158     Stat->Initialized = false;
    159     Stat->Value = 0;
    160   }
    161 
    162   // Clear the registration list and release the lock once we're done. Any
    163   // pending updates from other threads will safely take effect after we return.
    164   // That might not be what the user wants if they're measuring a compilation
    165   // but it's their responsibility to prevent concurrent compilations to make
    166   // a single compilation measurable.
    167   Stats.clear();
    168 }
    169 
    170 void llvm::PrintStatistics(raw_ostream &OS) {
    171   StatisticInfo &Stats = *StatInfo;
    172 
    173   // Figure out how long the biggest Value and Name fields are.
    174   unsigned MaxDebugTypeLen = 0, MaxValLen = 0;
    175   for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) {
    176     MaxValLen = std::max(MaxValLen,
    177                          (unsigned)utostr(Stats.Stats[i]->getValue()).size());
    178     MaxDebugTypeLen = std::max(MaxDebugTypeLen,
    179                          (unsigned)std::strlen(Stats.Stats[i]->getDebugType()));
    180   }
    181 
    182   Stats.sort();
    183 
    184   // Print out the statistics header...
    185   OS << "===" << std::string(73, '-') << "===\n"
    186      << "                          ... Statistics Collected ...\n"
    187      << "===" << std::string(73, '-') << "===\n\n";
    188 
    189   // Print all of the statistics.
    190   for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i)
    191     OS << format("%*u %-*s - %s\n",
    192                  MaxValLen, Stats.Stats[i]->getValue(),
    193                  MaxDebugTypeLen, Stats.Stats[i]->getDebugType(),
    194                  Stats.Stats[i]->getDesc());
    195 
    196   OS << '\n';  // Flush the output stream.
    197   OS.flush();
    198 }
    199 
    200 void llvm::PrintStatisticsJSON(raw_ostream &OS) {
    201   sys::SmartScopedLock<true> Reader(*StatLock);
    202   StatisticInfo &Stats = *StatInfo;
    203 
    204   Stats.sort();
    205 
    206   // Print all of the statistics.
    207   OS << "{\n";
    208   const char *delim = "";
    209   for (const TrackingStatistic *Stat : Stats.Stats) {
    210     OS << delim;
    211     assert(yaml::needsQuotes(Stat->getDebugType()) == yaml::QuotingType::None &&
    212            "Statistic group/type name is simple.");
    213     assert(yaml::needsQuotes(Stat->getName()) == yaml::QuotingType::None &&
    214            "Statistic name is simple");
    215     OS << "\t\"" << Stat->getDebugType() << '.' << Stat->getName() << "\": "
    216        << Stat->getValue();
    217     delim = ",\n";
    218   }
    219   // Print timers.
    220   TimerGroup::printAllJSONValues(OS, delim);
    221 
    222   OS << "\n}\n";
    223   OS.flush();
    224 }
    225 
    226 void llvm::PrintStatistics() {
    227 #if LLVM_ENABLE_STATS
    228   sys::SmartScopedLock<true> Reader(*StatLock);
    229   StatisticInfo &Stats = *StatInfo;
    230 
    231   // Statistics not enabled?
    232   if (Stats.Stats.empty()) return;
    233 
    234   // Get the stream to write to.
    235   std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
    236   if (StatsAsJSON)
    237     PrintStatisticsJSON(*OutStream);
    238   else
    239     PrintStatistics(*OutStream);
    240 
    241 #else
    242   // Check if the -stats option is set instead of checking
    243   // !Stats.Stats.empty().  In release builds, Statistics operators
    244   // do nothing, so stats are never Registered.
    245   if (EnableStats) {
    246     // Get the stream to write to.
    247     std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
    248     (*OutStream) << "Statistics are disabled.  "
    249                  << "Build with asserts or with -DLLVM_FORCE_ENABLE_STATS\n";
    250   }
    251 #endif
    252 }
    253 
    254 const std::vector<std::pair<StringRef, unsigned>> llvm::GetStatistics() {
    255   sys::SmartScopedLock<true> Reader(*StatLock);
    256   std::vector<std::pair<StringRef, unsigned>> ReturnStats;
    257 
    258   for (const auto &Stat : StatInfo->statistics())
    259     ReturnStats.emplace_back(Stat->getName(), Stat->getValue());
    260   return ReturnStats;
    261 }
    262 
    263 void llvm::ResetStatistics() {
    264   StatInfo->reset();
    265 }
    266