Skip to content

Commit

Permalink
[libclang] Add a flag to create the precompiled preamble on the first…
Browse files Browse the repository at this point in the history
… 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

llvm-svn: 255635
  • Loading branch information
d0k committed Dec 15, 2015
1 parent 6045cc8 commit 5c248d8
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 29 deletions.
10 changes: 9 additions & 1 deletion clang/include/clang-c/Index.h
Expand Up @@ -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
};

/**
Expand Down
16 changes: 10 additions & 6 deletions clang/include/clang/Frontend/ASTUnit.h
Expand Up @@ -737,14 +737,15 @@ class ASTUnit : public ModuleLoader {
/// \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<PCHContainerOperations> PCHContainerOps,
bool PrecompilePreamble);
unsigned PrecompilePreambleAfterNParses);

public:

Expand Down Expand Up @@ -783,7 +784,8 @@ class ASTUnit : public ModuleLoader {
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<ASTUnit> *ErrAST = nullptr);
Expand All @@ -807,7 +809,8 @@ class ASTUnit : public ModuleLoader {
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
IntrusiveRefCntPtr<DiagnosticsEngine> 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);
Expand Down Expand Up @@ -842,7 +845,8 @@ class ASTUnit : public ModuleLoader {
bool OnlyLocalDecls = false, bool CaptureDiagnostics = false,
ArrayRef<RemappedFile> 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,
Expand Down
35 changes: 19 additions & 16 deletions clang/lib/Frontend/ASTUnit.cpp
Expand Up @@ -1725,9 +1725,10 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, ASTFrontendAction *Action,
ASTUnit *Unit, bool Persistent, StringRef ResourceFilesPath,
bool OnlyLocalDecls, bool CaptureDiagnostics, bool PrecompilePreamble,
bool CacheCodeCompletionResults, bool IncludeBriefCommentsInCodeCompletion,
bool UserFilesAreVolatile, std::unique_ptr<ASTUnit> *ErrAST) {
bool OnlyLocalDecls, bool CaptureDiagnostics,
unsigned PrecompilePreambleAfterNParses, bool CacheCodeCompletionResults,
bool IncludeBriefCommentsInCodeCompletion, bool UserFilesAreVolatile,
std::unique_ptr<ASTUnit> *ErrAST) {
assert(CI && "A CompilerInvocation is required");

std::unique_ptr<ASTUnit> OwnAST;
Expand All @@ -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
Expand Down Expand Up @@ -1864,7 +1865,7 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(

bool ASTUnit::LoadFromCompilerInvocation(
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
bool PrecompilePreamble) {
unsigned PrecompilePreambleAfterNParses) {
if (!Invocation)
return true;

Expand All @@ -1874,8 +1875,8 @@ bool ASTUnit::LoadFromCompilerInvocation(
ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts());

std::unique_ptr<llvm::MemoryBuffer> OverrideMainBuffer;
if (PrecompilePreamble) {
PreambleRebuildCounter = 2;
if (PrecompilePreambleAfterNParses > 0) {
PreambleRebuildCounter = PrecompilePreambleAfterNParses;
OverrideMainBuffer =
getMainBufferWithPrecompiledPreamble(PCHContainerOps, *Invocation);
}
Expand All @@ -1894,9 +1895,10 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
CompilerInvocation *CI,
std::shared_ptr<PCHContainerOperations> PCHContainerOps,
IntrusiveRefCntPtr<DiagnosticsEngine> 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<ASTUnit> AST(new ASTUnit(false));
ConfigureDiags(Diags, *AST, CaptureDiagnostics);
Expand All @@ -1919,7 +1921,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCompilerInvocation(
llvm::CrashRecoveryContextReleaseRefCleanup<DiagnosticsEngine> >
DiagCleanup(Diags.get());

if (AST->LoadFromCompilerInvocation(PCHContainerOps, PrecompilePreamble))
if (AST->LoadFromCompilerInvocation(PCHContainerOps,
PrecompilePreambleAfterNParses))
return nullptr;
return AST;
}
Expand All @@ -1930,12 +1933,11 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
IntrusiveRefCntPtr<DiagnosticsEngine> Diags, StringRef ResourceFilesPath,
bool OnlyLocalDecls, bool CaptureDiagnostics,
ArrayRef<RemappedFile> 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<StringRef> ModuleFormat,
std::unique_ptr<ASTUnit> *ErrAST) {
llvm::Optional<StringRef> ModuleFormat, std::unique_ptr<ASTUnit> *ErrAST) {
assert(Diags.get() && "no DiagnosticsEngine was provided");

SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
Expand Down Expand Up @@ -2002,7 +2004,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(
llvm::CrashRecoveryContextCleanupRegistrar<ASTUnit>
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) {
Expand Down
13 changes: 11 additions & 2 deletions clang/test/Index/complete-preamble.cpp
Expand Up @@ -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)
4 changes: 3 additions & 1 deletion clang/tools/c-index-test/c-index-test.c
Expand Up @@ -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;
}

Expand Down
11 changes: 9 additions & 2 deletions clang/tools/libclang/CIndex.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -3157,13 +3159,18 @@ clang_parseTranslationUnit_Impl(CXIndex CIdx, const char *source_filename,

unsigned NumErrors = Diags->getClient()->getNumErrors();
std::unique_ptr<ASTUnit> 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<ASTUnit> 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(),
Expand Down
10 changes: 9 additions & 1 deletion clang/tools/libclang/Indexing.cpp
Expand Up @@ -601,13 +601,16 @@ 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;

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;
Expand All @@ -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);
Expand Down

0 comments on commit 5c248d8

Please sign in to comment.