class Statistic {
public:
+ const char *DebugType;
const char *Name;
const char *Desc;
std::atomic<unsigned> Value;
bool Initialized;
unsigned getValue() const { return Value.load(std::memory_order_relaxed); }
+ const char *getDebugType() const { return DebugType; }
const char *getName() const { return Name; }
const char *getDesc() const { return Desc; }
/// construct - This should only be called for non-global statistics.
- void construct(const char *name, const char *desc) {
- Name = name; Desc = desc;
- Value = 0; Initialized = false;
+ void construct(const char *debugtype, const char *name, const char *desc) {
+ DebugType = debugtype;
+ Name = name;
+ Desc = desc;
+ Value = 0;
+ Initialized = false;
}
// Allow use of this class as the value itself.
// STATISTIC - A macro to make definition of statistics really simple. This
// automatically passes the DEBUG_TYPE of the file into the statistic.
#define STATISTIC(VARNAME, DESC) \
- static llvm::Statistic VARNAME = {DEBUG_TYPE, DESC, {0}, 0}
+ static llvm::Statistic VARNAME = {DEBUG_TYPE, #VARNAME, DESC, {0}, 0}
/// \brief Enable the collection and printing of statistics.
void EnableStatistics();
/// \brief Print statistics to the given output stream.
void PrintStatistics(raw_ostream &OS);
+/// Print statistics in JSON format.
+void PrintStatisticsJSON(raw_ostream &OS);
+
} // end llvm namespace
#endif // LLVM_ADT_STATISTIC_H
cl::desc("Enable statistics output from program (available with Asserts)"));
+static cl::opt<bool> StatsAsJSON("stats-json",
+ cl::desc("Display statistics as json data"));
+
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
std::vector<const Statistic*> Stats;
friend void llvm::PrintStatistics();
friend void llvm::PrintStatistics(raw_ostream &OS);
+ friend void llvm::PrintStatisticsJSON(raw_ostream &OS);
+
+ /// Sort statistics by debugtype,name,description.
+ void sort();
public:
~StatisticInfo();
return Enabled;
}
+void StatisticInfo::sort() {
+ std::stable_sort(Stats.begin(), Stats.end(),
+ [](const Statistic *LHS, const Statistic *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 llvm::PrintStatistics(raw_ostream &OS) {
StatisticInfo &Stats = *StatInfo;
// Figure out how long the biggest Value and Name fields are.
- unsigned MaxNameLen = 0, MaxValLen = 0;
+ unsigned MaxDebugTypeLen = 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()));
+ MaxDebugTypeLen = std::max(MaxDebugTypeLen,
+ (unsigned)std::strlen(Stats.Stats[i]->getDebugType()));
}
- // Sort the fields by name.
- std::stable_sort(Stats.Stats.begin(), Stats.Stats.end(),
- [](const Statistic *LHS, const Statistic *RHS) {
- if (int Cmp = std::strcmp(LHS->getName(), RHS->getName()))
- return Cmp < 0;
-
- // Secondary key is the description.
- return std::strcmp(LHS->getDesc(), RHS->getDesc()) < 0;
- });
+ Stats.sort();
// Print out the statistics header...
OS << "===" << std::string(73, '-') << "===\n"
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(),
+ MaxDebugTypeLen, Stats.Stats[i]->getDebugType(),
Stats.Stats[i]->getDesc());
OS << '\n'; // Flush the output stream.
OS.flush();
+}
+
+static void write_json_string_escaped(raw_ostream &OS, const char *string) {
+ // Out current usage should not need any escaping. Keep it simple and just
+ // check that the input is pure ASCII without special characers.
+#ifndef NDEBUG
+ for (const unsigned char *c = (const unsigned char*)string; *c != '\0'; ++c) {
+ assert(*c != '\\' && *c != '\"' && *c >= 0x20 && *c < 0x80);
+ }
+#endif
+ OS << string;
+}
+
+void llvm::PrintStatisticsJSON(raw_ostream &OS) {
+ StatisticInfo &Stats = *StatInfo;
+
+ Stats.sort();
+ // Print all of the statistics.
+ OS << "{\n";
+ const char *delim = "";
+ for (const Statistic *Stat : Stats.Stats) {
+ OS << delim;
+ OS << "\t\"";
+ write_json_string_escaped(OS, Stat->getDebugType());
+ OS << '.';
+ write_json_string_escaped(OS, Stat->getName());
+ OS << "\": " << Stat->getValue();
+ delim = ",\n";
+ }
+ OS << "\n}\n";
+ OS.flush();
}
void llvm::PrintStatistics() {
// Get the stream to write to.
std::unique_ptr<raw_ostream> OutStream = CreateInfoOutputFile();
- PrintStatistics(*OutStream);
+ if (StatsAsJSON)
+ PrintStatisticsJSON(*OutStream);
+ else
+ PrintStatistics(*OutStream);
#else
// Check if the -stats option is set instead of checking