Performance optimization for MSW directory time-stamping.

This commit is contained in:
Jeff Young 2018-08-08 20:07:26 +02:00 committed by jean-pierre charras
parent 15e0771ea8
commit f6f1c1e944
1 changed files with 76 additions and 25 deletions

View File

@ -533,11 +533,21 @@ bool std::less<wxPoint>::operator()( const wxPoint& aA, const wxPoint& aB ) cons
#endif #endif
// /**
// A wrapper around a wxFileName which avoids expensive calls to wxFileName::SplitPath() * Performance enhancements to file and directory operations.
// and string concatenations by caching the path and filename locally and only resolving *
// the wxFileName when it has to. * Note: while it's annoying to have to make copies of wxWidgets stuff and then
// * add platform-specific performance optimizations, the following routies offer
* SIGNIFICANT performance benefits.
*/
/**
* WX_FILENAME
*
* A wrapper around a wxFileName which avoids expensive calls to wxFileName::SplitPath()
* and string concatenations by caching the path and filename locally and only resolving
* the wxFileName when it has to.
*/
WX_FILENAME::WX_FILENAME( const wxString& aPath, const wxString& aFilename ) : WX_FILENAME::WX_FILENAME( const wxString& aPath, const wxString& aFilename ) :
m_fn( aPath, aFilename ), m_fn( aPath, aFilename ),
m_path( aPath ), m_path( aPath ),
@ -596,10 +606,12 @@ long long WX_FILENAME::GetTimestamp()
} }
// /**
// A copy of wxMatchWild (attributed to <dalewis@cs.Buffalo.EDU>) modified to use * A copy of wxMatchWild(), which wxWidgets attributes to Douglas A. Lewis
// POSIX-file-system-encoded inputs. * <dalewis@cs.Buffalo.EDU> and ircII's reg.c.
// *
* This version is modified to skip any encoding conversions (for performance).
*/
bool matchWild( const char* pat, const char* text, bool dot_special ) bool matchWild( const char* pat, const char* text, bool dot_special )
{ {
if ( !*text ) if ( !*text )
@ -703,32 +715,71 @@ bool matchWild( const char* pat, const char* text, bool dot_special )
} }
/**
* A copy of ConvertFileTimeToWx() because wxWidgets left it as a static function
* private to src/common/filename.cpp.
*/
#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__)
// Convert between wxDateTime and FILETIME which is a 64-bit value representing
// the number of 100-nanosecond intervals since January 1, 1601 UTC.
//
// This is the offset between FILETIME epoch and the Unix/wxDateTime Epoch.
static wxInt64 EPOCH_OFFSET_IN_MSEC = wxLL(11644473600000);
static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft)
{
wxLongLong t(ft.dwHighDateTime, ft.dwLowDateTime);
t /= 10000; // Convert hundreds of nanoseconds to milliseconds.
t -= EPOCH_OFFSET_IN_MSEC;
*dt = wxDateTime(t);
}
#endif // wxUSE_DATETIME && __WIN32__
/**
* TimestampDir
*
* This routine offers SIGNIFICANT performance benefits over using wxWidgets to gather
* timestamps from matching files in a directory.
* @param aDirPath the directory to search
* @param aFilespec a (wildcarded) file spec to match against
* @return a hash of the last-mod-dates of all matching files in the directory
*/
long long TimestampDir( const wxString& aDirPath, const wxString& aFilespec ) long long TimestampDir( const wxString& aDirPath, const wxString& aFilespec )
{ {
long long timestamp = 0; long long timestamp = 0;
#ifdef __WINDOWS__ #if defined(__WIN32__)
// wxFileName construction is egregiously slow. Construct it once and just swap out // Win32 version.
// the filename thereafter. // Save time by not searching for each path twice: once in wxDir.GetNext() and once in
WX_FILENAME fn( aDirPath, wxT( "dummyName" ) ); // wxFileName.GetModificationTime(). Also cuts out wxWidgets' string-matching and case
wxDir dir( aDirPath ); // conversion by staying on the MSW side of things.
wxString fullname; std::wstring filespec( aDirPath.t_str() );
filespec += '\\';
filespec += aFilespec.t_str();
if( dir.IsOpened() ) WIN32_FIND_DATA findData;
wxDateTime lastModDate;
HANDLE fileHandle = ::FindFirstFile( filespec.data(), &findData );
if( fileHandle != INVALID_HANDLE_VALUE )
{ {
if( dir.GetFirst( &fullname, aFilespec ) ) do
{ {
do ConvertFileTimeToWx( &lastModDate, findData.ftLastWriteTime );
{ timestamp += lastModDate.GetValue().GetValue();
fn.SetFullName( fullname );
timestamp += fn.GetTimestamp();
}
while( dir.GetNext( &fullname ) );
} }
while ( FindNextFile( fileHandle, &findData ) != 0);
} }
FindClose( fileHandle );
#else #else
// POSIX version. Save time by not converting between encodings -- do everything on // POSIX version.
// the file-system side. // Save time by not converting between encodings -- do everything on the file-system side.
std::string filespec( aFilespec.fn_str() ); std::string filespec( aFilespec.fn_str() );
std::string dir_path( aDirPath.fn_str() ); std::string dir_path( aDirPath.fn_str() );