瀏覽代碼

ENH: Improved file modification time comparison on Windows to use GetFileAttributesEx instead of CreateFile/GetFileTime/CloseHandle to get file times. This results in a 30% reduction in time to do a build system check.

Brad King 20 年之前
父節點
當前提交
946c9a2cc6
共有 2 個文件被更改,包括 55 次插入56 次删除
  1. 49 32
      Source/cmFileTimeComparison.cxx
  2. 6 24
      Source/kwsys/SystemTools.cxx

+ 49 - 32
Source/cmFileTimeComparison.cxx

@@ -9,22 +9,19 @@
   Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
   See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
 
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
      PURPOSE.  See the above copyright notices for more information.
 
 =========================================================================*/
 #include "cmFileTimeComparison.h"
 
-#include <cmsys/Directory.hxx>
-#include <cmsys/RegularExpression.hxx>
-#include <cmsys/SystemTools.hxx>
-
+// Use a hash table to avoid duplicate file time checks from disk.
 #if defined(CMAKE_BUILD_WITH_CMAKE)
 # include <cmsys/hash_map.hxx>
 #endif
 
-
+// Use a platform-specific API to get file times efficiently.
 #if !defined(_WIN32) || defined(__CYGWIN__)
 #  define cmFileTimeComparison_Type struct stat
 #  include <ctype.h>
@@ -34,13 +31,16 @@
 #  include <windows.h>
 #endif
 
+//----------------------------------------------------------------------------
 class cmFileTimeComparisonInternal
 {
 public:
+  // Internal comparison method.
   inline bool FileTimeCompare(const char* f1, const char* f2, int* result);
 
 private:
 #if defined(CMAKE_BUILD_WITH_CMAKE)
+  // Use a hash table to efficiently map from file name to modification time.
   class HashString
     {
   public:
@@ -50,67 +50,78 @@ private:
       }
     cmsys::hash<const char*> h;
     };
-  typedef cmsys::hash_map<cmStdString, cmFileTimeComparison_Type, HashString> FileStatsMap;
+  typedef cmsys::hash_map<cmStdString,
+                          cmFileTimeComparison_Type, HashString> FileStatsMap;
   FileStatsMap Files;
 #endif
 
+  // Internal methods to lookup and compare modification times.
   inline bool Stat(const char* fname, cmFileTimeComparison_Type* st);
-  inline int Compare(cmFileTimeComparison_Type* st1, cmFileTimeComparison_Type* st2);
+  inline int Compare(cmFileTimeComparison_Type* st1,
+                     cmFileTimeComparison_Type* st2);
 };
 
-bool cmFileTimeComparisonInternal::Stat(const char* fname, cmFileTimeComparison_Type* st)
+//----------------------------------------------------------------------------
+bool cmFileTimeComparisonInternal::Stat(const char* fname,
+                                        cmFileTimeComparison_Type* st)
 {
 #if defined(CMAKE_BUILD_WITH_CMAKE)
-  cmFileTimeComparisonInternal::FileStatsMap::iterator fit = this->Files.find(fname);
+  // Use the stored time if available.
+  cmFileTimeComparisonInternal::FileStatsMap::iterator fit =
+    this->Files.find(fname);
   if ( fit != this->Files.end() )
     {
     *st = fit->second;
     return true;
     }
 #endif
+
 #if !defined(_WIN32) || defined(__CYGWIN__)
+  // POSIX version.  Use the stat function.
   int res = ::stat(fname, st);
   if ( res != 0 )
     {
     return false;
     }
 #else
-  // Windows version.  Create file handles and get the modification times.
-  HANDLE hf1 = CreateFile(fname, GENERIC_READ, FILE_SHARE_READ,
-                          NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
-                          NULL);
-  if(hf1 == INVALID_HANDLE_VALUE)
-    {
-    return false;
-    }
-  if(!GetFileTime(hf1, 0, 0, st))
+  // Windows version.  Get the modification time from extended file attributes.
+  WIN32_FILE_ATTRIBUTE_DATA fdata;
+  if(!GetFileAttributesEx(fname, GetFileExInfoStandard, &fdata))
     {
-    CloseHandle(hf1);
     return false;
     }
-  CloseHandle(hf1);
+
+  // Copy the file time to the output location.
+  *st = fdata.ftLastWriteTime;
 #endif
+
 #if defined(CMAKE_BUILD_WITH_CMAKE)
+  // Store the time for future use.
   this->Files[fname] = *st;
 #endif
+
   return true;
 }
 
+//----------------------------------------------------------------------------
 cmFileTimeComparison::cmFileTimeComparison()
 {
   m_Internals = new cmFileTimeComparisonInternal;
 }
 
+//----------------------------------------------------------------------------
 cmFileTimeComparison::~cmFileTimeComparison()
 {
   delete m_Internals;
 }
 
+//----------------------------------------------------------------------------
 bool cmFileTimeComparison::FileTimeCompare(const char* f1, const char* f2, int* result)
 {
   return m_Internals->FileTimeCompare(f1, f2, result);
 }
 
+//----------------------------------------------------------------------------
 int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1, cmFileTimeComparison_Type* s2)
 {
 #if !defined(_WIN32) || defined(__CYGWIN__)
@@ -143,27 +154,33 @@ int cmFileTimeComparisonInternal::Compare(cmFileTimeComparison_Type* s1, cmFileT
     return 1;
     }
 # endif
+  // Files have the same time.
   return 0;
 #else
+  // Compare using system-provided function.
   return (int)CompareFileTime(s1, s2);
 #endif
 }
 
-bool cmFileTimeComparisonInternal::FileTimeCompare(const char* f1, const char* f2, int* result)
+//----------------------------------------------------------------------------
+bool cmFileTimeComparisonInternal::FileTimeCompare(const char* f1,
+                                                   const char* f2,
+                                                   int* result)
 {
-  // Default to same time.
-  *result = 0;
+  // Get the modification time for each file.
   cmFileTimeComparison_Type s1;
-  if(!this->Stat(f1, &s1))
+  cmFileTimeComparison_Type s2;
+  if(this->Stat(f1, &s1) &&
+     this->Stat(f2, &s2))
     {
-    return false;
+    // Compare the two modification times.
+    *result = this->Compare(&s1, &s2);
+    return true;
     }
-  cmFileTimeComparison_Type s2;
-  if(!this->Stat(f2, &s2))
+  else
     {
+    // No comparison available.  Default to the same time.
+    *result = 0;
     return false;
     }
-  *result = this->Compare(&s1, &s2);
-  return true;
 }
-

+ 6 - 24
Source/kwsys/SystemTools.cxx

@@ -786,38 +786,20 @@ bool SystemTools::FileTimeCompare(const char* f1, const char* f2,
     }
 # endif
 #else
-  // Windows version.  Create file handles and get the modification times.
-  HANDLE hf1 = CreateFile(f1, GENERIC_READ, FILE_SHARE_READ,
-                          NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
-                          NULL);
-  if(hf1 == INVALID_HANDLE_VALUE)
+  // Windows version.  Get the modification time from extended file attributes.
+  WIN32_FILE_ATTRIBUTE_DATA f1d;
+  WIN32_FILE_ATTRIBUTE_DATA f2d;
+  if(!GetFileAttributesEx(f1, GetFileExInfoStandard, &f1d))
     {
     return false;
     }
-  FILETIME tf1;
-  if(!GetFileTime(hf1, 0, 0, &tf1))
+  if(!GetFileAttributesEx(f2, GetFileExInfoStandard, &f2d))
     {
-    CloseHandle(hf1);
     return false;
     }
-  CloseHandle(hf1);
-  HANDLE hf2 = CreateFile(f2, GENERIC_READ, FILE_SHARE_READ,
-                          NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS,
-                          NULL);
-  if(hf2 == INVALID_HANDLE_VALUE)
-    {
-    return false;
-    }
-  FILETIME tf2;
-  if(!GetFileTime(hf2, 0, 0, &tf2))
-    {
-    CloseHandle(hf2);
-    return false;
-    }
-  CloseHandle(hf2);
 
   // Compare the file times using resolution provided by system call.
-  *result = (int)CompareFileTime(&tf1, &tf2);
+  *result = (int)CompareFileTime(&f1d.ftLastWriteTime, &f2d.ftLastWriteTime);
 #endif
   return true;
 }