Nous recherchons une bibliothèque universelle rapide pour travailler avec des fichiers graphiques, comprendre le benchmark Google



De nos jours, lorsque les réseaux de neurones labourent les étendues du Big Data et que l'intelligence artificielle se demande s'il est rentable pour lui de se faire payer pour son travail dans Bitcoin, la tâche que j'ai eue de trouver la bibliothèque multiplateforme ouverte la plus rapide pour télécharger, enregistrer et transcoder des fichiers graphiques ressemblait à un véritable anachronisme . Mais en fait, cette tâche est plus pertinente que jamais - pour toutes les technologies de vision par ordinateur et d'apprentissage automatique, des gigaoctets d'images doivent être téléchargés, et parfois les données intermédiaires doivent être enregistrées sous forme d'images. Il est donc très souhaitable de le faire de la manière la plus rapide. Dans cet article, nous trouverons la bibliothèque que nous recherchons et, plus important encore, nous traiterons d'un produit très utile qui simplifie considérablement les tâches similaires et bien d'autres - Google Benchmark.

Ainsi, l'énoncé exact du problème indique: dans l'application, les fichiers jpeg et tiff avec une profondeur de couleur de 24 et 8 bits, ainsi que le bmp 32 bits sont chargés en mémoire. Les tailles d'image vont de minuscule (32x32 pixels) à grande, avec une résolution de 15K. Au cours du processus, les fichiers sont modifiés, après quoi ils doivent être enregistrés sur le disque dans les formats spécifiés. Et cela devrait être fait par une bibliothèque open source multiplateforme qui offre des performances maximales sur les processeurs Intel modernes avec la prise en charge des instructions vectorielles AVX2. La bibliothèque prend également en charge la bibliothèque de formats de texture compressée DirectX DXT1. Le composant d'imagerie Windows est considéré comme la référence en matière de performances - le cadre standard pour travailler avec des images sur Windows, c'est-à-dire que vous devez trouver une bibliothèque qui fonctionne sur un pied d'égalité ou plus rapidement que WIC.

Mais l'exigence la plus importante est qu'une solution soit nécessaire dès maintenant, mais mieux hier.

Rencontrez les bibliothèques pour travailler avec bmp, tiff, jpeg


La solution commence par une étape évidente et simple, bien que pas très rapide - une étude approfondie de Wikileaks github , stackoverflow et autres google à la recherche de candidats appropriés pour le rôle de la bibliothèque souhaitée. Il y en avait peu:

  • FreeImage . Un shell sur les fameuses librairies LibJPEG, LibPNG, LibTIFF. Le support DXT1 est présent via le plugin. L'inconvénient est que la qualité de l'enregistrement jpeg dans l'API est définie de manière trop discrète - 100, 75,50 et 25%. Pour modifier ce paramètre, vous devrez comprendre et modifier le code. Le projet est vivant et en développement - la dernière version 3.18.0 est sortie le 31 juillet 2018. L'assemblage sous Windows est trivial, tous les composants sont construits automatiquement.
  • Cimg Il s'agit d'un wrapper de fichier d'en-tête C ++ sur un ancien paquet d' artefacts ImageMagick . Le paquet nécessite une build-installation séparée, il est également possible de l'utiliser directement, en contournant Cimg. Il a beaucoup de possibilités pour travailler avec des images: filtres, transformations, définition de la morphologie, etc. Prend en charge HDR, ne prend pas en charge DXT1.
  • DevIL ( Bibliothèque d'images du développeur ). Une bibliothèque C de style OpenGL très simple. Il contient un shell sur LibJPEG, LibPNG, LibTIFF, mais possède également de nombreuses fonctionnalités intégrées, prend également en charge de nombreux formats d'image, y compris DXT1. Pour l'assemblage, utilisez CMake. La plupart des dépendances, y compris LibJPEG, LibPNG, LibTIFF, ne sont pas incluses dans DevIL et doivent être téléchargées et compilées séparément séparément. La dernière mise à jour de DevIL concernant le système de construction est datée du 01/01/2017, et la précédente s'est généralement produite en 2014, donc s'il y a des problèmes avec la bibliothèque, il peut y avoir des problèmes avec leur solution.
  • OpenImageIO . Il se positionne comme un outil de développement de logiciels professionnels pour travailler avec des images. Il prend en charge sous forme de plug-ins de travail avec de nombreux formats photo exotiques et même vidéo. Build for Windows nécessite Boost et Qt 4. précompilés. Il n'y a pas de version assemblée prête à l'emploi pour les tests.
  • Boost GIL (Generic Image Library) Boost et c'est tout. Mais pas tous. Cette bibliothèque contient également un wrapper sur LibJPEG, LibPNG et LibTIFF.
  • SDL_image 2.0 Utilisé avec la bibliothèque SDL et, vous allez en rire, mais contient également un shell sur LibJPEG, LibPNG et LibTIFF.

Toutes les bibliothèques trouvées ont été compilées sous Windows en utilisant le niveau maximal d'optimisation du compilateur Visual Studio et du commutateur / arch: AVX2.

Il en va de même pour les bibliothèques LibJPEG, LibPNG et LibTIFF, afin d'accélérer le travail extrait du nouveau package de bibliothèque OpenCV .

Rencontrez le Google Benchmark


La prochaine étape de la solution est également évidente: la création d'un point de référence pour comparer les performances des bibliothèques trouvées et l'utilisation de la bibliothèque de micro-analyse de Google Benchmark, largement connue dans les cercles étroits, la rendent simple et rapide.
Google Benchmark peut mesurer avec précision les performances des morceaux de code que vous avez insérés dans le corps du cycle C ++ 11.

static void BM_foo1(benchmark::State& state) { //     Init_your_code(); for (auto _ : state){ //  -  your_code_to_benchmark(); } 

dans les fonctions enregistrées comme référence

 //       BENCHMARK(BM_foo1); 

Et exécutez-les:

 BENCHMARK_MAIN(); 

Ensuite, émettez un rapport au format spécifié - sortie console, json, csv.

Le rapport contiendra des données sur le système d'exécution (processeur, configuration du cache), le temps de fonctionnement global total de chacune des fonctions mesurées, ainsi que le temps nécessaire au processeur. Ces temps diffèrent généralement - le premier, par exemple, inclut un délai de lecture / écriture, et le second pour les tests de référence multithread est la somme du temps de fonctionnement de tous les cœurs.

Le dernier paramètre affiché par Google benchmark est le nombre d'itérations effectuées pour la fonction, qui est nécessaire pour une mesure précise statistiquement correcte de son temps de fonctionnement. Le système le sélectionne vous-même, automatiquement, en effectuant des mesures préliminaires.

Qu'est-ce qu'une «mesure précise» du temps d'exécution? Vous pouvez rédiger des dissertations sur ce sujet, mais dans ce cas il suffit de dire que:

  • Par défaut, la mesure est en grappes de processeurs, c'est-à-dire que l'ordre théorique de précision est exactement le suivant. La sortie par défaut est en nanosecondes;
  • les résultats de tous les tests que j'ai vus sont très stables d'un lancement à l'autre;
  • selon mes données de renseignement, le benchmark de Google est utilisé et entièrement approuvé par ses résultats par les développeurs de logiciels informatiques embarqués de l'une des plus grandes entreprises automobiles du monde. Nous allons donc croire.

La seule chose à laquelle il faut faire attention: Google benchmark ne fournit pas de "nettoyage" du cache entre les débuts des itérations de référence. Si nécessaire, vous devez vous en occuper vous-même.

Mais le benchmark de Google peut faire beaucoup d'autres choses:

  • calculer la complexité asymptotique de l'algorithme (O);
  • travailler correctement avec des benchmarks multi-threads, mesurer leur durée non pas en ticks du processeur, mais en mode «temps réel» (horloge murale);
  • utiliser votre propre fonction de mesure du temps "manuelle", qui peut être utile, par exemple, pour mesurer le travail sur le GPU;
  • définir automatiquement des repères avec différents ensembles d'arguments pour un corps donné de la fonction mesurée;
  • montrer la valeur moyenne, la médiane et l'écart type pour plusieurs démarrages de l'indice de référence;
  • Définissez vos propres compteurs et balises qui seront reflétés dans le rapport de référence Google.

Le benchmark Google est téléchargé à partir du référentiel github , assemblé pour la plate-forme appropriée à l'aide de Cmake (l'assembly Visual Studio est disponible pour Windows), la bibliothèque résultante sera liée à votre projet (dans le cas de Windows, un lien avec la bibliothèque shlwapi sera également requis), le fichier d'en-tête du benchmark sera ajouté à votre code .h, après quoi tout fonctionne comme décrit ci-dessus.

Si cela ne fonctionne pas, le seul endroit, à part le site déjà indiqué , où vous pouvez obtenir au moins des informations et de l'aide sur le benchmark Google est un forum spécialisé sur les produits .

Dans notre cas, tout a fonctionné sans problème. Après avoir communiqué avec les clients, 4 benchmarks ont été définis, qui se chargent et se sauvegardent sous un nom différent:

  • Fichier jpeg 8 bits avec une résolution de 15k
  • Fichier jpeg 24 bits avec une résolution de 15k
  • Fichier tiff 24 bits avec une résolution de 15k
  • Fichier bmp 32 bits avec une résolution de 32x32

Rencontrez les résultats


Il était initialement prévu que toutes les bibliothèques trouvées, c'est-à-dire FreeImage, Cimg, DevIL, OpenImageIO, Boost GIL et SDL_image 2.0, participeront aux tests de comparaison avec le composant d'imagerie Windows (WIC). Mais les trois dernières bibliothèques, en fonction de "monstres" tels que Boost et SDL, ont été invitées par les clients à partir en réserve en cas d'urgence, si la bibliothèque souhaitée n'est pas trouvée parmi les trois premières. Et, heureusement, elle a été retrouvée. Mais pas immédiatement.

Ce qui suit est un rapport généré par Google benchmark, qui montre que:

  • FreeImage complètement avec un score d'écrasement perd le WIC dans tous les tests, donc il ne peut plus être pris en compte.
  • Cimg perd WIC proprement partout, sauf pour le chargement de tiff, où il est légèrement (moins de 5%) plus rapide. Hélas, il devra également être supprimé. De plus, cela s'applique à l'utilisation directe du package ImageMagick.

Reste la bibliothèque DevIL. Il montre d'excellents résultats en cas de chargement de bmp et de tiff (3 et 2,8 fois plus élevé que WIC!), Jpeg noir et blanc (1,75x meilleur que WIC), mais il ralentit un peu lors du chargement d'un jpeg 24 bits régulier - il le fait par 3 % plus lent que WIC.
08/15/18 11:15:44
Running c:\WIC\WIC_test\Release\WIC_test.exe
Run on (8 X 4008 MHz CPU s)
CPU Caches:
L1 Data 32K (x4)
L1 Instruction 32K (x4)
L2 Unified 262K (x4)
L3 Unified 8388K (x1)
BenchmarkTimeCPUIterations
BM_WIC8jpeg72 ms70 ms11
BM_cimg8jpeg562 ms52 ms10
BM_FreeImage8jpeg147 ms144 ms5
BM_devIL8jpeg41 ms41 ms17
BM_WIC24jpeg266 ms260 ms3
BM_cimg24jpeg656 ms128 ms6
BM_FreeImage24jpeg594 ms594 ms1
BM_devIL24jpeg276 ms276 ms3
BM_WIC24tiff844 ms844 ms1
BM_cimg24tiff808 ms131 ms5
BM_FreeImage24tiff953 ms938 ms1
BM_devIL24tiff305 ms305 ms2
BM_WIC323 ms3 ms236
BM_cimg3271 ms7 ms90
BM_FreeImage326 ms5 ms112
BM_devIL321 ms1 ms747
Bien sûr, DevIL pourrait également être rejeté à ce stade, mais ici une autre bibliothèque apparaît dans le cadre - Libjpeg-turbo .

Sa sortie peut être facilement satisfaite par des applaudissements - Libjpeg-turbo est une bibliothèque multiplateforme qui implémente entièrement la fonctionnalité libjpeg (API) et ajoute sa propre fonctionnalité (par exemple, en travaillant avec des tampons 32 bits). Dans le même temps, pour l'architecture x86, Libjpeg-turbo utilise activement les instructions vectorielles (SSE2, AVX2) et, selon ses créateurs, est 2 à 6 fois plus rapide que libjpeg (!)

Par conséquent, l'étape suivante consiste à créer DevIL avec Libjpeg-turbo au lieu de libjpeg. Libjpeg-turbo avec l'aide de CMake construit Visual Studio sans problème, puis presque immédiatement (avec le remplacement du seul #define, qui détermine la version de libjpeg dans le fichier d'en-tête DevIL) commence à fonctionner dans le cadre de DevIL.

Par conséquent, le rapport de référence Google ressemble à ceci:
BenchmarkTimeCPUIterations
BM_WIC8jpeg72 ms68 ms9
BM_cimg8jpeg565 ms39 ms10
BM_FreeImage8jpeg148 ms141 ms5
BM_devIL8jpeg31 ms31 ms24
BM_WIC24jpeg269 ms266 ms2
BM_cimg24jpeg675 ms131 ms5
BM_FreeImage24jpeg604 ms594 ms1
BM_devIL24jpeg149 ms150 ms5
BM_WIC24tiff833 ms828 ms1
BM_cimg24tiff785 ms138 ms5
BM_FreeImage24tiff943 ms938 ms1
BM_devIL24tiff318 ms320 ms2
BM_WIC324 ms3 ms236
BM_cimg3274 ms8 ms56
BM_FreeImage326 ms5 ms100
BM_devIL321 ms1 ms747
Bien sûr, les améliorations de performances avec jpeg ne sont même pas doubles par rapport à libjpeg, mais cela devrait être le cas - car la supériorité de vitesse ne s'applique qu'au codage / décodage jpeg, et le test inclut les frais généraux de lecture / écriture d'un fichier.

Mais on peut voir qu'en moyenne, DevIL est plus rapide que WIC dans le cas de jpeg 8 bits 2,3 fois, jpeg 24 bits 1,8 fois, tiff 24 bits - 2,7 fois, bmp 32 bits - 3,5 fois.

Le problème est résolu. Trois jours ouvrables d'été avant les vacances ont été entièrement consacrés à la décision. Bien sûr, s'il y en avait un peu plus, il serait possible qu'il y ait une bibliothèque avec des résultats encore plus impressionnants, et si c'était beaucoup plus, alors j'écrirais peut-être la bibliothèque que je cherchais moi-même.

Mais même ce qui est impressionnant. Par conséquent, si vous recherchez une bibliothèque multiplateforme pour travailler avec des fichiers graphiques qui est rapide et facile dans tous les sens, alors faites attention à DevIL , et si vous avez besoin de faire rapidement et avec précision des mesures comparatives du code, alors la référence Google est à votre service.

Source: https://habr.com/ru/post/fr425021/


All Articles