зеркало из https://github.com/microsoft/clang.git
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@120066 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
fe4ea55700
Коммит
5cc1c738b0
|
@ -61,7 +61,7 @@ class FileEntry {
|
|||
|
||||
/// 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.
|
||||
|
|
|
@ -400,11 +400,24 @@ void FileManager::FixupRelativePath(llvm::sys::Path &path,
|
|||
|
||||
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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче