diff options
author | Jan Svoboda <jan_svoboda@apple.com> | 2025-05-14 14:31:23 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-05-14 14:31:23 -0700 |
commit | 960afcc90e8fb75b725ed331f4bc60eb2398d6e5 (patch) | |
tree | 9415bb216da3f252bc15f7c43218b695f0238f04 /clang | |
parent | a608b4914209f4238fe83a6b5fa8fd7219f11115 (diff) | |
download | llvm-960afcc90e8fb75b725ed331f4bc60eb2398d6e5.zip llvm-960afcc90e8fb75b725ed331f4bc60eb2398d6e5.tar.gz llvm-960afcc90e8fb75b725ed331f4bc60eb2398d6e5.tar.bz2 |
[clang][modules] Timestamp-less validation API (#138983)
Timestamps are an implementation detail of the cross-process module
cache implementation. This PR hides it from the `ModuleCache` API, which
simplifies the in-process implementation.
Diffstat (limited to 'clang')
13 files changed, 51 insertions, 59 deletions
diff --git a/clang/include/clang/Serialization/ModuleCache.h b/clang/include/clang/Serialization/ModuleCache.h index 3117d95..df95090 100644 --- a/clang/include/clang/Serialization/ModuleCache.h +++ b/clang/include/clang/Serialization/ModuleCache.h @@ -33,17 +33,14 @@ public: virtual std::unique_ptr<llvm::AdvisoryLock> 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; + /// Checks whether the inputs of the module file were marked as validated. + virtual bool isMarkedUpToDate(StringRef ModuleFilename) = 0; - /// Updates the timestamp denoting the last time inputs of the module file - /// were validated. - virtual void updateModuleTimestamp(StringRef ModuleFilename) = 0; + /// Marks the inputs of the module file as validated. + virtual void markUpToDate(StringRef ModuleFilename) = 0; /// Returns this process's view of the module cache. virtual InMemoryModuleCache &getInMemoryModuleCache() = 0; @@ -58,7 +55,8 @@ public: /// operated on by multiple processes. This instance must be used across all /// \c CompilerInstance instances participating in building modules for single /// translation unit in order to share the same \c InMemoryModuleCache. -IntrusiveRefCntPtr<ModuleCache> createCrossProcessModuleCache(); +IntrusiveRefCntPtr<ModuleCache> +createCrossProcessModuleCache(std::time_t BuildSessionTimestamp); } // namespace clang #endif diff --git a/clang/include/clang/Serialization/ModuleFile.h b/clang/include/clang/Serialization/ModuleFile.h index f20cb2f..5b6e31da 100644 --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -270,11 +270,9 @@ public: // system input files reside at [NumUserInputFiles, InputFilesLoaded.size()). unsigned NumUserInputFiles = 0; - /// If non-zero, specifies the time when we last validated input - /// files. Zero means we never validated them. - /// - /// The time is specified in seconds since the start of the Epoch. - uint64_t InputFilesValidationTimestamp = 0; + /// Specifies whether the input files have been validated (i.e. checked + /// whether they are up-to-date). + bool InputFilesValidated = false; // === Source Locations === diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h index 4e97c7b..22f670cb 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h @@ -12,7 +12,6 @@ #include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h" #include "clang/Tooling/DependencyScanning/InProcessModuleCache.h" #include "llvm/ADT/BitmaskEnum.h" -#include "llvm/Support/Chrono.h" namespace clang { namespace tooling { @@ -85,9 +84,7 @@ public: DependencyScanningService( ScanningMode Mode, ScanningOutputFormat Format, 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; } @@ -105,8 +102,6 @@ public: ModuleCacheEntries &getModuleCacheEntries() { return ModCacheEntries; } - std::time_t getBuildSessionTimestamp() const { return BuildSessionTimestamp; } - private: const ScanningMode Mode; const ScanningOutputFormat Format; @@ -120,8 +115,6 @@ private: DependencyScanningFilesystemSharedCache SharedCache; /// The global module cache entries. ModuleCacheEntries ModCacheEntries; - /// The build session timestamp. - std::time_t BuildSessionTimestamp; }; } // end namespace dependencies diff --git a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h index 213e60b..fa11af2 100644 --- a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h +++ b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h @@ -20,7 +20,7 @@ namespace tooling { namespace dependencies { struct ModuleCacheEntry { std::shared_mutex CompilationMutex; - std::atomic<std::time_t> Timestamp = 0; + std::atomic<bool> UpToDate = false; }; struct ModuleCacheEntries { diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index 5a79fe0..eb8483d 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -829,9 +829,10 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromASTFile( AST->SourceMgr = new SourceManager(AST->getDiagnostics(), AST->getFileManager(), UserFilesAreVolatile); - AST->ModCache = createCrossProcessModuleCache(); AST->HSOpts = std::make_unique<HeaderSearchOptions>(HSOpts); AST->HSOpts->ModuleFormat = std::string(PCHContainerRdr.getFormats().front()); + AST->ModCache = + createCrossProcessModuleCache(AST->HSOpts->BuildSessionTimestamp); AST->HeaderInfo.reset(new HeaderSearch(AST->getHeaderSearchOpts(), AST->getSourceManager(), AST->getDiagnostics(), @@ -1548,7 +1549,8 @@ ASTUnit::create(std::shared_ptr<CompilerInvocation> CI, AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->SourceMgr = new SourceManager(AST->getDiagnostics(), *AST->FileMgr, UserFilesAreVolatile); - AST->ModCache = createCrossProcessModuleCache(); + AST->ModCache = createCrossProcessModuleCache( + AST->Invocation->getHeaderSearchOpts().BuildSessionTimestamp); return AST; } @@ -1834,7 +1836,6 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine( AST->FileMgr = new FileManager(AST->FileSystemOpts, VFS); AST->StorePreamblesInMemory = StorePreamblesInMemory; AST->PreambleStoragePath = PreambleStoragePath; - AST->ModCache = createCrossProcessModuleCache(); AST->OnlyLocalDecls = OnlyLocalDecls; AST->CaptureDiagnostics = CaptureDiagnostics; AST->TUKind = TUKind; @@ -1843,6 +1844,8 @@ std::unique_ptr<ASTUnit> ASTUnit::LoadFromCommandLine( = IncludeBriefCommentsInCodeCompletion; AST->UserFilesAreVolatile = UserFilesAreVolatile; AST->Invocation = CI; + AST->ModCache = createCrossProcessModuleCache( + AST->Invocation->getHeaderSearchOpts().BuildSessionTimestamp); AST->SkipFunctionBodies = SkipFunctionBodies; if (ForSerialization) AST->WriterData.reset(new ASTWriterData(*AST->ModCache)); @@ -2378,7 +2381,6 @@ bool ASTUnit::serialize(raw_ostream &OS) { SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); - IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache(); ASTWriter Writer(Stream, Buffer, *ModCache, {}); return serializeUnit(Writer, Buffer, getSema(), OS); } diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 503d364..b3a23e6 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -72,7 +72,9 @@ CompilerInstance::CompilerInstance( ModuleCache *ModCache) : ModuleLoader(/*BuildingModule=*/ModCache), Invocation(std::move(Invocation)), - ModCache(ModCache ? ModCache : createCrossProcessModuleCache()), + ModCache(ModCache ? ModCache + : createCrossProcessModuleCache( + getHeaderSearchOpts().BuildSessionTimestamp)), ThePCHContainerOperations(std::move(PCHContainerOps)) { assert(this->Invocation && "Invocation must not be null"); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index d068f5e1..2462b5c 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3103,8 +3103,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, unsigned N = ValidateSystemInputs ? NumInputs : NumUserInputs; if (HSOpts.ModulesValidateOncePerBuildSession && - F.InputFilesValidationTimestamp > HSOpts.BuildSessionTimestamp && - F.Kind == MK_ImplicitModule) + F.InputFilesValidated && F.Kind == MK_ImplicitModule) N = ForceValidateUserInputs ? NumUserInputs : 0; for (unsigned I = 0; I < N; ++I) { @@ -4950,10 +4949,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, ModuleKind Type, // timestamp files are up-to-date in this build session. for (unsigned I = 0, N = Loaded.size(); I != N; ++I) { ImportedModule &M = Loaded[I]; - if (M.Mod->Kind == MK_ImplicitModule && - M.Mod->InputFilesValidationTimestamp < HSOpts.BuildSessionTimestamp) - getModuleManager().getModuleCache().updateModuleTimestamp( - M.Mod->FileName); + if (M.Mod->Kind == MK_ImplicitModule && !M.Mod->InputFilesValidated) + getModuleManager().getModuleCache().markUpToDate(M.Mod->FileName); } } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 1b3d3c2..491149b 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5391,7 +5391,7 @@ ASTWriter::WriteAST(llvm::PointerUnion<Sema *, Preprocessor *> Subject, if (WritingModule && PPRef.getHeaderSearchInfo() .getHeaderSearchOpts() .ModulesValidateOncePerBuildSession) - ModCache.updateModuleTimestamp(OutputFile); + ModCache.markUpToDate(OutputFile); if (ShouldCacheASTInMemory) { // Construct MemoryBuffer and update buffer manager. diff --git a/clang/lib/Serialization/ModuleCache.cpp b/clang/lib/Serialization/ModuleCache.cpp index 4ae49c4..43f8ff8 100644 --- a/clang/lib/Serialization/ModuleCache.cpp +++ b/clang/lib/Serialization/ModuleCache.cpp @@ -20,7 +20,12 @@ namespace { class CrossProcessModuleCache : public ModuleCache { InMemoryModuleCache InMemory; + std::time_t BuildSessionTimestamp; + public: + explicit CrossProcessModuleCache(std::time_t BuildSessionTimestamp) + : BuildSessionTimestamp(BuildSessionTimestamp) {} + void prepareForGetLock(StringRef ModuleFilename) override { // FIXME: Do this in LockFileManager and only if the directory doesn't // exist. @@ -33,16 +38,17 @@ public: return std::make_unique<llvm::LockFileManager>(ModuleFilename); } - std::time_t getModuleTimestamp(StringRef ModuleFilename) override { + bool isMarkedUpToDate(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()); + return false; + return llvm::sys::toTimeT(Status.getLastModificationTime()) > + BuildSessionTimestamp; } - void updateModuleTimestamp(StringRef ModuleFilename) override { + void markUpToDate(StringRef ModuleFilename) override { // Overwrite the timestamp file contents so that file's mtime changes. std::error_code EC; llvm::raw_fd_ostream OS( @@ -62,6 +68,8 @@ public: }; } // namespace -IntrusiveRefCntPtr<ModuleCache> clang::createCrossProcessModuleCache() { - return llvm::makeIntrusiveRefCnt<CrossProcessModuleCache>(); +IntrusiveRefCntPtr<ModuleCache> +clang::createCrossProcessModuleCache(std::time_t BuildSessionTimestamp) { + return llvm::makeIntrusiveRefCnt<CrossProcessModuleCache>( + BuildSessionTimestamp); } diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index fa9533b..9fd7505 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -174,11 +174,11 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, NewModule->Index = Chain.size(); NewModule->FileName = FileName.str(); NewModule->ImportLoc = ImportLoc; - NewModule->InputFilesValidationTimestamp = 0; + NewModule->InputFilesValidated = false; if (NewModule->Kind == MK_ImplicitModule) - NewModule->InputFilesValidationTimestamp = - ModCache->getModuleTimestamp(NewModule->FileName); + NewModule->InputFilesValidated = + ModCache->isMarkedUpToDate(NewModule->FileName); // Load the contents of the module if (std::unique_ptr<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) { diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp index 7f40c99..96fe40c 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp @@ -14,8 +14,6 @@ using namespace dependencies; DependencyScanningService::DependencyScanningService( ScanningMode Mode, ScanningOutputFormat Format, - ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool TraceVFS, - std::time_t BuildSessionTimestamp) + ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool TraceVFS) : Mode(Mode), Format(Format), OptimizeArgs(OptimizeArgs), - EagerLoadModules(EagerLoadModules), TraceVFS(TraceVFS), - BuildSessionTimestamp(BuildSessionTimestamp) {} + EagerLoadModules(EagerLoadModules), TraceVFS(TraceVFS) {} diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 21eea72..e30e997 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -428,10 +428,6 @@ public: 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 80db2d4..ccfe42c 100644 --- a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp +++ b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp @@ -75,29 +75,29 @@ public: return std::make_unique<ReaderWriterLock>(CompilationMutex); } - std::time_t getModuleTimestamp(StringRef Filename) override { - auto &Timestamp = [&]() -> std::atomic<std::time_t> & { + bool isMarkedUpToDate(StringRef Filename) override { + auto &IsUpToDate = [&]() -> std::atomic<bool> & { std::lock_guard<std::mutex> Lock(Entries.Mutex); auto &Entry = Entries.Map[Filename]; if (!Entry) Entry = std::make_unique<ModuleCacheEntry>(); - return Entry->Timestamp; + return Entry->UpToDate; }(); - return Timestamp.load(); + return IsUpToDate; } - void updateModuleTimestamp(StringRef Filename) override { + void markUpToDate(StringRef Filename) override { // Note: This essentially replaces FS contention with mutex contention. - auto &Timestamp = [&]() -> std::atomic<std::time_t> & { + auto &IsUpToDate = [&]() -> std::atomic<bool> & { std::lock_guard<std::mutex> Lock(Entries.Mutex); auto &Entry = Entries.Map[Filename]; if (!Entry) Entry = std::make_unique<ModuleCacheEntry>(); - return Entry->Timestamp; + return Entry->UpToDate; }(); - Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now())); + IsUpToDate = true; } InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; } |