Dans le cadre d’un projet spécifique, j’ai besoin de calculer des distances de Hamming entre des entiers 64 bits. Pour optimiser le temps de calcul j’ai utilisé l’instruction POPCOUNT des processeurs Intel. J’ai pu observer un gain de performance significatif.
Introduction
Le but de mon projet spécifique est de benchmarker les systèmes de reverse image search. Pour mener mes tests, j’ai implémenté mon propre prototype en C++ avec la librairie pHash. Cette dernière me permet, à partir du contenu d’une image, de calculer un perceptual hash. La principale propriété de ce type de hash est de ne pas trop changer pour des images similaires. Dans le cadre de mon prototype j’indexe un grand nombre d’image, donc lorsque j’effectue une recherche, je compare le perceptual hash de mon image requête avec tous les perceptual hash de toutes les images indexées. La distance utilisée est celle de Hamming, c’est à dire que la distance entre deux perceptual hash est le nombre de bits sur lesquels les hashs sont différents. Pour accélérer le calcul de cette distance j’ai utilisé l’instruction POPCOUNT des processeurs Intel.
Optimisation du calcul
Comme la librairie pHash est sous licence GPLv3, j’ai pu accéder au code source pour vérifier comment est implémentée la fonction de calcul de la distance de Hamming. La voici :
Je me suis rappelé que les processeurs Intel avaient une instruction pour compter le nombre de bits à 1 dans un nombre et j’ai pensé que c’était possible de l’utiliser pour calculer la distance de Hamming. Je n’ai pas eu besoin de chercher longtemps sur internet, d’autres l’avaient déjà fait.
Attention lors de la compilation il est nécessaire de préciser l’architecture pour laquelle compiler sinon gcc va émuler l’instruction, ce qui est encore moins performant que la solution de pHash. Voici le code assembleur généré :
Je n’ai pas vraiment analysé en détail le code ci-dessus, ce que je sais c’est qu’à aucun moment l’instruction POPCOUNT n’est utilisée donc il n’y a pas vraiment d’accélération matérielle.
Pour préciser à gcc que l’ordinateur sur lequel va tourner l’application est capable d’exécuter les instructions POPCOUNT, il faut lui donner l’architecture pour laquelle compiler. Mon ordinateur étant équipé d’un i7 de seconde génération je mets le paramètre -march=corei7
. Pendant qu’on y est on lui demande aussi de compiler en 64 bits avec le paramètre -m64
. Je ne suis pas certain mais je pense que ça peut l’encourager à faire directement les traitements sur les hash 64 bits avec un registre 64 bits plutôt que deux de 32 bits. J’ai aussi utilisé le paramètre -O3
qui permet d’optimiser le code. Dans le cas de la fonction calculant la distance de Hamming, ce paramètre permet d’appliquer l’instruction POPCOUNT directement sur les registres contenant les paramètres de la fonction plutôt que de les enregistrer inutilement sur la pile. Finalement voici le code assembleur de la fonction :
Benchmark
Pour benchmarker le temps d’exécution de ces deux fonctions je génère un tableau de N entiers non signés 64 bits et je calcule toutes les distances entre eux, il y en a donc 2 parmi N. Voici le code utilisé pour le benchmark :
Pour compiler et tester j’utilise les lignes de commande suivantes :
Résultats
Les deux versions retournent la même distance moyenne, on a donc une bonne confiance quant à la validité de la nouvelle implémentation de la fonction. La version utilisant l’instruction POPCOUNT est au moins deux fois plus rapide que la version de pHash. Puisque ces deux temps d’exécution contiennent une partie constante liée à la génération des données de test, on peut en déduire que la version utilisant l’instruction POPCOUNT doit être au moins deux fois plus rapide que la version de pHash.
Discussion
La méthode de test n’est pas vraiment menée parfaitement. Je n’ai lancé le test que deux fois, les cas que je teste ne sont pas exhaustifs, je mesure le temps d’exécution du programme complet, j’ai effectué les tests dans une machine virtuelle et potentiellement d’autres biais que je n’ai pas imaginé. D’un autre côté, le résultat m’a l’air très significatif par rapport aux biais possibles.
Conclusion
La version utilisant l’instruction POPCOUNT est significativement plus rapide que la version fournie dans la librairie pHash.
Pour en savoir plus
- Zauner, Christoph. Master’s thesis, Upper Austria University of Applied Sciences, Hagenberg Campus, 2010. Implementation and Benchmarking of Perceptual Image Hash Functions [en ligne].
- Perceptual hashing dans Wikipédia, l’encyclopédie libre [en ligne]. https://en.wikipedia.org/wiki/Perceptual_hashing [Consulté le 14 Décembre 2016]