From aedd994560e8714127a244f57d8a01474082c3f0 Mon Sep 17 00:00:00 2001 From: Samuel Benzaquen Date: Thu, 23 Oct 2014 17:23:20 +0000 Subject: [PATCH] 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 --- clang-tools-extra/clang-tidy/ClangTidy.cpp | 12 ++++- clang-tools-extra/clang-tidy/ClangTidy.h | 7 ++- .../clang-tidy/ClangTidyDiagnosticConsumer.cpp | 7 ++- .../clang-tidy/ClangTidyDiagnosticConsumer.h | 16 +++++++ .../clang-tidy/tool/ClangTidyMain.cpp | 52 +++++++++++++++++++++- 5 files changed, 89 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 0712f69..b8afc08 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -216,8 +216,13 @@ ClangTidyASTConsumerFactory::CreateASTConsumer( std::vector> Checks; CheckFactories->createChecks(&Context, Checks); + ast_matchers::MatchFinder::MatchFinderOptions FinderOptions; + if (auto *P = Context.getCheckProfileData()) + FinderOptions.CheckProfiling.emplace(P->Records); + std::unique_ptr Finder( - new ast_matchers::MatchFinder); + new ast_matchers::MatchFinder(std::move(FinderOptions))); + for (auto &Check : Checks) { Check->registerMatchers(&*Finder); Check->registerPPCallbacks(Compiler); @@ -356,9 +361,12 @@ ClangTidyStats runClangTidy(std::unique_ptr OptionsProvider, const tooling::CompilationDatabase &Compilations, ArrayRef InputFiles, - std::vector *Errors) { + std::vector *Errors, ProfileData *Profile) { ClangTool Tool(Compilations, InputFiles); clang::tidy::ClangTidyContext Context(std::move(OptionsProvider)); + if (Profile) + Context.setCheckProfileData(Profile); + ClangTidyDiagnosticConsumer DiagConsumer(Context); Tool.setDiagnosticConsumer(&DiagConsumer); diff --git a/clang-tools-extra/clang-tidy/ClangTidy.h b/clang-tools-extra/clang-tidy/ClangTidy.h index 0892298..4038d03 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.h +++ b/clang-tools-extra/clang-tidy/ClangTidy.h @@ -152,6 +152,7 @@ public: private: void run(const ast_matchers::MatchFinder::MatchResult &Result) override; + StringRef getID() const override { return CheckName; } std::string CheckName; ClangTidyContext *Context; @@ -196,11 +197,15 @@ std::vector getCheckNames(const ClangTidyOptions &Options); ClangTidyOptions::OptionMap getCheckOptions(const ClangTidyOptions &Options); /// \brief Run a set of clang-tidy checks on a set of files. +/// +/// \param Profile if provided, it enables check profile collection in +/// MatchFinder, and will contain the result of the profile. ClangTidyStats runClangTidy(std::unique_ptr OptionsProvider, const tooling::CompilationDatabase &Compilations, ArrayRef InputFiles, - std::vector *Errors); + std::vector *Errors, + ProfileData *Profile = nullptr); // FIXME: This interface will need to be significantly extended to be useful. // FIXME: Implement confidence levels for displaying/fixing errors. diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index 49e2035..38c99ef 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -162,7 +162,8 @@ bool GlobList::contains(StringRef S, bool Contains) { ClangTidyContext::ClangTidyContext( std::unique_ptr OptionsProvider) - : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)) { + : DiagEngine(nullptr), OptionsProvider(std::move(OptionsProvider)), + Profile(nullptr) { // Before the first translation unit we can get errors related to command-line // parsing, use empty string for the file name in this case. setCurrentFile(""); @@ -221,6 +222,10 @@ const ClangTidyOptions &ClangTidyContext::getOptions() const { return CurrentOptions; } +void ClangTidyContext::setCheckProfileData(ProfileData *P) { + Profile = P; +} + GlobList &ClangTidyContext::getChecksFilter() { assert(CheckFilter != nullptr); return *CheckFilter; diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 25bc6ed..592f560 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -15,7 +15,9 @@ #include "clang/Basic/SourceManager.h" #include "clang/Tooling/Refactoring.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/Regex.h" +#include "llvm/Support/Timer.h" namespace clang { @@ -105,6 +107,11 @@ struct ClangTidyStats { } }; +/// \brief Container for clang-tidy profiling data. +struct ProfileData { + llvm::StringMap Records; +}; + /// \brief Every \c ClangTidyCheck reports errors through a \c DiagnosticEngine /// provided by this context. /// @@ -162,6 +169,13 @@ public: /// \brief Clears collected errors. void clearErrors() { Errors.clear(); } + /// \brief Set the output struct for profile data. + /// + /// Setting a non-null pointer here will enable profile collection in + /// clang-tidy. + void setCheckProfileData(ProfileData* Profile); + ProfileData* getCheckProfileData() const { return Profile; } + private: // Calls setDiagnosticsEngine() and storeError(). friend class ClangTidyDiagnosticConsumer; @@ -184,6 +198,8 @@ private: ClangTidyStats Stats; llvm::DenseMap CheckNamesByDiagnosticID; + + ProfileData *Profile; }; /// \brief A diagnostic consumer that turns each \c Diagnostic into a 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 @@ DumpConfig("dump-config", cl::desc("Dumps configuration in the YAML format to stdout."), cl::init(false), cl::cat(ClangTidyCategory)); +static cl::opt 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 AnalyzeTemporaryDtors( "analyze-temporary-dtors", cl::desc("Enable temporary destructor-aware analysis in\n" @@ -143,6 +148,45 @@ static void printStats(const ClangTidyStats &Stats) { } } +static void printProfileData(const ProfileData &Profile, + llvm::raw_ostream &OS) { + // Time is first to allow for sorting by it. + std::vector> 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 createOptionsProvider() { ClangTidyGlobalOptions GlobalOptions; if (std::error_code Err = parseLineFilter(LineFilter, GlobalOptions)) { @@ -220,10 +264,13 @@ int clangTidyMain(int argc, const char **argv) { return 1; } + ProfileData Profile; + std::vector 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 @@ int clangTidyMain(int argc, const char **argv) { } printStats(Stats); + if (EnableCheckProfile) + printProfileData(Profile, llvm::errs()); + return 0; } -- 2.7.4