Hi alexfh,
Add support for profiling the matchers used.
This will be connected with clang-tidy to generate a report to determine
and debug slow checks.
http://reviews.llvm.org/D5911
Files:
include/clang/ASTMatchers/ASTMatchFinder.h
lib/ASTMatchers/ASTMatchFinder.cpp
unittests/ASTMatchers/ASTMatchersTest.cpp
Index: include/clang/ASTMatchers/ASTMatchFinder.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchFinder.h
+++ include/clang/ASTMatchers/ASTMatchFinder.h
@@ -102,6 +102,12 @@
///
/// Optionally override to do per translation unit tasks.
virtual void onEndOfTranslationUnit() {}
+
+ /// \brief An id used to group the matchers.
+ ///
+ /// This id is used, for example, for the profiling output.
+ /// It defaults to "<unknown>".
+ virtual StringRef getID() const;
};
/// \brief Called when parsing is finished. Intended for testing only.
@@ -111,7 +117,18 @@
virtual void run() = 0;
};
- MatchFinder();
+ struct MatchFinderOptions {
+ struct ProfileChecks {
+ /// \brief Output for the report. If null, it prints to llvm::errs()
+ std::unique_ptr<llvm::raw_ostream> OS;
+ };
+ /// \brief Enables per-check timers.
+ ///
+ /// It prints a report after match.
+ std::unique_ptr<ProfileChecks> EnableCheckProfiling;
+ };
+
+ MatchFinder(MatchFinderOptions Options = MatchFinderOptions());
~MatchFinder();
/// \brief Adds a matcher to execute when running over the AST.
@@ -191,6 +208,8 @@
private:
MatchersByType Matchers;
+ MatchFinderOptions Options;
+
/// \brief Called when parsing is done.
ParsingDoneTestCallback *ParsingDone;
};
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -20,7 +20,10 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Timer.h"
#include <deque>
+#include <memory>
#include <set>
namespace clang {
@@ -292,17 +295,35 @@
class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>,
public ASTMatchFinder {
public:
- MatchASTVisitor(const MatchFinder::MatchersByType *Matchers)
- : Matchers(Matchers), ActiveASTContext(nullptr) {}
+ MatchASTVisitor(const MatchFinder::MatchersByType *Matchers,
+ const MatchFinder::MatchFinderOptions &Options)
+ : MatchTimerGroup("ASTMatchFinder"), Matchers(Matchers), Options(Options),
+ ActiveASTContext(nullptr) {}
+
+ ~MatchASTVisitor() {
+ if (Options.EnableCheckProfiling) {
+ MatchTimerGroup.print(Options.EnableCheckProfiling->OS
+ ? *Options.EnableCheckProfiling->OS
+ : llvm::errs());
+ }
+ }
void onStartOfTranslationUnit() {
- for (MatchCallback *MC : Matchers->AllCallbacks)
+ const bool EnableCheckProfiling = Options.EnableCheckProfiling != nullptr;
+ for (MatchCallback *MC : Matchers->AllCallbacks) {
+ llvm::TimeRegion Timer(
+ EnableCheckProfiling ? getTimerForBucket(MC->getID()) : nullptr);
MC->onStartOfTranslationUnit();
+ }
}
void onEndOfTranslationUnit() {
- for (MatchCallback *MC : Matchers->AllCallbacks)
+ const bool EnableCheckProfiling = Options.EnableCheckProfiling != nullptr;
+ for (MatchCallback *MC : Matchers->AllCallbacks) {
+ llvm::TimeRegion Timer(
+ EnableCheckProfiling ? getTimerForBucket(MC->getID()) : nullptr);
MC->onEndOfTranslationUnit();
+ }
}
void set_active_ast_context(ASTContext *NewActiveASTContext) {
@@ -471,12 +492,25 @@
bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
private:
+ /// \brief Returns a timer for the bucket represented by \p Bucket
+ llvm::Timer *getTimerForBucket(StringRef Bucket) {
+ auto &Timer = TimersByBucket[Bucket];
+ if (Timer == nullptr) {
+ Timer = llvm::make_unique<llvm::Timer>(Bucket, MatchTimerGroup);
+ }
+ return Timer.get();
+ }
+
/// \brief Runs all the \p Matchers on \p Node.
///
/// Used by \c matchDispatch() below.
template <typename T, typename MC>
void matchImpl(const T &Node, const MC &Matchers) {
+ const bool EnableCheckProfiling = Options.EnableCheckProfiling != nullptr;
for (const auto &MP : Matchers) {
+ llvm::TimeRegion Timer(EnableCheckProfiling
+ ? getTimerForBucket(MP.second->getID())
+ : nullptr);
BoundNodesTreeBuilder Builder;
if (MP.first.matches(Node, this, &Builder)) {
MatchVisitor Visitor(ActiveASTContext, MP.second);
@@ -627,7 +661,18 @@
return false;
}
+ /// \brief Timer group used by the finder instance.
+ ///
+ /// All check timers will be registered here.
+ llvm::TimerGroup MatchTimerGroup;
+
+ /// \brief Bucket to Timer map.
+ ///
+ /// Used to get the appropriate bucket for each matcher.
+ llvm::StringMap<std::unique_ptr<llvm::Timer>> TimersByBucket;
+
const MatchFinder::MatchersByType *Matchers;
+ const MatchFinder::MatchFinderOptions &Options;
ASTContext *ActiveASTContext;
// Maps a canonical type to its TypedefDecls.
@@ -790,7 +835,8 @@
MatchFinder::MatchCallback::~MatchCallback() {}
MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {}
-MatchFinder::MatchFinder() : ParsingDone(nullptr) {}
+MatchFinder::MatchFinder(MatchFinderOptions Options)
+ : Options(std::move(Options)), ParsingDone(nullptr) {}
MatchFinder::~MatchFinder() {}
@@ -860,13 +906,13 @@
void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node,
ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&Matchers);
+ internal::MatchASTVisitor Visitor(&Matchers, Options);
Visitor.set_active_ast_context(&Context);
Visitor.match(Node);
}
void MatchFinder::matchAST(ASTContext &Context) {
- internal::MatchASTVisitor Visitor(&Matchers);
+ internal::MatchASTVisitor Visitor(&Matchers, Options);
Visitor.set_active_ast_context(&Context);
Visitor.onStartOfTranslationUnit();
Visitor.TraverseDecl(Context.getTranslationUnitDecl());
@@ -878,5 +924,7 @@
ParsingDone = NewParsingDone;
}
+StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; }
+
} // end namespace ast_matchers
} // end namespace clang
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -4421,6 +4421,30 @@
new VerifyAncestorHasChildIsEqual<IfStmt>()));
}
+TEST(MatchFinder, CheckProfiling) {
+ MatchFinder::MatchFinderOptions Options;
+ Options.EnableCheckProfiling =
+ llvm::make_unique<MatchFinder::MatchFinderOptions::ProfileChecks>();
+ std::string Report;
+ Options.EnableCheckProfiling->OS =
+ llvm::make_unique<llvm::raw_string_ostream>(Report);
+ MatchFinder Finder(std::move(Options));
+
+ struct NamedCallback : public MatchFinder::MatchCallback {
+ void run(const MatchFinder::MatchResult &Result) override {}
+ StringRef getID() const override { return "MyID"; }
+ } Callback;
+ Finder.addMatcher(decl(), &Callback);
+ std::unique_ptr<FrontendActionFactory> Factory(
+ newFrontendActionFactory(&Finder));
+ ASSERT_TRUE(tooling::runToolOnCode(Factory->create(), "int x;"));
+
+ // Verify that the report was printed and that it contains the callback
+ // defined above.
+ EXPECT_TRUE(Report.find("ASTMatchFinder") != Report.npos);
+ EXPECT_TRUE(Report.find("MyID") != Report.npos);
+}
+
class VerifyStartOfTranslationUnit : public MatchFinder::MatchCallback {
public:
VerifyStartOfTranslationUnit() : Called(false) {}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits