[cfe-commits] r120066 - in /cfe/trunk: include/clang/Basic/FileManager.h lib/Basic/FileManager.cpp lib/Basic/FileSystemStatCache.cpp

Chris Lattner sabre at nondot.org
Tue Nov 23 14:32:37 PST 2010


Author: lattner
Date: Tue Nov 23 16:32:37 2010
New Revision: 120066

URL: http://llvm.org/viewvc/llvm-project?rev=120066&view=rev
Log:
The final result of all this refactoring: instead of doing stat immediately
followed by an open for every source file we open, probe the file system with
'open' and then do an fstat when it succeeds.  open+fstat is faster than
stat+open because the kernel only has to perform the string->inode mapping
once.  Presumably it gets faster the deeper in your filesystem a lookup
happens.

For -Eonly on cocoa.h, this reduces system time from 0.042s to 0.039s on
my machine, a 7.7% speedup.


Modified:
    cfe/trunk/include/clang/Basic/FileManager.h
    cfe/trunk/lib/Basic/FileManager.cpp
    cfe/trunk/lib/Basic/FileSystemStatCache.cpp

Modified: cfe/trunk/include/clang/Basic/FileManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/FileManager.h?rev=120066&r1=120065&r2=120066&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/FileManager.h (original)
+++ cfe/trunk/include/clang/Basic/FileManager.h Tue Nov 23 16:32:37 2010
@@ -61,7 +61,7 @@
   
   /// FD - The file descriptor for the file entry if it is opened and owned
   /// by the FileEntry.  If not, this is set to -1.
-  int FD;
+  mutable int FD;
   friend class FileManager;
   
   void operator=(const FileEntry&); // DO NOT IMPLEMENT.

Modified: cfe/trunk/lib/Basic/FileManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileManager.cpp?rev=120066&r1=120065&r2=120066&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/FileManager.cpp (original)
+++ cfe/trunk/lib/Basic/FileManager.cpp Tue Nov 23 16:32:37 2010
@@ -400,11 +400,24 @@
 
 llvm::MemoryBuffer *FileManager::
 getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
-  llvm::StringRef Filename = Entry->getName();
-  if (FileSystemOpts.WorkingDir.empty())
+  if (FileSystemOpts.WorkingDir.empty()) {
+    const char *Filename = Entry->getName();
+    // If the file is already open, use the open file descriptor.
+    if (Entry->FD != -1) {
+      llvm::MemoryBuffer *Buf =
+        llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, ErrorStr,
+                                        Entry->getSize());
+      // getOpenFile will have closed the file descriptor, don't reuse or
+      // reclose it.
+      Entry->FD = -1;
+      return Buf;
+    }
+
+    // Otherwise, open the file.
     return llvm::MemoryBuffer::getFile(Filename, ErrorStr, Entry->getSize());
+  }
   
-  llvm::sys::Path FilePath(Filename);
+  llvm::sys::Path FilePath(Entry->getName());
   FixupRelativePath(FilePath, FileSystemOpts);
   return llvm::MemoryBuffer::getFile(FilePath.c_str(), ErrorStr,
                                      Entry->getSize());

Modified: cfe/trunk/lib/Basic/FileSystemStatCache.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/FileSystemStatCache.cpp?rev=120066&r1=120065&r2=120066&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/FileSystemStatCache.cpp (original)
+++ cfe/trunk/lib/Basic/FileSystemStatCache.cpp Tue Nov 23 16:32:37 2010
@@ -13,6 +13,7 @@
 
 #include "clang/Basic/FileSystemStatCache.h"
 #include "llvm/System/Path.h"
+#include <fcntl.h>
 
 // FIXME: This is terrible, we need this for ::close.
 #if !defined(_MSC_VER) && !defined(__MINGW32__)
@@ -39,18 +40,52 @@
 bool FileSystemStatCache::get(const char *Path, struct stat &StatBuf,
                               int *FileDescriptor, FileSystemStatCache *Cache) {
   LookupResult R;
-  
+  bool isForDir = FileDescriptor == 0;
+
+  // If we have a cache, use it to resolve the stat query.
   if (Cache)
     R = Cache->getStat(Path, StatBuf, FileDescriptor);
-  else
+  else if (isForDir) {
+    // If this is a directory and we have no cache, just go to the file system.
     R = ::stat(Path, &StatBuf) != 0 ? CacheMissing : CacheExists;
+  } else {
+    // Otherwise, we have to go to the filesystem.  We can always just use
+    // 'stat' here, but (for files) the client is asking whether the file exists
+    // because it wants to turn around and *open* it.  It is more efficient to
+    // do "open+fstat" on success than it is to do "stat+open".
+    //
+    // Because of this, check to see if the file exists with 'open'.  If the
+    // open succeeds, use fstat to get the stat info.
+    int OpenFlags = O_RDONLY;
+#ifdef O_BINARY
+    OpenFlags |= O_BINARY;  // Open input file in binary mode on win32.
+#endif
+    *FileDescriptor = ::open(Path, OpenFlags);
+    
+    if (*FileDescriptor == -1) {
+      // If the open fails, our "stat" fails.
+      R = CacheMissing;
+    } else {
+      // Otherwise, the open succeeded.  Do an fstat to get the information
+      // about the file.  We'll end up returning the open file descriptor to the
+      // client to do what they please with it.
+      if (::fstat(*FileDescriptor, &StatBuf) == 0)
+        R = CacheExists;
+      else {
+        // fstat rarely fails.  If it does, claim the initial open didn't
+        // succeed.
+        R = CacheMissing;
+        ::close(*FileDescriptor);
+        *FileDescriptor = -1;
+      }
+    }
+  }
 
   // If the path doesn't exist, return failure.
   if (R == CacheMissing) return true;
   
   // If the path exists, make sure that its "directoryness" matches the clients
   // demands.
-  bool isForDir = FileDescriptor == 0;
   if (S_ISDIR(StatBuf.st_mode) != isForDir) {
     // If not, close the file if opened.
     if (FileDescriptor && *FileDescriptor != -1) {





More information about the cfe-commits mailing list