[llvm] r272826 - Statistic: Add machine parseable json output

Matthias Braun via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 15 13:19:16 PDT 2016


Author: matze
Date: Wed Jun 15 15:19:16 2016
New Revision: 272826

URL: http://llvm.org/viewvc/llvm-project?rev=272826&view=rev
Log:
Statistic: Add machine parseable json output

- We lacked a short unique identifier for a statistics, so I renamed the
  current "Name" field that just contained the DEBUG_TYPE name of the
  current file to DebugType and added a new "Name" field that contains
  the C++ identifier of the statistic variable.
- Add the -stats-json option which outputs statistics in json format.

Differential Revision: http://reviews.llvm.org/D20995

Added:
    llvm/trunk/test/Other/statistic.ll
Modified:
    llvm/trunk/include/llvm/ADT/Statistic.h
    llvm/trunk/lib/Support/Statistic.cpp

Modified: llvm/trunk/include/llvm/ADT/Statistic.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/Statistic.h?rev=272826&r1=272825&r2=272826&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/Statistic.h (original)
+++ llvm/trunk/include/llvm/ADT/Statistic.h Wed Jun 15 15:19:16 2016
@@ -37,19 +37,24 @@ class raw_fd_ostream;
 
 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.
@@ -141,7 +146,7 @@ protected:
 // 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();
@@ -158,6 +163,9 @@ void PrintStatistics();
 /// \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

Modified: llvm/trunk/lib/Support/Statistic.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Statistic.cpp?rev=272826&r1=272825&r2=272826&view=diff
==============================================================================
--- llvm/trunk/lib/Support/Statistic.cpp (original)
+++ llvm/trunk/lib/Support/Statistic.cpp Wed Jun 15 15:19:16 2016
@@ -43,6 +43,9 @@ Enabled(
     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
@@ -51,6 +54,10 @@ class StatisticInfo {
   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();
 
@@ -95,27 +102,32 @@ bool llvm::AreStatisticsEnabled() {
   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"
@@ -126,12 +138,43 @@ void llvm::PrintStatistics(raw_ostream &
   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() {
@@ -143,7 +186,10 @@ 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

Added: llvm/trunk/test/Other/statistic.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Other/statistic.ll?rev=272826&view=auto
==============================================================================
--- llvm/trunk/test/Other/statistic.ll (added)
+++ llvm/trunk/test/Other/statistic.ll Wed Jun 15 15:19:16 2016
@@ -0,0 +1,16 @@
+; RUN: opt < %s -o /dev/null -instsimplify -stats -stats-json 2>&1 | FileCheck %s --check-prefix=JSON
+; RUN: opt < %s -o /dev/null -instsimplify -stats -stats-json -info-output-file %t && FileCheck %s < %t --check-prefix=JSON
+; RUN: opt < %s -o /dev/null -instsimplify -stats 2>&1 | FileCheck %s --check-prefix=DEFAULT
+; RUN: opt < %s -o /dev/null -instsimplify -stats -info-output-file %t && FileCheck %s < %t --check-prefix=DEFAULT
+; REQUIRES: asserts
+
+; JSON: {
+; JSON:   "instsimplify.NumSimplified": 1
+; JSON: }
+
+; DEFAULT: 1 instsimplify - Number of redundant instructions removed
+
+define i32 @foo() {
+  %res = add i32 5, 4
+  ret i32 %res
+}




More information about the llvm-commits mailing list