Skip to content

Commit 96a972f

Browse files
committed
[clang][deps] Print tracing VFS data (llvm#108056)
Clang's `-cc1 -print-stats` shows lots of useful internal data including basic `FileManager` stats. Since this layer caches some results, it is unclear how that information translates to actual filesystem accesses. This PR uses `llvm::vfs::TracingFileSystem` to provide that missing information. Similar mechanism is implemented for `clang-scan-deps`'s verbose mode (`-v`). IO contention proved to be a real bottleneck a couple of times already and this new feature should make those easier to detect in the future. The tracing VFS is inserted below the caching FS and above the real FS. (cherry picked from commit 6e4dcbb)
1 parent 4a906ad commit 96a972f

File tree

10 files changed

+102
-4
lines changed

10 files changed

+102
-4
lines changed

clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ class DependencyScanningService {
9696
std::shared_ptr<llvm::cas::ActionCache> Cache,
9797
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> SharedFS,
9898
ScanningOptimizations OptimizeArgs = ScanningOptimizations::Default,
99-
bool EagerLoadModules = false);
99+
bool EagerLoadModules = false, bool TraceVFS = false);
100100

101101
ScanningMode getMode() const { return Mode; }
102102

@@ -106,6 +106,8 @@ class DependencyScanningService {
106106

107107
bool shouldEagerLoadModules() const { return EagerLoadModules; }
108108

109+
bool shouldTraceVFS() const { return TraceVFS; }
110+
109111
DependencyScanningFilesystemSharedCache &getSharedCache() {
110112
assert(!SharedFS && "Expected not to have a CASFS");
111113
assert(SharedCache && "Expected a shared cache");
@@ -131,6 +133,8 @@ class DependencyScanningService {
131133
const ScanningOptimizations OptimizeArgs;
132134
/// Whether to set up command-lines to load PCM files eagerly.
133135
const bool EagerLoadModules;
136+
/// Whether to trace VFS accesses.
137+
const bool TraceVFS;
134138
/// Shared CachingOnDiskFileSystem. Set to nullptr to not use CAS dependency
135139
/// scanning.
136140
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> SharedFS;

clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ class DependencyScanningTool {
191191
StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,
192192
LookupModuleOutputCallback LookupModuleOutput);
193193

194+
llvm::vfs::FileSystem &getWorkerVFS() const { return Worker.getVFS(); }
195+
194196
ScanningOutputFormat getScanningFormat() const {
195197
return Worker.getScanningFormat();
196198
}

clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ class DependencyScanningWorker {
162162

163163
bool shouldEagerLoadModules() const { return EagerLoadModules; }
164164

165+
llvm::vfs::FileSystem &getVFS() const { return *BaseFS; }
166+
165167
private:
166168
std::shared_ptr<PCHContainerOperations> PCHContainerOps;
167169
/// The file system to be used during the scan.

clang/lib/Basic/FileManager.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,5 +711,16 @@ void FileManager::PrintStats() const {
711711
llvm::errs() << NumFileLookups << " file lookups, "
712712
<< NumFileCacheMisses << " file cache misses.\n";
713713

714+
getVirtualFileSystem().visit([](llvm::vfs::FileSystem &VFS) {
715+
if (auto *T = dyn_cast_or_null<llvm::vfs::TracingFileSystem>(&VFS))
716+
llvm::errs() << "\n*** Virtual File System Stats:\n"
717+
<< T->NumStatusCalls << " status() calls\n"
718+
<< T->NumOpenFileForReadCalls << " openFileForRead() calls\n"
719+
<< T->NumDirBeginCalls << " dir_begin() calls\n"
720+
<< T->NumGetRealPathCalls << " getRealPath() calls\n"
721+
<< T->NumExistsCalls << " exists() calls\n"
722+
<< T->NumIsLocalCalls << " isLocal() calls\n";
723+
});
724+
714725
//llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
715726
}

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,9 @@ FileManager *CompilerInstance::createFileManager(
397397
: createVFSFromCompilerInvocation(getInvocation(),
398398
getDiagnostics(), CAS);
399399
assert(VFS && "FileManager has no VFS?");
400+
if (getFrontendOpts().ShowStats)
401+
VFS =
402+
llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(std::move(VFS));
400403
FileMgr = new FileManager(getFileSystemOpts(), std::move(VFS));
401404
return FileMgr.get();
402405
}

clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ DependencyScanningService::DependencyScanningService(
2121
std::shared_ptr<llvm::cas::ObjectStore> CAS,
2222
std::shared_ptr<llvm::cas::ActionCache> Cache,
2323
IntrusiveRefCntPtr<llvm::cas::CachingOnDiskFileSystem> SharedFS,
24-
ScanningOptimizations OptimizeArgs, bool EagerLoadModules)
24+
ScanningOptimizations OptimizeArgs, bool EagerLoadModules, bool TraceVFS)
2525
: Mode(Mode), Format(Format), CASOpts(std::move(CASOpts)), CAS(std::move(CAS)), Cache(std::move(Cache)),
26-
OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules),
26+
OptimizeArgs(OptimizeArgs), EagerLoadModules(EagerLoadModules), TraceVFS(TraceVFS),
2727
SharedFS(std::move(SharedFS)) {
2828
if (!this->SharedFS)
2929
SharedCache.emplace();

clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,9 @@ DependencyScanningWorker::DependencyScanningWorker(
711711
// The scanner itself writes only raw ast files.
712712
PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
713713

714+
if (Service.shouldTraceVFS())
715+
FS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(std::move(FS));
716+
714717
if (Service.useCASFS()) {
715718
CacheFS = Service.getSharedFS().createProxyFS();
716719
DepCASFS = new DependencyScanningCASFilesystem(CacheFS, *Service.getCache());

clang/test/ClangScanDeps/verbose.test

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.in > %t/cdb.json
4+
5+
// RUN: clang-scan-deps -compilation-database %t/cdb.json -v -o %t/result.json 2>&1 | FileCheck %s
6+
// CHECK: *** Virtual File System Stats:
7+
// CHECK-NEXT: {{[[:digit:]]+}} status() calls
8+
// CHECK-NEXT: {{[[:digit:]]+}} openFileForRead() calls
9+
// CHECK-NEXT: {{[[:digit:]]+}} dir_begin() calls
10+
// CHECK-NEXT: {{[[:digit:]]+}} getRealPath() calls
11+
// CHECK-NEXT: {{[[:digit:]]+}} exists() calls
12+
// CHECK-NEXT: {{[[:digit:]]+}} isLocal() calls
13+
14+
//--- tu.c
15+
16+
//--- cdb.json.in
17+
[
18+
{
19+
"file": "DIR/tu.c"
20+
"directory": "DIR",
21+
"command": "clang -c DIR/tu.c -o DIR/tu.o"
22+
},
23+
{
24+
"file": "DIR/tu.c"
25+
"directory": "DIR",
26+
"command": "clang -c DIR/tu.c -o DIR/tu.o"
27+
}
28+
]

clang/test/Misc/print-stats-vfs.test

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
4+
// RUN: %clang_cc1 -fsyntax-only %t/tu.c -I %t/dir1 -I %t/dir2 -print-stats 2>&1 | FileCheck %s
5+
6+
//--- tu.c
7+
#include "header.h"
8+
//--- dir1/other.h
9+
//--- dir2/header.h
10+
11+
// CHECK: *** Virtual File System Stats:
12+
// CHECK-NEXT: {{[[:digit:]]+}} status() calls
13+
// CHECK-NEXT: {{[[:digit:]]+}} openFileForRead() calls
14+
// CHECK-NEXT: {{[[:digit:]]+}} dir_begin() calls
15+
// CHECK-NEXT: {{[[:digit:]]+}} getRealPath() calls
16+
// CHECK-NEXT: {{[[:digit:]]+}} exists() calls
17+
// CHECK-NEXT: {{[[:digit:]]+}} isLocal() calls

clang/tools/clang-scan-deps/ClangScanDeps.cpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,13 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
12751275
Format == ScanningOutputFormat::FullTree)
12761276
FD.emplace(ModuleName.empty() ? Inputs.size() : 0);
12771277

1278+
std::atomic<size_t> NumStatusCalls = 0;
1279+
std::atomic<size_t> NumOpenFileForReadCalls = 0;
1280+
std::atomic<size_t> NumDirBeginCalls = 0;
1281+
std::atomic<size_t> NumGetRealPathCalls = 0;
1282+
std::atomic<size_t> NumExistsCalls = 0;
1283+
std::atomic<size_t> NumIsLocalCalls = 0;
1284+
12781285
auto ScanningTask = [&](DependencyScanningService &Service) {
12791286
std::unique_ptr<llvm::vfs::FileSystem> FS = llvm::vfs::createPhysicalFileSystem();
12801287
if (CAS)
@@ -1373,10 +1380,21 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
13731380
HadErrors = true;
13741381
}
13751382
}
1383+
1384+
WorkerTool.getWorkerVFS().visit([&](llvm::vfs::FileSystem &VFS) {
1385+
if (auto *T = dyn_cast_or_null<llvm::vfs::TracingFileSystem>(&VFS)) {
1386+
NumStatusCalls += T->NumStatusCalls;
1387+
NumOpenFileForReadCalls += T->NumOpenFileForReadCalls;
1388+
NumDirBeginCalls += T->NumDirBeginCalls;
1389+
NumGetRealPathCalls += T->NumGetRealPathCalls;
1390+
NumExistsCalls += T->NumExistsCalls;
1391+
NumIsLocalCalls += T->NumIsLocalCalls;
1392+
}
1393+
});
13761394
};
13771395

13781396
DependencyScanningService Service(ScanMode, Format, CASOpts, CAS, Cache, FS,
1379-
OptimizeArgs, EagerLoadModules);
1397+
OptimizeArgs, EagerLoadModules, /*TraceVFS=*/Verbose);
13801398

13811399
llvm::Timer T;
13821400
T.startTimer();
@@ -1398,6 +1416,16 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
13981416
}
13991417

14001418
T.stopTimer();
1419+
1420+
if (Verbose)
1421+
llvm::errs() << "\n*** Virtual File System Stats:\n"
1422+
<< NumStatusCalls << " status() calls\n"
1423+
<< NumOpenFileForReadCalls << " openFileForRead() calls\n"
1424+
<< NumDirBeginCalls << " dir_begin() calls\n"
1425+
<< NumGetRealPathCalls << " getRealPath() calls\n"
1426+
<< NumExistsCalls << " exists() calls\n"
1427+
<< NumIsLocalCalls << " isLocal() calls\n";
1428+
14011429
if (PrintTiming) {
14021430
llvm::errs() << "wall time [s]\t"
14031431
<< "process time [s]\t"

0 commit comments

Comments
 (0)