summaryrefslogtreecommitdiffstats
path: root/clang/lib/Basic/FileSystemStatCache.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-11-23 22:32:37 +0000
committerChris Lattner <sabre@nondot.org>2010-11-23 22:32:37 +0000
commit5ea7d07d2ab204144f1f36c4673a17a122a514bc (patch)
tree8a0b9f4fbd36e9420ca3d613c3f6c63c0c0cfd8a /clang/lib/Basic/FileSystemStatCache.cpp
parent6bf4e6d8b20d25d9263d61d5f9ae1967806a0807 (diff)
downloadbcm5719-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.cpp41
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) {
OpenPOWER on IntegriCloud