xref: /llvm-project/clang/lib/Basic/FileManager.cpp (revision e2951f48bfb5cbe5d5cbdefaeda43b72a8e7a117)
1 //===--- FileManager.cpp - File System Probing and Caching ----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file implements the FileManager interface.
11 //
12 //===----------------------------------------------------------------------===//
13 //
14 // TODO: This should index all interesting directories with dirent calls.
15 //  getdirentries ?
16 //  opendir/readdir_r/closedir ?
17 //
18 //===----------------------------------------------------------------------===//
19 
20 #include "clang/Basic/FileManager.h"
21 #include "clang/Basic/FileSystemStatCache.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/raw_ostream.h"
26 #include "llvm/Support/Path.h"
27 #include "llvm/Support/system_error.h"
28 #include "llvm/Config/llvm-config.h"
29 #include <map>
30 #include <set>
31 #include <string>
32 
33 // FIXME: This is terrible, we need this for ::close.
34 #if !defined(_MSC_VER) && !defined(__MINGW32__)
35 #include <unistd.h>
36 #include <sys/uio.h>
37 #else
38 #include <io.h>
39 #endif
40 using namespace clang;
41 
42 // FIXME: Enhance libsystem to support inode and other fields.
43 #include <sys/stat.h>
44 
45 /// NON_EXISTENT_DIR - A special value distinct from null that is used to
46 /// represent a dir name that doesn't exist on the disk.
47 #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
48 
49 /// NON_EXISTENT_FILE - A special value distinct from null that is used to
50 /// represent a filename that doesn't exist on the disk.
51 #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
52 
53 
54 FileEntry::~FileEntry() {
55   // If this FileEntry owns an open file descriptor that never got used, close
56   // it.
57   if (FD != -1) ::close(FD);
58 }
59 
60 bool FileEntry::isNamedPipe() const {
61   return FileMode & S_IFIFO;
62 }
63 
64 //===----------------------------------------------------------------------===//
65 // Windows.
66 //===----------------------------------------------------------------------===//
67 
68 #ifdef LLVM_ON_WIN32
69 
70 namespace {
71   static std::string GetFullPath(const char *relPath) {
72     char *absPathStrPtr = _fullpath(NULL, relPath, 0);
73     assert(absPathStrPtr && "_fullpath() returned NULL!");
74 
75     std::string absPath(absPathStrPtr);
76 
77     free(absPathStrPtr);
78     return absPath;
79   }
80 }
81 
82 class FileManager::UniqueDirContainer {
83   /// UniqueDirs - Cache from full path to existing directories/files.
84   ///
85   llvm::StringMap<DirectoryEntry> UniqueDirs;
86 
87 public:
88   /// getDirectory - Return an existing DirectoryEntry with the given
89   /// name if there is already one; otherwise create and return a
90   /// default-constructed DirectoryEntry.
91   DirectoryEntry &getDirectory(const char *Name,
92                                const struct stat & /*StatBuf*/) {
93     std::string FullPath(GetFullPath(Name));
94     return UniqueDirs.GetOrCreateValue(FullPath).getValue();
95   }
96 
97   size_t size() const { return UniqueDirs.size(); }
98 };
99 
100 class FileManager::UniqueFileContainer {
101   /// UniqueFiles - Cache from full path to existing directories/files.
102   ///
103   llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles;
104 
105 public:
106   /// getFile - Return an existing FileEntry with the given name if
107   /// there is already one; otherwise create and return a
108   /// default-constructed FileEntry.
109   FileEntry &getFile(const char *Name, const struct stat & /*StatBuf*/) {
110     std::string FullPath(GetFullPath(Name));
111 
112     // Lowercase string because Windows filesystem is case insensitive.
113     FullPath = StringRef(FullPath).lower();
114     return UniqueFiles.GetOrCreateValue(FullPath).getValue();
115   }
116 
117   size_t size() const { return UniqueFiles.size(); }
118 
119   void erase(const FileEntry *Entry) {
120     std::string FullPath(GetFullPath(Entry->getName()));
121 
122     // Lowercase string because Windows filesystem is case insensitive.
123     FullPath = StringRef(FullPath).lower();
124     UniqueFiles.erase(FullPath);
125   }
126 };
127 
128 //===----------------------------------------------------------------------===//
129 // Unix-like Systems.
130 //===----------------------------------------------------------------------===//
131 
132 #else
133 
134 class FileManager::UniqueDirContainer {
135   /// UniqueDirs - Cache from ID's to existing directories/files.
136   std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
137 
138 public:
139   /// getDirectory - Return an existing DirectoryEntry with the given
140   /// ID's if there is already one; otherwise create and return a
141   /// default-constructed DirectoryEntry.
142   DirectoryEntry &getDirectory(const char * /*Name*/,
143                                const struct stat &StatBuf) {
144     return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
145   }
146 
147   size_t size() const { return UniqueDirs.size(); }
148 };
149 
150 class FileManager::UniqueFileContainer {
151   /// UniqueFiles - Cache from ID's to existing directories/files.
152   std::set<FileEntry> UniqueFiles;
153 
154 public:
155   /// getFile - Return an existing FileEntry with the given ID's if
156   /// there is already one; otherwise create and return a
157   /// default-constructed FileEntry.
158   FileEntry &getFile(const char * /*Name*/, const struct stat &StatBuf) {
159     return
160       const_cast<FileEntry&>(
161                     *UniqueFiles.insert(FileEntry(StatBuf.st_dev,
162                                                   StatBuf.st_ino,
163                                                   StatBuf.st_mode)).first);
164   }
165 
166   size_t size() const { return UniqueFiles.size(); }
167 
168   void erase(const FileEntry *Entry) { UniqueFiles.erase(*Entry); }
169 };
170 
171 #endif
172 
173 //===----------------------------------------------------------------------===//
174 // Common logic.
175 //===----------------------------------------------------------------------===//
176 
177 FileManager::FileManager(const FileSystemOptions &FSO)
178   : FileSystemOpts(FSO),
179     UniqueRealDirs(*new UniqueDirContainer()),
180     UniqueRealFiles(*new UniqueFileContainer()),
181     SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
182   NumDirLookups = NumFileLookups = 0;
183   NumDirCacheMisses = NumFileCacheMisses = 0;
184 }
185 
186 FileManager::~FileManager() {
187   delete &UniqueRealDirs;
188   delete &UniqueRealFiles;
189   for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i)
190     delete VirtualFileEntries[i];
191   for (unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i)
192     delete VirtualDirectoryEntries[i];
193 }
194 
195 void FileManager::addStatCache(FileSystemStatCache *statCache,
196                                bool AtBeginning) {
197   assert(statCache && "No stat cache provided?");
198   if (AtBeginning || StatCache.get() == 0) {
199     statCache->setNextStatCache(StatCache.take());
200     StatCache.reset(statCache);
201     return;
202   }
203 
204   FileSystemStatCache *LastCache = StatCache.get();
205   while (LastCache->getNextStatCache())
206     LastCache = LastCache->getNextStatCache();
207 
208   LastCache->setNextStatCache(statCache);
209 }
210 
211 void FileManager::removeStatCache(FileSystemStatCache *statCache) {
212   if (!statCache)
213     return;
214 
215   if (StatCache.get() == statCache) {
216     // This is the first stat cache.
217     StatCache.reset(StatCache->takeNextStatCache());
218     return;
219   }
220 
221   // Find the stat cache in the list.
222   FileSystemStatCache *PrevCache = StatCache.get();
223   while (PrevCache && PrevCache->getNextStatCache() != statCache)
224     PrevCache = PrevCache->getNextStatCache();
225 
226   assert(PrevCache && "Stat cache not found for removal");
227   PrevCache->setNextStatCache(statCache->getNextStatCache());
228 }
229 
230 void FileManager::clearStatCaches() {
231   StatCache.reset(0);
232 }
233 
234 /// \brief Retrieve the directory that the given file name resides in.
235 /// Filename can point to either a real file or a virtual file.
236 static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
237                                                   StringRef Filename,
238                                                   bool CacheFailure) {
239   if (Filename.empty())
240     return NULL;
241 
242   if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
243     return NULL;  // If Filename is a directory.
244 
245   StringRef DirName = llvm::sys::path::parent_path(Filename);
246   // Use the current directory if file has no path component.
247   if (DirName.empty())
248     DirName = ".";
249 
250   return FileMgr.getDirectory(DirName, CacheFailure);
251 }
252 
253 /// Add all ancestors of the given path (pointing to either a file or
254 /// a directory) as virtual directories.
255 void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
256   StringRef DirName = llvm::sys::path::parent_path(Path);
257   if (DirName.empty())
258     return;
259 
260   llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
261     SeenDirEntries.GetOrCreateValue(DirName);
262 
263   // When caching a virtual directory, we always cache its ancestors
264   // at the same time.  Therefore, if DirName is already in the cache,
265   // we don't need to recurse as its ancestors must also already be in
266   // the cache.
267   if (NamedDirEnt.getValue())
268     return;
269 
270   // Add the virtual directory to the cache.
271   DirectoryEntry *UDE = new DirectoryEntry;
272   UDE->Name = NamedDirEnt.getKeyData();
273   NamedDirEnt.setValue(UDE);
274   VirtualDirectoryEntries.push_back(UDE);
275 
276   // Recursively add the other ancestors.
277   addAncestorsAsVirtualDirs(DirName);
278 }
279 
280 const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
281                                                 bool CacheFailure) {
282   // stat doesn't like trailing separators except for root directory.
283   // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
284   // (though it can strip '\\')
285   if (DirName.size() > 1 &&
286       DirName != llvm::sys::path::root_path(DirName) &&
287       llvm::sys::path::is_separator(DirName.back()))
288     DirName = DirName.substr(0, DirName.size()-1);
289 
290   ++NumDirLookups;
291   llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
292     SeenDirEntries.GetOrCreateValue(DirName);
293 
294   // See if there was already an entry in the map.  Note that the map
295   // contains both virtual and real directories.
296   if (NamedDirEnt.getValue())
297     return NamedDirEnt.getValue() == NON_EXISTENT_DIR
298               ? 0 : NamedDirEnt.getValue();
299 
300   ++NumDirCacheMisses;
301 
302   // By default, initialize it to invalid.
303   NamedDirEnt.setValue(NON_EXISTENT_DIR);
304 
305   // Get the null-terminated directory name as stored as the key of the
306   // SeenDirEntries map.
307   const char *InterndDirName = NamedDirEnt.getKeyData();
308 
309   // Check to see if the directory exists.
310   struct stat StatBuf;
311   if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) {
312     // There's no real directory at the given path.
313     if (!CacheFailure)
314       SeenDirEntries.erase(DirName);
315     return 0;
316   }
317 
318   // It exists.  See if we have already opened a directory with the
319   // same inode (this occurs on Unix-like systems when one dir is
320   // symlinked to another, for example) or the same path (on
321   // Windows).
322   DirectoryEntry &UDE = UniqueRealDirs.getDirectory(InterndDirName, StatBuf);
323 
324   NamedDirEnt.setValue(&UDE);
325   if (!UDE.getName()) {
326     // We don't have this directory yet, add it.  We use the string
327     // key from the SeenDirEntries map as the string.
328     UDE.Name  = InterndDirName;
329   }
330 
331   return &UDE;
332 }
333 
334 const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
335                                       bool CacheFailure) {
336   ++NumFileLookups;
337 
338   // See if there is already an entry in the map.
339   llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
340     SeenFileEntries.GetOrCreateValue(Filename);
341 
342   // See if there is already an entry in the map.
343   if (NamedFileEnt.getValue())
344     return NamedFileEnt.getValue() == NON_EXISTENT_FILE
345                  ? 0 : NamedFileEnt.getValue();
346 
347   ++NumFileCacheMisses;
348 
349   // By default, initialize it to invalid.
350   NamedFileEnt.setValue(NON_EXISTENT_FILE);
351 
352   // Get the null-terminated file name as stored as the key of the
353   // SeenFileEntries map.
354   const char *InterndFileName = NamedFileEnt.getKeyData();
355 
356   // Look up the directory for the file.  When looking up something like
357   // sys/foo.h we'll discover all of the search directories that have a 'sys'
358   // subdirectory.  This will let us avoid having to waste time on known-to-fail
359   // searches when we go to find sys/bar.h, because all the search directories
360   // without a 'sys' subdir will get a cached failure result.
361   const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
362                                                        CacheFailure);
363   if (DirInfo == 0) {  // Directory doesn't exist, file can't exist.
364     if (!CacheFailure)
365       SeenFileEntries.erase(Filename);
366 
367     return 0;
368   }
369 
370   // FIXME: Use the directory info to prune this, before doing the stat syscall.
371   // FIXME: This will reduce the # syscalls.
372 
373   // Nope, there isn't.  Check to see if the file exists.
374   int FileDescriptor = -1;
375   struct stat StatBuf;
376   if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) {
377     // There's no real file at the given path.
378     if (!CacheFailure)
379       SeenFileEntries.erase(Filename);
380 
381     return 0;
382   }
383 
384   if (FileDescriptor != -1 && !openFile) {
385     close(FileDescriptor);
386     FileDescriptor = -1;
387   }
388 
389   // It exists.  See if we have already opened a file with the same inode.
390   // This occurs when one dir is symlinked to another, for example.
391   FileEntry &UFE = UniqueRealFiles.getFile(InterndFileName, StatBuf);
392 
393   NamedFileEnt.setValue(&UFE);
394   if (UFE.getName()) { // Already have an entry with this inode, return it.
395     // If the stat process opened the file, close it to avoid a FD leak.
396     if (FileDescriptor != -1)
397       close(FileDescriptor);
398 
399     return &UFE;
400   }
401 
402   // Otherwise, we don't have this directory yet, add it.
403   // FIXME: Change the name to be a char* that points back to the
404   // 'SeenFileEntries' key.
405   UFE.Name    = InterndFileName;
406   UFE.Size    = StatBuf.st_size;
407   UFE.ModTime = StatBuf.st_mtime;
408   UFE.Dir     = DirInfo;
409   UFE.UID     = NextFileUID++;
410   UFE.FD      = FileDescriptor;
411   return &UFE;
412 }
413 
414 const FileEntry *
415 FileManager::getVirtualFile(StringRef Filename, off_t Size,
416                             time_t ModificationTime) {
417   ++NumFileLookups;
418 
419   // See if there is already an entry in the map.
420   llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
421     SeenFileEntries.GetOrCreateValue(Filename);
422 
423   // See if there is already an entry in the map.
424   if (NamedFileEnt.getValue() && NamedFileEnt.getValue() != NON_EXISTENT_FILE)
425     return NamedFileEnt.getValue();
426 
427   ++NumFileCacheMisses;
428 
429   // By default, initialize it to invalid.
430   NamedFileEnt.setValue(NON_EXISTENT_FILE);
431 
432   addAncestorsAsVirtualDirs(Filename);
433   FileEntry *UFE = 0;
434 
435   // Now that all ancestors of Filename are in the cache, the
436   // following call is guaranteed to find the DirectoryEntry from the
437   // cache.
438   const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
439                                                        /*CacheFailure=*/true);
440   assert(DirInfo &&
441          "The directory of a virtual file should already be in the cache.");
442 
443   // Check to see if the file exists. If so, drop the virtual file
444   int FileDescriptor = -1;
445   struct stat StatBuf;
446   const char *InterndFileName = NamedFileEnt.getKeyData();
447   if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) {
448     // If the stat process opened the file, close it to avoid a FD leak.
449     if (FileDescriptor != -1)
450       close(FileDescriptor);
451 
452     StatBuf.st_size = Size;
453     StatBuf.st_mtime = ModificationTime;
454     UFE = &UniqueRealFiles.getFile(InterndFileName, StatBuf);
455 
456     NamedFileEnt.setValue(UFE);
457 
458     // If we had already opened this file, close it now so we don't
459     // leak the descriptor. We're not going to use the file
460     // descriptor anyway, since this is a virtual file.
461     if (UFE->FD != -1) {
462       close(UFE->FD);
463       UFE->FD = -1;
464     }
465 
466     // If we already have an entry with this inode, return it.
467     if (UFE->getName())
468       return UFE;
469   }
470 
471   if (!UFE) {
472     UFE = new FileEntry();
473     VirtualFileEntries.push_back(UFE);
474     NamedFileEnt.setValue(UFE);
475   }
476 
477   UFE->Name    = InterndFileName;
478   UFE->Size    = Size;
479   UFE->ModTime = ModificationTime;
480   UFE->Dir     = DirInfo;
481   UFE->UID     = NextFileUID++;
482   UFE->FD      = -1;
483   return UFE;
484 }
485 
486 void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
487   StringRef pathRef(path.data(), path.size());
488 
489   if (FileSystemOpts.WorkingDir.empty()
490       || llvm::sys::path::is_absolute(pathRef))
491     return;
492 
493   SmallString<128> NewPath(FileSystemOpts.WorkingDir);
494   llvm::sys::path::append(NewPath, pathRef);
495   path = NewPath;
496 }
497 
498 llvm::MemoryBuffer *FileManager::
499 getBufferForFile(const FileEntry *Entry, std::string *ErrorStr,
500                  bool isVolatile) {
501   OwningPtr<llvm::MemoryBuffer> Result;
502   llvm::error_code ec;
503 
504   uint64_t FileSize = Entry->getSize();
505   // If there's a high enough chance that the file have changed since we
506   // got its size, force a stat before opening it.
507   if (isVolatile)
508     FileSize = -1;
509 
510   const char *Filename = Entry->getName();
511   // If the file is already open, use the open file descriptor.
512   if (Entry->FD != -1) {
513     ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result, FileSize);
514     if (ErrorStr)
515       *ErrorStr = ec.message();
516 
517     close(Entry->FD);
518     Entry->FD = -1;
519     return Result.take();
520   }
521 
522   // Otherwise, open the file.
523 
524   if (FileSystemOpts.WorkingDir.empty()) {
525     ec = llvm::MemoryBuffer::getFile(Filename, Result, FileSize);
526     if (ec && ErrorStr)
527       *ErrorStr = ec.message();
528     return Result.take();
529   }
530 
531   SmallString<128> FilePath(Entry->getName());
532   FixupRelativePath(FilePath);
533   ec = llvm::MemoryBuffer::getFile(FilePath.str(), Result, FileSize);
534   if (ec && ErrorStr)
535     *ErrorStr = ec.message();
536   return Result.take();
537 }
538 
539 llvm::MemoryBuffer *FileManager::
540 getBufferForFile(StringRef Filename, std::string *ErrorStr) {
541   OwningPtr<llvm::MemoryBuffer> Result;
542   llvm::error_code ec;
543   if (FileSystemOpts.WorkingDir.empty()) {
544     ec = llvm::MemoryBuffer::getFile(Filename, Result);
545     if (ec && ErrorStr)
546       *ErrorStr = ec.message();
547     return Result.take();
548   }
549 
550   SmallString<128> FilePath(Filename);
551   FixupRelativePath(FilePath);
552   ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result);
553   if (ec && ErrorStr)
554     *ErrorStr = ec.message();
555   return Result.take();
556 }
557 
558 /// getStatValue - Get the 'stat' information for the specified path,
559 /// using the cache to accelerate it if possible.  This returns true
560 /// if the path points to a virtual file or does not exist, or returns
561 /// false if it's an existent real file.  If FileDescriptor is NULL,
562 /// do directory look-up instead of file look-up.
563 bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
564                                int *FileDescriptor) {
565   // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
566   // absolute!
567   if (FileSystemOpts.WorkingDir.empty())
568     return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
569                                     StatCache.get());
570 
571   SmallString<128> FilePath(Path);
572   FixupRelativePath(FilePath);
573 
574   return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
575                                   StatCache.get());
576 }
577 
578 bool FileManager::getNoncachedStatValue(StringRef Path,
579                                         struct stat &StatBuf) {
580   SmallString<128> FilePath(Path);
581   FixupRelativePath(FilePath);
582 
583   return ::stat(FilePath.c_str(), &StatBuf) != 0;
584 }
585 
586 void FileManager::invalidateCache(const FileEntry *Entry) {
587   assert(Entry && "Cannot invalidate a NULL FileEntry");
588 
589   SeenFileEntries.erase(Entry->getName());
590 
591   // FileEntry invalidation should not block future optimizations in the file
592   // caches. Possible alternatives are cache truncation (invalidate last N) or
593   // invalidation of the whole cache.
594   UniqueRealFiles.erase(Entry);
595 }
596 
597 
598 void FileManager::GetUniqueIDMapping(
599                    SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
600   UIDToFiles.clear();
601   UIDToFiles.resize(NextFileUID);
602 
603   // Map file entries
604   for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
605          FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
606        FE != FEEnd; ++FE)
607     if (FE->getValue() && FE->getValue() != NON_EXISTENT_FILE)
608       UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
609 
610   // Map virtual file entries
611   for (SmallVector<FileEntry*, 4>::const_iterator
612          VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end();
613        VFE != VFEEnd; ++VFE)
614     if (*VFE && *VFE != NON_EXISTENT_FILE)
615       UIDToFiles[(*VFE)->getUID()] = *VFE;
616 }
617 
618 void FileManager::modifyFileEntry(FileEntry *File,
619                                   off_t Size, time_t ModificationTime) {
620   File->Size = Size;
621   File->ModTime = ModificationTime;
622 }
623 
624 
625 void FileManager::PrintStats() const {
626   llvm::errs() << "\n*** File Manager Stats:\n";
627   llvm::errs() << UniqueRealFiles.size() << " real files found, "
628                << UniqueRealDirs.size() << " real dirs found.\n";
629   llvm::errs() << VirtualFileEntries.size() << " virtual files found, "
630                << VirtualDirectoryEntries.size() << " virtual dirs found.\n";
631   llvm::errs() << NumDirLookups << " dir lookups, "
632                << NumDirCacheMisses << " dir cache misses.\n";
633   llvm::errs() << NumFileLookups << " file lookups, "
634                << NumFileCacheMisses << " file cache misses.\n";
635 
636   //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
637 }
638