https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/129751
>From 7dadb10f4e63e419a230270b5f26a145d7015ae7 Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Wed, 12 Mar 2025 10:20:16 -0700 Subject: [PATCH] [clang][deps] Implement efficient in-process `ModuleCache` --- .../DependencyScanningService.h | 5 ++ .../DependencyScanning/InProcessModuleCache.h | 31 +++++++ .../Tooling/DependencyScanning/CMakeLists.txt | 1 + .../DependencyScanningWorker.cpp | 5 +- .../InProcessModuleCache.cpp | 87 +++++++++++++++++++ 5 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h create mode 100644 clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h index 816e122eb3003..996a26716eea2 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGSERVICE_H #include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h" +#include "clang/Tooling/DependencyScanning/InProcessModuleCache.h" #include "llvm/ADT/BitmaskEnum.h" namespace clang { @@ -99,6 +100,8 @@ class DependencyScanningService { return SharedCache; } + ModuleCacheMutexes &getModuleCacheMutexes() { return ModuleCacheMutexes; } + private: const ScanningMode Mode; const ScanningOutputFormat Format; @@ -110,6 +113,8 @@ class DependencyScanningService { const bool TraceVFS; /// The global file system cache. DependencyScanningFilesystemSharedCache SharedCache; + /// The global module cache mutexes. + ModuleCacheMutexes ModuleCacheMutexes; }; } // end namespace dependencies diff --git a/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h new file mode 100644 index 0000000000000..a22647584d8c5 --- /dev/null +++ b/clang/include/clang/Tooling/DependencyScanning/InProcessModuleCache.h @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_INPROCESSMODULECACHE_H +#define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_INPROCESSMODULECACHE_H + +#include "clang/Serialization/ModuleCache.h" +#include "llvm/ADT/StringMap.h" + +#include <shared_mutex> + +namespace clang { +namespace tooling { +namespace dependencies { +struct ModuleCacheMutexes { + std::mutex Mutex; + llvm::StringMap<std::unique_ptr<std::shared_mutex>> Map; +}; + +IntrusiveRefCntPtr<ModuleCache> +makeInProcessModuleCache(ModuleCacheMutexes &Mutexes); +} // namespace dependencies +} // namespace tooling +} // namespace clang + +#endif diff --git a/clang/lib/Tooling/DependencyScanning/CMakeLists.txt b/clang/lib/Tooling/DependencyScanning/CMakeLists.txt index 6b500a183bcfc..993dc093a781c 100644 --- a/clang/lib/Tooling/DependencyScanning/CMakeLists.txt +++ b/clang/lib/Tooling/DependencyScanning/CMakeLists.txt @@ -10,6 +10,7 @@ add_clang_library(clangDependencyScanning DependencyScanningService.cpp DependencyScanningWorker.cpp DependencyScanningTool.cpp + InProcessModuleCache.cpp ModuleDepCollector.cpp DEPENDS diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 697f26ee5d12f..ca15a088c308d 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -22,6 +22,7 @@ #include "clang/Lex/PreprocessorOptions.h" #include "clang/Serialization/ObjectFilePCHContainerReader.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" +#include "clang/Tooling/DependencyScanning/InProcessModuleCache.h" #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" @@ -315,9 +316,11 @@ class DependencyScanningAction : public tooling::ToolAction { Scanned = true; // Create a compiler instance to handle the actual work. - ScanInstanceStorage.emplace(std::move(PCHContainerOps)); + auto ModCache = makeInProcessModuleCache(Service.getModuleCacheMutexes()); + ScanInstanceStorage.emplace(std::move(PCHContainerOps), ModCache.get()); CompilerInstance &ScanInstance = *ScanInstanceStorage; ScanInstance.setInvocation(std::move(Invocation)); + ScanInstance.setBuildingModule(false); // Create the compiler's actual diagnostics engine. sanitizeDiagOpts(ScanInstance.getDiagnosticOpts()); diff --git a/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp new file mode 100644 index 0000000000000..079e00c38b140 --- /dev/null +++ b/clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/DependencyScanning/InProcessModuleCache.h" + +#include "clang/Serialization/InMemoryModuleCache.h" +#include "llvm/Support/AdvisoryLock.h" + +#include <mutex> + +using namespace clang; +using namespace tooling; +using namespace dependencies; + +namespace { +class ReaderWriterLock : public llvm::AdvisoryLock { + // TODO: Consider using std::atomic::{wait,notify_all} when we move to C++20. + std::unique_lock<std::shared_mutex> OwningLock; + +public: + ReaderWriterLock(std::shared_mutex &Mutex) + : OwningLock(Mutex, std::defer_lock) {} + + Expected<bool> tryLock() override { return OwningLock.try_lock(); } + + llvm::WaitForUnlockResult + waitForUnlockFor(std::chrono::seconds MaxSeconds) override { + assert(!OwningLock); + // We do not respect the timeout here. It's very generous for implicit + // modules, so we'd typically only reach it if the owner crashed (but so did + // we, since we run in the same process), or encountered deadlock. + (void)MaxSeconds; + std::shared_lock Lock(*OwningLock.mutex()); + return llvm::WaitForUnlockResult::Success; + } + + std::error_code unsafeMaybeUnlock() override { + // Unlocking the mutex here would trigger UB and we don't expect this to be + // actually called when compiling scanning modules due to the no-timeout + // guarantee above. + return {}; + } + + ~ReaderWriterLock() override = default; +}; + +class InProcessModuleCache : public ModuleCache { + ModuleCacheMutexes &Mutexes; + + // TODO: If we changed the InMemoryModuleCache API and relied on strict + // context hash, we could probably create more efficient thread-safe + // implementation of the InMemoryModuleCache such that it does need to be + // recreated for each translation unit. + InMemoryModuleCache InMemory; + +public: + InProcessModuleCache(ModuleCacheMutexes &Mutexes) : Mutexes(Mutexes) {} + + void prepareForGetLock(StringRef Filename) override {} + + std::unique_ptr<llvm::AdvisoryLock> getLock(StringRef Filename) override { + auto &Mtx = [&]() -> std::shared_mutex & { + std::lock_guard Lock(Mutexes.Mutex); + auto &Mutex = Mutexes.Map[Filename]; + if (!Mutex) + Mutex = std::make_unique<std::shared_mutex>(); + return *Mutex; + }(); + return std::make_unique<ReaderWriterLock>(Mtx); + } + + InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; } + const InMemoryModuleCache &getInMemoryModuleCache() const override { + return InMemory; + } +}; +} // namespace + +IntrusiveRefCntPtr<ModuleCache> +dependencies::makeInProcessModuleCache(ModuleCacheMutexes &Mutexes) { + return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Mutexes); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits