[cfe-commits] r64353 - in /cfe/trunk: Driver/CacheTokens.cpp include/clang/Lex/PTHManager.h include/clang/Lex/Preprocessor.h lib/Lex/PTHLexer.cpp lib/Lex/Preprocessor.cpp

Ted Kremenek kremenek at apple.com
Wed Feb 11 19:26:59 PST 2009


Author: kremenek
Date: Wed Feb 11 21:26:59 2009
New Revision: 64353

URL: http://llvm.org/viewvc/llvm-project?rev=64353&view=rev
Log:
PTH: Cache stat information for files in the PTH file.  Hook up FileManager
 to use this stat information in the PTH file using a 'StatSysCallCache' object.

Performance impact (Cocoa.h, PTH):
- number of stat calls reduces from 1230 to 425
- fsyntax-only: time improves by 4.2% 

We can reduce the number of stat calls to almost zero by caching negative stat
calls and directory stat calls in the PTH file as well.


Modified:
    cfe/trunk/Driver/CacheTokens.cpp
    cfe/trunk/include/clang/Lex/PTHManager.h
    cfe/trunk/include/clang/Lex/Preprocessor.h
    cfe/trunk/lib/Lex/PTHLexer.cpp
    cfe/trunk/lib/Lex/Preprocessor.cpp

Modified: cfe/trunk/Driver/CacheTokens.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/CacheTokens.cpp?rev=64353&r1=64352&r2=64353&view=diff

==============================================================================
--- cfe/trunk/Driver/CacheTokens.cpp (original)
+++ cfe/trunk/Driver/CacheTokens.cpp Wed Feb 11 21:26:59 2009
@@ -47,6 +47,17 @@
   Out << (unsigned char)(V >> 24);
 }
 
+static void Emit64(llvm::raw_ostream& Out, uint64_t V) {
+  Out << (unsigned char)(V);
+  Out << (unsigned char)(V >>  8);
+  Out << (unsigned char)(V >> 16);
+  Out << (unsigned char)(V >> 24);
+  Out << (unsigned char)(V >> 32);
+  Out << (unsigned char)(V >> 40);
+  Out << (unsigned char)(V >> 48);
+  Out << (unsigned char)(V >> 56);
+}
+
 static void Pad(llvm::raw_fd_ostream& Out, unsigned A) {
   Offset off = (Offset) Out.tell();
   uint32_t n = ((uintptr_t)(off+A-1) & ~(uintptr_t)(A-1)) - off;
@@ -149,7 +160,7 @@
         const std::pair<unsigned, unsigned>& Len = 
           Info::EmitKeyDataLength(out, I->key, I->data);
         Info::EmitKey(out, I->key, Len.first);
-        Info::EmitData(out, I->data, Len.second);
+        Info::EmitData(out, I->key, I->data, Len.second);
       }
     }
     
@@ -212,16 +223,23 @@
 
     unsigned n = strlen(FE->getName()) + 1;
     ::Emit16(Out, n);
-    return std::make_pair(n, 8);
+    return std::make_pair(n,(4*2)+(4+4+2+8+8));
   }
   
   static void EmitKey(llvm::raw_ostream& Out, const FileEntry* FE, unsigned n) {
     Out.write(FE->getName(), n);
   }
   
-  static void EmitData(llvm::raw_ostream& Out, const PCHEntry& E, unsigned) {
+  static void EmitData(llvm::raw_ostream& Out, const FileEntry* FE, 
+                       const PCHEntry& E, unsigned) {
     ::Emit32(Out, E.getTokenOffset());
     ::Emit32(Out, E.getPPCondTableOffset());
+    // Emit stat information.
+    ::Emit32(Out, FE->getInode());
+    ::Emit32(Out, FE->getDevice());
+    ::Emit16(Out, FE->getFileMode());
+    ::Emit64(Out, FE->getModificationTime());
+    ::Emit64(Out, FE->getSize());
   }        
 };
   
@@ -537,8 +555,6 @@
     if (!P.isAbsolute())
       continue;
 
-    // assert(!PM.count(FE) && "fileinfo's are not uniqued on FileEntry?");
-    
     const llvm::MemoryBuffer *B = C.getBuffer();
     if (!B) continue;
 
@@ -620,7 +636,8 @@
     Out.write(key->II->getName(), n);
   }
   
-  static void EmitData(llvm::raw_ostream& Out, uint32_t pID, unsigned) {
+  static void EmitData(llvm::raw_ostream& Out, PCHIdKey*, uint32_t pID,
+                       unsigned) {
     ::Emit32(Out, pID);
   }        
 };

Modified: cfe/trunk/include/clang/Lex/PTHManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/PTHManager.h?rev=64353&r1=64352&r2=64353&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/PTHManager.h (original)
+++ cfe/trunk/include/clang/Lex/PTHManager.h Wed Feb 11 21:26:59 2009
@@ -30,6 +30,7 @@
 class FileEntry;
 class PTHLexer;
 class Diagnostic;
+class StatSysCallCache;
   
 class PTHManager : public IdentifierInfoLookup {
   friend class PTHLexer;
@@ -95,7 +96,7 @@
   
 public:
   // The current PTH version.
-  enum { Version = 6 };
+  enum { Version = 7 };
 
   ~PTHManager();
   
@@ -115,6 +116,12 @@
   ///  specified file.  This method returns NULL if no cached tokens exist.
   ///  It is the responsibility of the caller to 'delete' the returned object.
   PTHLexer *CreateLexer(FileID FID);  
+  
+  /// createStatCache - Returns a StatSysCallCache object for use with
+  ///  FileManager objects.  These objects use the PTH data to speed up
+  ///  calls to stat by memoizing their results from when the PTH file
+  ///  was generated.
+  StatSysCallCache *createStatCache();
 };
   
 }  // end namespace clang

Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=64353&r1=64352&r2=64353&view=diff

==============================================================================
--- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
+++ cfe/trunk/include/clang/Lex/Preprocessor.h Wed Feb 11 21:26:59 2009
@@ -206,7 +206,7 @@
   IdentifierTable &getIdentifierTable() { return Identifiers; }
   SelectorTable &getSelectorTable() { return Selectors; }
   
-  void setPTHManager(PTHManager* pm) { PTH.reset(pm); }
+  void setPTHManager(PTHManager* pm);
 
   /// SetCommentRetentionState - Control whether or not the preprocessor retains
   /// comments in output.

Modified: cfe/trunk/lib/Lex/PTHLexer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PTHLexer.cpp?rev=64353&r1=64352&r2=64353&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/PTHLexer.cpp (original)
+++ cfe/trunk/lib/Lex/PTHLexer.cpp Wed Feb 11 21:26:59 2009
@@ -25,6 +25,7 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/System/Host.h"
+#include <sys/stat.h>
 using namespace clang;
 
 #define DISK_TOKEN_SIZE (1+1+2+4+4)
@@ -49,6 +50,19 @@
   return V;
 }
 
+static inline uint64_t ReadUnalignedLE64(const unsigned char *&Data) {
+  uint64_t V = ((uint64_t)Data[0])  |
+    ((uint64_t)Data[1] << 8)  |
+    ((uint64_t)Data[2] << 16) |
+    ((uint64_t)Data[3] << 24) |
+    ((uint64_t)Data[1] << 32) |
+    ((uint64_t)Data[2] << 40) |
+    ((uint64_t)Data[3] << 48) |
+    ((uint64_t)Data[3] << 56);
+  Data += 8;
+  return V;
+}
+
 static inline uint32_t ReadLE32(const unsigned char *&Data) {
   // Hosts that directly support little-endian 32-bit loads can just
   // use them.  Big-endian hosts need a bswap.
@@ -353,7 +367,11 @@
                "'buckets' must have a 4-byte alignment");
       }
 
-  
+  unsigned getNumBuckets() const { return NumBuckets; }
+  unsigned getNumEntries() const { return NumEntries; }
+  const unsigned char* const getBase() const { return Base; }
+  const unsigned char* const getBuckets() const { return Buckets; }
+
   bool isEmpty() const { return NumEntries == 0; }
   
   class iterator {
@@ -451,32 +469,37 @@
   uint32_t getPPCondOffset() const { return PPCondOff; }  
 };
   
-class VISIBILITY_HIDDEN PTHFileLookupTrait {
+  
+class VISIBILITY_HIDDEN PTHFileLookupCommonTrait {
 public:
-  typedef PTHFileData      data_type;
-  typedef const FileEntry* external_key_type;
   typedef const char*      internal_key_type;
   
   static bool EqualKey(const char* a, const char* b) {
     return strcmp(a, b) == 0;
   }
-
+  
   static unsigned ComputeHash(const char* x) {
     return BernsteinHash(x);
   }
-
-  static const char* GetInternalKey(const FileEntry* FE) {
-    return FE->getName();
-  }
   
   static std::pair<unsigned, unsigned>
   ReadKeyDataLength(const unsigned char*& d) {
-    return std::make_pair((unsigned) ReadUnalignedLE16(d), 8U);
+    return std::make_pair((unsigned) ReadUnalignedLE16(d), 8U + (4+4+2+8+8));
   }
   
   static const char* ReadKey(const unsigned char* d, unsigned) {
     return (const char*) d;
   }
+};
+  
+class VISIBILITY_HIDDEN PTHFileLookupTrait : public PTHFileLookupCommonTrait {
+public:
+  typedef const FileEntry* external_key_type;
+  typedef PTHFileData      data_type;
+  
+  static const char* GetInternalKey(const FileEntry* FE) {
+    return FE->getName();
+  }
   
   static PTHFileData ReadData(const unsigned char* d, unsigned) {
     uint32_t x = ::ReadUnalignedLE32(d);
@@ -737,3 +760,70 @@
   assert(PP && "No preprocessor set yet!");
   return new PTHLexer(*PP, FID, data, ppcond, *this); 
 }
+
+//===----------------------------------------------------------------------===//
+// 'stat' caching.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class VISIBILITY_HIDDEN PTHStatData {
+public:
+  const ino_t ino;
+  const dev_t dev;
+  const mode_t mode;
+  const time_t mtime;
+  const off_t size;
+  
+  PTHStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s)
+  : ino(i), dev(d), mode(mo), mtime(m), size(s) {}  
+};
+  
+class VISIBILITY_HIDDEN PTHStatLookupTrait : public PTHFileLookupCommonTrait {
+public:
+  typedef internal_key_type external_key_type;  // const char*
+  typedef PTHStatData data_type;
+    
+  static const char* GetInternalKey(external_key_type x) { return x; }
+  
+  static data_type ReadData(const unsigned char* d, unsigned) {
+    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);
+    time_t mtime = (time_t) ReadUnalignedLE64(d);    
+    return data_type(ino, dev, mode, mtime, (off_t) ReadUnalignedLE64(d));
+  }
+};
+}
+
+class VISIBILITY_HIDDEN PTHStatCache : public StatSysCallCache {
+  typedef OnDiskChainedHashTable<PTHStatLookupTrait> CacheTy;
+  CacheTy Cache;
+
+public:  
+  PTHStatCache(PTHFileLookup &FL) :
+    Cache(FL.getNumBuckets(), FL.getNumEntries(), FL.getBuckets(),
+          FL.getBase()) {}
+
+  ~PTHStatCache() {}
+  
+  int stat(const char *path, struct stat *buf) {
+    // Do the lookup for the file's data in the PTH file.
+    CacheTy::iterator I = Cache.find(path);
+
+    // If we don't get a hit in the PTH file just forward to 'stat'.
+    if (I == Cache.end()) return ::stat(path, buf);
+    
+    const PTHStatData& Data = *I;
+    buf->st_ino = Data.ino;
+    buf->st_dev = Data.dev;
+    buf->st_mtime = Data.mtime;
+    buf->st_mode = Data.mode;
+    buf->st_size = Data.size;
+    return 0;
+  }
+};
+
+StatSysCallCache *PTHManager::createStatCache() {
+  return new PTHStatCache(*((PTHFileLookup*) FileLookup));
+}

Modified: cfe/trunk/lib/Lex/Preprocessor.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Preprocessor.cpp?rev=64353&r1=64352&r2=64353&view=diff

==============================================================================
--- cfe/trunk/lib/Lex/Preprocessor.cpp (original)
+++ cfe/trunk/lib/Lex/Preprocessor.cpp Wed Feb 11 21:26:59 2009
@@ -32,6 +32,7 @@
 #include "clang/Lex/ScratchBuffer.h"
 #include "clang/Lex/LexDiagnostic.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Basic/FileManager.h"
 #include "clang/Basic/TargetInfo.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/SmallVector.h"
@@ -117,6 +118,11 @@
   delete Callbacks;
 }
 
+void Preprocessor::setPTHManager(PTHManager* pm) {
+  PTH.reset(pm);
+  FileMgr.setStatCache(PTH->createStatCache());
+}
+
 void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const {
   llvm::cerr << tok::getTokenName(Tok.getKind()) << " '"
              << getSpelling(Tok) << "'";





More information about the cfe-commits mailing list