зеркало из https://github.com/microsoft/clang-1.git
PTH: Cache directory and negative 'stat' calls. This gives us a 1% performance improvement on Cocoa.h (fsyntax-only+PTH).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64490 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
f161d4155f
Коммит
ad6ce5cb0e
|
@ -207,25 +207,23 @@ public:
|
|||
|
||||
|
||||
class VISIBILITY_HIDDEN PTHEntryKeyVariant {
|
||||
union { const FileEntry* FE; const DirectoryEntry* DE; const char* Path; };
|
||||
union { const FileEntry* FE; const char* Path; };
|
||||
enum { IsFE = 0x1, IsDE = 0x2, IsNoExist = 0x0 } Kind;
|
||||
struct stat *StatBuf;
|
||||
public:
|
||||
PTHEntryKeyVariant(const FileEntry *fe) : FE(fe), Kind(IsFE) {}
|
||||
PTHEntryKeyVariant(const DirectoryEntry *de) : DE(de), Kind(IsDE) {}
|
||||
PTHEntryKeyVariant(const char* path) : Path(path), Kind(IsNoExist) {}
|
||||
PTHEntryKeyVariant(const FileEntry *fe)
|
||||
: FE(fe), Kind(IsFE), StatBuf(0) {}
|
||||
|
||||
const FileEntry *getFile() const { return Kind == IsFE ? FE : 0; }
|
||||
const DirectoryEntry *getDir() const { return Kind == IsDE ? DE : 0; }
|
||||
const char* getNameOfNonExistantFile() const {
|
||||
return Kind == IsNoExist ? Path : 0;
|
||||
}
|
||||
PTHEntryKeyVariant(struct stat* statbuf, const char* path)
|
||||
: Path(path), Kind(IsDE), StatBuf(new struct stat(*statbuf)) {}
|
||||
|
||||
PTHEntryKeyVariant(const char* path)
|
||||
: Path(path), Kind(IsNoExist), StatBuf(0) {}
|
||||
|
||||
bool isFile() const { return Kind == IsFE; }
|
||||
|
||||
const char* getCString() const {
|
||||
switch (Kind) {
|
||||
case IsFE: return FE->getName();
|
||||
case IsDE: return DE->getName();
|
||||
default: return Path;
|
||||
}
|
||||
return Kind == IsFE ? FE->getName() : Path;
|
||||
}
|
||||
|
||||
unsigned getKind() const { return (unsigned) Kind; }
|
||||
|
@ -241,18 +239,21 @@ public:
|
|||
::Emit64(Out, FE->getSize());
|
||||
break;
|
||||
case IsDE:
|
||||
// FIXME
|
||||
default: break;
|
||||
// Emit nothing.
|
||||
// Emit stat information.
|
||||
::Emit32(Out, (uint32_t) StatBuf->st_ino);
|
||||
::Emit32(Out, (uint32_t) StatBuf->st_dev);
|
||||
::Emit16(Out, (uint16_t) StatBuf->st_mode);
|
||||
::Emit64(Out, (uint64_t) StatBuf->st_mtime);
|
||||
::Emit64(Out, (uint64_t) StatBuf->st_size);
|
||||
delete StatBuf;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned getRepresentationLength() const {
|
||||
switch (Kind) {
|
||||
case IsFE: return 4 + 4 + 2 + 8 + 8;
|
||||
case IsDE: // FIXME
|
||||
default: return 0;
|
||||
}
|
||||
return Kind == IsNoExist ? 0 : 4 + 4 + 2 + 8 + 8;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -275,7 +276,7 @@ public:
|
|||
unsigned n = strlen(V.getCString()) + 1 + 1;
|
||||
::Emit16(Out, n);
|
||||
|
||||
unsigned m = V.getRepresentationLength() + (V.getFile() ? 4 + 4 : 0);
|
||||
unsigned m = V.getRepresentationLength() + (V.isFile() ? 4 + 4 : 0);
|
||||
::Emit8(Out, m);
|
||||
|
||||
return std::make_pair(n, m);
|
||||
|
@ -294,7 +295,7 @@ public:
|
|||
|
||||
// For file entries emit the offsets into the PTH file for token data
|
||||
// and the preprocessor blocks table.
|
||||
if (V.getFile()) {
|
||||
if (V.isFile()) {
|
||||
::Emit32(Out, E.getTokenOffset());
|
||||
::Emit32(Out, E.getPPCondTableOffset());
|
||||
}
|
||||
|
@ -368,11 +369,43 @@ class VISIBILITY_HIDDEN PTHWriter {
|
|||
PTHEntry LexTokens(Lexer& L);
|
||||
Offset EmitCachedSpellings();
|
||||
|
||||
/// StatListener - A simple "interpose" object used to monitor stat calls
|
||||
/// invoked by FileManager while processing the original sources used
|
||||
/// as input to PTH generation. StatListener populates the PTHWriter's
|
||||
/// file map with stat information for directories as well as negative stats.
|
||||
/// Stat information for files are populated elsewhere.
|
||||
class StatListener : public StatSysCallCache {
|
||||
PTHMap& PM;
|
||||
public:
|
||||
StatListener(PTHMap& pm) : PM(pm) {}
|
||||
~StatListener() {}
|
||||
|
||||
int stat(const char *path, struct stat *buf) {
|
||||
int result = ::stat(path, buf);
|
||||
|
||||
if (result != 0) // Failed 'stat'.
|
||||
PM.insert(path, PTHEntry());
|
||||
else if (S_ISDIR(buf->st_mode)) {
|
||||
// Only cache directories with absolute paths.
|
||||
if (!llvm::sys::Path(path).isAbsolute())
|
||||
return result;
|
||||
|
||||
PM.insert(PTHEntryKeyVariant(buf, path), PTHEntry());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
PTHWriter(llvm::raw_fd_ostream& out, Preprocessor& pp)
|
||||
: Out(out), PP(pp), idcount(0), CurStrOffset(0) {}
|
||||
|
||||
void GeneratePTH();
|
||||
|
||||
StatSysCallCache *createStatListener() {
|
||||
return new StatListener(PM);
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
|
@ -642,12 +675,6 @@ void PTHWriter::GeneratePTH() {
|
|||
}
|
||||
|
||||
void clang::CacheTokens(Preprocessor& PP, const std::string& OutFile) {
|
||||
// Lex through the entire file. This will populate SourceManager with
|
||||
// all of the header information.
|
||||
Token Tok;
|
||||
PP.EnterMainSourceFile();
|
||||
do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
|
||||
|
||||
// Open up the PTH file.
|
||||
std::string ErrMsg;
|
||||
llvm::raw_fd_ostream Out(OutFile.c_str(), true, ErrMsg);
|
||||
|
@ -657,8 +684,22 @@ void clang::CacheTokens(Preprocessor& PP, const std::string& OutFile) {
|
|||
return;
|
||||
}
|
||||
|
||||
// Create the PTHWriter and generate the PTH file.
|
||||
// Create the PTHWriter.
|
||||
PTHWriter PW(Out, PP);
|
||||
|
||||
// Install the 'stat' system call listener in the FileManager.
|
||||
PP.getFileManager().setStatCache(PW.createStatListener());
|
||||
|
||||
// Lex through the entire file. This will populate SourceManager with
|
||||
// all of the header information.
|
||||
Token Tok;
|
||||
PP.EnterMainSourceFile();
|
||||
do { PP.Lex(Tok); } while (Tok.isNot(tok::eof));
|
||||
|
||||
|
||||
|
||||
// Generate the PTH file.
|
||||
PP.getFileManager().setStatCache(0);
|
||||
PW.GeneratePTH();
|
||||
}
|
||||
|
||||
|
@ -750,5 +791,3 @@ std::pair<Offset,Offset> PTHWriter::EmitIdentifierTable() {
|
|||
|
||||
return std::make_pair(IDOff, StringTableOffset);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -808,8 +808,9 @@ public:
|
|||
|
||||
static data_type ReadData(const internal_key_type& k, const unsigned char* d,
|
||||
unsigned) {
|
||||
if (k.first == 0x1 /* File */) {
|
||||
d += 4 * 2; // Skip the first 2 words.
|
||||
|
||||
if (k.first /* File or Directory */) {
|
||||
if (k.first == 0x1 /* File */) d += 4 * 2; // Skip the first 2 words.
|
||||
ino_t ino = (ino_t) ReadUnalignedLE32(d);
|
||||
dev_t dev = (dev_t) ReadUnalignedLE32(d);
|
||||
mode_t mode = (mode_t) ReadUnalignedLE16(d);
|
||||
|
@ -817,6 +818,7 @@ public:
|
|||
return data_type(ino, dev, mode, mtime, (off_t) ReadUnalignedLE64(d));
|
||||
}
|
||||
|
||||
// Negative stat. Don't read anything.
|
||||
return data_type();
|
||||
}
|
||||
};
|
||||
|
@ -841,6 +843,10 @@ public:
|
|||
if (I == Cache.end()) return ::stat(path, buf);
|
||||
|
||||
const PTHStatData& Data = *I;
|
||||
|
||||
if (!Data.hasStat)
|
||||
return 1;
|
||||
|
||||
buf->st_ino = Data.ino;
|
||||
buf->st_dev = Data.dev;
|
||||
buf->st_mtime = Data.mtime;
|
||||
|
|
Загрузка…
Ссылка в новой задаче