Skip to content

[DNM] PR for stress testing #10734

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: stable/20240723
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions clang/include/clang/Serialization/ModuleCache.h
Original file line number Diff line number Diff line change
@@ -12,8 +12,6 @@
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"

#include <ctime>

namespace llvm {
class AdvisoryLock;
} // namespace llvm
@@ -33,23 +31,11 @@ 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;

/// 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;
};
Original file line number Diff line number Diff line change
@@ -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<llvm::cas::ActionCache> Cache,
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> 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<llvm::cas::CachingOnDiskFileSystem> SharedFS;
/// The global file system cache.
std::optional<DependencyScanningFilesystemSharedCache> 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
Original file line number Diff line number Diff line change
@@ -18,18 +18,13 @@
namespace clang {
namespace tooling {
namespace dependencies {
struct ModuleCacheEntry {
std::shared_mutex CompilationMutex;
std::atomic<std::time_t> Timestamp = 0;
};

struct ModuleCacheEntries {
struct ModuleCacheMutexes {
std::mutex Mutex;
llvm::StringMap<std::unique_ptr<ModuleCacheEntry>> Map;
llvm::StringMap<std::unique_ptr<std::shared_mutex>> Map;
};

IntrusiveRefCntPtr<ModuleCache>
makeInProcessModuleCache(ModuleCacheEntries &Entries);
makeInProcessModuleCache(ModuleCacheMutexes &Mutexes);
} // namespace dependencies
} // namespace tooling
} // namespace clang
12 changes: 12 additions & 0 deletions clang/lib/Serialization/ASTCommon.cpp
Original file line number Diff line number Diff line change
@@ -501,3 +501,15 @@ bool serialization::needsAnonymousDeclarationNumber(const NamedDecl *D) {
return false;
return isa<TagDecl, FieldDecl>(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.
}
2 changes: 2 additions & 0 deletions clang/lib/Serialization/ASTCommon.h
Original file line number Diff line number Diff line change
@@ -101,6 +101,8 @@ inline bool isPartOfPerModuleInitializer(const Decl *D) {
return false;
}

void updateModuleTimestamp(StringRef ModuleFilename);

} // namespace serialization

} // namespace clang
3 changes: 1 addition & 2 deletions clang/lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
}

2 changes: 1 addition & 1 deletion clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
@@ -5034,7 +5034,7 @@ ASTWriter::WriteAST(llvm::PointerUnion<Sema *, Preprocessor *> Subject,
if (WritingModule && PPRef.getHeaderSearchInfo()
.getHeaderSearchOpts()
.ModulesValidateOncePerBuildSession)
ModCache.updateModuleTimestamp(OutputFile);
updateModuleTimestamp(OutputFile);

if (ShouldCacheASTInMemory) {
// Construct MemoryBuffer and update buffer manager.
23 changes: 0 additions & 23 deletions clang/lib/Serialization/ModuleCache.cpp
Original file line number Diff line number Diff line change
@@ -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<llvm::LockFileManager>(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;
12 changes: 9 additions & 3 deletions clang/lib/Serialization/ModuleManager.cpp
Original file line number Diff line number Diff line change
@@ -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<llvm::MemoryBuffer> Buffer = lookupBuffer(FileName)) {
Original file line number Diff line number Diff line change
@@ -21,12 +21,10 @@ DependencyScanningService::DependencyScanningService(
std::shared_ptr<llvm::cas::ObjectStore> CAS,
std::shared_ptr<llvm::cas::ActionCache> Cache,
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> 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();

Original file line number Diff line number Diff line change
@@ -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
48 changes: 11 additions & 37 deletions clang/lib/Tooling/DependencyScanning/InProcessModuleCache.cpp
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@

#include "clang/Serialization/InMemoryModuleCache.h"
#include "llvm/Support/AdvisoryLock.h"
#include "llvm/Support/Chrono.h"

#include <mutex>

@@ -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<llvm::AdvisoryLock> getLock(StringRef Filename) override {
auto &CompilationMutex = [&]() -> std::shared_mutex & {
std::lock_guard<std::mutex> Lock(Entries.Mutex);
auto &Entry = Entries.Map[Filename];
if (!Entry)
Entry = std::make_unique<ModuleCacheEntry>();
return Entry->CompilationMutex;
auto &Mtx = [&]() -> std::shared_mutex & {
std::lock_guard<std::mutex> Lock(Mutexes.Mutex);
auto &Mutex = Mutexes.Map[Filename];
if (!Mutex)
Mutex = std::make_unique<std::shared_mutex>();
return *Mutex;
}();
return std::make_unique<ReaderWriterLock>(CompilationMutex);
}

std::time_t getModuleTimestamp(StringRef Filename) override {
auto &Timestamp = [&]() -> std::atomic<std::time_t> & {
std::lock_guard<std::mutex> Lock(Entries.Mutex);
auto &Entry = Entries.Map[Filename];
if (!Entry)
Entry = std::make_unique<ModuleCacheEntry>();
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::time_t> & {
std::lock_guard<std::mutex> Lock(Entries.Mutex);
auto &Entry = Entries.Map[Filename];
if (!Entry)
Entry = std::make_unique<ModuleCacheEntry>();
return Entry->Timestamp;
}();

Timestamp.store(llvm::sys::toTimeT(std::chrono::system_clock::now()));
return std::make_unique<ReaderWriterLock>(Mtx);
}

InMemoryModuleCache &getInMemoryModuleCache() override { return InMemory; }
@@ -108,6 +82,6 @@ class InProcessModuleCache : public ModuleCache {
} // namespace

IntrusiveRefCntPtr<ModuleCache>
dependencies::makeInProcessModuleCache(ModuleCacheEntries &Entries) {
return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Entries);
dependencies::makeInProcessModuleCache(ModuleCacheMutexes &Mutexes) {
return llvm::makeIntrusiveRefCnt<InProcessModuleCache>(Mutexes);
}