From: Benjamin Kramer Date: Tue, 15 Dec 2015 09:30:31 +0000 (+0000) Subject: [libclang] Add a flag to create the precompiled preamble on the first parse. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bdb673743a14ba6d761febf41176581d7674df34;p=clang [libclang] Add a flag to create the precompiled preamble on the first parse. Summary: The current default is to create the preamble on the first reparse, aka second parse. This is useful for clients that do not want to block when opening a file because serializing the preamble takes a bit of time. However, this makes the reparse much more expensive and that may be on the critical path as it's the first interaction a user has with the source code. YouCompleteMe currently optimizes for the first code interaction by parsing the file twice when loaded. That's just unnecessarily slow and this flag helps to avoid that. Reviewers: doug.gregor, klimek Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D15490 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@255635 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index e7ba2b26a4..09e2160826 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -1200,7 +1200,15 @@ enum CXTranslationUnit_Flags { * included into the set of code completions returned from this translation * unit. */ - CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80 + CXTranslationUnit_IncludeBriefCommentsInCodeCompletion = 0x80, + + /** + * \brief Used to indicate that the precompiled preamble should be created on + * the first parse. Otherwise it will be created on the first reparse. This + * trades runtime on the first parse (serializing the preamble takes time) for + * reduced runtime on the second parse (can now reuse the preamble). + */ + CXTranslationUnit_CreatePreambleOnFirstParse = 0x100 }; /** diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index d326a53dc2..a5f7af5714 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -737,14 +737,15 @@ private: /// \brief Helper function for \c LoadFromCompilerInvocation() and /// \c LoadFromCommandLine(), which loads an AST from a compiler invocation. /// - /// \param PrecompilePreamble Whether to precompile the preamble of this - /// translation unit, to improve the performance of reparsing. + /// \param PrecompilePreambleAfterNParses After how many parses the preamble + /// of this translation unit should be precompiled, to improve the performance + /// of reparsing. Set to zero to disable preambles. /// /// \returns \c true if a catastrophic failure occurred (which means that the /// \c ASTUnit itself is invalid), or \c false otherwise. bool LoadFromCompilerInvocation( std::shared_ptr PCHContainerOps, - bool PrecompilePreamble); + unsigned PrecompilePreambleAfterNParses); public: @@ -783,7 +784,8 @@ public: ASTFrontendAction *Action = nullptr, ASTUnit *Unit = nullptr, bool Persistent = true, StringRef ResourceFilesPath = StringRef(), bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, - bool PrecompilePreamble = false, bool CacheCodeCompletionResults = false, + unsigned PrecompilePreambleAfterNParses = 0, + bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false, std::unique_ptr *ErrAST = nullptr); @@ -807,7 +809,8 @@ public: std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FileManager *FileMgr, bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, - bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool UserFilesAreVolatile = false); @@ -842,7 +845,8 @@ public: bool OnlyLocalDecls = false, bool CaptureDiagnostics = false, ArrayRef RemappedFiles = None, bool RemappedFilesKeepOriginalName = true, - bool PrecompilePreamble = false, TranslationUnitKind TUKind = TU_Complete, + unsigned PrecompilePreambleAfterNParses = 0, + TranslationUnitKind TUKind = TU_Complete, bool CacheCodeCompletionResults = false, bool IncludeBriefCommentsInCodeCompletion = false, bool AllowPCHWithCompilerErrors = false, bool SkipFunctionBodies = false, diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 0d5dd53658..e6ba29201f 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1725,9 +1725,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, ASTFrontendAction *Action, ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath, - bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, - bool UserFilesAreVolatile, std::unique_ptr *ErrAST) { + bool OnlyLocalDecls, bool CaptureDiagnostics, + unsigned PrecompilePreambleAfterNParses, bool CacheCodeCompletionResults, + bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile, + std::unique_ptr *ErrAST) { assert(CI && "A CompilerInvocation is required"); std::unique_ptr OwnAST; @@ -1746,8 +1747,8 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( } AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; - if (PrecompilePreamble) - AST->PreambleRebuildCounter = 2; + if (PrecompilePreambleAfterNParses > 0) + AST->PreambleRebuildCounter = PrecompilePreambleAfterNParses; AST->TUKind = Action ? Action->getTranslationUnitKind() : TU_Complete; AST->ShouldCacheCodeCompletionResults = CacheCodeCompletionResults; AST->IncludeBriefCommentsInCodeCompletion @@ -1864,7 +1865,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction( bool ASTUnit::LoadFromCompilerInvocation( std::shared_ptr PCHContainerOps, - bool PrecompilePreamble) { + unsigned PrecompilePreambleAfterNParses) { if (!Invocation) return true; @@ -1874,8 +1875,8 @@ bool ASTUnit::LoadFromCompilerInvocation( ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); std::unique_ptr OverrideMainBuffer; - if (PrecompilePreamble) { - PreambleRebuildCounter = 2; + if (PrecompilePreambleAfterNParses > 0) { + PreambleRebuildCounter = PrecompilePreambleAfterNParses; OverrideMainBuffer = getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation); } @@ -1894,9 +1895,10 @@ std::unique_ptr ASTUnit::LoadFromCompilerInvocation( CompilerInvocation *CI, std::shared_ptr PCHContainerOps, IntrusiveRefCntPtr Diags, FileManager *FileMgr, - bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble, - TranslationUnitKind TUKind, bool CacheCodeCompletionResults, - bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile) { + bool OnlyLocalDecls, bool CaptureDiagnostics, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, + bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, + bool UserFilesAreVolatile) { // Create the AST unit. std::unique_ptr AST(new ASTUnit(false)); ConfigureDiags(Diags, *AST, CaptureDiagnostics); @@ -1919,7 +1921,8 @@ std::unique_ptr ASTUnit::LoadFromCompilerInvocation( llvm::CrashRecoveryContextReleaseRefCleanup > DiagCleanup(Diags.get()); - if (AST->LoadFromCompilerInvocation(PCHContainerOps, PrecompilePreamble)) + if (AST->LoadFromCompilerInvocation(PCHContainerOps, + PrecompilePreambleAfterNParses)) return nullptr; return AST; } @@ -1930,12 +1933,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine( IntrusiveRefCntPtr Diags, StringRef ResourceFilesPath, bool OnlyLocalDecls, bool CaptureDiagnostics, ArrayRef RemappedFiles, bool RemappedFilesKeepOriginalName, - bool PrecompilePreamble, TranslationUnitKind TUKind, + unsigned PrecompilePreambleAfterNParses, TranslationUnitKind TUKind, bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion, bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, bool UserFilesAreVolatile, bool ForSerialization, - llvm::Optional ModuleFormat, - std::unique_ptr *ErrAST) { + llvm::Optional ModuleFormat, std::unique_ptr *ErrAST) { assert(Diags.get() && "no DiagnosticsEngine was provided"); SmallVector StoredDiagnostics; @@ -2002,7 +2004,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine( llvm::CrashRecoveryContextCleanupRegistrar ASTUnitCleanup(AST.get()); - if (AST->LoadFromCompilerInvocation(PCHContainerOps, PrecompilePreamble)) { + if (AST->LoadFromCompilerInvocation(PCHContainerOps, + PrecompilePreambleAfterNParses)) { // Some error occurred, if caller wants to examine diagnostics, pass it the // ASTUnit. if (ErrAST) { diff --git a/test/Index/complete-preamble.cpp b/test/Index/complete-preamble.cpp index c57c88ab33..15720f9a29 100644 --- a/test/Index/complete-preamble.cpp +++ b/test/Index/complete-preamble.cpp @@ -3,6 +3,15 @@ void f() { std:: } -// RUN: env CINDEXTEST_EDITING=1 c-index-test -code-completion-at=%s:3:8 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s -// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50) +// RUN: env CINDEXTEST_EDITING=1 LIBCLANG_TIMING=1 c-index-test -code-completion-at=%s:3:8 %s -o - 2>&1 | FileCheck -check-prefix=CHECK-CC1 -check-prefix=SECOND %s +// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE=1 LIBCLANG_TIMING=1 c-index-test -code-completion-at=%s:3:8 %s -o - 2>&1 | FileCheck -check-prefix=CHECK-CC1 -check-prefix=FIRST %s + +// FIRST: Precompiling preamble +// FIRST: Parsing +// FIRST: Reparsing +// SECOND: Parsing +// SECOND: Precompiling preamble +// SECOND: Reparsing + +// CHECK-CC1: {ResultType void}{TypedText wibble}{LeftParen (}{RightParen )} (50) diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 948195deba..48f22eb4bb 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -76,7 +76,9 @@ static unsigned getDefaultParsingOptions() { options |= CXTranslationUnit_SkipFunctionBodies; if (getenv("CINDEXTEST_COMPLETION_BRIEF_COMMENTS")) options |= CXTranslationUnit_IncludeBriefCommentsInCodeCompletion; - + if (getenv("CINDEXTEST_CREATE_PREAMBLE_ON_FIRST_PARSE")) + options |= CXTranslationUnit_CreatePreambleOnFirstParse; + return options; } diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 768cd6a5b2..5022417d9a 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -3083,6 +3083,8 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, setThreadBackgroundPriority(); bool PrecompilePreamble = options & CXTranslationUnit_PrecompiledPreamble; + bool CreatePreambleOnFirstParse = + options & CXTranslationUnit_CreatePreambleOnFirstParse; // FIXME: Add a flag for modules. TranslationUnitKind TUKind = (options & CXTranslationUnit_Incomplete)? TU_Prefix : TU_Complete; @@ -3157,13 +3159,18 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename, unsigned NumErrors = Diags->getClient()->getNumErrors(); std::unique_ptr ErrUnit; + // Unless the user specified that they want the preamble on the first parse + // set it up to be created on the first reparse. This makes the first parse + // faster, trading for a slower (first) reparse. + unsigned PrecompilePreambleAfterNParses = + !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; std::unique_ptr Unit(ASTUnit::LoadFromCommandLine( Args->data(), Args->data() + Args->size(), CXXIdx->getPCHContainerOperations(), Diags, CXXIdx->getClangResourcesPath(), CXXIdx->getOnlyLocalDecls(), /*CaptureDiagnostics=*/true, *RemappedFiles.get(), - /*RemappedFilesKeepOriginalName=*/true, PrecompilePreamble, TUKind, - CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, + /*RemappedFilesKeepOriginalName=*/true, PrecompilePreambleAfterNParses, + TUKind, CacheCodeCompletionResults, IncludeBriefCommentsInCodeCompletion, /*AllowPCHWithCompilerErrors=*/true, SkipFunctionBodies, /*UserFilesAreVolatile=*/true, ForSerialization, CXXIdx->getPCHContainerOperations()->getRawReader().getFormat(), diff --git a/tools/libclang/Indexing.cpp b/tools/libclang/Indexing.cpp index d198f404a0..5bfc4245ea 100644 --- a/tools/libclang/Indexing.cpp +++ b/tools/libclang/Indexing.cpp @@ -601,6 +601,7 @@ static CXErrorCode clang_indexSourceFile_Impl( bool Persistent = requestedToGetTU; bool OnlyLocalDecls = false; bool PrecompilePreamble = false; + bool CreatePreambleOnFirstParse = false; bool CacheCodeCompletionResults = false; PreprocessorOptions &PPOpts = CInvok->getPreprocessorOpts(); PPOpts.AllowPCHWithCompilerErrors = true; @@ -608,6 +609,8 @@ static CXErrorCode clang_indexSourceFile_Impl( if (requestedToGetTU) { OnlyLocalDecls = CXXIdx->getOnlyLocalDecls(); PrecompilePreamble = TU_options & CXTranslationUnit_PrecompiledPreamble; + CreatePreambleOnFirstParse = + TU_options & CXTranslationUnit_CreatePreambleOnFirstParse; // FIXME: Add a flag for modules. CacheCodeCompletionResults = TU_options & CXTranslationUnit_CacheCompletionResults; @@ -620,11 +623,16 @@ static CXErrorCode clang_indexSourceFile_Impl( if (!requestedToGetTU && !CInvok->getLangOpts()->Modules) PPOpts.DetailedRecord = false; + // Unless the user specified that they want the preamble on the first parse + // set it up to be created on the first reparse. This makes the first parse + // faster, trading for a slower (first) reparse. + unsigned PrecompilePreambleAfterNParses = + !PrecompilePreamble ? 0 : 2 - CreatePreambleOnFirstParse; DiagnosticErrorTrap DiagTrap(*Diags); bool Success = ASTUnit::LoadFromCompilerInvocationAction( CInvok.get(), CXXIdx->getPCHContainerOperations(), Diags, IndexAction.get(), Unit, Persistent, CXXIdx->getClangResourcesPath(), - OnlyLocalDecls, CaptureDiagnostics, PrecompilePreamble, + OnlyLocalDecls, CaptureDiagnostics, PrecompilePreambleAfterNParses, CacheCodeCompletionResults, /*IncludeBriefCommentsInCodeCompletion=*/false, /*UserFilesAreVolatile=*/true);