From 02ca9496e82ee7df2ac85d2fb204b3d1991ee563 Mon Sep 17 00:00:00 2001 From: espr14 Date: Mon, 8 Mar 2021 20:56:51 +0100 Subject: [PATCH 1/7] File: use insert sort --- Firmware/Configuration_adv.h | 1 + Firmware/cardreader.cpp | 67 ++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 997aafd19..165f1170b 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -230,6 +230,7 @@ #define SD_SORT_ALPHA 1 #define SD_SORT_NONE 2 // #define SHELLSORT + #define INSERTSORT // #define SORTING_DUMP #define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256). diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp index a62e66f3b..fab88f3d1 100644 --- a/Firmware/cardreader.cpp +++ b/Firmware/cardreader.cpp @@ -922,6 +922,73 @@ void CardReader::presort() { } } +#elif defined(INSERTSORT) + +#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2) +#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp > crmodTime)) || (crmod_date_bckp > crmodDate)) + +#if HAS_FOLDER_SORTING +#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs < 0 ? dir1 : !dir1)) +#define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1)) +#endif + + uint16_t counter = 0; + menu_progressbar_init(fileCnt * fileCnt / 2, _i("Sorting files")); + + for (uint16_t i = 1; i < fileCnt; ++i){ + // if (!IS_SD_INSERTED) return; + menu_progressbar_update(counter); + counter += i; + + /// pop the position + const uint16_t o1 = sort_order[i]; + getfilename_simple(sort_positions[o1]); + strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) + crmod_date_bckp = crmodDate; + crmod_time_bckp = crmodTime; + #if HAS_FOLDER_SORTING + bool dir1 = filenameIsDir; + #endif + + /// find proper place + uint16_t j = i; + for (; j > 0; --j){ + if (!IS_SD_INSERTED) return; + + #ifdef SORTING_DUMP + for (uint16_t z = 0; z < fileCnt; z++){ + printf_P(PSTR("%2u "), sort_order[z]); + } + MYSERIAL.println(); + #endif + + manage_heater(); + const uint16_t o2 = sort_order[j - 1]; + + getfilename_simple(sort_positions[o2]); + char *name2 = LONGEST_FILENAME; // use the string in-place + + // Sort the current pair according to settings. + if ( + #if HAS_FOLDER_SORTING + (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_DIR(FOLDER_SORTING)) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_DIR(FOLDER_SORTING)) + #else + (sdSort == SD_SORT_TIME && _SORT_CMP_TIME_NODIR()) || (sdSort == SD_SORT_ALPHA && !_SORT_CMP_NODIR()) + #endif + ) + { + break; + } else { + #ifdef SORTING_DUMP + puts_P(PSTR("shift")); + #endif + sort_order[j] = o2; + } + } + /// place the position + sort_order[j] = o1; + } + #else //Bubble Sort #define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2) From 490754a0f03f5f16a5664d7e6ee26fa79fe82a95 Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Sat, 2 Jul 2022 20:52:48 +0200 Subject: [PATCH 2/7] Fix build --- Firmware/cardreader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp index fab88f3d1..51556ec97 100644 --- a/Firmware/cardreader.cpp +++ b/Firmware/cardreader.cpp @@ -942,7 +942,7 @@ void CardReader::presort() { /// pop the position const uint16_t o1 = sort_order[i]; - getfilename_simple(sort_positions[o1]); + getfilename_simple(sort_entries[o1]); strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) crmod_date_bckp = crmodDate; crmod_time_bckp = crmodTime; @@ -965,7 +965,7 @@ void CardReader::presort() { manage_heater(); const uint16_t o2 = sort_order[j - 1]; - getfilename_simple(sort_positions[o2]); + getfilename_simple(sort_entries[o2]); char *name2 = LONGEST_FILENAME; // use the string in-place // Sort the current pair according to settings. From cac2b9ae40ce8fff508da9639c1d3e2cf9f565db Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Sat, 2 Jul 2022 21:09:36 +0200 Subject: [PATCH 3/7] Implement timer elapsed function also fix build --- Firmware/Timer.cpp | 13 +++++++++++++ Firmware/Timer.h | 1 + 2 files changed, 14 insertions(+) diff --git a/Firmware/Timer.cpp b/Firmware/Timer.cpp index a94a8586a..f63bf2969 100644 --- a/Firmware/Timer.cpp +++ b/Firmware/Timer.cpp @@ -64,5 +64,18 @@ bool Timer::expired(T msPeriod) return expired; } +/** + * @brief Ticks since the timer was started + * + * This function returns 0 if the timer is not started. Otherwise, it returns + * the time in milliseconds since the timer was started. + * This function is expected to handle wrap around of time register well. + * The maximum elapsed time is dictated by the template type + */ +template +T Timer::elapsed() { + return m_isRunning ? (_millis() - m_started) : 0; +} + template class Timer; template class Timer; diff --git a/Firmware/Timer.h b/Firmware/Timer.h index 599371b4e..dcff52232 100644 --- a/Firmware/Timer.h +++ b/Firmware/Timer.h @@ -22,6 +22,7 @@ public: void stop(){m_isRunning = false;} bool running()const {return m_isRunning;} bool expired(T msPeriod); + T elapsed(); protected: T started()const {return m_started;} private: From c100df7ba38a385024cdb71f1755dda3a9b7ef8f Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Sat, 2 Jul 2022 21:36:33 +0200 Subject: [PATCH 4/7] Remove quicksort, shellsort and add performance benchmark --- Firmware/Configuration_adv.h | 4 +- Firmware/cardreader.cpp | 93 ++++-------------------------------- Firmware/cardreader.h | 4 -- 3 files changed, 12 insertions(+), 89 deletions(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 165f1170b..5acff3269 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -229,9 +229,9 @@ #define SD_SORT_TIME 0 #define SD_SORT_ALPHA 1 #define SD_SORT_NONE 2 - // #define SHELLSORT - #define INSERTSORT + #define INSERTSORT // #define SORTING_DUMP + #define SORTING_SPEEDTEST #define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256). #define FOLDER_SORTING -1 // -1=above 0=none 1=below diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp index 51556ec97..03c541997 100644 --- a/Firmware/cardreader.cpp +++ b/Firmware/cardreader.cpp @@ -840,89 +840,12 @@ void CardReader::presort() { #endif } -#ifdef QUICKSORT - quicksort(0, fileCnt - 1); -#elif defined(SHELLSORT) +#ifdef SORTING_SPEEDTEST + LongTimer sortingSpeedtestTimer; + sortingSpeedtestTimer.start(); +#endif //SORTING_SPEEDTEST -#define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2) -#define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp < crmodTime)) || (crmod_date_bckp < crmodDate)) - -#if HAS_FOLDER_SORTING -#define _SORT_CMP_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_NODIR() : (fs < 0 ? dir1 : !dir1)) -#define _SORT_CMP_TIME_DIR(fs) ((dir1 == filenameIsDir) ? _SORT_CMP_TIME_NODIR() : (fs < 0 ? dir1 : !dir1)) -#endif - - for (uint8_t runs = 0; runs < 2; runs++) - { - //run=0: sorts all files and moves folders to the beginning - //run=1: assumes all folders are at the beginning of the list and sorts them - uint16_t sortCountFiles = 0; - if (runs == 0) - { - sortCountFiles = fileCnt; - } - #if HAS_FOLDER_SORTING - else - { - sortCountFiles = dirCnt; - } - #endif - - uint16_t counter = 0; - uint16_t total = 0; - for (uint16_t i = sortCountFiles/2; i > 0; i /= 2) total += sortCountFiles - i; //total runs for progress bar - menu_progressbar_init( - total, (runs == 0) - ? _i("Sorting files") ////MSG_SORTING_FILES c=20 - : _i("Sorting folders")); ////MSG_SORTING_FOLDERS c=20 - - for (uint16_t gap = sortCountFiles/2; gap > 0; gap /= 2) - { - for (uint16_t i = gap; i < sortCountFiles; i++) - { - if (!IS_SD_INSERTED) return; - - menu_progressbar_update(counter); - counter++; - - manage_heater(); - uint8_t orderBckp = sort_order[i]; - getfilename_simple(sort_entries[orderBckp]); - strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) - crmod_date_bckp = crmodDate; - crmod_time_bckp = crmodTime; - #if HAS_FOLDER_SORTING - bool dir1 = filenameIsDir; - #endif - - uint16_t j = i; - getfilename_simple(sort_entries[sort_order[j - gap]]); - char *name2 = LONGEST_FILENAME; // use the string in-place - #if HAS_FOLDER_SORTING - while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_DIR(FOLDER_SORTING):_SORT_CMP_DIR(FOLDER_SORTING))) - #else - while (j >= gap && ((sdSort == SD_SORT_TIME)?_SORT_CMP_TIME_NODIR():_SORT_CMP_NODIR())) - #endif - { - sort_order[j] = sort_order[j - gap]; - j -= gap; - #ifdef SORTING_DUMP - for (uint16_t z = 0; z < sortCountFiles; z++) - { - printf_P(PSTR("%2u "), sort_order[z]); - } - printf_P(PSTR("i%2d j%2d gap%2d orderBckp%2d\n"), i, j, gap, orderBckp); - #endif - if (j < gap) break; - getfilename_simple(sort_entries[sort_order[j - gap]]); - name2 = LONGEST_FILENAME; // use the string in-place - } - sort_order[j] = orderBckp; - } - } - } - -#elif defined(INSERTSORT) +#ifdef INSERTSORT #define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2) #define _SORT_CMP_TIME_NODIR() (((crmod_date_bckp == crmodDate) && (crmod_time_bckp > crmodTime)) || (crmod_date_bckp > crmodDate)) @@ -1053,7 +976,11 @@ void CardReader::presort() { if (!didSwap) break; } //end of bubble sort loop #endif - + +#ifdef SORTING_SPEEDTEST + printf_P(PSTR("sortingSpeedtestTimer:%lu\n"), sortingSpeedtestTimer.elapsed()); +#endif //SORTING_SPEEDTEST + #ifdef SORTING_DUMP for (uint16_t z = 0; z < fileCnt; z++) printf_P(PSTR("%2u "), sort_order[z]); diff --git a/Firmware/cardreader.h b/Firmware/cardreader.h index d267d0b64..3d3054557 100644 --- a/Firmware/cardreader.h +++ b/Firmware/cardreader.h @@ -63,10 +63,6 @@ public: #ifdef SDCARD_SORT_ALPHA void presort(); - #ifdef SDSORT_QUICKSORT - void swap(uint8_t left, uint8_t right); - void quicksort(uint8_t left, uint8_t right); - #endif //SDSORT_QUICKSORT void getfilename_sorted(const uint16_t nr, uint8_t sdSort); #endif From d9d3d68217da0c0074dffd8270f3b3f7a3bdc54b Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Sat, 2 Jul 2022 22:16:57 +0200 Subject: [PATCH 5/7] Remove postponed sorting of elements Now that the position is a uint16_t instead of uint32_t, it is simpler to just sort the positions in place without using the uint8_t indices. Also, this approach is considerably lighter on the stack usage and it also removes a delay after the sorting happens --- Firmware/cardreader.cpp | 52 +++++++++++------------------------------ 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp index 03c541997..50f292d63 100644 --- a/Firmware/cardreader.cpp +++ b/Firmware/cardreader.cpp @@ -825,7 +825,6 @@ void CardReader::presort() { if (fileCnt > 1) { // Init sort order. - uint8_t sort_order[fileCnt]; for (uint16_t i = 0; i < fileCnt; i++) { if (!IS_SD_INSERTED) return; manage_heater(); @@ -833,7 +832,6 @@ void CardReader::presort() { getfilename(0); else getfilename_next(position); - sort_order[i] = i; sort_entries[i] = position >> 5; #if HAS_FOLDER_SORTING if (filenameIsDir) dirCnt++; @@ -864,8 +862,8 @@ void CardReader::presort() { counter += i; /// pop the position - const uint16_t o1 = sort_order[i]; - getfilename_simple(sort_entries[o1]); + const uint16_t o1 = sort_entries[i]; + getfilename_simple(o1); strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) crmod_date_bckp = crmodDate; crmod_time_bckp = crmodTime; @@ -880,15 +878,15 @@ void CardReader::presort() { #ifdef SORTING_DUMP for (uint16_t z = 0; z < fileCnt; z++){ - printf_P(PSTR("%2u "), sort_order[z]); + printf_P(PSTR("%2u "), sort_entries[z]); } MYSERIAL.println(); #endif manage_heater(); - const uint16_t o2 = sort_order[j - 1]; + const uint16_t o2 = sort_entries[j - 1]; - getfilename_simple(sort_entries[o2]); + getfilename_simple(o2); char *name2 = LONGEST_FILENAME; // use the string in-place // Sort the current pair according to settings. @@ -905,11 +903,11 @@ void CardReader::presort() { #ifdef SORTING_DUMP puts_P(PSTR("shift")); #endif - sort_order[j] = o2; + sort_entries[j] = o2; } } /// place the position - sort_order[j] = o1; + sort_entries[j] = o1; } #else //Bubble Sort @@ -937,22 +935,22 @@ void CardReader::presort() { #ifdef SORTING_DUMP for (uint16_t z = 0; z < fileCnt; z++) { - printf_P(PSTR("%2u "), sort_order[z]); + printf_P(PSTR("%2u "), sort_entries[z]); } MYSERIAL.println(); #endif manage_heater(); - const uint16_t o1 = sort_order[j], o2 = sort_order[j + 1]; + const uint16_t o1 = sort_entries[j], o2 = sort_entries[j + 1]; counter++; - getfilename_simple(sort_entries[o1]); + getfilename_simple(o1); strcpy(name1, LONGEST_FILENAME); // save (or getfilename below will trounce it) crmod_date_bckp = crmodDate; crmod_time_bckp = crmodTime; #if HAS_FOLDER_SORTING bool dir1 = filenameIsDir; #endif - getfilename_simple(sort_entries[o2]); + getfilename_simple(o2); char *name2 = LONGEST_FILENAME; // use the string in-place // Sort the current pair according to settings. @@ -968,8 +966,8 @@ void CardReader::presort() { puts_P(PSTR("swap")); #endif - sort_order[j] = o2; - sort_order[j + 1] = o1; + sort_entries[j] = o2; + sort_entries[j + 1] = o1; didSwap = true; } } @@ -983,32 +981,10 @@ void CardReader::presort() { #ifdef SORTING_DUMP for (uint16_t z = 0; z < fileCnt; z++) - printf_P(PSTR("%2u "), sort_order[z]); + printf_P(PSTR("%2u "), sort_entries[z]); SERIAL_PROTOCOLLN(); #endif - uint8_t sort_order_reverse_index[fileCnt]; - for (uint8_t i = 0; i < fileCnt; i++) - sort_order_reverse_index[sort_order[i]] = i; - for (uint8_t i = 0; i < fileCnt; i++) - { - if (sort_order_reverse_index[i] != i) - { - uint32_t el = sort_entries[i]; - uint8_t idx = sort_order_reverse_index[i]; - while (idx != i) - { - uint32_t el1 = sort_entries[idx]; - uint8_t idx1 = sort_order_reverse_index[idx]; - sort_order_reverse_index[idx] = idx; - sort_entries[idx] = el; - idx = idx1; - el = el1; - } - sort_order_reverse_index[idx] = idx; - sort_entries[idx] = el; - } - } menu_progressbar_finish(); } else { From e79e15b12f3ac087a177d0622490a4fe191b2671 Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Sun, 3 Jul 2022 21:26:46 +0200 Subject: [PATCH 6/7] Use the sd cache for positions even when not sorting --- Firmware/cardreader.cpp | 63 +++++++++++++++++------------------------ Firmware/ultralcd.cpp | 10 ++----- 2 files changed, 28 insertions(+), 45 deletions(-) diff --git a/Firmware/cardreader.cpp b/Firmware/cardreader.cpp index 50f292d63..101c421c1 100644 --- a/Firmware/cardreader.cpp +++ b/Firmware/cardreader.cpp @@ -791,58 +791,53 @@ void CardReader::getfilename_sorted(const uint16_t nr, uint8_t sdSort) { * - Most RAM: Buffer the directory and return filenames from RAM */ void CardReader::presort() { + // Throw away old sort index + flush_presort(); + if (farm_mode || IS_SD_INSERTED == false) return; //sorting is not used in farm mode uint8_t sdSort = eeprom_read_byte((uint8_t*)EEPROM_SD_SORT); - if (sdSort == SD_SORT_NONE) return; //sd sort is turned off - KEEPALIVE_STATE(IN_HANDLER); - // Throw away old sort index - flush_presort(); - // If there are files, sort up to the limit uint16_t fileCnt = getnrfilenames(); if (fileCnt > 0) { - // Never sort more than the max allowed // If you use folders to organize, 20 may be enough if (fileCnt > SDSORT_LIMIT) { - lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=6 + if (sdSort != SD_SORT_NONE) { + lcd_show_fullscreen_message_and_wait_P(_i("Some files will not be sorted. Max. No. of files in 1 folder for sorting is 100."));////MSG_FILE_CNT c=20 r=6 + } fileCnt = SDSORT_LIMIT; } - // By default re-read the names from SD for every compare - // retaining only two filenames at a time. This is very - // slow but is safest and uses minimal RAM. - char name1[LONG_FILENAME_LENGTH]; - uint16_t crmod_time_bckp; - uint16_t crmod_date_bckp; + sort_count = fileCnt; + + // Init sort order. + for (uint16_t i = 0; i < fileCnt; i++) { + if (!IS_SD_INSERTED) return; + manage_heater(); + if (i == 0) + getfilename(0); + else + getfilename_next(position); + sort_entries[i] = position >> 5; + } - #if HAS_FOLDER_SORTING - uint16_t dirCnt = 0; - #endif - - if (fileCnt > 1) { - // Init sort order. - for (uint16_t i = 0; i < fileCnt; i++) { - if (!IS_SD_INSERTED) return; - manage_heater(); - if (i == 0) - getfilename(0); - else - getfilename_next(position); - sort_entries[i] = position >> 5; - #if HAS_FOLDER_SORTING - if (filenameIsDir) dirCnt++; - #endif - } + if ((fileCnt > 1) && (sdSort != SD_SORT_NONE)) { #ifdef SORTING_SPEEDTEST LongTimer sortingSpeedtestTimer; sortingSpeedtestTimer.start(); #endif //SORTING_SPEEDTEST + // By default re-read the names from SD for every compare + // retaining only two filenames at a time. This is very + // slow but is safest and uses minimal RAM. + char name1[LONG_FILENAME_LENGTH]; + uint16_t crmod_time_bckp; + uint16_t crmod_date_bckp; + #ifdef INSERTSORT #define _SORT_CMP_NODIR() (strcasecmp(name1, name2) < 0) //true if lowercase(name1) < lowercase(name2) @@ -987,12 +982,6 @@ void CardReader::presort() { menu_progressbar_finish(); } - else { - getfilename(0); - sort_entries[0] = position >> 5; - } - - sort_count = fileCnt; } lcd_update(2); diff --git a/Firmware/ultralcd.cpp b/Firmware/ultralcd.cpp index 704d9bb83..f1bd7cd04 100755 --- a/Firmware/ultralcd.cpp +++ b/Firmware/ultralcd.cpp @@ -6437,10 +6437,7 @@ void lcd_sdcard_menu() { //load filename to memory. #ifdef SDCARD_SORT_ALPHA - if (_md->sdSort == SD_SORT_NONE) - card.getfilename(i); - else - card.getfilename_sorted(i, _md->sdSort); + card.getfilename_sorted(i, _md->sdSort); #else card.getfilename(i); #endif @@ -6468,10 +6465,7 @@ void lcd_sdcard_menu() { //load filename to memory. #ifdef SDCARD_SORT_ALPHA - if (_md->sdSort == SD_SORT_NONE) - card.getfilename(_md->selectedFileID); - else - card.getfilename_sorted(_md->selectedFileID, _md->sdSort); + card.getfilename_sorted(_md->selectedFileID, _md->sdSort); #else card.getfilename(_md->selectedFileID); #endif From 61b8dbbab5fa47c4d24f92e317013543fb598eeb Mon Sep 17 00:00:00 2001 From: Alex Voinea Date: Sun, 3 Jul 2022 21:51:44 +0200 Subject: [PATCH 7/7] Disable sorting speedtest --- Firmware/Configuration_adv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Firmware/Configuration_adv.h b/Firmware/Configuration_adv.h index 5acff3269..c6f8a81f0 100644 --- a/Firmware/Configuration_adv.h +++ b/Firmware/Configuration_adv.h @@ -231,7 +231,7 @@ #define SD_SORT_NONE 2 #define INSERTSORT // #define SORTING_DUMP - #define SORTING_SPEEDTEST + // #define SORTING_SPEEDTEST #define SDSORT_LIMIT 100 // Maximum number of sorted items (10-256). #define FOLDER_SORTING -1 // -1=above 0=none 1=below