diff --git a/clang/include/clang/Serialization/ModuleCache.h b/clang/include/clang/Serialization/ModuleCache.h index 3117d954a09cc..a7ba26bc4daae 100644 --- a/clang/include/clang/Serialization/ModuleCache.h +++ b/clang/include/clang/Serialization/ModuleCache.h @@ -12,8 +12,6 @@ #include "clang/Basic/LLVM.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" -#include - namespace llvm { class AdvisoryLock; } // namespace llvm @@ -33,23 +31,11 @@ class ModuleCache : public RefCountedBase { virtual std::unique_ptr getLock(StringRef ModuleFilename) = 0; - // TODO: Abstract away timestamps with isUpToDate() and markUpToDate(). - // TODO: Consider exposing a "validation lock" API to prevent multiple clients - // concurrently noticing an out-of-date module file and validating its inputs. - - /// Returns the timestamp denoting the last time inputs of the module file - /// were validated. - virtual std::time_t getModuleTimestamp(StringRef ModuleFilename) = 0; - - /// Updates the timestamp denoting the last time inputs of the module file - /// were validated. - virtual void updateModuleTimestamp(StringRef ModuleFilename) = 0; - /// Returns this process's view of the module cache. virtual InMemoryModuleCache &getInMemoryModuleCache() = 0; virtual const InMemoryModuleCache &getInMemoryModuleCache() const = 0; - // TODO: Virtualize writing/reading PCM files, pruning, etc. + // TODO: Virtualize writing/reading PCM files, timestamping, pruning, etc. virtual ~ModuleCache() = default; }; diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h index 811c184b35a6b..acbc7712c6537 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h @@ -15,7 +15,6 @@ #include "clang/Tooling/DependencyScanning/InProcessModuleCache.h" #include "llvm/ADT/BitmaskEnum.h" #include "llvm/CAS/ActionCache.h" -#include "llvm/Support/Chrono.h" namespace clang { namespace tooling { @@ -105,9 +104,7 @@ class DependencyScanningService { std::shared_ptr Cache, IntrusiveRefCntPtr SharedFS, ScanningOptimizations OptimizeArgs = ScanningOptimizations::Default, - bool EagerLoadModules = false, bool TraceVFS = false, - std::time_t BuildSessionTimestamp = - llvm::sys::toTimeT(std::chrono::system_clock::now())); + bool EagerLoadModules = false, bool TraceVFS = false); ScanningMode getMode() const { return Mode; } @@ -134,9 +131,7 @@ class DependencyScanningService { bool useCASFS() const { return (bool)SharedFS; } - ModuleCacheEntries &getModuleCacheEntries() { return ModCacheEntries; } - - std::time_t getBuildSessionTimestamp() const { return BuildSessionTimestamp; } + ModuleCacheMutexes &getModuleCacheMutexes() { return ModCacheMutexes; } private: const ScanningMode Mode; @@ -155,10 +150,8 @@ class DependencyScanningService { IntrusiveRefCntPtr SharedFS; /// The global file system cache. std::optional SharedCache; - /// The global module cache entries. - ModuleCacheEntries ModCacheEntries; - /// The build session timestamp. - std::time_t BuildSessionTimestamp; + /// The global module cache mutexes. + ModuleCacheMutexes ModCacheMutexes; }; } // end namespace dependencies diff --git a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h index 213e60b39c199..ba0454380b665 100644 --- a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h +++ b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h @@ -18,18 +18,13 @@ namespace clang { namespace tooling { namespace dependencies { -struct ModuleCacheEntry { - std::shared_mutex CompilationMutex; - std::atomic Timestamp = 0; -}; - -struct ModuleCacheEntries { +struct ModuleCacheMutexes { std::mutex Mutex; - llvm::StringMap> Map; + llvm::StringMap> Map; }; IntrusiveRefCntPtr -makeInProcessModuleCache(ModuleCacheEntries &Entries); +makeInProcessModuleCache(ModuleCacheMutexes &Mutexes); } // namespace dependencies } // namespace tooling } // namespace clang diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index 19d82c72be569..2a1e6974553a5 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -501,3 +501,15 @@ bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) { return false; return isa(D); } + +void serialization::updateModuleTimestamp(StringRef ModuleFilename) { + // Overwrite the timestamp file contents so that file's mtime changes. + std::error_code EC; + llvm::raw_fd_ostream OS(ModuleFile::getTimestampFilename(ModuleFilename), EC, + llvm::sys::fs::OF_TextWithCRLF); + if (EC) + return; + OS << "Timestamp file\n"; + OS.close(); + OS.clear_error(); // Avoid triggering a fatal error. +} diff --git a/clang/lib/Serialization/ASTCommon.h b/clang/lib/Serialization/ASTCommon.h index 2ba8cbb6cd26e..2a765eafe0895 100644 --- a/clang/lib/Serialization/ASTCommon.h +++ b/clang/lib/Serialization/ASTCommon.h @@ -101,6 +101,8 @@ inline bool isPartOfPerModuleInitializer(const Decl *D) { return false; } +void updateModuleTimestamp(StringRef ModuleFilename); + } // namespace serialization } // namespace clang diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 8a04e70f7debf..bf4cdf0983432 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4752,8 +4752,7 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleKind Type, ImportedModule &M = Loaded[I]; if (M.Mod->Kind == MK_ImplicitModule && M.Mod->InputFilesValidationTimestamp < HSOpts.BuildSessionTimestamp) - getModuleManager().getModuleCache().updateModuleTimestamp( - M.Mod->FileName); + updateModuleTimestamp(M.Mod->FileName); } } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 3541be99e5984..c0690141f419c 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5034,7 +5034,7 @@ ASTWriter::WriteAST(llvm::PointerUnion Subject, if (WritingModule && PPRef.getHeaderSearchInfo() .getHeaderSearchOpts() .ModulesValidateOncePerBuildSession) - ModCache.updateModuleTimestamp(OutputFile); + updateModuleTimestamp(OutputFile); if (ShouldCacheASTInMemory) { // Construct MemoryBuffer and update buffer manager. diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp index 4ae49c4ec9a05..955e5f322bcc3 100644 --- a/clang/lib/Serialization/ModuleCache.cpp +++ b/clang/lib/Serialization/ModuleCache.cpp @@ -9,7 +9,6 @@ #include "clang/Serialization/ModuleCache.h" #include "clang/Serialization/InMemoryModuleCache.h" -#include "clang/Serialization/ModuleFile.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/LockFileManager.h" #include "llvm/Support/Path.h" @@ -33,28 +32,6 @@ class CrossProcessModuleCache : public ModuleCache { return std::make_unique(ModuleFilename); } - std::time_t getModuleTimestamp(StringRef ModuleFilename) override { - std::string TimestampFilename = - serialization::ModuleFile::getTimestampFilename(ModuleFilename); - llvm::sys::fs::file_status Status; - if (llvm::sys::fs::status(ModuleFilename, Status) != std::error_code{}) - return 0; - return llvm::sys::toTimeT(Status.getLastModificationTime()); - } - - void updateModuleTimestamp(StringRef ModuleFilename) override { - // Overwrite the timestamp file contents so that file's mtime changes. - std::error_code EC; - llvm::raw_fd_ostream OS( - serialization::ModuleFile::getTimestampFilename(ModuleFilename), EC, - llvm::sys::fs::OF_TextWithCRLF); - if (EC) - return; - OS << "Timestamp file\n"; - OS.close(); - OS.clear_error(); // Avoid triggering a fatal error. - } - InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; } const InMemoryModuleCache &getInMemoryModuleCache() const override { return InMemory; diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index c2547ea96c474..ae126528405c4 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -186,9 +186,15 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, NewModule->ImportLoc = ImportLoc; NewModule->InputFilesValidationTimestamp = 0; - if (NewModule->Kind == MK_ImplicitModule) - NewModule->InputFilesValidationTimestamp = - ModCache->getModuleTimestamp(NewModule->FileName); + if (NewModule->Kind == MK_ImplicitModule) { + std::string TimestampFilename = + ModuleFile::getTimestampFilename(NewModule->FileName); + llvm::vfs::Status Status; + // A cached stat value would be fine as well. + if (!FileMgr.getNoncachedStatValue(TimestampFilename, Status)) + NewModule->InputFilesValidationTimestamp = + llvm::sys::toTimeT(Status.getLastModificationTime()); + } // Load the contents of the module if (std::unique_ptr Buffer = lookupBuffer(FileName)) { diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp index 75b05091623a8..8d6e0fb0f9fc9 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp @@ -21,12 +21,10 @@ DependencyScanningService::DependencyScanningService( std::shared_ptr CAS, std::shared_ptr Cache, IntrusiveRefCntPtr SharedFS, - ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool TraceVFS, - std::time_t BuildSessionTimestamp) + ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool TraceVFS) : Mode(Mode), Format(Format), CASOpts(std::move(CASOpts)), CAS(std::move(CAS)), Cache(std::move(Cache)), OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules), TraceVFS(TraceVFS), - SharedFS(std::move(SharedFS)), - BuildSessionTimestamp(BuildSessionTimestamp) { + SharedFS(std::move(SharedFS)) { if (!this->SharedFS) SharedCache.emplace(); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 41ac425e67f91..fd1612befa0e5 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -441,7 +441,7 @@ class DependencyScanningAction : public tooling::ToolAction { Scanned = true; // Create a compiler instance to handle the actual work. - auto ModCache = makeInProcessModuleCache(Service.getModuleCacheEntries()); + auto ModCache = makeInProcessModuleCache(Service.getModuleCacheMutexes()); ScanInstanceStorage.emplace(std::move(PCHContainerOps), ModCache.get()); CompilerInstance &ScanInstance = *ScanInstanceStorage; ScanInstance.setInvocation(std::move(Invocation)); @@ -461,10 +461,6 @@ class DependencyScanningAction : public tooling::ToolAction { ScanInstance.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = true; - if (ScanInstance.getHeaderSearchOpts().ModulesValidateOncePerBuildSession) - ScanInstance.getHeaderSearchOpts().BuildSessionTimestamp = - Service.getBuildSessionTimestamp(); - ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false; ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false; // This will prevent us compiling individual modules asynchronously since diff --git a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp index 80db2d47d940e..71ce4d098932b 100644 --- a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp +++ b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp @@ -10,7 +10,6 @@ #include "clang/Serialization/InMemoryModuleCache.h" #include "llvm/Support/AdvisoryLock.h" -#include "llvm/Support/Chrono.h" #include @@ -51,7 +50,7 @@ class ReaderWriterLock : public llvm::AdvisoryLock { }; class InProcessModuleCache : public ModuleCache { - ModuleCacheEntries &Entries; + ModuleCacheMutexes &Mutexes; // TODO: If we changed the InMemoryModuleCache API and relied on strict // context hash, we could probably create more efficient thread-safe @@ -60,44 +59,19 @@ class InProcessModuleCache : public ModuleCache { InMemoryModuleCache InMemory; public: - InProcessModuleCache(ModuleCacheEntries &Entries) : Entries(Entries) {} + InProcessModuleCache(ModuleCacheMutexes &Mutexes) : Mutexes(Mutexes) {} void prepareForGetLock(StringRef Filename) override {} std::unique_ptr getLock(StringRef Filename) override { - auto &CompilationMutex = [&]() -> std::shared_mutex & { - std::lock_guard Lock(Entries.Mutex); - auto &Entry = Entries.Map[Filename]; - if (!Entry) - Entry = std::make_unique(); - return Entry->CompilationMutex; + auto &Mtx = [&]() -> std::shared_mutex & { + std::lock_guard Lock(Mutexes.Mutex); + auto &Mutex = Mutexes.Map[Filename]; + if (!Mutex) + Mutex = std::make_unique(); + return *Mutex; }(); - return std::make_unique(CompilationMutex); - } - - std::time_t getModuleTimestamp(StringRef Filename) override { - auto &Timestamp = [&]() -> std::atomic & { - std::lock_guard Lock(Entries.Mutex); - auto &Entry = Entries.Map[Filename]; - if (!Entry) - Entry = std::make_unique(); - return Entry->Timestamp; - }(); - - return Timestamp.load(); - } - - void updateModuleTimestamp(StringRef Filename) override { - // Note: This essentially replaces FS contention with mutex contention. - auto &Timestamp = [&]() -> std::atomic & { - std::lock_guard Lock(Entries.Mutex); - auto &Entry = Entries.Map[Filename]; - if (!Entry) - Entry = std::make_unique(); - return Entry->Timestamp; - }(); - - Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now())); + return std::make_unique(Mtx); } InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; } @@ -108,6 +82,6 @@ class InProcessModuleCache : public ModuleCache { } // namespace IntrusiveRefCntPtr -dependencies::makeInProcessModuleCache(ModuleCacheEntries &Entries) { - return llvm::makeIntrusiveRefCnt(Entries); +dependencies::makeInProcessModuleCache(ModuleCacheMutexes &Mutexes) { + return llvm::makeIntrusiveRefCnt(Mutexes); }