[clang] [llvm] [llvm][support] Implement tracing virtual file system (PR #88326)
Jan Svoboda via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 12 18:52:26 PDT 2024
https://github.com/jansvoboda11 updated https://github.com/llvm/llvm-project/pull/88326
>From 44791e807564e9c6eb489eccdefb1c0f2647a38a Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Fri, 12 Apr 2024 10:47:13 -0700
Subject: [PATCH] [llvm][support] Implement tracing virtual file system
---
.../DependencyScanningFilesystemTest.cpp | 34 +---------
llvm/include/llvm/Support/VirtualFileSystem.h | 54 ++++++++++++++++
llvm/lib/Support/VirtualFileSystem.cpp | 13 ++++
.../Support/VirtualFileSystemTest.cpp | 64 +++++++++++++++++++
4 files changed, 134 insertions(+), 31 deletions(-)
diff --git a/clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp b/clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp
index 87bb67cfd9327c..691cd3641eb045 100644
--- a/clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp
+++ b/clang/unittests/Tooling/DependencyScanning/DependencyScanningFilesystemTest.cpp
@@ -13,39 +13,11 @@
using namespace clang::tooling::dependencies;
-namespace {
-struct InstrumentingFilesystem
- : llvm::RTTIExtends<InstrumentingFilesystem, llvm::vfs::ProxyFileSystem> {
- unsigned NumStatusCalls = 0;
- unsigned NumGetRealPathCalls = 0;
- unsigned NumExistsCalls = 0;
-
- using llvm::RTTIExtends<InstrumentingFilesystem,
- llvm::vfs::ProxyFileSystem>::RTTIExtends;
-
- llvm::ErrorOr<llvm::vfs::Status> status(const llvm::Twine &Path) override {
- ++NumStatusCalls;
- return ProxyFileSystem::status(Path);
- }
-
- std::error_code getRealPath(const llvm::Twine &Path,
- llvm::SmallVectorImpl<char> &Output) override {
- ++NumGetRealPathCalls;
- return ProxyFileSystem::getRealPath(Path, Output);
- }
-
- bool exists(const llvm::Twine &Path) override {
- ++NumExistsCalls;
- return ProxyFileSystem::exists(Path);
- }
-};
-} // namespace
-
TEST(DependencyScanningWorkerFilesystem, CacheStatusFailures) {
auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
auto InstrumentingFS =
- llvm::makeIntrusiveRefCnt<InstrumentingFilesystem>(InMemoryFS);
+ llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(InMemoryFS);
DependencyScanningFilesystemSharedCache SharedCache;
DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS);
@@ -71,7 +43,7 @@ TEST(DependencyScanningFilesystem, CacheGetRealPath) {
InMemoryFS->addFile("/bar", 0, llvm::MemoryBuffer::getMemBuffer(""));
auto InstrumentingFS =
- llvm::makeIntrusiveRefCnt<InstrumentingFilesystem>(InMemoryFS);
+ llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(InMemoryFS);
DependencyScanningFilesystemSharedCache SharedCache;
DependencyScanningWorkerFilesystem DepFS(SharedCache, InstrumentingFS);
@@ -157,7 +129,7 @@ TEST(DependencyScanningFilesystem, RealPathAndStatusInvariants) {
TEST(DependencyScanningFilesystem, CacheStatOnExists) {
auto InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
auto InstrumentingFS =
- llvm::makeIntrusiveRefCnt<InstrumentingFilesystem>(InMemoryFS);
+ llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(InMemoryFS);
InMemoryFS->setCurrentWorkingDirectory("/");
InMemoryFS->addFile("/foo", 0, llvm::MemoryBuffer::getMemBuffer(""));
InMemoryFS->addFile("/bar", 0, llvm::MemoryBuffer::getMemBuffer(""));
diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h
index 0113d6b7da25d3..f128c123907ef7 100644
--- a/llvm/include/llvm/Support/VirtualFileSystem.h
+++ b/llvm/include/llvm/Support/VirtualFileSystem.h
@@ -1129,6 +1129,60 @@ class YAMLVFSWriter {
void write(llvm::raw_ostream &OS);
};
+/// File system that tracks the number of calls to the underlying file system.
+/// This is particularly useful when wrapped around \c RealFileSystem to add
+/// lightweight tracking of expensive syscalls.
+class TracingFileSystem
+ : public llvm::RTTIExtends<TracingFileSystem, ProxyFileSystem> {
+public:
+ static const char ID;
+
+ std::size_t NumStatusCalls = 0;
+ std::size_t NumOpenFileForReadCalls = 0;
+ std::size_t NumDirBeginCalls = 0;
+ std::size_t NumGetRealPathCalls = 0;
+ std::size_t NumExistsCalls = 0;
+ std::size_t NumIsLocalCalls = 0;
+
+ TracingFileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
+ : RTTIExtends(std::move(FS)) {}
+
+ ErrorOr<Status> status(const Twine &Path) override {
+ ++NumStatusCalls;
+ return ProxyFileSystem::status(Path);
+ }
+
+ ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override {
+ ++NumOpenFileForReadCalls;
+ return ProxyFileSystem::openFileForRead(Path);
+ }
+
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override {
+ ++NumDirBeginCalls;
+ return ProxyFileSystem::dir_begin(Dir, EC);
+ }
+
+ std::error_code getRealPath(const Twine &Path,
+ SmallVectorImpl<char> &Output) override {
+ ++NumGetRealPathCalls;
+ return ProxyFileSystem::getRealPath(Path, Output);
+ }
+
+ bool exists(const Twine &Path) override {
+ ++NumExistsCalls;
+ return ProxyFileSystem::exists(Path);
+ }
+
+ std::error_code isLocal(const Twine &Path, bool &Result) override {
+ ++NumIsLocalCalls;
+ return ProxyFileSystem::isLocal(Path, Result);
+ }
+
+protected:
+ void printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const override;
+};
+
} // namespace vfs
} // namespace llvm
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index 921af30bfcde9f..0c5fe4fdf289d7 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -2933,8 +2933,21 @@ recursive_directory_iterator::increment(std::error_code &EC) {
return *this;
}
+void TracingFileSystem::printImpl(raw_ostream &OS, PrintType Type,
+ unsigned IndentLevel) const {
+ printIndent(OS, IndentLevel);
+ OS << "TracingFileSystem\n";
+ if (Type == PrintType::Summary)
+ return;
+
+ if (Type == PrintType::Contents)
+ Type = PrintType::Summary;
+ getUnderlyingFS().print(OS, Type, IndentLevel + 1);
+}
+
const char FileSystem::ID = 0;
const char OverlayFileSystem::ID = 0;
const char ProxyFileSystem::ID = 0;
const char InMemoryFileSystem::ID = 0;
const char RedirectingFileSystem::ID = 0;
+const char TracingFileSystem::ID = 0;
diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp
index e9b4ac3d92e1dd..d03f43e8126c7d 100644
--- a/llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -3560,3 +3560,67 @@ TEST(RedirectingFileSystemTest, ExistsRedirectOnly) {
EXPECT_FALSE(Redirecting->exists("/b"));
EXPECT_TRUE(Redirecting->exists("/vfile"));
}
+
+TEST(TracingFileSystemTest, TracingWorks) {
+ auto InMemoryFS = makeIntrusiveRefCnt<vfs::InMemoryFileSystem>();
+ auto TracingFS =
+ makeIntrusiveRefCnt<vfs::TracingFileSystem>(std::move(InMemoryFS));
+
+ EXPECT_EQ(TracingFS->NumStatusCalls, 0u);
+ EXPECT_EQ(TracingFS->NumOpenFileForReadCalls, 0u);
+ EXPECT_EQ(TracingFS->NumDirBeginCalls, 0u);
+ EXPECT_EQ(TracingFS->NumGetRealPathCalls, 0u);
+ EXPECT_EQ(TracingFS->NumExistsCalls, 0u);
+ EXPECT_EQ(TracingFS->NumIsLocalCalls, 0u);
+
+ (void)TracingFS->status("/foo");
+ EXPECT_EQ(TracingFS->NumStatusCalls, 1u);
+ EXPECT_EQ(TracingFS->NumOpenFileForReadCalls, 0u);
+ EXPECT_EQ(TracingFS->NumDirBeginCalls, 0u);
+ EXPECT_EQ(TracingFS->NumGetRealPathCalls, 0u);
+ EXPECT_EQ(TracingFS->NumExistsCalls, 0u);
+ EXPECT_EQ(TracingFS->NumIsLocalCalls, 0u);
+
+ (void)TracingFS->openFileForRead("/foo");
+ EXPECT_EQ(TracingFS->NumStatusCalls, 1u);
+ EXPECT_EQ(TracingFS->NumOpenFileForReadCalls, 1u);
+ EXPECT_EQ(TracingFS->NumDirBeginCalls, 0u);
+ EXPECT_EQ(TracingFS->NumGetRealPathCalls, 0u);
+ EXPECT_EQ(TracingFS->NumExistsCalls, 0u);
+ EXPECT_EQ(TracingFS->NumIsLocalCalls, 0u);
+
+ std::error_code EC;
+ (void)TracingFS->dir_begin("/foo", EC);
+ EXPECT_EQ(TracingFS->NumStatusCalls, 1u);
+ EXPECT_EQ(TracingFS->NumOpenFileForReadCalls, 1u);
+ EXPECT_EQ(TracingFS->NumDirBeginCalls, 1u);
+ EXPECT_EQ(TracingFS->NumGetRealPathCalls, 0u);
+ EXPECT_EQ(TracingFS->NumExistsCalls, 0u);
+ EXPECT_EQ(TracingFS->NumIsLocalCalls, 0u);
+
+ SmallString<128> RealPath;
+ (void)TracingFS->getRealPath("/foo", RealPath);
+ EXPECT_EQ(TracingFS->NumStatusCalls, 1u);
+ EXPECT_EQ(TracingFS->NumOpenFileForReadCalls, 1u);
+ EXPECT_EQ(TracingFS->NumDirBeginCalls, 1u);
+ EXPECT_EQ(TracingFS->NumGetRealPathCalls, 1u);
+ EXPECT_EQ(TracingFS->NumExistsCalls, 0u);
+ EXPECT_EQ(TracingFS->NumIsLocalCalls, 0u);
+
+ (void)TracingFS->exists("/foo");
+ EXPECT_EQ(TracingFS->NumStatusCalls, 1u);
+ EXPECT_EQ(TracingFS->NumOpenFileForReadCalls, 1u);
+ EXPECT_EQ(TracingFS->NumDirBeginCalls, 1u);
+ EXPECT_EQ(TracingFS->NumGetRealPathCalls, 1u);
+ EXPECT_EQ(TracingFS->NumExistsCalls, 1u);
+ EXPECT_EQ(TracingFS->NumIsLocalCalls, 0u);
+
+ bool IsLocal;
+ (void)TracingFS->isLocal("/foo", IsLocal);
+ EXPECT_EQ(TracingFS->NumStatusCalls, 1u);
+ EXPECT_EQ(TracingFS->NumOpenFileForReadCalls, 1u);
+ EXPECT_EQ(TracingFS->NumDirBeginCalls, 1u);
+ EXPECT_EQ(TracingFS->NumGetRealPathCalls, 1u);
+ EXPECT_EQ(TracingFS->NumExistsCalls, 1u);
+ EXPECT_EQ(TracingFS->NumIsLocalCalls, 1u);
+}
More information about the llvm-commits
mailing list