[cfe-dev] Analysing a file with AST matcher tool takes significant more time than just compile the same file

Han Wang wanghan02 at gmail.com
Thu Jul 16 03:07:28 PDT 2015


We use truly a lot of templates in the files. Is it a possible reason why
it's so slow?

On Thu, Jul 16, 2015 at 11:57 AM, Han Wang <wanghan02 at gmail.com> wrote:

> Hi Manuel,
>
> After using -O2 the speed is 30% faster from 10min to 7min. If I use clang
> to just compile this source file, it takes 40sec.
>
> Best regards,
> Han
>
> On Thu, Jul 16, 2015 at 11:33 AM, Manuel Klimek <klimek at google.com> wrote:
>
>> You'll want to use Lexer::getSourceText instead of trying to write your
>> own (trust me, it's hard ;), but otherwise your code looks innocent enough.
>> Are you compiling with at least -O2 and NDEBUG enabled?
>>
>> On Thu, Jul 16, 2015 at 11:26 AM Han Wang <wanghan02 at gmail.com> wrote:
>>
>>> #include <stdio.h>
>>> #include <string>
>>> #include <vector>
>>> #include <system_error>
>>> #include <type_traits>
>>> #include "clang/AST/AST.h"
>>> #include "clang/Frontend/TextDiagnosticPrinter.h"
>>> #include "clang/Tooling/CommonOptionsParser.h"
>>> #include "clang/ASTMatchers/ASTMatchers.h"
>>> #include "clang/ASTMatchers/ASTMatchFinder.h"
>>> #include "clang/Basic/SourceManager.h"
>>> #include "clang/Frontend/FrontendActions.h"
>>> #include "clang/Lex/Lexer.h"
>>> #include "clang/Tooling/CompilationDatabase.h"
>>> #include "clang/Tooling/Refactoring.h"
>>> #include "clang/Tooling/Tooling.h"
>>> #include "llvm/ADT/Twine.h"
>>> #include "llvm/Support/CommandLine.h"
>>> #include "llvm/Support/MemoryBuffer.h"
>>> #include "llvm/Support/Path.h"
>>> #include "llvm/Support/Signals.h"
>>> #include "llvm/Support/raw_ostream.h"
>>> #include "llvm/Support/TargetSelect.h"
>>>
>>> using namespace llvm;
>>> using clang::tooling::newFrontendActionFactory;
>>> using clang::tooling::Replacement;
>>> using clang::tooling::CompilationDatabase;
>>> using namespace clang;
>>> using namespace clang::ast_matchers;
>>> using namespace clang::driver;
>>> using namespace clang::tooling;
>>>
>>> static llvm::cl::OptionCategory ToolingSampleCategory("IsEmpty");
>>>
>>>
>>> // Returns the text that makes up 'node' in the source.
>>> // Returns an empty string if the text cannot be found.
>>> template <typename T>
>>> static std::string getText(const SourceManager &SourceManager, const T
>>> &Node) {
>>>   SourceLocation StartSpellingLocation =
>>>       SourceManager.getSpellingLoc(Node.getLocStart());
>>>   SourceLocation EndSpellingLocation =
>>>       SourceManager.getSpellingLoc(Node.getLocEnd());
>>>   if (!StartSpellingLocation.isValid() ||
>>> !EndSpellingLocation.isValid()) {
>>>     return std::string();
>>>   }
>>>   bool Invalid = true;
>>>   const char *Text =
>>>       SourceManager.getCharacterData(StartSpellingLocation, &Invalid);
>>>   if (Invalid) {
>>>     return std::string();
>>>   }
>>>   std::pair<FileID, unsigned> Start =
>>>       SourceManager.getDecomposedLoc(StartSpellingLocation);
>>>   std::pair<FileID, unsigned> End =
>>>       SourceManager.getDecomposedLoc(Lexer::getLocForEndOfToken(
>>>           EndSpellingLocation, 0, SourceManager, LangOptions()));
>>>   if (Start.first != End.first) {
>>>     // Start and end are in different files.
>>>     return std::string();
>>>   }
>>>   if (End.second < Start.second) {
>>>     // Shuffling text with macros may cause this.
>>>     return std::string();
>>>   }
>>>   return std::string(Text, End.second - Start.second);
>>> }
>>>
>>> class ColIsEmptyHandler: public MatchFinder::MatchCallback {
>>> public:
>>>   ColIsEmptyHandler(Replacements *Replace): Replace(Replace) {};
>>>   virtual void run(const MatchFinder::MatchResult &Result) {
>>>     if (const CXXMemberCallExpr *callExpr =
>>> Result.Nodes.getNodeAs<clang::CXXMemberCallExpr>("Col::IsEmptyExpr")) {
>>>       const std::string text = getText(*(Result.SourceManager),
>>> *callExpr);
>>>       Replacement Rep(*(Result.SourceManager),
>>> CharSourceRange::getTokenRange(SourceRange(callExpr->getCallee()->getExprLoc())),
>>> "IsEmpty");
>>>       Replace->insert(Rep);
>>>     }
>>>   }
>>> private:
>>>   Replacements *Replace;
>>> };
>>>
>>> class ColIsEmptyInClassHandler: public MatchFinder::MatchCallback {
>>> public:
>>>   ColIsEmptyInClassHandler(Replacements *Replace): Replace(Replace) {};
>>>   virtual void run(const MatchFinder::MatchResult &Result) {
>>>     if (const CXXMethodDecl *decl =
>>> Result.Nodes.getNodeAs<clang::CXXMethodDecl>("Col::IsEmptyInClass")) {
>>>       const std::string text = getText(*(Result.SourceManager), *decl);
>>>       Replacement Rep(*(Result.SourceManager),
>>> CharSourceRange::getTokenRange(SourceRange(decl->getNameInfo().getLoc())),
>>> "IsEmpty");
>>>       Replace->insert(Rep);
>>>     }
>>>   }
>>> private:
>>>   Replacements *Replace;
>>> };
>>>
>>> int main(int argc, const char **argv) {
>>>   llvm::InitializeAllTargets();
>>>   llvm::InitializeAllTargetMCs();
>>>   llvm::InitializeAllAsmPrinters();
>>>   llvm::InitializeAllAsmParsers();
>>>   CommonOptionsParser op(argc, argv, ToolingSampleCategory);
>>>   RefactoringTool Tool(op.getCompilations(), op.getSourcePathList());
>>>   // Set up AST matcher callbacks.
>>>   ColIsEmptyHandler HandlerForColIsEmpty(&Tool.getReplacements());
>>>   ColIsEmptyInClassHandler
>>> HandlerForColIsEmptyInClass(&Tool.getReplacements());
>>>   MatchFinder Finder;
>>>   Finder.addMatcher(memberCallExpr(hasDeclaration(methodDecl(
>>>   hasName("Empty"),
>>> ofClass(isSameOrDerivedFrom(hasName("Col")))))).bind("Col::IsEmptyExpr"),
>>> &HandlerForColIsEmpty);
>>>   Finder.addMatcher(methodDecl(hasName("Empty"),
>>> ofClass(isSameOrDerivedFrom(hasName("Col")))).bind("Col::IsEmptyInClass"),
>>> &HandlerForColIsEmptyInClass);
>>>   // Run the tool and collect a list of replacements.
>>>   if (int Result =
>>> Tool.runAndSave(newFrontendActionFactory(&Finder).get())) {
>>>     return Result;
>>>   }
>>>   llvm::outs() << "Replacements collected by the tool:\n";
>>>   for (auto &r : Tool.getReplacements()) {
>>>     llvm::outs() << r.toString() << "\n";
>>>   }
>>>   return 0;
>>> }
>>>
>>> On Thu, Jul 16, 2015 at 11:11 AM, Manuel Klimek <klimek at google.com>
>>> wrote:
>>>
>>>> Can you post the code for the matcher?
>>>>
>>>> On Thu, Jul 16, 2015 at 11:02 AM Han Wang <wanghan02 at gmail.com> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> I'm using clang AST matcher tool on MAC to analyse complex files with
>>>>> many many headers included. It turns out that it takes more than 10 times
>>>>> longer than just compile the same file with clang. Is it normal or am I
>>>>> doing something wrong? Thanks!
>>>>>
>>>>> Best regards,
>>>>> Han
>>>>> _______________________________________________
>>>>> cfe-dev mailing list
>>>>> cfe-dev at cs.uiuc.edu
>>>>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>>>>>
>>>>
>>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20150716/6d253233/attachment.html>


More information about the cfe-dev mailing list