Author: Jan Svoboda Date: 2025-05-14T14:31:23-07:00 New Revision: 960afcc90e8fb75b725ed331f4bc60eb2398d6e5
URL: https://github.com/llvm/llvm-project/commit/960afcc90e8fb75b725ed331f4bc60eb2398d6e5 DIFF: https://github.com/llvm/llvm-project/commit/960afcc90e8fb75b725ed331f4bc60eb2398d6e5.diff LOG: [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. Added: Modified: clang-tools-extra/clangd/ModulesBuilder.cpp clang/include/clang/Serialization/ModuleCache.h clang/include/clang/Serialization/ModuleFile.h clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h clang/lib/Frontend/ASTUnit.cpp clang/lib/Frontend/CompilerInstance.cpp clang/lib/Serialization/ASTReader.cpp clang/lib/Serialization/ASTWriter.cpp clang/lib/Serialization/ModuleCache.cpp clang/lib/Serialization/ModuleManager.cpp clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clangd/ModulesBuilder.cpp b/clang-tools-extra/clangd/ModulesBuilder.cpp index c1878f91b5e16..5350f1b83a7f0 100644 --- a/clang-tools-extra/clangd/ModulesBuilder.cpp +++ b/clang-tools-extra/clangd/ModulesBuilder.cpp @@ -207,7 +207,8 @@ bool IsModuleFileUpToDate(PathRef ModuleFilePath, Preprocessor PP(PPOpts, *Diags, LangOpts, SourceMgr, HeaderInfo, ModuleLoader); - IntrusiveRefCntPtr<ModuleCache> ModCache = createCrossProcessModuleCache(); + IntrusiveRefCntPtr<ModuleCache> ModCache = + createCrossProcessModuleCache(HSOpts.BuildSessionTimestamp); PCHContainerOperations PCHOperations; ASTReader Reader(PP, *ModCache, /*ASTContext=*/nullptr, PCHOperations.getRawReader(), {}); diff --git a/clang/include/clang/Serialization/ModuleCache.h b/clang/include/clang/Serialization/ModuleCache.h index 3117d954a09cc..df950906333ba 100644 --- a/clang/include/clang/Serialization/ModuleCache.h +++ b/clang/include/clang/Serialization/ModuleCache.h @@ -33,17 +33,14 @@ class ModuleCache : public RefCountedBase<ModuleCache> { 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 @@ class ModuleCache : public RefCountedBase<ModuleCache> { /// 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 f20cb2f9f35ae..5b6e31dac39ed 100644 --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -270,11 +270,9 @@ class ModuleFile { // 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 4e97c7bc9f36e..22f670cb821e2 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 @@ class DependencyScanningService { 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 @@ class DependencyScanningService { ModuleCacheEntries &getModuleCacheEntries() { return ModCacheEntries; } - std::time_t getBuildSessionTimestamp() const { return BuildSessionTimestamp; } - private: const ScanningMode Mode; const ScanningOutputFormat Format; @@ -120,8 +115,6 @@ class DependencyScanningService { 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 213e60b39c199..fa11af2be5a67 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 5a79fe070c384..eb8483dcfc008 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 503d36467653e..b3a23e64dbada 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 d068f5e163176..2462b5c1f1421 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 1b3d3c22aa9f5..491149b33f1d8 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 4ae49c4ec9a05..43f8ff8d681fe 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 @@ class CrossProcessModuleCache : public ModuleCache { 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 @@ class CrossProcessModuleCache : public ModuleCache { }; } // 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 fa9533b7efd78..9fd7505726973 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 7f40c99f07287..96fe40c079c65 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 21eea72b198b3..e30e997e40581 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -428,10 +428,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..ccfe42c092f58 100644 --- a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp +++ b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp @@ -75,29 +75,29 @@ class InProcessModuleCache : public ModuleCache { 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; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits