From 3ff38b6bfe39da9355f56c6203887f164cba4072 Mon Sep 17 00:00:00 2001 From: Jonathan Campbell Date: Sun, 16 Jun 2024 22:35:55 -0700 Subject: [PATCH] DOS drive cache: Fix directory listing performance issues by deferring filename sort until after all entries have been added. [https://github.com/joncampbell123/dosbox-x/issues/5039] --- CHANGELOG | 3 +++ include/dos_system.h | 2 +- src/dos/drive_cache.cpp | 11 +++++++---- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8fc555e4ae..c1289de393 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,7 @@ Next: + - DOS drive cache: When listing a directory, defer the filename sort until + the entire list is built. This improves directory listing performance + in directories with many files. (joncampbell123). - INT 10h, if instructed, will now use the video parameter table to set standard VGA modes instead of internal logic. (joncampbell123). - Removed erroneous VGA display compensation code for certain EGA/VGA diff --git a/include/dos_system.h b/include/dos_system.h index 43de12d5df..e4e348f68d 100644 --- a/include/dos_system.h +++ b/include/dos_system.h @@ -270,7 +270,7 @@ class DOS_Drive_Cache { CFileInfo* FindDirInfo (const char* path, char* expandedPath); bool RemoveSpaces (char* str); bool OpenDir (CFileInfo* dir, const char* expand, uint16_t& id); - char* CreateEntry (CFileInfo* dir, const char* name, const char* sname, bool is_directory); + char* CreateEntry (CFileInfo* dir, const char* name, const char* sname, bool is_directory, bool skipSort=false); void CopyEntry (CFileInfo* dir, CFileInfo* from); uint16_t GetFreeID (CFileInfo* dir); void Clear (void); diff --git a/src/dos/drive_cache.cpp b/src/dos/drive_cache.cpp index 70d545b1d5..13b84ca226 100644 --- a/src/dos/drive_cache.cpp +++ b/src/dos/drive_cache.cpp @@ -824,7 +824,7 @@ bool DOS_Drive_Cache::OpenDir(CFileInfo* dir, const char* expand, uint16_t& id) return false; } -char* DOS_Drive_Cache::CreateEntry(CFileInfo* dir, const char* name, const char* sname, bool is_directory) { +char* DOS_Drive_Cache::CreateEntry(CFileInfo* dir, const char* name, const char* sname, bool is_directory, bool skipSort) { CFileInfo* info = new CFileInfo; strcpy(info->shortname, sname); strcpy(info->orgname, name); @@ -835,7 +835,7 @@ char* DOS_Drive_Cache::CreateEntry(CFileInfo* dir, const char* name, const char* if (sname[0]==0) CreateShortName(dir, info); // keep list sorted (so GetLongName works correctly, used by CreateShortName in this routine) - if (dir->fileList.size()>0) { + if (dir->fileList.size()>0 && !skipSort) { if (!(strcmp(info->shortname,dir->fileList.back()->shortname)<0)) { // append at end of list dir->fileList.push_back(info); @@ -891,12 +891,15 @@ bool DOS_Drive_Cache::ReadDir(uint16_t id, char* &result, char * &lresult) { char dir_name[CROSS_LEN], dir_sname[DOS_NAMELENGTH+1]; bool is_directory; if (drive->read_directory_first(dirp, dir_name, dir_sname, is_directory)) { - CreateEntry(dirSearch[id], dir_name, dir_sname, is_directory); + CreateEntry(dirSearch[id], dir_name, dir_sname, is_directory, /*skip search*/true); while (drive->read_directory_next(dirp, dir_name, dir_sname, is_directory)) { - CreateEntry(dirSearch[id], dir_name, dir_sname, is_directory); + CreateEntry(dirSearch[id], dir_name, dir_sname, is_directory, /*skip search*/true); } } + // Insertion skipped sorting, now sort in one go, which should be faster when faced with many files + std::sort(dirSearch[id]->fileList.begin(), dirSearch[id]->fileList.end(), SortByName); + // close dir drive->closedir(dirp);