summaryrefslogtreecommitdiff
path: root/lib/Support/Statistic.cpp
blob: 9c28176b730e954dd10a1a4422423359d2dc2b0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//===-- Statistic.cpp - Easy way to expose stats information --------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the 'Statistic' class, which is designed to be an easy
// way to expose various success metrics from passes.  These statistics are
// printed at the end of a run, when the -stats command line option is enabled
// on the command line.
//
// This is useful for reporting information like the number of instructions
// simplified, optimized or removed by various transformations, like this:
//
// static Statistic NumInstEliminated("GCSE", "Number of instructions killed");
//
// Later, in the code: ++NumInstEliminated;
//
//===----------------------------------------------------------------------===//

#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstring>
using namespace llvm;

// CreateInfoOutputFile - Return a file stream to print our output on.
namespace llvm { extern raw_ostream *CreateInfoOutputFile(); }

/// -stats - Command line option to cause transformations to emit stats about
/// what they did.
///
static cl::opt<bool>
Enabled(
    "stats",
    cl::desc("Enable statistics output from program (available with Asserts)"));


namespace {
/// StatisticInfo - This class is used in a ManagedStatic so that it is created
/// on demand (when the first statistic is bumped) and destroyed only when
/// llvm_shutdown is called.  We print statistics from the destructor.
class StatisticInfo {
  std::vector<const Statistic*> Stats;
  friend void llvm::PrintStatistics();
  friend void llvm::PrintStatistics(raw_ostream &OS);
public:
  ~StatisticInfo();

  void addStatistic(const Statistic *S) {
    Stats.push_back(S);
  }
};
}

static ManagedStatic<StatisticInfo> StatInfo;
static ManagedStatic<sys::SmartMutex<true> > StatLock;

/// RegisterStatistic - The first time a statistic is bumped, this method is
/// called.
void Statistic::RegisterStatistic() {
  // If stats are enabled, inform StatInfo that this statistic should be
  // printed.
  sys::SmartScopedLock<true> Writer(*StatLock);
  if (!Initialized) {
    if (Enabled)
      StatInfo->addStatistic(this);

    TsanHappensBefore(this);
    sys::MemoryFence();
    // Remember we have been registered.
    TsanIgnoreWritesBegin();
    Initialized = true;
    TsanIgnoreWritesEnd();
  }
}

namespace {

struct NameCompare {
  bool operator()(const Statistic *LHS, const Statistic *RHS) const {
    int Cmp = std::strcmp(LHS->getName(), RHS->getName());
    if (Cmp != 0) return Cmp < 0;

    // Secondary key is the description.
    return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0;
  }
};

}

// Print information when destroyed, iff command line option is specified.
StatisticInfo::~StatisticInfo() {
  llvm::PrintStatistics();
}

void llvm::EnableStatistics() {
  Enabled.setValue(true);
}

bool llvm::AreStatisticsEnabled() {
  return Enabled;
}

void llvm::PrintStatistics(raw_ostream &OS) {
  StatisticInfo &Stats = *StatInfo;

  // Figure out how long the biggest Value and Name fields are.
  unsigned MaxNameLen = 0, MaxValLen = 0;
  for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i) {
    MaxValLen = std::max(MaxValLen,
                         (unsigned)utostr(Stats.Stats[i]->getValue()).size());
    MaxNameLen = std::max(MaxNameLen,
                          (unsigned)std::strlen(Stats.Stats[i]->getName()));
  }

  // Sort the fields by name.
  std::stable_sort(Stats.Stats.begin(), Stats.Stats.end(), NameCompare());

  // Print out the statistics header...
  OS << "===" << std::string(73, '-') << "===\n"
     << "                          ... Statistics Collected ...\n"
     << "===" << std::string(73, '-') << "===\n\n";

  // Print all of the statistics.
  for (size_t i = 0, e = Stats.Stats.size(); i != e; ++i)
    OS << format("%*u %-*s - %s\n",
                 MaxValLen, Stats.Stats[i]->getValue(),
                 MaxNameLen, Stats.Stats[i]->getName(),
                 Stats.Stats[i]->getDesc());

  OS << '\n';  // Flush the output stream.
  OS.flush();

}

void llvm::PrintStatistics() {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_STATS)
  StatisticInfo &Stats = *StatInfo;

  // Statistics not enabled?
  if (Stats.Stats.empty()) return;

  // Get the stream to write to.
  raw_ostream &OutStream = *CreateInfoOutputFile();
  PrintStatistics(OutStream);
  delete &OutStream;   // Close the file.
#else
  // Check if the -stats option is set instead of checking
  // !Stats.Stats.empty().  In release builds, Statistics operators
  // do nothing, so stats are never Registered.
  if (Enabled) {
    // Get the stream to write to.
    raw_ostream &OutStream = *CreateInfoOutputFile();
    OutStream << "Statistics are disabled.  "
            << "Build with asserts or with -DLLVM_ENABLE_STATS\n";
    OutStream.flush();
    delete &OutStream;   // Close the file.
  }
#endif
}