Change the implementation of statistic to not need destructors at all.

Instead, the stat info is printed when llvm_shutdown() is called.
These also don't need static ctors, but getting rid of them is uglier:
still investigating.  This reduces the number of static dtors in llvm from
~1400 to ~750.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@32372 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2006-12-08 20:00:42 +00:00
parent 4d9a186b10
commit 975f05852d
2 changed files with 98 additions and 76 deletions

View File

@ -31,29 +31,36 @@ namespace llvm {
class Statistic {
const char *Name;
const char *Desc;
unsigned Value;
static unsigned NumStats;
unsigned Value : 31;
bool Initialized : 1;
public:
// Normal constructor, default initialize data item...
Statistic(const char *name, const char *desc)
: Name(name), Desc(desc), Value(0) {
++NumStats; // Keep track of how many stats are created...
: Name(name), Desc(desc), Value(0), Initialized(0) {
}
// Print information when destroyed, iff command line option is specified
~Statistic();
// Allow use of this class as the value itself...
unsigned getValue() const { return Value; }
const char *getName() const { return Name; }
const char *getDesc() const { return Desc; }
// Allow use of this class as the value itself.
operator unsigned() const { return Value; }
const Statistic &operator=(unsigned Val) { Value = Val; return *this; }
const Statistic &operator++() { ++Value; return *this; }
unsigned operator++(int) { return Value++; }
const Statistic &operator--() { --Value; return *this; }
unsigned operator--(int) { return Value--; }
const Statistic &operator+=(const unsigned &V) { Value += V; return *this; }
const Statistic &operator-=(const unsigned &V) { Value -= V; return *this; }
const Statistic &operator*=(const unsigned &V) { Value *= V; return *this; }
const Statistic &operator/=(const unsigned &V) { Value /= V; return *this; }
const Statistic &operator=(unsigned Val) { Value = Val; return init(); }
const Statistic &operator++() { ++Value; return init(); }
unsigned operator++(int) { init(); return Value++; }
const Statistic &operator--() { --Value; return init(); }
unsigned operator--(int) { init(); return Value--; }
const Statistic &operator+=(const unsigned &V) { Value += V; return init(); }
const Statistic &operator-=(const unsigned &V) { Value -= V; return init(); }
const Statistic &operator*=(const unsigned &V) { Value *= V; return init(); }
const Statistic &operator/=(const unsigned &V) { Value /= V; return init(); }
private:
Statistic &init() {
if (!Initialized) RegisterStatistic();
return *this;
}
void RegisterStatistic();
};
} // End llvm namespace

View File

@ -15,7 +15,7 @@
// 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");
// static Statistic NumInstEliminated("GCSE", "Number of instructions killed");
//
// Later, in the code: ++NumInstEliminated;
//
@ -23,84 +23,99 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Streams.h"
#include "llvm/ADT/StringExtras.h"
#include <algorithm>
#include <ostream>
using namespace llvm;
// GetLibSupportInfoOutputFile - Return a file stream to print our output on...
// GetLibSupportInfoOutputFile - Return a file stream to print our output on.
namespace llvm { extern std::ostream *GetLibSupportInfoOutputFile(); }
unsigned Statistic::NumStats = 0;
// -stats - Command line option to cause transformations to emit stats about
// what they did.
//
/// -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"));
struct StatRecord {
std::string Value;
const char *Name, *Desc;
StatRecord(const std::string &V, const char *N, const char *D)
: Value(V), Name(N), Desc(D) {}
bool operator<(const StatRecord &SR) const {
return std::strcmp(Name, SR.Name) < 0;
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;
public:
~StatisticInfo();
void addStatistic(const Statistic *S) {
Stats.push_back(S);
}
};
}
void print(unsigned ValFieldSize, unsigned NameFieldSize,
std::ostream &OS) {
OS << std::string(ValFieldSize-Value.length(), ' ')
<< Value << " " << Name
<< std::string(NameFieldSize-std::strlen(Name), ' ')
<< " - " << Desc << "\n";
static ManagedStatic<StatisticInfo> StatInfo;
/// 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.
if (Enabled)
StatInfo->addStatistic(this);
// Remember we have been registered.
Initialized = true;
}
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;
}
};
static std::vector<StatRecord> *AccumStats = 0;
// Print information when destroyed, iff command line option is specified.
StatisticInfo::~StatisticInfo() {
// Statistics not enabled?
if (Stats.empty()) return;
// Print information when destroyed, iff command line option is specified
Statistic::~Statistic() {
if (Enabled && Value != 0) {
if (AccumStats == 0)
AccumStats = new std::vector<StatRecord>();
// Get the stream to write to.
std::ostream &OutStream = *GetLibSupportInfoOutputFile();
AccumStats->push_back(StatRecord(utostr(Value), Name, Desc));
// Figure out how long the biggest Value and Name fields are.
unsigned MaxNameLen = 0, MaxValLen = 0;
for (unsigned i = 0, e = Stats.size(); i != e; ++i) {
MaxValLen = std::max(MaxValLen,
(unsigned)utostr(Stats[i]->getValue()).size());
MaxNameLen = std::max(MaxNameLen,
(unsigned)std::strlen(Stats[i]->getName()));
}
// Sort the fields by name.
std::stable_sort(Stats.begin(), Stats.end(), NameCompare());
if (--NumStats == 0 && AccumStats) {
std::ostream *OutStream = GetLibSupportInfoOutputFile();
// Figure out how long the biggest Value and Name fields are...
unsigned MaxNameLen = 0, MaxValLen = 0;
for (unsigned i = 0, e = AccumStats->size(); i != e; ++i) {
MaxValLen = std::max(MaxValLen,
(unsigned)(*AccumStats)[i].Value.length());
MaxNameLen = std::max(MaxNameLen,
(unsigned)std::strlen((*AccumStats)[i].Name));
}
// Sort the fields...
std::stable_sort(AccumStats->begin(), AccumStats->end());
// Print out the statistics header...
*OutStream << "===" << std::string(73, '-') << "===\n"
<< " ... Statistics Collected ...\n"
<< "===" << std::string(73, '-') << "===\n\n";
// Print all of the statistics accumulated...
for (unsigned i = 0, e = AccumStats->size(); i != e; ++i)
(*AccumStats)[i].print(MaxValLen, MaxNameLen, *OutStream);
*OutStream << std::endl; // Flush the output stream...
// Free all accumulated statistics...
delete AccumStats;
AccumStats = 0;
if (OutStream != cerr.stream() && OutStream != cout.stream())
delete OutStream; // Close the file...
// Print out the statistics header...
OutStream << "===" << std::string(73, '-') << "===\n"
<< " ... Statistics Collected ...\n"
<< "===" << std::string(73, '-') << "===\n\n";
// Print all of the statistics.
for (unsigned i = 0, e = Stats.size(); i != e; ++i) {
std::string CountStr = utostr(Stats[i]->getValue());
OutStream << std::string(MaxValLen-CountStr.size(), ' ')
<< CountStr << " " << Stats[i]->getName()
<< std::string(MaxNameLen-std::strlen(Stats[i]->getName()), ' ')
<< " - " << Stats[i]->getDesc() << "\n";
}
OutStream << std::endl; // Flush the output stream...
if (&OutStream != cerr.stream() && &OutStream != cout.stream())
delete &OutStream; // Close the file.
}