Home | History | Annotate | Download | only in Support
      1 //===-- Statistic.cpp - Easy way to expose stats information --------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file implements the 'Statistic' class, which is designed to be an easy
     11 // way to expose various success metrics from passes.  These statistics are
     12 // printed at the end of a run, when the -stats command line option is enabled
     13 // on the command line.
     14 //
     15 // This is useful for reporting information like the number of instructions
     16 // simplified, optimized or removed by various transformations, like this:
     17 //
     18 // static Statistic NumInstEliminated("GCSE", "Number of instructions killed");
     19 //
     20 // Later, in the code: ++NumInstEliminated;
     21 //
     22 //===----------------------------------------------------------------------===//
     23 
     24 #include "llvm/ADT/Statistic.h"
     25 #include "llvm/ADT/StringExtras.h"
     26 #include "llvm/Support/CommandLine.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/raw_ostream.h"
     32 #include <algorithm>
     33 #include <cstring>
     34 using namespace llvm;
     35 
     36 // CreateInfoOutputFile - Return a file stream to print our output on.
     37 namespace llvm { extern raw_ostream *CreateInfoOutputFile(); }
     38 
     39 /// -stats - Command line option to cause transformations to emit stats about
     40 /// what they did.
     41 ///
     42 static cl::opt<bool>
     43 Enabled(
     44     "stats",
     45     cl::desc("Enable statistics output from program (available with Asserts)"));
     46 
     47 
     48 namespace {
     49 /// StatisticInfo - This class is used in a ManagedStatic so that it is created
     50 /// on demand (when the first statistic is bumped) and destroyed only when
     51 /// llvm_shutdown is called.  We print statistics from the destructor.
     52 class StatisticInfo {
     53   std::vector<const Statistic*> Stats;
     54   friend void llvm::PrintStatistics();
     55   friend void llvm::PrintStatistics(raw_ostream &OS);
     56 public:
     57   ~StatisticInfo();
     58 
     59   void addStatistic(const Statistic *S) {
     60     Stats.push_back(S);
     61   }
     62 };
     63 }
     64 
     65 static ManagedStatic<StatisticInfo> StatInfo;
     66 static ManagedStatic<sys::SmartMutex<true> > StatLock;
     67 
     68 /// RegisterStatistic - The first time a statistic is bumped, this method is
     69 /// called.
     70 void Statistic::RegisterStatistic() {
     71   // If stats are enabled, inform StatInfo that this statistic should be
     72   // printed.
     73   sys::SmartScopedLock<true> Writer(*StatLock);
     74   if (!Initialized) {
     75     if (Enabled)
     76       StatInfo->addStatistic(this);
     77 
     78     TsanHappensBefore(this);
     79     sys::MemoryFence();
     80     // Remember we have been registered.
     81     TsanIgnoreWritesBegin();
     82     Initialized = true;
     83     TsanIgnoreWritesEnd();
     84   }
     85 }
     86 
     87 namespace {
     88 
     89 struct NameCompare {
     90   bool operator()(const Statistic *LHS, const Statistic *RHS) const {
     91     int Cmp = std::strcmp(LHS->getName(), RHS->getName());
     92     if (Cmp != 0) return Cmp < 0;
     93 
     94     // Secondary key is the description.
     95     return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0;
     96   }
     97 };
     98 
     99 }
    100 
    101 // Print information when destroyed, iff command line option is specified.
    102 StatisticInfo::~StatisticInfo() {
    103   llvm::PrintStatistics();
    104 }
    105 
    106 void llvm::EnableStatistics() {
    107   Enabled.setValue(true);
    108 }
    109 
    110 bool llvm::AreStatisticsEnabled() {
    111   return Enabled;
    112 }
    113 
    114 void llvm::PrintStatistics(raw_ostream &OS) {
    115   StatisticInfo &Stats = *StatInfo;
    116 
    117   // Figure out how long the biggest Value and Name fields are.
    118   unsigned MaxNameLen = 0, MaxValLen = 0;
    119   for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) {
    120     MaxValLen = std::max(MaxValLen,
    121                          (unsigned)utostr(Stats.Stats[i]->getValue()).size());
    122     MaxNameLen = std::max(MaxNameLen,
    123                           (unsigned)std::strlen(Stats.Stats[i]->getName()));
    124   }
    125 
    126   // Sort the fields by name.
    127   std::stable_sort(Stats.Stats.begin(), Stats.Stats.end(), NameCompare());
    128 
    129   // Print out the statistics header...
    130   OS << "===" << std::string(73, '-') << "===\n"
    131      << "                          ... Statistics Collected ...\n"
    132      << "===" << std::string(73, '-') << "===\n\n";
    133 
    134   // Print all of the statistics.
    135   for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i)
    136     OS << format("%*u %-*s - %s\n",
    137                  MaxValLen, Stats.Stats[i]->getValue(),
    138                  MaxNameLen, Stats.Stats[i]->getName(),
    139                  Stats.Stats[i]->getDesc());
    140 
    141   OS << '\n';  // Flush the output stream.
    142   OS.flush();
    143 
    144 }
    145 
    146 void llvm::PrintStatistics() {
    147 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
    148   StatisticInfo &Stats = *StatInfo;
    149 
    150   // Statistics not enabled?
    151   if (Stats.Stats.empty()) return;
    152 
    153   // Get the stream to write to.
    154   raw_ostream &OutStream = *CreateInfoOutputFile();
    155   PrintStatistics(OutStream);
    156   delete &OutStream;   // Close the file.
    157 #else
    158   // Check if the -stats option is set instead of checking
    159   // !Stats.Stats.empty().  In release builds, Statistics operators
    160   // do nothing, so stats are never Registered.
    161   if (Enabled) {
    162     // Get the stream to write to.
    163     raw_ostream &OutStream = *CreateInfoOutputFile();
    164     OutStream << "Statistics are disabled.  "
    165             << "Build with asserts or with -DLLVM_ENABLE_STATS\n";
    166     OutStream.flush();
    167     delete &OutStream;   // Close the file.
    168   }
    169 #endif
    170 }
    171