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/Compiler.h"
     28 #include "llvm/Support/Debug.h"
     29 #include "llvm/Support/Format.h"
     30 #include "llvm/Support/ManagedStatic.h"
     31 #include "llvm/Support/Mutex.h"
     32 #include "llvm/Support/raw_ostream.h"
     33 #include <algorithm>
     34 #include <cstring>
     35 using namespace llvm;
     36 
     37 /// -stats - Command line option to cause transformations to emit stats about
     38 /// what they did.
     39 ///
     40 static cl::opt<bool>
     41 Enabled(
     42     "stats",
     43     cl::desc("Enable statistics output from program (available with Asserts)"));
     44 
     45 
     46 static cl::opt<bool> StatsAsJSON("stats-json",
     47                                  cl::desc("Display statistics as json data"));
     48 
     49 namespace {
     50 /// StatisticInfo - This class is used in a ManagedStatic so that it is created
     51 /// on demand (when the first statistic is bumped) and destroyed only when
     52 /// llvm_shutdown is called.  We print statistics from the destructor.
     53 class StatisticInfo {
     54   std::vector<const Statistic*> Stats;
     55   friend void llvm::PrintStatistics();
     56   friend void llvm::PrintStatistics(raw_ostream &OS);
     57   friend void llvm::PrintStatisticsJSON(raw_ostream &OS);
     58 
     59   /// Sort statistics by debugtype,name,description.
     60   void sort();
     61 public:
     62   ~StatisticInfo();
     63 
     64   void addStatistic(const Statistic *S) {
     65     Stats.push_back(S);
     66   }
     67 };
     68 }
     69 
     70 static ManagedStatic<StatisticInfo> StatInfo;
     71 static ManagedStatic<sys::SmartMutex<true> > StatLock;
     72 
     73 /// RegisterStatistic - The first time a statistic is bumped, this method is
     74 /// called.
     75 void Statistic::RegisterStatistic() {
     76   // If stats are enabled, inform StatInfo that this statistic should be
     77   // printed.
     78   sys::SmartScopedLock<true> Writer(*StatLock);
     79   if (!Initialized) {
     80     if (Enabled)
     81       StatInfo->addStatistic(this);
     82 
     83     TsanHappensBefore(this);
     84     sys::MemoryFence();
     85     // Remember we have been registered.
     86     TsanIgnoreWritesBegin();
     87     Initialized = true;
     88     TsanIgnoreWritesEnd();
     89   }
     90 }
     91 
     92 // Print information when destroyed, iff command line option is specified.
     93 StatisticInfo::~StatisticInfo() {
     94   llvm::PrintStatistics();
     95 }
     96 
     97 void llvm::EnableStatistics() {
     98   Enabled.setValue(true);
     99 }
    100 
    101 bool llvm::AreStatisticsEnabled() {
    102   return Enabled;
    103 }
    104 
    105 void StatisticInfo::sort() {
    106   std::stable_sort(Stats.begin(), Stats.end(),
    107                    [](const Statistic *LHS, const Statistic *RHS) {
    108     if (int Cmp = std::strcmp(LHS->getDebugType(), RHS->getDebugType()))
    109       return Cmp < 0;
    110 
    111     if (int Cmp = std::strcmp(LHS->getName(), RHS->getName()))
    112       return Cmp < 0;
    113 
    114     return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0;
    115   });
    116 }
    117 
    118 void llvm::PrintStatistics(raw_ostream &OS) {
    119   StatisticInfo &Stats = *StatInfo;
    120 
    121   // Figure out how long the biggest Value and Name fields are.
    122   unsigned MaxDebugTypeLen = 0, MaxValLen = 0;
    123   for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) {
    124     MaxValLen = std::max(MaxValLen,
    125                          (unsigned)utostr(Stats.Stats[i]->getValue()).size());
    126     MaxDebugTypeLen = std::max(MaxDebugTypeLen,
    127                          (unsigned)std::strlen(Stats.Stats[i]->getDebugType()));
    128   }
    129 
    130   Stats.sort();
    131 
    132   // Print out the statistics header...
    133   OS << "===" << std::string(73, '-') << "===\n"
    134      << "                          ... Statistics Collected ...\n"
    135      << "===" << std::string(73, '-') << "===\n\n";
    136 
    137   // Print all of the statistics.
    138   for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i)
    139     OS << format("%*u %-*s - %s\n",
    140                  MaxValLen, Stats.Stats[i]->getValue(),
    141                  MaxDebugTypeLen, Stats.Stats[i]->getDebugType(),
    142                  Stats.Stats[i]->getDesc());
    143 
    144   OS << '\n';  // Flush the output stream.
    145   OS.flush();
    146 }
    147 
    148 static void write_json_string_escaped(raw_ostream &OS, const char *string) {
    149   // Out current usage should not need any escaping. Keep it simple and just
    150   // check that the input is pure ASCII without special characers.
    151 #ifndef NDEBUG
    152   for (const unsigned char *c = (const unsigned char*)string; *c != '\0'; ++c) {
    153     assert(*c != '\\' && *c != '\"' && *c >= 0x20 && *c < 0x80);
    154   }
    155 #endif
    156   OS << string;
    157 }
    158 
    159 void llvm::PrintStatisticsJSON(raw_ostream &OS) {
    160   StatisticInfo &Stats = *StatInfo;
    161 
    162   Stats.sort();
    163 
    164   // Print all of the statistics.
    165   OS << "{\n";
    166   const char *delim = "";
    167   for (const Statistic *Stat : Stats.Stats) {
    168     OS << delim;
    169     OS << "\t\"";
    170     write_json_string_escaped(OS, Stat->getDebugType());
    171     OS << '.';
    172     write_json_string_escaped(OS, Stat->getName());
    173     OS << "\": " << Stat->getValue();
    174     delim = ",\n";
    175   }
    176   OS << "\n}\n";
    177   OS.flush();
    178 }
    179 
    180 void llvm::PrintStatistics() {
    181 #if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
    182   StatisticInfo &Stats = *StatInfo;
    183 
    184   // Statistics not enabled?
    185   if (Stats.Stats.empty()) return;
    186 
    187   // Get the stream to write to.
    188   std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
    189   if (StatsAsJSON)
    190     PrintStatisticsJSON(*OutStream);
    191   else
    192     PrintStatistics(*OutStream);
    193 
    194 #else
    195   // Check if the -stats option is set instead of checking
    196   // !Stats.Stats.empty().  In release builds, Statistics operators
    197   // do nothing, so stats are never Registered.
    198   if (Enabled) {
    199     // Get the stream to write to.
    200     std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
    201     (*OutStream) << "Statistics are disabled.  "
    202                  << "Build with asserts or with -DLLVM_ENABLE_STATS\n";
    203   }
    204 #endif
    205 }
    206