-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang-scan-deps] Fix contention when updating TrackingStatistic
s in hot code paths in FileManager
.
#88427
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
Conversation
…tic`s in hot code paths in `FileManager`.
@llvm/pr-subscribers-clang Author: Alexandre Ganea (aganea) Changes
After this PR, we update these variables iff the user wants to print statistics. On my use case, this saves about 49 sec over 1 min 47 sec of
Without that, there's just too much OS noise from the high volume of Full diff: https://github.com/llvm/llvm-project/pull/88427.diff 8 Files Affected:
diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h
index 2245fd78bfc9f0..24256a7368ccc8 100644
--- a/clang/include/clang/Basic/FileManager.h
+++ b/clang/include/clang/Basic/FileManager.h
@@ -114,6 +114,9 @@ class FileManager : public RefCountedBase<FileManager> {
///
unsigned NextFileUID;
+ /// Whether we want to print statistics. This impacts the collection of data.
+ bool EnablePrintStats;
+
// Caching.
std::unique_ptr<FileSystemStatCache> StatCache;
@@ -134,7 +137,8 @@ class FileManager : public RefCountedBase<FileManager> {
/// \param FS if non-null, the VFS to use. Otherwise uses
/// llvm::vfs::getRealFileSystem().
FileManager(const FileSystemOptions &FileSystemOpts,
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr);
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = nullptr,
+ bool PrintStats = false);
~FileManager();
/// Installs the provided FileSystemStatCache object within
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
index 557f0e547ab4a8..7b869bb7976f2a 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h
@@ -76,7 +76,7 @@ class DependencyScanningService {
DependencyScanningService(
ScanningMode Mode, ScanningOutputFormat Format,
ScanningOptimizations OptimizeArgs = ScanningOptimizations::Default,
- bool EagerLoadModules = false);
+ bool EagerLoadModules = false, bool PrintStats = false);
ScanningMode getMode() const { return Mode; }
@@ -90,6 +90,8 @@ class DependencyScanningService {
return SharedCache;
}
+ bool getPrintStats() const { return PrintStats; }
+
private:
const ScanningMode Mode;
const ScanningOutputFormat Format;
@@ -97,6 +99,8 @@ class DependencyScanningService {
const ScanningOptimizations OptimizeArgs;
/// Whether to set up command-lines to load PCM files eagerly.
const bool EagerLoadModules;
+ /// Whether we should collect statistics during execution.
+ const bool PrintStats;
/// The global file system cache.
DependencyScanningFilesystemSharedCache SharedCache;
};
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index 0f607862194b31..27b96c964ce83d 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -119,6 +119,8 @@ class DependencyScanningWorker {
ScanningOptimizations OptimizeArgs;
/// Whether to set up command-lines to load PCM files eagerly.
bool EagerLoadModules;
+ /// Whether we should collect statistics during execution.
+ bool PrintStats;
};
} // end namespace dependencies
diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp
index cd520a6375e07e..1071f6ae53dd78 100644
--- a/clang/lib/Basic/FileManager.cpp
+++ b/clang/lib/Basic/FileManager.cpp
@@ -50,9 +50,10 @@ ALWAYS_ENABLED_STATISTIC(NumFileCacheMisses, "Number of file cache misses.");
//===----------------------------------------------------------------------===//
FileManager::FileManager(const FileSystemOptions &FSO,
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
+ IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
+ bool PrintStats)
: FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
- SeenFileEntries(64), NextFileUID(0) {
+ SeenFileEntries(64), NextFileUID(0), EnablePrintStats(PrintStats) {
// If the caller doesn't provide a virtual file system, just grab the real
// file system.
if (!this->FS)
@@ -134,7 +135,8 @@ FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) {
}
}
- ++NumDirLookups;
+ if (EnablePrintStats)
+ ++NumDirLookups;
// See if there was already an entry in the map. Note that the map
// contains both virtual and real directories.
@@ -147,7 +149,8 @@ FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) {
}
// We've not seen this before. Fill it in.
- ++NumDirCacheMisses;
+ if (EnablePrintStats)
+ ++NumDirCacheMisses;
auto &NamedDirEnt = *SeenDirInsertResult.first;
assert(!NamedDirEnt.second && "should be newly-created");
@@ -202,7 +205,8 @@ FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
llvm::Expected<FileEntryRef>
FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
- ++NumFileLookups;
+ if (EnablePrintStats)
+ ++NumFileLookups;
// See if there is already an entry in the map.
auto SeenFileInsertResult =
@@ -215,7 +219,8 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
}
// We've not seen this before. Fill it in.
- ++NumFileCacheMisses;
+ if (EnablePrintStats)
+ ++NumFileCacheMisses;
auto *NamedFileEnt = &*SeenFileInsertResult.first;
assert(!NamedFileEnt->second && "should be newly-created");
@@ -377,7 +382,8 @@ const FileEntry *FileManager::getVirtualFile(StringRef Filename, off_t Size,
FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size,
time_t ModificationTime) {
- ++NumFileLookups;
+ if (EnablePrintStats)
+ ++NumFileLookups;
// See if there is already an entry in the map for an existing file.
auto &NamedFileEnt = *SeenFileEntries.insert(
@@ -390,7 +396,8 @@ FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size,
}
// We've not seen this before, or the file is cached as non-existent.
- ++NumFileCacheMisses;
+ if (EnablePrintStats)
+ ++NumFileCacheMisses;
addAncestorsAsVirtualDirs(Filename);
FileEntry *UFE = nullptr;
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 6e3baf83864415..d29bc92a953d66 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -381,7 +381,8 @@ FileManager *CompilerInstance::createFileManager(
: createVFSFromCompilerInvocation(getInvocation(),
getDiagnostics());
assert(VFS && "FileManager has no VFS?");
- FileMgr = new FileManager(getFileSystemOpts(), std::move(VFS));
+ FileMgr = new FileManager(getFileSystemOpts(), std::move(VFS),
+ getFrontendOpts().ShowStats);
return FileMgr.get();
}
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
index 7458ef484b16c4..584066df85aa66 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
@@ -15,9 +15,9 @@ using namespace dependencies;
DependencyScanningService::DependencyScanningService(
ScanningMode Mode, ScanningOutputFormat Format,
- ScanningOptimizations OptimizeArgs, bool EagerLoadModules)
+ ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool PrintStats)
: Mode(Mode), Format(Format), OptimizeArgs(OptimizeArgs),
- EagerLoadModules(EagerLoadModules) {
+ EagerLoadModules(EagerLoadModules), PrintStats(PrintStats) {
// Initialize targets for object file support.
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 32850f5eea92a9..a684ba9cf5ca0e 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -501,6 +501,8 @@ DependencyScanningWorker::DependencyScanningWorker(
BaseFS = FS;
break;
}
+
+ PrintStats = Service.getPrintStats();
}
llvm::Error DependencyScanningWorker::computeDependencies(
@@ -623,8 +625,8 @@ bool DependencyScanningWorker::computeDependencies(
ModifiedCommandLine ? *ModifiedCommandLine : CommandLine;
auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS;
- auto FileMgr =
- llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FinalFS);
+ auto FileMgr = llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{},
+ FinalFS, PrintStats);
std::vector<const char *> FinalCCommandLine(FinalCommandLine.size(), nullptr);
llvm::transform(FinalCommandLine, FinalCCommandLine.begin(),
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index eaa76dd43e41dd..bef96213cd6e54 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -973,7 +973,7 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
};
DependencyScanningService Service(ScanMode, Format, OptimizeArgs,
- EagerLoadModules);
+ EagerLoadModules, PrintTiming);
llvm::Timer T;
T.startTimer();
|
I'd like for @vsapsai to chime in. As an alternative approach: could we turn these into member variables, make them non-atomic and take care to update the stats of the superior |
The bigger idea is that not enabled stats should be negligibly cheap. As for me, the problem is in that not being true. Let me check how we have expensive stats all the time. Extra fixes are good but I'm concerned they help only with these specific stats while others might still cause problems in different contexts. |
I think in the short term @jansvoboda11's suggestion should be good enough. But if we want |
As suggested. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
(Out of interest, what machine are you seeing the contention with?) |
Thanks for the review!
It's a ThreadRipper Pro 3975WX 32c/64t running on Windows 11. |
(BTW: https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it/74223 The recommendation is to avoid the github "hidden email" feature.) |
Thanks for pointing that out @MaskRay ! |
FileManager::getDirectoryRef
andFileManager::getFileRef
are hot code paths inclang-scan-deps
. In these functions, we update a couple of atomic variables related to printing statistics, which causes contention on high core count machines.After this PR, we update these variables iff the user wants to print statistics.
On my use case, this saves about 49 sec over 1 min 47 sec of
clang-scan-deps
run time (1 min 47 sec before, 58 sec after). These figures are after applying my suggestion in #88152 (comment), that is:Without the above, there's just too much OS noise from the high volume of
status()
calls with regular non-modules C++ code. Tested on Windows with clang-cl.