Procházet zdrojové kódy

PERF: apply patch for bug 2575 speeds up depend scanning

Bill Hoffman před 20 roky
rodič
revize
92b6c8e742
3 změnil soubory, kde provedl 174 přidání a 25 odebrání
  1. 153 22
      Source/cmDependsC.cxx
  2. 16 2
      Source/cmDependsC.h
  3. 5 1
      Source/cmLocalUnixMakefileGenerator3.cxx

+ 153 - 22
Source/cmDependsC.cxx

@@ -17,6 +17,7 @@
 #include "cmDependsC.h"
 
 #include "cmSystemTools.h"
+#include "cmFileTimeComparison.h"
 
 #include <ctype.h> // isspace
 
@@ -30,18 +31,28 @@ cmDependsC::cmDependsC():
 // yummy look at all those constructor arguments
 cmDependsC::cmDependsC(std::vector<std::string> const& includes,
                        const char* scanRegex, const char* complainRegex,
-                       std::set<cmStdString> const& generatedFiles):
+                       std::set<cmStdString> const& generatedFiles, 
+                       const cmStdString& cacheFileName):
   m_IncludePath(&includes),
   m_IncludeRegexLine("^[ \t]*#[ \t]*include[ \t]*[<\"]([^\">]+)([\">])"),
   m_IncludeRegexScan(scanRegex),
   m_IncludeRegexComplain(complainRegex),
-  m_GeneratedFiles(&generatedFiles)
+  m_GeneratedFiles(&generatedFiles),
+  m_cacheFileName(cacheFileName)
 {
+  this->ReadCacheFile();
 }
 
 //----------------------------------------------------------------------------
 cmDependsC::~cmDependsC()
 {
+  this->WriteCacheFile();
+
+  for (std::map<cmStdString, cmIncludeLines*>::iterator it=m_fileCache.begin(); 
+       it!=m_fileCache.end(); ++it)
+    {
+    delete it->second;
+    }
 }
 
 //----------------------------------------------------------------------------
@@ -142,42 +153,159 @@ bool cmDependsC::WriteDependencies(const char *src, const char *obj,
       // Record scanned files.
       scanned.insert(fullName);
 
-      // Try to scan the file.  Just leave it out if we cannot find
-      // it.
-      std::ifstream fin(fullName.c_str());
-      if(fin)
+      // Check whether this file is already in the cache
+      std::map<cmStdString, cmIncludeLines*>::iterator fileIt=m_fileCache.find(fullName);
+      if (fileIt!=m_fileCache.end())
         {
-        // Add this file as a dependency.
+        fileIt->second->used=true;
         dependencies.insert(fullName);
-
-        // Scan this file for new dependencies.  Pass the directory
-        // containing the file to handle double-quote includes.
-        std::string dir = cmSystemTools::GetFilenamePath(fullName);
-        this->Scan(fin, dir.c_str());
+        for (std::list<UnscannedEntry>::const_iterator incIt=
+               fileIt->second->list.begin(); incIt!=fileIt->second->list.end(); ++incIt)
+          {
+          if (m_Encountered.find(incIt->FileName) == m_Encountered.end())
+            {
+            m_Encountered.insert(incIt->FileName);
+            m_Unscanned.push(*incIt);
+            }
+          }
+        }
+      else
+        {
+        
+        // Try to scan the file.  Just leave it out if we cannot find
+        // it.
+        std::ifstream fin(fullName.c_str());
+        if(fin)
+          {
+          // Add this file as a dependency.
+          dependencies.insert(fullName);
+          
+          // Scan this file for new dependencies.  Pass the directory
+          // containing the file to handle double-quote includes.
+          std::string dir = cmSystemTools::GetFilenamePath(fullName);
+          this->Scan(fin, dir.c_str(), fullName);
+          }
         }
       }
-
+    
     first = false;
     }
-
+  
   // Write the dependencies to the output stream.
   internalDepends << obj << std::endl;
   for(std::set<cmStdString>::iterator i=dependencies.begin();
       i != dependencies.end(); ++i)
     {
     makeDepends << obj << ": "
-       << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
-       << std::endl;
+                << cmSystemTools::ConvertToOutputPath(i->c_str()).c_str()
+                << std::endl;
     internalDepends << " " << i->c_str() << std::endl;
     }
   makeDepends << std::endl;
-
+  
   return true;
 }
 
 //----------------------------------------------------------------------------
-void cmDependsC::Scan(std::istream& is, const char* directory)
+void cmDependsC::ReadCacheFile()
 {
+  if(m_cacheFileName.size() == 0)
+    {
+    return;
+    }
+  std::ifstream fin(m_cacheFileName.c_str());
+  if(!fin)
+    {
+    return;
+    }
+  
+  std::string line;
+  cmIncludeLines* cacheEntry=0;
+  bool haveFileName=false;
+  
+  while(cmSystemTools::GetLineFromStream(fin, line))
+    {
+    if (line.empty())
+      {
+      cacheEntry=0;
+      haveFileName=false;
+      continue;
+      }
+    //the first line after an empty line is the name of the parsed file
+    if (haveFileName==false)
+      {
+      haveFileName=true;
+      int newer=0;
+      cmFileTimeComparison comp;
+      bool res=comp.FileTimeCompare(m_cacheFileName.c_str(), line.c_str(), &newer);
+      
+      if ((res==true) && (newer==1)) //cache is newer than the parsed file
+        {
+        cacheEntry=new cmIncludeLines;
+        m_fileCache[line]=cacheEntry; 
+        }
+      }
+    else if (cacheEntry!=0)
+      {
+      UnscannedEntry entry;
+      entry.FileName = line;
+      if (cmSystemTools::GetLineFromStream(fin, line))
+        {
+        if (line!="-")
+          {
+          entry.QuotedLocation=line;
+          }
+        cacheEntry->list.push_back(entry);
+        }
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmDependsC::WriteCacheFile() const
+{
+  if(m_cacheFileName.size() == 0)
+    {
+    return;
+    }
+  std::ofstream cacheOut(m_cacheFileName.c_str());
+  if(!cacheOut)
+    {
+    return;
+    }
+  
+  for (std::map<cmStdString, cmIncludeLines*>::const_iterator fileIt=m_fileCache.begin(); 
+       fileIt!=m_fileCache.end(); ++fileIt)
+    {
+    if (fileIt->second->used)
+      {
+      cacheOut<<fileIt->first.c_str()<<std::endl;
+      
+      for (std::list<UnscannedEntry>::const_iterator incIt=fileIt->second->list.begin(); 
+           incIt!=fileIt->second->list.end(); ++incIt)
+        {
+        cacheOut<<incIt->FileName.c_str()<<std::endl;
+        if (incIt->QuotedLocation.empty())
+          {
+          cacheOut<<"-"<<std::endl;
+          }
+        else
+          {
+          cacheOut<<incIt->QuotedLocation.c_str()<<std::endl;
+          }
+        }
+      cacheOut<<std::endl;
+      }
+   }
+}
+
+//----------------------------------------------------------------------------
+void cmDependsC::Scan(std::istream& is, const char* directory, const cmStdString& fullName)
+{
+  cmIncludeLines* newCacheEntry=new cmIncludeLines;
+  newCacheEntry->used=true;
+  m_fileCache[fullName]=newCacheEntry;
+  
   // Read one line at a time.
   std::string line;
   while(cmSystemTools::GetLineFromStream(is, line))
@@ -204,11 +332,14 @@ void cmDependsC::Scan(std::istream& is, const char* directory)
       // is included by double-quotes and the other by angle brackets.
       // This kind of problem will be fixed when a more
       // preprocessor-like implementation of this scanner is created.
-      if(m_Encountered.find(entry.FileName) == m_Encountered.end() &&
-         m_IncludeRegexScan.find(entry.FileName.c_str()))
+      if (m_IncludeRegexScan.find(entry.FileName.c_str()))
         {
-        m_Encountered.insert(entry.FileName);
-        m_Unscanned.push(entry);
+        newCacheEntry->list.push_back(entry);
+        if(m_Encountered.find(entry.FileName) == m_Encountered.end())
+          {
+          m_Encountered.insert(entry.FileName);
+          m_Unscanned.push(entry);
+          }
         }
       }
     }

+ 16 - 2
Source/cmDependsC.h

@@ -32,7 +32,7 @@ public:
   cmDependsC();
   cmDependsC(std::vector<std::string> const& includes,
              const char* scanRegex, const char* complainRegex,
-             std::set<cmStdString> const& generatedFiles);
+             std::set<cmStdString> const& generatedFiles, const cmStdString& cachFileName);
 
   /** Virtual destructor to cleanup subclasses properly.  */
   virtual ~cmDependsC();
@@ -47,7 +47,7 @@ protected:
                                  std::ostream& internalDepends);
 
   // Method to scan a single file.
-  void Scan(std::istream& is, const char* directory);
+  void Scan(std::istream& is, const char* directory, const cmStdString& fullName);
 
   // Method to test for the existence of a file.
   bool FileExistsOrIsGenerated(const std::string& fname,
@@ -74,10 +74,24 @@ protected:
     cmStdString FileName;
     cmStdString QuotedLocation;
   };
+
+  struct cmIncludeLines
+  {
+     cmIncludeLines():used(false) {}
+     std::list<UnscannedEntry> list;
+     bool used;
+  };
+
   std::set<cmStdString> m_Encountered;
   std::queue<UnscannedEntry> m_Unscanned;
   t_CharBuffer m_Buffer;
 
+  std::map<cmStdString, cmIncludeLines *> m_fileCache;
+
+  cmStdString m_cacheFileName;
+
+  void WriteCacheFile() const;
+  void ReadCacheFile();
 private:
   cmDependsC(cmDependsC const&); // Purposely not implemented.
   void operator=(cmDependsC const&); // Purposely not implemented.

+ 5 - 1
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -2790,11 +2790,15 @@ cmLocalUnixMakefileGenerator3
     cmDepends *scanner = 0;
     if(lang == "C" || lang == "CXX" || lang == "RC")
       {
+      std::string includeCacheFileName = dir;
+      includeCacheFileName += "/includecache.";
+      includeCacheFileName += lang;
+      
       // TODO: Handle RC (resource files) dependencies correctly.
       scanner = new cmDependsC(includes,
                                includeRegexScan.c_str(),
                                includeRegexComplain.c_str(),
-                               generatedFiles);
+                               generatedFiles, includeCacheFileName);
       }
 #ifdef CMAKE_BUILD_WITH_CMAKE
     else if(lang == "Fortran")