diff options
author | Chris Lattner <sabre@nondot.org> | 2010-11-23 22:32:37 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2010-11-23 22:32:37 +0000 |
commit | 5ea7d07d2ab204144f1f36c4673a17a122a514bc (patch) | |
tree | 8a0b9f4fbd36e9420ca3d613c3f6c63c0c0cfd8a /clang/lib/Basic/FileSystemStatCache.cpp | |
parent | 6bf4e6d8b20d25d9263d61d5f9ae1967806a0807 (diff) | |
download | bcm5719-llvm-5ea7d07d2ab204144f1f36c4673a17a122a514bc.tar.gz bcm5719-llvm-5ea7d07d2ab204144f1f36c4673a17a122a514bc.zip |
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.
llvm-svn: 120066
Diffstat (limited to 'clang/lib/Basic/FileSystemStatCache.cpp')
-rw-r--r-- | clang/lib/Basic/FileSystemStatCache.cpp | 41 |
1 files changed, 38 insertions, 3 deletions
diff --git a/clang/lib/Basic/FileSystemStatCache.cpp b/clang/lib/Basic/FileSystemStatCache.cpp index c6b11e9024c..14f762e9887 100644 --- a/clang/lib/Basic/FileSystemStatCache.cpp +++ b/clang/lib/Basic/FileSystemStatCache.cpp @@ -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 @@ using namespace clang; 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) { |