summaryrefslogtreecommitdiffstats
path: root/clang/lib/Serialization
diff options
context:
space:
mode:
authorDmitri Gribenko <gribozavr@gmail.com>2014-02-12 10:33:14 +0000
committerDmitri Gribenko <gribozavr@gmail.com>2014-02-12 10:33:14 +0000
commitf430da4de68b5569634b03df30b38d1133dc169b (patch)
tree3cbc33ed201f16def4c5052e05004820a6800b0e /clang/lib/Serialization
parentecbe18e01dc42fb5e60fdac361ce74f9ab8c5307 (diff)
downloadbcm5719-llvm-f430da4de68b5569634b03df30b38d1133dc169b.tar.gz
bcm5719-llvm-f430da4de68b5569634b03df30b38d1133dc169b.zip
Add an option to allow Clang verify source files for a module only once during
the build When Clang loads the module, it verifies the user source files that the module was built from. If any file was changed, the module is rebuilt. There are two problems with this: 1. correctness: we don't verify system files (there are too many of them, and stat'ing all of them would take a lot of time); 2. performance: the same module file is verified again and again during a single build. This change allows the build system to optimize source file verification. The idea is based on the fact that while the project is being built, the source files don't change. This allows us to verify the module only once during a single build session. The build system passes a flag, -fbuild-session-timestamp=, to inform Clang of the time when the build started. The build system also requests to enable this feature by passing -fmodules-validate-once-per-build-session. If these flags are not passed, the behavior is not changed. When Clang verifies the module the first time, it writes out a timestamp file. Then, when Clang loads the module the second time, it finds a timestamp file, so it can compare the verification timestamp of the module with the time when the build started. If the verification timestamp is too old, the module is verified again, and the timestamp file is updated. llvm-svn: 201224
Diffstat (limited to 'clang/lib/Serialization')
-rw-r--r--clang/lib/Serialization/ASTReader.cpp49
-rw-r--r--clang/lib/Serialization/ModuleManager.cpp10
2 files changed, 54 insertions, 5 deletions
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 674aefeb1c5..fb1d7edcbad 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -49,6 +49,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SaveAndRestore.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
#include <algorithm>
#include <cstdio>
@@ -1827,16 +1828,28 @@ ASTReader::ReadControlBlock(ModuleFile &F,
case llvm::BitstreamEntry::Error:
Error("malformed block record in AST file");
return Failure;
- case llvm::BitstreamEntry::EndBlock:
- // Validate all of the non-system input files.
- if (!DisableValidation) {
+ case llvm::BitstreamEntry::EndBlock: {
+ // Validate input files.
+ const HeaderSearchOptions &HSOpts =
+ PP.getHeaderSearchInfo().getHeaderSearchOpts();
+ if (!DisableValidation &&
+ (!HSOpts.ModulesValidateOncePerBuildSession ||
+ F.InputFilesValidationTimestamp <= HSOpts.BuildSessionTimestamp)) {
bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0;
// All user input files reside at the index range [0, Record[1]), and
// system input files reside at [Record[1], Record[0]).
// Record is the one from INPUT_FILE_OFFSETS.
+ //
+ // If we are reading a module, we will create a verification timestamp,
+ // so we verify all input files. Otherwise, verify only user input
+ // files.
unsigned NumInputs = Record[0];
unsigned NumUserInputs = Record[1];
- unsigned N = ValidateSystemInputs ? NumInputs : NumUserInputs;
+ unsigned N = ValidateSystemInputs ||
+ (HSOpts.ModulesValidateOncePerBuildSession &&
+ F.Kind == MK_Module)
+ ? NumInputs
+ : NumUserInputs;
for (unsigned I = 0; I < N; ++I) {
InputFile IF = getInputFile(F, I+1, Complain);
if (!IF.getFile() || IF.isOutOfDate())
@@ -1844,7 +1857,8 @@ ASTReader::ReadControlBlock(ModuleFile &F,
}
}
return Success;
-
+ }
+
case llvm::BitstreamEntry::SubBlock:
switch (Entry.ID) {
case INPUT_FILES_BLOCK_ID:
@@ -2922,6 +2936,16 @@ bool ASTReader::isGlobalIndexUnavailable() const {
!hasGlobalIndex() && TriedLoadingGlobalIndex;
}
+static void updateModuleTimestamp(ModuleFile &MF) {
+ // Overwrite the timestamp file contents so that file's mtime changes.
+ std::string TimestampFilename = MF.getTimestampFilename();
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream OS(TimestampFilename.c_str(), ErrorInfo);
+ if (!ErrorInfo.empty())
+ return;
+ OS << "Timestamp file\n";
+}
+
ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
ModuleKind Type,
SourceLocation ImportLoc,
@@ -3080,6 +3104,21 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName,
PreviousGeneration);
}
+ if (PP.getHeaderSearchInfo()
+ .getHeaderSearchOpts()
+ .ModulesValidateOncePerBuildSession) {
+ // Now we are certain that the module and all modules it depends on are
+ // up to date. Create or update timestamp files for modules that are
+ // located in the module cache (not for PCH files that could be anywhere
+ // in the filesystem).
+ for (unsigned I = 0, N = Loaded.size(); I != N; ++I) {
+ ImportedModule &M = Loaded[I];
+ if (M.Mod->Kind == MK_Module) {
+ updateModuleTimestamp(*M.Mod);
+ }
+ }
+ }
+
return Success;
}
diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp
index 9c4b3d92bef..711afcd2dca 100644
--- a/clang/lib/Serialization/ModuleManager.cpp
+++ b/clang/lib/Serialization/ModuleManager.cpp
@@ -86,6 +86,16 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
NewModule = true;
ModuleEntry = New;
+ New->InputFilesValidationTimestamp = 0;
+ if (New->Kind == MK_Module) {
+ std::string TimestampFilename = New->getTimestampFilename();
+ llvm::sys::fs::file_status Status;
+ // A cached stat value would be fine as well.
+ if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))
+ New->InputFilesValidationTimestamp =
+ Status.getLastModificationTime().toEpochTime();
+ }
+
// Load the contents of the module
if (llvm::MemoryBuffer *Buffer = lookupBuffer(FileName)) {
// The buffer was already provided for us.
OpenPOWER on IntegriCloud