Skip to content

Commit f656d0d

Browse files
committed
[clang][modules] Timestamp PCM files when writing (llvm#112452)
Clang uses timestamp files to track the last time an implicitly-built PCM file was verified to be up-to-date with regard to its inputs. With `-fbuild-session-{file,timestamp}=` and `-fmodules-validate-once-per-build-session` this reduces the number of times a PCM file is checked per "build session". The behavior I'm seeing with the current scheme is that when lots of Clang instances wait for the same PCM to be built, they race to validate it as soon as the file lock gets released, causing lots of concurrent IO. This patch makes it so that the timestamp is written by the same Clang instance responsible for building the PCM while still holding the lock. This makes it so that whenever a PCM file gets compiled, it's never re-validated in the same build session. I believe this is as sound as the current scheme. One thing to be aware of is that there might be a time interval between accessing input file N and writing the timestamp file, where changes to input files 0..<N would not result in a rebuild. Since this is the case current scheme too, I'm not too concerned about that. I've seen this speed up `clang-scan-deps` by ~27%. (cherry picked from commit 0ffa29f)
1 parent 417d34b commit f656d0d

File tree

6 files changed

+30
-17
lines changed

6 files changed

+30
-17
lines changed

clang/include/clang/Serialization/ModuleFile.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_CLANG_SERIALIZATION_MODULEFILE_H
1616

1717
#include "clang/Basic/FileManager.h"
18+
#include "clang/Basic/LLVM.h"
1819
#include "clang/Basic/Module.h"
1920
#include "clang/Basic/SourceLocation.h"
2021
#include "clang/Serialization/ASTBitCodes.h"
@@ -155,8 +156,8 @@ class ModuleFile {
155156
/// The base directory of the module.
156157
std::string BaseDirectory;
157158

158-
std::string getTimestampFilename() const {
159-
return FileName + ".timestamp";
159+
static std::string getTimestampFilename(StringRef FileName) {
160+
return (FileName + ".timestamp").str();
160161
}
161162

162163
/// The original source file name that was used to build the

clang/lib/Serialization/ASTCommon.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@
1515
#include "clang/AST/DeclObjC.h"
1616
#include "clang/Basic/IdentifierTable.h"
1717
#include "clang/Serialization/ASTDeserializationListener.h"
18+
#include "clang/Serialization/ModuleFile.h"
1819
#include "llvm/Support/DJB.h"
20+
#include "llvm/Support/FileSystem.h"
21+
#include "llvm/Support/raw_ostream.h"
1922

2023
using namespace clang;
2124

@@ -498,3 +501,15 @@ bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) {
498501
return false;
499502
return isa<TagDecl, FieldDecl>(D);
500503
}
504+
505+
void serialization::updateModuleTimestamp(StringRef ModuleFilename) {
506+
// Overwrite the timestamp file contents so that file's mtime changes.
507+
std::error_code EC;
508+
llvm::raw_fd_ostream OS(ModuleFile::getTimestampFilename(ModuleFilename), EC,
509+
llvm::sys::fs::OF_TextWithCRLF);
510+
if (EC)
511+
return;
512+
OS << "Timestamp file\n";
513+
OS.close();
514+
OS.clear_error(); // Avoid triggering a fatal error.
515+
}

clang/lib/Serialization/ASTCommon.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "clang/AST/ASTContext.h"
1717
#include "clang/AST/DeclFriend.h"
18+
#include "clang/Basic/LLVM.h"
1819
#include "clang/Serialization/ASTBitCodes.h"
1920

2021
namespace clang {
@@ -100,6 +101,8 @@ inline bool isPartOfPerModuleInitializer(const Decl *D) {
100101
return false;
101102
}
102103

104+
void updateModuleTimestamp(StringRef ModuleFilename);
105+
103106
} // namespace serialization
104107

105108
} // namespace clang

clang/lib/Serialization/ASTReader.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4408,19 +4408,6 @@ bool ASTReader::isGlobalIndexUnavailable() const {
44084408
!hasGlobalIndex() && TriedLoadingGlobalIndex;
44094409
}
44104410

4411-
static void updateModuleTimestamp(ModuleFile &MF) {
4412-
// Overwrite the timestamp file contents so that file's mtime changes.
4413-
std::string TimestampFilename = MF.getTimestampFilename();
4414-
std::error_code EC;
4415-
llvm::raw_fd_ostream OS(TimestampFilename, EC,
4416-
llvm::sys::fs::OF_TextWithCRLF);
4417-
if (EC)
4418-
return;
4419-
OS << "Timestamp file\n";
4420-
OS.close();
4421-
OS.clear_error(); // Avoid triggering a fatal error.
4422-
}
4423-
44244411
/// Given a cursor at the start of an AST file, scan ahead and drop the
44254412
/// cursor into the start of the given block ID, returning false on success and
44264413
/// true on failure.
@@ -4699,7 +4686,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleKind Type,
46994686
ImportedModule &M = Loaded[I];
47004687
if (M.Mod->Kind == MK_ImplicitModule &&
47014688
M.Mod->InputFilesValidationTimestamp < HSOpts.BuildSessionTimestamp)
4702-
updateModuleTimestamp(*M.Mod);
4689+
updateModuleTimestamp(M.Mod->FileName);
47034690
}
47044691
}
47054692

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4892,6 +4892,12 @@ ASTFileSignature ASTWriter::WriteAST(Sema &SemaRef, StringRef OutputFile,
48924892
this->BaseDirectory.clear();
48934893

48944894
WritingAST = false;
4895+
4896+
if (WritingModule && SemaRef.PP.getHeaderSearchInfo()
4897+
.getHeaderSearchOpts()
4898+
.ModulesValidateOncePerBuildSession)
4899+
updateModuleTimestamp(OutputFile);
4900+
48954901
if (ShouldCacheASTInMemory) {
48964902
// Construct MemoryBuffer and update buffer manager.
48974903
ModuleCache.addBuiltPCM(OutputFile,

clang/lib/Serialization/ModuleManager.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type,
180180
NewModule->InputFilesValidationTimestamp = 0;
181181

182182
if (NewModule->Kind == MK_ImplicitModule) {
183-
std::string TimestampFilename = NewModule->getTimestampFilename();
183+
std::string TimestampFilename =
184+
ModuleFile::getTimestampFilename(NewModule->FileName);
184185
llvm::vfs::Status Status;
185186
// A cached stat value would be fine as well.
186187
if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status))

0 commit comments

Comments
 (0)