https://github.com/jansvoboda11 created https://github.com/llvm/llvm-project/pull/88326
None >From 540321e84dbd3c5687cfcc60e9deec79d790896e Mon Sep 17 00:00:00 2001 From: Jan Svoboda <jan_svob...@apple.com> Date: Wed, 10 Apr 2024 16:03:19 -0700 Subject: [PATCH] [llvm][clang] Trace VFS calls --- clang/include/clang/Driver/Compilation.h | 11 +++++ clang/include/clang/Driver/Options.td | 7 ++++ .../include/clang/Frontend/CompilerInstance.h | 8 ++++ .../clang/Frontend/CompilerInvocation.h | 10 +++-- .../include/clang/Frontend/FrontendOptions.h | 3 ++ clang/lib/Driver/Driver.cpp | 34 ++++++++++++++- clang/lib/Driver/ToolChains/Clang.cpp | 3 ++ clang/lib/Frontend/CompilerInstance.cpp | 2 +- clang/lib/Frontend/CompilerInvocation.cpp | 19 ++++++--- .../DependencyScanningWorker.cpp | 1 + .../DependencyScanning/ModuleDepCollector.cpp | 7 ++++ clang/test/ClangScanDeps/modules-inferred.m | 2 +- clang/tools/clang-scan-deps/ClangScanDeps.cpp | 25 ++++++++++- clang/tools/clang-scan-deps/Opts.td | 1 + clang/tools/driver/cc1_main.cpp | 13 ++++++ llvm/include/llvm/Support/VirtualFileSystem.h | 29 +++++++++++++ llvm/lib/Support/VirtualFileSystem.cpp | 42 +++++++++++++++++++ .../Support/VirtualFileSystemTest.cpp | 37 ++++++++++++++++ 18 files changed, 241 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h index 36ae85c4245143..baf55d6b0f6061 100644 --- a/clang/include/clang/Driver/Compilation.h +++ b/clang/include/clang/Driver/Compilation.h @@ -115,6 +115,9 @@ class Compilation { /// -ftime-trace result files. ArgStringMap TimeTraceFiles; + /// -fvfs-trace result files. + ArgStringMap VFSTraceFiles; + /// Optional redirection for stdin, stdout, stderr. std::vector<std::optional<StringRef>> Redirects; @@ -280,6 +283,14 @@ class Compilation { TimeTraceFiles[JA] = Name; } + const char *getVFSTraceFile(const JobAction *JA) const { + return VFSTraceFiles.lookup(JA); + } + void addVFSTraceFile(const char *Name, const JobAction *JA) { + assert(!VFSTraceFiles.contains(JA)); + VFSTraceFiles[JA] = Name; + } + /// CleanupFile - Delete a given file. /// /// \param IssueErrors - Report failures as errors. diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 0a74e6c75f95bb..630c1c763b5180 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3904,6 +3904,13 @@ def ftime_trace_EQ : Joined<["-"], "ftime-trace=">, Group<f_Group>, HelpText<"Similar to -ftime-trace. Specify the JSON file or a directory which will contain the JSON file">, Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, MarshallingInfoString<FrontendOpts<"TimeTracePath">>; +def fvfs_trace : Flag<["-"], "fvfs-trace">, Group<f_Group>, + HelpText<"Turn of virtual file system profiler. Generates text file based on output filename.">, + Visibility<[ClangOption, CLOption, DXCOption]>; +def fvfs_trace_EQ : Joined<["-"], "fvfs-trace=">, Group<f_Group>, + HelpText<"Similar to -fvfs-trace. Specify the text file or a directory that will contain the text file">, + Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, + MarshallingInfoString<FrontendOpts<"VFSTracePath">>; def fproc_stat_report : Joined<["-"], "fproc-stat-report">, Group<f_Group>, HelpText<"Print subprocess statistics">; def fproc_stat_report_EQ : Joined<["-"], "fproc-stat-report=">, Group<f_Group>, diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index 3464654284f199..2135002366a33a 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -35,6 +35,9 @@ namespace llvm { class raw_fd_ostream; class Timer; class TimerGroup; +namespace vfs { +struct InstrumentingFileSystem; +} } namespace clang { @@ -89,6 +92,11 @@ class CompilerInstance : public ModuleLoader { /// Auxiliary Target info. IntrusiveRefCntPtr<TargetInfo> AuxTarget; +public: + /// The instrumenting file system. + IntrusiveRefCntPtr<llvm::vfs::InstrumentingFileSystem> IVFS; +private: + /// The file manager. IntrusiveRefCntPtr<FileManager> FileMgr; diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 1a2a39411e58d8..b50e7c7da636ec 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -39,6 +39,7 @@ class ArgList; namespace vfs { class FileSystem; +struct InstrumentingFileSystem; } // namespace vfs @@ -390,13 +391,14 @@ class CowCompilerInvocation : public CompilerInvocationBase { /// @} }; -IntrusiveRefCntPtr<llvm::vfs::FileSystem> -createVFSFromCompilerInvocation(const CompilerInvocation &CI, - DiagnosticsEngine &Diags); +IntrusiveRefCntPtr<llvm::vfs::FileSystem> createVFSFromCompilerInvocation( + const CompilerInvocation &CI, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<llvm::vfs::InstrumentingFileSystem> *TracingFS = {}); IntrusiveRefCntPtr<llvm::vfs::FileSystem> createVFSFromCompilerInvocation( const CompilerInvocation &CI, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS); + IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS, + IntrusiveRefCntPtr<llvm::vfs::InstrumentingFileSystem> *TracingFS = {}); IntrusiveRefCntPtr<llvm::vfs::FileSystem> createVFSFromOverlayFiles(ArrayRef<std::string> VFSOverlayFiles, diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 5ee4d471670f48..2cbf8bd7735888 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -568,6 +568,9 @@ class FrontendOptions { /// Path which stores the output files for -ftime-trace std::string TimeTracePath; + /// Path which stores the output files for -fvfs-trace + std::string VFSTracePath; + public: FrontendOptions() : DisableFree(false), RelocatablePCH(false), ShowHelp(false), diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index e7335a61b10c53..9bd13a14f48b6e 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -5429,6 +5429,36 @@ static void handleTimeTrace(Compilation &C, const ArgList &Args, C.addResultFile(ResultFile, JA); } +static void handleVFSTrace(Compilation &C, const ArgList &Args, + const JobAction *JA, const char *BaseInput, + const InputInfo &Result) { + Arg *A = Args.getLastArg(options::OPT_fvfs_trace, options::OPT_fvfs_trace_EQ); + if (!A) + return; + SmallString<128> Path; + if (A->getOption().matches(options::OPT_fvfs_trace_EQ)) { + Path = A->getValue(); + if (llvm::sys::fs::is_directory(Path)) { + SmallString<128> Tmp(Result.getFilename()); + llvm::sys::path::replace_extension(Tmp, "vfs.txt"); + llvm::sys::path::append(Path, llvm::sys::path::filename(Tmp)); + } + } else { + if (Arg *DumpDir = Args.getLastArgNoClaim(options::OPT_dumpdir)) { + // The trace file is ${dumpdir}${basename}.vfs.txt. Note that dumpdir may + // not end with a path separator. + Path = DumpDir->getValue(); + Path += llvm::sys::path::filename(BaseInput); + } else { + Path = Result.getFilename(); + } + llvm::sys::path::replace_extension(Path, "vfs.txt"); + } + const char *ResultFile = C.getArgs().MakeArgString(Path); + C.addVFSTraceFile(ResultFile, JA); + C.addResultFile(ResultFile, JA); +} + InputInfoList Driver::BuildJobsForActionNoCache( Compilation &C, const Action *A, const ToolChain *TC, StringRef BoundArch, bool AtTopLevel, bool MultipleArchs, const char *LinkingOutput, @@ -5678,8 +5708,10 @@ InputInfoList Driver::BuildJobsForActionNoCache( AtTopLevel, MultipleArchs, OffloadingPrefix), BaseInput); - if (T->canEmitIR() && OffloadingPrefix.empty()) + if (T->canEmitIR() && OffloadingPrefix.empty()) { handleTimeTrace(C, Args, JA, BaseInput, Result); + handleVFSTrace(C, Args, JA, BaseInput, Result); + } } if (CCCPrintBindings && !CCGenDiagnostics) { diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 766a9b91e3c0ad..5e179d0497fab0 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -6759,6 +6759,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); } + if (const char *Name = C.getVFSTraceFile(&JA)) + CmdArgs.push_back(Args.MakeArgString("-fvfs-trace=" + Twine(Name))); + if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); CmdArgs.push_back(A->getValue()); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 6e3baf83864415..4620184a5f6b06 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -379,7 +379,7 @@ FileManager *CompilerInstance::createFileManager( if (!VFS) VFS = FileMgr ? &FileMgr->getVirtualFileSystem() : createVFSFromCompilerInvocation(getInvocation(), - getDiagnostics()); + getDiagnostics(), &IVFS); assert(VFS && "FileManager has no VFS?"); FileMgr = new FileManager(getFileSystemOpts(), std::move(VFS)); return FileMgr.get(); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 1f1f5440ddd75f..f6cae9d40591d4 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -4935,16 +4935,25 @@ void CompilerInvocation::clearImplicitModuleBuildOptions() { } IntrusiveRefCntPtr<llvm::vfs::FileSystem> -clang::createVFSFromCompilerInvocation(const CompilerInvocation &CI, - DiagnosticsEngine &Diags) { - return createVFSFromCompilerInvocation(CI, Diags, - llvm::vfs::getRealFileSystem()); +clang::createVFSFromCompilerInvocation( + const CompilerInvocation &CI, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr<llvm::vfs::InstrumentingFileSystem> *TracingFS) { + return createVFSFromCompilerInvocation( + CI, Diags, llvm::vfs::getRealFileSystem(), TracingFS); } IntrusiveRefCntPtr<llvm::vfs::FileSystem> clang::createVFSFromCompilerInvocation( const CompilerInvocation &CI, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) { + IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS, + IntrusiveRefCntPtr<llvm::vfs::InstrumentingFileSystem> *TracingFS) { + if (!CI.getFrontendOpts().VFSTracePath.empty()) { + auto TFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InstrumentingFileSystem>( + std::move(BaseFS)); + if (TracingFS) + *TracingFS = TFS; + BaseFS = std::move(TFS); + } return createVFSFromOverlayFiles(CI.getHeaderSearchOpts().VFSOverlayFiles, Diags, std::move(BaseFS)); } diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 32850f5eea92a9..39f8eb4bbb1e2e 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -338,6 +338,7 @@ class DependencyScanningAction : public tooling::ToolAction { ScanInstance.getFrontendOpts().GenerateGlobalModuleIndex = false; ScanInstance.getFrontendOpts().UseGlobalModuleIndex = false; ScanInstance.getFrontendOpts().ModulesShareFileManager = false; + ScanInstance.getFrontendOpts().VFSTracePath.clear(); ScanInstance.getHeaderSearchOpts().ModuleFormat = "raw"; ScanInstance.getHeaderSearchOpts().ModulesIncludeVFSUsage = any(OptimizeArgs & ScanningOptimizations::VFS); diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp index 94ccbd3351b09d..f8b43c682d5e52 100644 --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -152,6 +152,11 @@ void ModuleDepCollector::addOutputPaths(CowCompilerInvocation &CI, CI.getMutDependencyOutputOpts().Targets.push_back(std::string(Target)); } } + if (!CI.getMutFrontendOpts().VFSTracePath.empty()) { + SmallString<128> VFSTracePath{CI.getMutFrontendOpts().OutputFile}; + llvm::sys::path::replace_extension(VFSTracePath, "vfs.txt"); + CI.getMutFrontendOpts().VFSTracePath = VFSTracePath.str(); + } } static CowCompilerInvocation @@ -186,6 +191,8 @@ makeCommonInvocationForModuleBuild(CompilerInvocation CI) { CI.getDiagnosticOpts().DiagnosticSerializationFile = "-"; if (!CI.getDependencyOutputOpts().OutputFile.empty()) CI.getDependencyOutputOpts().OutputFile = "-"; + if (!CI.getFrontendOpts().VFSTracePath.empty()) + CI.getFrontendOpts().VFSTracePath = "-"; CI.getDependencyOutputOpts().Targets.clear(); CI.getFrontendOpts().ProgramAction = frontend::GenerateModule; diff --git a/clang/test/ClangScanDeps/modules-inferred.m b/clang/test/ClangScanDeps/modules-inferred.m index 4d18a20949205f..a10c7e4d9bde66 100644 --- a/clang/test/ClangScanDeps/modules-inferred.m +++ b/clang/test/ClangScanDeps/modules-inferred.m @@ -21,7 +21,7 @@ [{ "directory": "DIR", "file": "DIR/tu.m", - "command": "clang -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -F DIR/frameworks -c DIR/tu.m -o DIR/tu.o" + "command": "clang -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -F DIR/frameworks -c DIR/tu.m -o DIR/tu.o -fvfs-trace" }] // RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index eaa76dd43e41dd..a8f0e0cf5a7f18 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -84,6 +84,7 @@ static std::vector<std::string> ModuleDepTargets; static bool DeprecatedDriverCommand; static ResourceDirRecipeKind ResourceDirRecipe; static bool Verbose; +static bool PrintVFSTrace; static bool PrintTiming; static std::vector<const char *> CommandLine; @@ -219,6 +220,8 @@ static void ParseArgs(int argc, char **argv) { ResourceDirRecipe = *Kind; } + PrintVFSTrace = Args.hasArg(OPT_vfs_trace); + PrintTiming = Args.hasArg(OPT_print_timing); Verbose = Args.hasArg(OPT_verbose); @@ -886,8 +889,16 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { if (Format == ScanningOutputFormat::Full) FD.emplace(ModuleName.empty() ? Inputs.size() : 0); + std::atomic<std::size_t> NumStatusCalls = 0; + std::atomic<std::size_t> NumOpenCalls = 0; + std::atomic<std::size_t> NumDirBeginCalls = 0; + std::atomic<std::size_t> NumRealPathCalls = 0; + auto ScanningTask = [&](DependencyScanningService &Service) { - DependencyScanningTool WorkerTool(Service); + auto TracingFS = + llvm::makeIntrusiveRefCnt<llvm::vfs::InstrumentingFileSystem>( + llvm::vfs::createPhysicalFileSystem()); + DependencyScanningTool WorkerTool(Service, TracingFS); llvm::DenseSet<ModuleID> AlreadySeenModules; while (auto MaybeInputIndex = GetNextInputIndex()) { @@ -970,6 +981,11 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { HadErrors = true; } } + + NumStatusCalls += TracingFS->NumStatusCalls; + NumOpenCalls += TracingFS->NumOpenCalls; + NumDirBeginCalls += TracingFS->NumDirBeginCalls; + NumRealPathCalls += TracingFS->NumRealPathCalls; }; DependencyScanningService Service(ScanMode, Format, OptimizeArgs, @@ -1001,6 +1017,13 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { "clang-scan-deps timing: %0.2fs wall, %0.2fs process\n", T.getTotalTime().getWallTime(), T.getTotalTime().getProcessTime()); + if (PrintVFSTrace) + llvm::errs() << llvm::format( + "clang-scan-deps VFS trace: %d status, %d openFileForRead, %d " + "dir_begin, %d getRealPath\n", + NumStatusCalls.load(), NumOpenCalls.load(), NumDirBeginCalls.load(), + NumRealPathCalls.load()); + if (RoundTripArgs) if (FD && FD->roundTripCommands(llvm::errs())) HadErrors = true; diff --git a/clang/tools/clang-scan-deps/Opts.td b/clang/tools/clang-scan-deps/Opts.td index 5cd5d1a9fb37bc..07bc72c60d27db 100644 --- a/clang/tools/clang-scan-deps/Opts.td +++ b/clang/tools/clang-scan-deps/Opts.td @@ -31,6 +31,7 @@ def deprecated_driver_command : F<"deprecated-driver-command", "use a single dri defm resource_dir_recipe : Eq<"resource-dir-recipe", "How to produce missing '-resource-dir' argument">; +def vfs_trace: F<"fvfs-trace", "Profile virtual file system calls">; def print_timing : F<"print-timing", "Print timing information">; def verbose : F<"v", "Use verbose output">; diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp index b5c6be3c557bb3..408a942ff1f9b7 100644 --- a/clang/tools/driver/cc1_main.cpp +++ b/clang/tools/driver/cc1_main.cpp @@ -261,6 +261,19 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { } } + if (!Clang->getFrontendOpts().VFSTracePath.empty()) { + assert(Clang->IVFS); + if (auto VFSOutput = Clang->createOutputFile( + Clang->getFrontendOpts().VFSTracePath, /*Binary=*/false, + /*RemoveFileOnSignal=*/false, + /*useTemporary=*/false)) { + *VFSOutput << "status\t" << Clang->IVFS->NumStatusCalls << "\n" + << "openFileForRead\t" << Clang->IVFS->NumOpenCalls << "\n" + << "dir_begin\t" << Clang->IVFS->NumDirBeginCalls << "\n" + << "getRealPath\t" << Clang->IVFS->NumRealPathCalls << "\n"; + } + } + // Our error handler depends on the Diagnostics object, which we're // potentially about to delete. Uninstall the handler now so that any // later errors use the default handling behavior instead. diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h index 770ca8764426a4..e175996ee1c651 100644 --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -26,6 +26,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" +#include <atomic> #include <cassert> #include <cstdint> #include <ctime> @@ -1125,6 +1126,34 @@ 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. +struct InstrumentingFileSystem + : llvm::RTTIExtends<InstrumentingFileSystem, OverlayFileSystem> { + static const char ID; + + std::atomic<std::size_t> NumStatusCalls = 0; + std::atomic<std::size_t> NumOpenCalls = 0; + std::atomic<std::size_t> NumDirBeginCalls = 0; + mutable std::atomic<std::size_t> NumRealPathCalls = 0; + + InstrumentingFileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS); + + ErrorOr<Status> status(const Twine &Path) override; + + ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; + + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const override; + +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 057f8eae0552c6..70bc8c28a18ae4 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -2880,8 +2880,50 @@ recursive_directory_iterator::increment(std::error_code &EC) { return *this; } +InstrumentingFileSystem::InstrumentingFileSystem( + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) + : RTTIExtends(std::move(FS)) {} + +ErrorOr<Status> InstrumentingFileSystem::status(const Twine &Path) { + ++NumStatusCalls; + return OverlayFileSystem::status(Path); +} + +ErrorOr<std::unique_ptr<File>> +InstrumentingFileSystem::openFileForRead(const Twine &Path) { + ++NumOpenCalls; + return OverlayFileSystem::openFileForRead(Path); +} + +directory_iterator InstrumentingFileSystem::dir_begin(const Twine &Dir, + std::error_code &EC) { + ++NumDirBeginCalls; + return OverlayFileSystem::dir_begin(Dir, EC); +} + +std::error_code +InstrumentingFileSystem::getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const { + ++NumRealPathCalls; + return OverlayFileSystem::getRealPath(Path, Output); +} + +void InstrumentingFileSystem::printImpl(raw_ostream &OS, PrintType Type, + unsigned IndentLevel) const { + printIndent(OS, IndentLevel); + OS << "InstrumentingFileSystem\n"; + if (Type == PrintType::Summary) + return; + + if (Type == PrintType::Contents) + Type = PrintType::Summary; + for (const auto &FS : overlays_range()) + FS->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 InstrumentingFileSystem::ID = 0; diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp index 695b09343257f1..604d00b70757e0 100644 --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -3395,3 +3395,40 @@ TEST(RedirectingFileSystemTest, ExternalPaths) { EXPECT_EQ(CheckFS->SeenPaths, Expected); } + +TEST(InstrumentingFileSystemTest, Instrumentation) { + auto InMemoryFS = makeIntrusiveRefCnt<vfs::InMemoryFileSystem>(); + auto InstrumentingFS = + makeIntrusiveRefCnt<vfs::InstrumentingFileSystem>(std::move(InMemoryFS)); + + EXPECT_EQ(InstrumentingFS->NumStatusCalls, 0u); + EXPECT_EQ(InstrumentingFS->NumOpenCalls, 0u); + EXPECT_EQ(InstrumentingFS->NumDirBeginCalls, 0u); + EXPECT_EQ(InstrumentingFS->NumRealPathCalls, 0u); + + (void)InstrumentingFS->status("/foo"); + EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumOpenCalls, 0u); + EXPECT_EQ(InstrumentingFS->NumDirBeginCalls, 0u); + EXPECT_EQ(InstrumentingFS->NumRealPathCalls, 0u); + + (void)InstrumentingFS->openFileForRead("/foo"); + EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumOpenCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumDirBeginCalls, 0u); + EXPECT_EQ(InstrumentingFS->NumRealPathCalls, 0u); + + std::error_code EC; + (void)InstrumentingFS->dir_begin("/foo", EC); + EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumOpenCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumDirBeginCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumRealPathCalls, 0u); + + SmallString<128> RealPath; + (void)InstrumentingFS->getRealPath("/foo", RealPath); + EXPECT_EQ(InstrumentingFS->NumStatusCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumOpenCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumDirBeginCalls, 1u); + EXPECT_EQ(InstrumentingFS->NumRealPathCalls, 1u); +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits