Add flag --enable-check-profile to clang-tidy.

Summary:
Add flag --enable-check-profile to clang-tidy.
It turns on per-matcher profiles in MatchFinder and prints a report to
stderr at the end.

Reviewers: alexfh

Subscribers: curdeius, cfe-commits

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

llvm-svn: 220491
diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
index 8f45eaa..72d841e 100644
--- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -98,6 +98,11 @@
            cl::desc("Dumps configuration in the YAML format to stdout."),
            cl::init(false), cl::cat(ClangTidyCategory));
 
+static cl::opt<bool> EnableCheckProfile(
+    "enable-check-profile",
+    cl::desc("Enable per-check timing profiles, and print a report to stderr."),
+    cl::init(false), cl::cat(ClangTidyCategory));
+
 static cl::opt<bool> AnalyzeTemporaryDtors(
     "analyze-temporary-dtors",
     cl::desc("Enable temporary destructor-aware analysis in\n"
@@ -143,6 +148,45 @@
   }
 }
 
+static void printProfileData(const ProfileData &Profile,
+                             llvm::raw_ostream &OS) {
+  // Time is first to allow for sorting by it.
+  std::vector<std::pair<llvm::TimeRecord, StringRef>> Timers;
+  TimeRecord Total;
+
+  for (const auto& P : Profile.Records) {
+    Timers.emplace_back(P.getValue(), P.getKey());
+    Total += P.getValue();
+  }
+
+  std::sort(Timers.begin(), Timers.end());
+
+  std::string Line = "===" + std::string(73, '-') + "===\n";
+  OS << Line;
+
+  if (Total.getUserTime())
+    OS << "   ---User Time---";
+  if (Total.getSystemTime())
+    OS << "   --System Time--";
+  if (Total.getProcessTime())
+    OS << "   --User+System--";
+  OS << "   ---Wall Time---";
+  if (Total.getMemUsed())
+    OS << "  ---Mem---";
+  OS << "  --- Name ---\n";
+
+  // Loop through all of the timing data, printing it out.
+  for (auto I = Timers.rbegin(), E = Timers.rend(); I != E; ++I) {
+    I->first.print(Total, OS);
+    OS << I->second << '\n';
+  }
+
+  Total.print(Total, OS);
+  OS << "Total\n";
+  OS << Line << "\n";
+  OS.flush();
+}
+
 std::unique_ptr<ClangTidyOptionsProvider> createOptionsProvider() {
   ClangTidyGlobalOptions GlobalOptions;
   if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) {
@@ -220,10 +264,13 @@
     return 1;
   }
 
+  ProfileData Profile;
+
   std::vector<ClangTidyError> Errors;
   ClangTidyStats Stats =
       runClangTidy(std::move(OptionsProvider), OptionsParser.getCompilations(),
-                   OptionsParser.getSourcePathList(), &Errors);
+                   OptionsParser.getSourcePathList(), &Errors,
+                   EnableCheckProfile ? &Profile : nullptr);
   handleErrors(Errors, Fix);
 
   if (!ExportFixes.empty() && !Errors.empty()) {
@@ -237,6 +284,9 @@
   }
 
   printStats(Stats);
+  if (EnableCheckProfile)
+    printProfileData(Profile, llvm::errs());
+
   return 0;
 }