Petite séance d'optimisation aujourd'hui, où nous tentions d'améliorer une routine qui cherche des fichiers dans un répertoire.
En bon dev C++, nous sommes allés chercher ce bon vieux std::filesystem::path
et ce non moins bon vieux std::filesystem::recursive_directory_iterator
. Sauf que ça prend des plombes. Mais vraiment. Sur un système de fichiers distant (NFS) et un répertoire de 5000 fichiers pas accédé depuis quelques temps, cela peut monter à des dizaines de secondes. Mais que se passe-t-il ?
Avant de se lancer dans de complexes manipulations avec vtune
ou encore gprof
, pstack
nous indique que l'on passe beaucoup de temps dans l'appel à stat
. En effet, std::filesystem::recursive_directory_iterator
nous donne un std::filesystem::directory_entry
qui contient tout un tas d'infos tout à fait intéressantes, mais qui sont chères à récupérer...
Alors que peut-on faire ?
Eh bien, revenir aux bases, et à cette bonne vieille libc, qui contient l'appel readdir
, lequel justement ne récupère pas d'informations sur le fichier autre que son type (ce qui est pratique pour explorer récursivement un répertoire). Et n'oublions pas non plus glob
, lequel est justement conçu pour aller chercher un fichier efficacement à partir d'un motif.
Testons, alors. Et sur notre répertoire de 5000 fichiers, cela donne maintenant:
filesystem 40s readdir 30ms glob 3ms
Glob est donc plus de 10000 fois plus rapide qu'une recherche manuelle !
Conclusion : méfiance, donc ! Malgré ses qualités, std::filesystem::path
peut coûter très cher, et revenir à des appels plus bas niveau est parfois salutaire.
Aucun commentaire:
Enregistrer un commentaire