/// \brief Print statistics to the given output stream.
void PrintStatistics(raw_ostream &OS);
-/// Print statistics in JSON format.
+/// Print statistics in JSON format. This does include all global timers (\see
+/// Timer, TimerGroup). Note that the timers are cleared after printing and will
+/// not be printed in human readable form or in a second call of
+/// PrintStatisticsJSON().
void PrintStatisticsJSON(raw_ostream &OS);
} // end namespace llvm
/// destroy a TimerGroup object before all of the Timers in it are gone. A
/// TimerGroup can be specified for a newly created timer in its constructor.
class TimerGroup {
+ struct PrintRecord {
+ TimeRecord Time;
+ std::string Name;
+ std::string Description;
+
+ PrintRecord(const PrintRecord &Other) = default;
+ PrintRecord(const TimeRecord &Time, const std::string &Name,
+ const std::string &Description)
+ : Time(Time), Name(Name), Description(Description) {}
+
+ bool operator <(const PrintRecord &Other) const {
+ return Time < Other.Time;
+ }
+ };
std::string Name;
std::string Description;
Timer *FirstTimer = nullptr; ///< First timer in the group.
- std::vector<std::pair<TimeRecord, std::string>> TimersToPrint;
+ std::vector<PrintRecord> TimersToPrint;
TimerGroup **Prev; ///< Pointer to Next field of previous timergroup in list.
TimerGroup *Next; ///< Pointer to next timergroup in list.
/// This static method prints all timers and clears them all out.
static void printAll(raw_ostream &OS);
+ /// Ensure global timer group lists are initialized. This function is mostly
+ /// used by the Statistic code to influence the construction and destruction
+ /// order of the global timer lists.
+ static void ConstructTimerLists();
private:
friend class Timer;
+ friend void PrintStatisticsJSON(raw_ostream &OS);
void addTimer(Timer &T);
void removeTimer(Timer &T);
+ void prepareToPrintList();
void PrintQueuedTimers(raw_ostream &OS);
+ void printJSONValue(raw_ostream &OS, const PrintRecord &R,
+ const char *suffix, double Value);
+ const char *printJSONValues(raw_ostream &OS, const char *delim);
+ static const char *printAllJSONValues(raw_ostream &OS, const char *delim);
};
} // end namespace llvm
#include "llvm/Support/Format.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/YAMLTraits.h"
#include <algorithm>
#include <cstring>
using namespace llvm;
/// Sort statistics by debugtype,name,description.
void sort();
public:
+ StatisticInfo();
~StatisticInfo();
void addStatistic(const Statistic *S) {
}
}
+StatisticInfo::StatisticInfo() {
+ // Ensure timergroup lists are created first so they are destructed after us.
+ TimerGroup::ConstructTimerLists();
+}
+
// Print information when destroyed, iff command line option is specified.
StatisticInfo::~StatisticInfo() {
if (::Stats || PrintOnExit)
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;
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();
+ assert(!yaml::needsQuotes(Stat->getDebugType()) &&
+ "Statistic group/type name is simple.");
+ assert(!yaml::needsQuotes(Stat->getName()) && "Statistic name is simple");
+ OS << "\t\"" << Stat->getDebugType() << '.' << Stat->getName() << "\": "
+ << Stat->getValue();
delim = ",\n";
}
+ // Print timers.
+ TimerGroup::printAllJSONValues(OS, delim);
+
OS << "\n}\n";
OS.flush();
}
#include "llvm/Support/Mutex.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/YAMLTraits.h"
using namespace llvm;
// This ugly hack is brought to you courtesy of constructor/destructor ordering
// If the timer was started, move its data to TimersToPrint.
if (T.hasTriggered())
- TimersToPrint.emplace_back(T.Time, T.Description);
+ TimersToPrint.emplace_back(T.Time, T.Name, T.Description);
T.TG = nullptr;
std::sort(TimersToPrint.begin(), TimersToPrint.end());
TimeRecord Total;
- for (auto &RecordNamePair : TimersToPrint)
- Total += RecordNamePair.first;
+ for (const PrintRecord &Record : TimersToPrint)
+ Total += Record.Time;
// Print out timing header.
OS << "===" << std::string(73, '-') << "===\n";
OS << " --- Name ---\n";
// Loop through all of the timing data, printing it out.
- for (unsigned i = 0, e = TimersToPrint.size(); i != e; ++i) {
- const std::pair<TimeRecord, std::string> &Entry = TimersToPrint[e-i-1];
- Entry.first.print(Total, OS);
- OS << Entry.second << '\n';
+ for (const PrintRecord &Record : make_range(TimersToPrint.rbegin(),
+ TimersToPrint.rend())) {
+ Record.Time.print(Total, OS);
+ OS << Record.Description << '\n';
}
Total.print(Total, OS);
TimersToPrint.clear();
}
-void TimerGroup::print(raw_ostream &OS) {
- sys::SmartScopedLock<true> L(*TimerLock);
-
+void TimerGroup::prepareToPrintList() {
// See if any of our timers were started, if so add them to TimersToPrint and
// reset them.
for (Timer *T = FirstTimer; T; T = T->Next) {
if (!T->hasTriggered()) continue;
- TimersToPrint.emplace_back(T->Time, T->Description);
+ TimersToPrint.emplace_back(T->Time, T->Name, T->Description);
// Clear out the time.
T->clear();
}
+}
+
+void TimerGroup::print(raw_ostream &OS) {
+ sys::SmartScopedLock<true> L(*TimerLock);
+
+ prepareToPrintList();
// If any timers were started, print the group.
if (!TimersToPrint.empty())
for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
TG->print(OS);
}
+
+void TimerGroup::printJSONValue(raw_ostream &OS, const PrintRecord &R,
+ const char *suffix, double Value) {
+ assert(!yaml::needsQuotes(Name) && "TimerGroup name needs no quotes");
+ assert(!yaml::needsQuotes(R.Name) && "Timer name needs no quotes");
+ OS << "\t\"time." << Name << '.' << R.Name << suffix << "\": " << Value;
+}
+
+const char *TimerGroup::printJSONValues(raw_ostream &OS, const char *delim) {
+ prepareToPrintList();
+ for (const PrintRecord &R : TimersToPrint) {
+ OS << delim;
+ delim = ",\n";
+
+ const TimeRecord &T = R.Time;
+ printJSONValue(OS, R, ".wall", T.getWallTime());
+ OS << delim;
+ printJSONValue(OS, R, ".user", T.getUserTime());
+ OS << delim;
+ printJSONValue(OS, R, ".sys", T.getSystemTime());
+ }
+ TimersToPrint.clear();
+ return delim;
+}
+
+const char *TimerGroup::printAllJSONValues(raw_ostream &OS, const char *delim) {
+ sys::SmartScopedLock<true> L(*TimerLock);
+ for (TimerGroup *TG = TimerGroupList; TG; TG = TG->Next)
+ delim = TG->printJSONValues(OS, delim);
+ return delim;
+}
+
+void TimerGroup::ConstructTimerLists() {
+ (void)*NamedGroupedTimers;
+}
; 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 -stats-json -time-passes 2>&1 | FileCheck %s --check-prefixes=JSON,JSONTIME
+; RUN: opt < %s -o /dev/null -instsimplify -stats -stats-json -time-passes -info-output-file %t && FileCheck %s < %t --check-prefixes=JSON,JSONTIME
; 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-DAG: "instsimplify.NumSimplified": 1
+; JSONTIME-DAG: "time.pass.Remove redundant instructions.wall"
+; JSONTIME-DAG: "time.pass.Remove redundant instructions.user"
+; JSONTIME-DAG: "time.pass.Remove redundant instructions.sys"
; JSON: }
; DEFAULT: 1 instsimplify - Number of redundant instructions removed