Beschleunigte Verzeichnisauflistung bei sehr vielen MP3s

Hi,
Ich hatte in dem anderen Thread schon geschrieben, ich bin kein großer Fan von impliziten „Zusätzen“ an Strings um Information zu transportieren. Das ist anfällig darauf, dass man vergisst, wieso etwas gemacht wurde und dann geändert wird. Plus, die Interpretation von „//“ ist abhängig von der Implementation (das hatte ich nicht gewusst, eigentlich dacht ich, das in POSIX/Linux 2 oder mehr / als einer gewertet werden → ich mag Stackoverflow, da lernt man immer was neues dazu :laughing:):

A pathname that begins with two successive slashes may be interpreted in an implementation-defined manner
POSIX Pathname Resolution specification

Nach ein wenig Stöbern würde ich vorschlagen, dass wir etweder ein std::pair<String, bool> (mit der Info Pathname / isDirectory) oder direkt den Pointer auf den struct dirent zurückgeben. Bei dem Pointer sind dann alle Informationen schon enthalten. Der relative Pfad (bzw nur der Dateiname) kommt uns in Zukunft zu gute. Aktuell unterstützen wir aber keine relativen Pfade, aber ein concat ist recht leicht zu implementieren.

Dazu würde ich eine neue Funktion in unserer FS.h empfehlen, das macht das Aktuell halten einfacher als wenn die Patches in bestehenden Funktionen eingreifen.

2 „Gefällt mir“

Finde das klingt gut. @tueddy was hälst du davon? Wenn das Filesystem schon direkt diese Information liefert kann der Code noch kompakter werden und man spart sich den doppelten Code in Web.cpp und SdCard.cpp.
Falls du es gut findest aber gerade nicht selbst machen willst kann ich mir das auch im Filesystem anschauen…

Der Plan war die Funktion brauchbar ins offizielle Arduino Release zu bekommen aber mein Gemeckere hat leider Nichts gebracht :frowning:

Habe Eure Anregungen aufgenommen & eine neue überladene Funktion gemacht:

String getNextFileName(boolean *isDir);

Die Web-Auflistung sieht dann so aus:

    #ifdef HAS_FILEEXPLORER_SPEEDUP  
	bool isDir;
    String MyfileName = root.getNextFileName(&isDir);
    while (MyfileName != "") {
        // ignore hidden folders, e.g. MacOS spotlight files
        if (!startsWith( MyfileName.c_str() , (char *)"/.")) {
            JsonObject entry = obj.createNestedObject();
            convertAsciiToUtf8(MyfileName.c_str(), filePath);
            std::string path = filePath;
            std::string fileName = path.substr(path.find_last_of("/") + 1);
            entry["name"] = fileName;
            entry["dir"].set(isDir);
        }
        MyfileName = root.getNextFileName(&isDir);
    }
    #else
    ..

Ich würde auch einen PR bei arduino-esp32 machen damit das offiziell werden kann. Eine überladene Funktion hat da evt. die besten Chancen. So oder so es sollte verwendbar sein.

4 „Gefällt mir“

Sehr cool! :+1:

Jupp, wenn du versuchst es in den Upstream zu bekommen macht es Sinn dass Interface nicht zu stark zu ändern. Mit der Funktion kann auch ich gut leben.

1 „Gefällt mir“

Würdest du das so wie so für deine Umbauten in SdCard.cpp anpassen oder soll ich die entsprechende Stelle Mal anschauen?

@Joe91 ist schon hier eingebaut, aber noch nicht getestet & Geschwindigkeit gemessen.

1 „Gefällt mir“

Sehr cool! Gerade mal aufgespielt und was mir sofort positiv auffällt, ist dass es nicht mehr die lange „Verzögerung“ beim ersten mal abspielen eines Ordners gibt (die Generierung des Playlist-Caches).

Ich kann auch im Betrieb nichts negatives bezüglich der Geschwindigkeit feststellen. Auch das löschen von Dateien und wieder neu hinzufügen funktioniert super (nur die aktuell spielende Datei sollte man nicht löschen :wink: )…

Konnte bei mir mit 50 Titeln in einem Ordner testen und konnte keinerlei „Verzögerung“ oder ähnlich beim Start festellen.

Gefällt mir sehr viel besser als mit den PlaylistCacheFiles! Hammer!!

Das ist ja schon mal fein das es sich subjektiv schneller/flüssiger anfühlt!

Mein Messergebnis mit einem Ordner mit 24 Dateien:

#define CACHED_PLAYLIST_ENABLE aktiv aber noch keine Cachedatei vorhanden:

[ 561819 ]  Playlist-Generierung: uncached
[ 561880 ]  Anzahl gültiger Files/Webstreams: 24
[ 561880 ]  build playlist from SD-card finished: 82 ms

#define CACHED_PLAYLIST_ENABLE aktiv & playlistcache-Datei vorhanden::

[ 643103 ]  Gebe Speicher der alten Playlist frei.
[ 643103 ]  Freier Speicher nach Aufräumen: 110256
[ 643139 ]  Playlist-Generierung: cached
[ 643187 ]  Freier Speicher: 110060
[ 643189 ]  Anzahl gültiger Files/Webstreams: 24
[ 643189 ]  build playlist from SD-card finished: 86 ms

CACHED_PLAYLIST_ENABLE auskommentiert, also komplett ohne Cache:

[ 25516 ]  Playlist-Generierung: uncached
[ 25532 ]  Anzahl gültiger Files/Webstreams: 24
[ 25532 ]  build playlist from SD-card finished: 26 ms

Also ohne Cache scheint das tatsächlich noch schneller zu sein als mit Cache. Kann das jemand noch bestätigen?

2 „Gefällt mir“

Alles auf deinem Branch:
#define CACHED_PLAYLIST_ENABLE aktiv aber noch keine Cachedatei vorhanden:

[ 71833 ]  Playlist-Generierung: uncached
[ 72140 ]  Anzahl gültiger Files/Webstreams: 50
[ 72140 ]  build playlist from SD-card finished: 385 ms

#define CACHED_PLAYLIST_ENABLE aktiv & playlistcache-Datei vorhanden::

[ 120845 ]  Playlist-Generierung: cached
[ 120965 ]  Freier Speicher: 79908
[ 120982 ]  Anzahl gültiger Files/Webstreams: 50
[ 120982 ]  build playlist from SD-card finished: 207 ms

CACHED_PLAYLIST_ENABLE auskommentiert, also komplett ohne Cache:

[ 41361 ]  Playlist-Generierung: uncached
[ 41410 ]  Anzahl gültiger Files/Webstreams: 50
[ 41410 ]  build playlist from SD-card finished: 57 ms

Also ja, tatsächlich deutlich besser ohne :slight_smile: .
Das define CACHED_PLAYLIST_ENABLE könnte man in diesem Zuge auch gleich ganz raus nehmen. Ich kann mir morgen auch nochmal die originalen Zeiten zum Vergleich anschauen. Das sollte ganz spannend sein.
Gute Nacht zusammen!

2 „Gefällt mir“

Hattest du bei den Messungen Musik abgespielt? Weil die Unterschiede zu tueddy scheinen doch sehr hoch zu sein (oder nutzt du SPI). Würde mich nur interessieren, da du so große Untershiede hast. Kann natürlich auch an der SD-Karte selbst liegen :upside_down_face:.

Ohne der Cache sind die Werte aber deutlich besser (wahrscheinlich weil es einfach fixer geht den FAT32 Directory table auszulesen als die Linked List der Datei). Sehr überzeugend :laughing:. Muss nur die Zeit finden meine Playlist Branch nochmal anzugreifen… RL funkt da gerade leider ein wenig dazwischen…

Messungen sind jeweils zum Start des Abspielens implementiert. Ich verwende das normale Kit ohne SPI.

Aber ich finde die Unterschiede gar nicht so gravierend. Dass das erstellen der Playlist und speichern länger dauert wenn es mehr Dateien sind und die SD nur langsam schreibt passt.
Beim lesen des Chache-Files bei ca. doppelter Anzahl an Einträgen auch etwa doppelt so lange wirkt auch plausibel.
Und beim lesen der Table ohne das Cache file ebenfalls etwa doppelt so lange bei doppelt so vielen Einträgen…

@tueddy wie stehst du zum „erhalten“ oder „entfernen“ der cached playlist?
Siehst du noch Gründe warum wir die behalten sollten?

Bin sicher das die Messungen passen, die SD-Karten sind unterschiedlich schnell und befüllt, @Joe91 hat 50 Dateien, ich 24 im Ordner gehabt.
Habe das auch noch mit SPI getestet, da ist der Turbo nochmal größer. Bei SPI hatte ich mit einer stark befüllten Karten Watchdog Reset (weil das Laden des Explorer-Trees ewig gedauert hat), jetzt flutscht das.

Aus meiner Sicht ist der Playlist Cache dann obsolet. Ich werde ihn im kommenden PR aber nicht entfernen sondern nur deaktivieren

2 „Gefällt mir“

Ich habe ein Bug / Verbesserungsvorschlag. In getNextFileName solltest du definitiv prüfen, ob du NULL bei isDir bekommen hast. Wenn es NULL ist, versuchst du Adresse 0x00 zu schreiben, generierst damit eine Exception und der Code stürzt ab.

Eine einfache Möglichkeit wäre eine Prüfung in Zeile 562 vor den Schreiben auf NULL:

    name += fname;
    // check entry is a directory
    if(isDir) {
        *isDir = (file->d_type == DT_DIR);
    }
    return name;

Plus die Formatierung deines neuen Codes passt nicht mit dem restlichen in der Lib zusammen (du nutzt Tabs statt Leerzeichen ).

@laszloh Danke für den Hinweis, hab’s aufgenommen.

Huhuhu, es gibt gute Chancen das diese Funktion Teil des nächsten Arduino Release wird. Mein Pull-Request ist bereits „approved“. Könnte also mit 2.0.8 kommen, bis dahin kann man aber auch gut mit der angepassten FS Bibliothek leben :wink:

1 „Gefällt mir“

Die verbesserte Funktion ist tatsächlich im aktuellen Arduino Release 2.0.8 angekommen. Daher habe ich das jetzt mal offiziell eingereicht:

Hoffe es passt Alles, gerne Feedback hier!

2 „Gefällt mir“

Auf den ersten Blick ist mir aufgefallen, dass du auch ein Commit von Torsten drin hast: d34da44

Der existiert nur auf dem Master, nicht aber in der Dev. Ich denke, hier musst du noch ein Rebase auf den aktuellen Dev-Branch machen.

Ein Punkt ist wichtig, da hast du beim Random Folder auswahl die Bedigung falsch (du wählst nur Dateien aus, statt Ordner): FS speedup by factor > 20 (playlist generation, Web-UI file listing) by tueddy · Pull Request #233 · biologist79/ESPuino · GitHub

Der Rest ist Kleinigkeiten.

4 „Gefällt mir“

@laszloh Vielen Dank für die Code-Review, hast ja noch einen Bug gefunden!

Keine Ahnung warum in der Historie da Änderungen in der Readme angezeigt werden. Vermute das kam durch ein Sync vom Dev-Branch und Torsten hatte diese Datei aktualisiert.
Am Ende taucht die aber nicht mehr auf und ist synchron zur aktuellen Readme:

grafik

1 „Gefällt mir“

Hi @tueddy

Tolle Arbeit. Seit einigen Tagen habe ich es laufen und ich hoffe es kommt noch in den Master bevor ich nächste Woche die Box meiner Enkelin zum Update erhalte. Cached_Playlist ist deaktiviert und ich denke auch nicht mehr erforderlich. Gefühlt ist da kein Unterschied. :+1:

1 „Gefällt mir“