#include "llvm/ADT/Statistic.h"
#include "DebugOptions.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cstring>
using namespace llvm;
static bool EnableStats;
static bool StatsAsJSON;
static bool Enabled;
static bool PrintOnExit;
void llvm::initStatisticOptions() {
static cl::opt<bool, true> registerEnableStats{
"stats",
cl::desc(
"Enable statistics output from program (available with Asserts)"),
cl::location(EnableStats), cl::Hidden};
static cl::opt<bool, true> registerStatsAsJson{
"stats-json", cl::desc("Display statistics as json data"),
cl::location(StatsAsJSON), cl::Hidden};
}
namespace {
class StatisticInfo {
std::vector<TrackingStatistic *> Stats;
friend void llvm::PrintStatistics();
friend void llvm::PrintStatistics(raw_ostream &OS);
friend void llvm::PrintStatisticsJSON(raw_ostream &OS);
void sort();
public:
using const_iterator = std::vector<TrackingStatistic *>::const_iterator;
StatisticInfo();
~StatisticInfo();
void addStatistic(TrackingStatistic *S) { Stats.push_back(S); }
const_iterator begin() const { return Stats.begin(); }
const_iterator end() const { return Stats.end(); }
iterator_range<const_iterator> statistics() const {
return {begin(), end()};
}
void reset();
};
}
static ManagedStatic<StatisticInfo> StatInfo;
static ManagedStatic<sys::SmartMutex<true> > StatLock;
void TrackingStatistic::RegisterStatistic() {
if (!Initialized.load(std::memory_order_relaxed)) {
sys::SmartMutex<true> &Lock = *StatLock;
StatisticInfo &SI = *StatInfo;
sys::SmartScopedLock<true> Writer(Lock);
if (Initialized.load(std::memory_order_relaxed))
return;
if (EnableStats || Enabled)
SI.addStatistic(this);
Initialized.store(true, std::memory_order_release);
}
}
StatisticInfo::StatisticInfo() {
TimerGroup::ConstructTimerLists();
}
StatisticInfo::~StatisticInfo() {
if (EnableStats || PrintOnExit)
llvm::PrintStatistics();
}
void llvm::EnableStatistics(bool DoPrintOnExit) {
Enabled = true;
PrintOnExit = DoPrintOnExit;
}
bool llvm::AreStatisticsEnabled() { return Enabled || EnableStats; }
void StatisticInfo::sort() {
llvm::stable_sort(
Stats, [](const TrackingStatistic *LHS, const TrackingStatistic *RHS) {
if (int Cmp = std::strcmp(LHS->getDebugType(), RHS->getDebugType()))
return Cmp < 0;
if (int Cmp = std::strcmp(LHS->getName(), RHS->getName()))
return Cmp < 0;
return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0;
});
}
void StatisticInfo::reset() {
sys::SmartScopedLock<true> Writer(*StatLock);
for (auto *Stat : Stats) {
Stat->Initialized = false;
Stat->Value = 0;
}
Stats.clear();
}
void llvm::PrintStatistics(raw_ostream &OS) {
StatisticInfo &Stats = *StatInfo;
unsigned MaxDebugTypeLen = 0, MaxValLen = 0;
for (TrackingStatistic *Stat : Stats.Stats) {
MaxValLen = std::max(MaxValLen, (unsigned)utostr(Stat->getValue()).size());
MaxDebugTypeLen =
std::max(MaxDebugTypeLen, (unsigned)std::strlen(Stat->getDebugType()));
}
Stats.sort();
OS << "===" << std::string(73, '-') << "===\n"
<< " ... Statistics Collected ...\n"
<< "===" << std::string(73, '-') << "===\n\n";
for (TrackingStatistic *Stat : Stats.Stats)
OS << format("%*" PRIu64 " %-*s - %s\n", MaxValLen, Stat->getValue(),
MaxDebugTypeLen, Stat->getDebugType(), Stat->getDesc());
OS << '\n'; OS.flush();
}
void llvm::PrintStatisticsJSON(raw_ostream &OS) {
sys::SmartScopedLock<true> Reader(*StatLock);
StatisticInfo &Stats = *StatInfo;
Stats.sort();
OS << "{\n";
const char *delim = "";
for (const TrackingStatistic *Stat : Stats.Stats) {
OS << delim;
assert(yaml::needsQuotes(Stat->getDebugType()) == yaml::QuotingType::None &&
"Statistic group/type name is simple.");
assert(yaml::needsQuotes(Stat->getName()) == yaml::QuotingType::None &&
"Statistic name is simple");
OS << "\t\"" << Stat->getDebugType() << '.' << Stat->getName() << "\": "
<< Stat->getValue();
delim = ",\n";
}
TimerGroup::printAllJSONValues(OS, delim);
OS << "\n}\n";
OS.flush();
}
void llvm::PrintStatistics() {
#if LLVM_ENABLE_STATS
sys::SmartScopedLock<true> Reader(*StatLock);
StatisticInfo &Stats = *StatInfo;
if (Stats.Stats.empty()) return;
std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
if (StatsAsJSON)
PrintStatisticsJSON(*OutStream);
else
PrintStatistics(*OutStream);
#else
if (EnableStats) {
std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
(*OutStream) << "Statistics are disabled. "
<< "Build with asserts or with -DLLVM_FORCE_ENABLE_STATS\n";
}
#endif
}
const std::vector<std::pair<StringRef, uint64_t>> llvm::GetStatistics() {
sys::SmartScopedLock<true> Reader(*StatLock);
std::vector<std::pair<StringRef, uint64_t>> ReturnStats;
for (const auto &Stat : StatInfo->statistics())
ReturnStats.emplace_back(Stat->getName(), Stat->getValue());
return ReturnStats;
}
void llvm::ResetStatistics() {
StatInfo->reset();
}