
Heutzutage, als neuronale Netze die Weiten von Big Data pflügen und künstliche Intelligenz überlegt, ob es für ihn rentabel ist, ein Gehalt für seine Arbeit in Bitcoin zu erhalten, sah die Aufgabe, die schnellste offene plattformübergreifende Bibliothek zum Laden, Speichern und Transcodieren von Grafikdateien zu finden, wie ein echter Anachronismus aus . Tatsächlich ist diese Aufgabe relevanter denn je - für alle Technologien der Bildverarbeitung und des maschinellen Lernens müssen Gigabyte an Bildern heruntergeladen und manchmal die Zwischendaten als Bilder gespeichert werden. Dies auf dem schnellsten Weg zu tun, ist daher sehr wünschenswert. In diesem Artikel finden wir die Bibliothek, nach der wir suchen, und vor allem werden wir uns mit einem sehr nützlichen Produkt befassen, das ähnliche und viele andere Aufgaben erheblich vereinfacht - Google Benchmark.
Die genaue Aussage des Problems lautet also: In der Anwendung werden JPEG- und TIFF-Dateien mit 24- und 8-Bit-Farbtiefe sowie 32-Bit-BMP in den Speicher geladen. Die Bildgrößen reichen von winzig (32 x 32 Pixel) bis groß mit einer Auflösung von 15 KB. Dabei werden Dateien geändert und anschließend in den angegebenen Formaten auf der Festplatte gespeichert. Dies sollte durch eine plattformübergreifende Open-Source-Bibliothek erfolgen, die auf modernen Intel-Prozessoren maximale Leistung bietet und die Vektoranweisungen AVX2 unterstützt. Die Bibliothek unterstützt auch die komprimierte DirectX DXT1-Texturformatbibliothek. Die
Windows Imaging-Komponente wird als Maßstab für die Leistung verwendet - das Standardframework für die Arbeit mit Bildern unter Windows. Das heißt, Sie müssen eine Bibliothek finden, die gleichberechtigt oder schneller als WIC funktioniert.
Die wichtigste Voraussetzung ist jedoch, dass jetzt eine Lösung benötigt wird, aber gestern besser.
Treffen Sie die Bibliotheken für die Arbeit mit bmp, tiff, jpeg
Die Lösung beginnt mit einem offensichtlichen und unkomplizierten, wenn auch nicht sehr schnellen Schritt - einer gründlichen Untersuchung von
Wikileaks Github ,
Stackoverflow und anderem Google auf der Suche nach geeigneten Kandidaten für die Rolle der gewünschten Bibliothek. Es gab nur wenige davon:
- FreeImage . Eine Hülle über den berühmten Bibliotheken LibJPEG, LibPNG, LibTIFF. DXT1-Unterstützung ist über das Plugin vorhanden. Der Nachteil ist, dass die Qualität des JPEG-Speicherns in der API zu diskret eingestellt ist - 100, 75,50 und 25%. Um diesen Parameter zu ändern, müssen Sie den Code verstehen und bearbeiten. Das Projekt ist lebhaft und entwickelt sich weiter - die neueste Version 3.18.0 wurde am 31. Juli 2018 veröffentlicht. Die Assembly unter Windows ist trivial, alle Komponenten werden automatisch erstellt.
- Cimg Stellt eine C ++ - Header-Wrapper-Datei über einem alten ImageMagick-
Artefaktpaket dar . Das Paket erfordert eine separate Build-Installation. Es kann auch direkt unter Umgehung von Cimg verwendet werden. Es gibt viele Möglichkeiten, mit Bildern zu arbeiten: Filter, Transformationen, Definition der Morphologie usw. Unterstützt HDR, unterstützt DXT1 nicht. - DevIL ( Entwickler-Bildbibliothek ). Eine sehr einfache C-Bibliothek im OpenGL-Stil. Es enthält eine Shell über LibJPEG, LibPNG, LibTIFF, verfügt aber auch über umfangreiche integrierte Funktionen und unterstützt zusätzlich viele Bildformate, einschließlich DXT1. Für die Montage wird CMake verwendet. Die meisten Abhängigkeiten, einschließlich LibJPEG, LibPNG, LibTIFF, sind nicht in DevIL enthalten und müssen unabhängig heruntergeladen und separat kompiliert werden. Das neueste DevIL-Update für das Build-System ist vom 01.01.2017, und das vorherige Update fand im Allgemeinen im Jahr 2014 statt. Wenn also Probleme mit der Bibliothek auftreten, kann es zu Problemen mit deren Lösung kommen.
- OpenImageIO . Es ist als Entwicklertool für professionelle Software für die Arbeit mit Bildern positioniert. Es unterstützt in Form von Plug-Ins die Arbeit mit vielen exotischen Fotoformaten und sogar Videos. Build für Windows erfordert vorkompiliertes Boost und Qt 4. Es gibt keine vorgefertigte zusammengestellte Version zum Testen.
- Boost GIL (Generic Image Library) Boost und fertig. Obwohl nicht alle. Diese Bibliothek enthält auch einen Wrapper über LibJPEG, LibPNG und LibTIFF.
- SDL_image 2.0 Wird zusammen mit der SDL-Bibliothek verwendet und Sie werden lachen, enthält aber auch eine Shell über LibJPEG, LibPNG und LibTIFF.
Alle gefundenen Bibliotheken wurden unter Windows unter Verwendung der maximalen Optimierungsstufe des Visual Studio-Compilers und des Schalters / arch: AVX2 kompiliert.
Gleiches gilt für die Bibliotheken LibJPEG, LibPNG und LibTIFF, um die Arbeit aus dem neuen
OpenCV-Bibliothekspaket zu beschleunigen.
Treffen Sie den Google Benchmark
Der nächste Lösungsschritt liegt ebenfalls auf der Hand: Die Erstellung eines Benchmarks zum Vergleichen der Leistung gefundener Bibliotheken und die Verwendung der in engen Kreisen weithin bekannten Google Benchmark-Mikrobenchmarking-Bibliothek machen dies einfach und schnell.
Google Benchmark kann die Leistung der Codeteile, die Sie in den Hauptteil des C ++ 11-Zyklus eingefügt haben, genau messen.
static void BM_foo1(benchmark::State& state) {
in Funktionen, die als Benchmark registriert sind
Und lass sie laufen:
BENCHMARK_MAIN();
Geben Sie dann einen Bericht im angegebenen Format aus - Konsolenausgabe, json, csv.
Der Bericht enthält Daten zum Ausführungssystem (Prozessor, Cache-Konfiguration), die globale Gesamtbetriebszeit jeder der gemessenen Funktionen sowie die Zeit, die der Prozessor benötigt. Diese Zeiten unterscheiden sich im Allgemeinen - die erste enthält beispielsweise eine Lese- / Schreibverzögerung, und die zweite für Multithread-Benchmarks ist die Summe der Betriebszeit aller Kerne.
Der letzte vom Google-Benchmark angezeigte Parameter ist die Anzahl der für die Funktion durchgeführten Iterationen, die für die statistisch korrekte genaue Messung ihrer Betriebszeit erforderlich sind. Das System wählt es automatisch selbst aus und führt vorläufige Messungen durch.
Was ist eine „genaue Messung“ der Laufzeit? Sie können Dissertationen zu diesem Thema schreiben, aber in diesem Fall reicht es zu sagen:
- Standardmäßig erfolgt die Messung in Prozessorclustern, dh die theoretische Reihenfolge der Genauigkeit ist genau diese. Die Standardausgabe erfolgt in Nanosekunden.
- Die Ergebnisse aller Tests, die ich gesehen habe, sind von Start zu Start sehr stabil.
- Nach meinen Daten wird der Google-Benchmark von Entwicklern von Bordcomputersoftware eines der weltweit größten Automobilunternehmen verwendet und von seinen Ergebnissen voll vertrauenswürdig. Also werden wir glauben.
Das einzige, worauf Sie achten sollten: Google Benchmark bietet keine "Bereinigung" des Caches zwischen den Starts der Benchmark-Iterationen. Wenn nötig, sollten Sie sich selbst darum kümmern.
Der Google-Benchmark kann jedoch noch viele andere Dinge tun:
- Berechnen Sie die asymptotische Komplexität des Algorithmus (O).
- Arbeiten Sie korrekt mit Multithread-Benchmarks und messen Sie deren Dauer nicht in Prozessor-Ticks, sondern im Echtzeitmodus (Wanduhr).
- Verwenden Sie Ihre eigene Funktion der "manuellen" Zeitmessung, die beispielsweise bei der Messung der Arbeit an der GPU hilfreich sein kann.
- Setzen Sie automatisch Benchmarks mit unterschiedlichen Argumenten für einen bestimmten Körper der gemessenen Funktion.
- Zeigen Sie den Durchschnittswert, den Median und die Standardabweichung für mehrere Starts der Benchmark an.
- Legen Sie Ihre eigenen Zähler und Tags fest, die im Google-Benchmark-Bericht angezeigt werden.
Der Google-Benchmark wird aus
dem Github-Repository heruntergeladen und mit
Cmake für die entsprechende Plattform zusammengestellt (Visual Studio-Assembly ist für Windows verfügbar). Die resultierende Bibliothek wird mit Ihrem Projekt verknüpft (bei Windows wird auch ein Link mit der shlwapi-Bibliothek benötigt). Die Benchmark-Headerdatei wird Ihrem Code hinzugefügt .h, danach funktioniert alles wie oben beschrieben.
Wenn dies nicht funktioniert, ist neben der
bereits angegebenen Website der einzige Ort,
an dem Sie zumindest einige Informationen und Hilfe zum Google-Benchmark erhalten können, ein
spezialisiertes Produktforum .
In unserem Fall hat alles ohne Probleme funktioniert. Nach der Kommunikation mit Kunden wurden 4 Benchmarks definiert, die unter einem anderen Namen geladen und gespeichert werden:
- 8-Bit-JPEG-Datei mit einer Auflösung von 15k
- 24-Bit-JPEG-Datei mit einer Auflösung von 15k
- 24-Bit-TIFF-Datei mit einer Auflösung von 15k
- 32-Bit-BMP-Datei mit einer Auflösung von 32x32
Treffen Sie die Ergebnisse
Es war ursprünglich geplant, dass alle gefundenen Bibliotheken, d. H. FreeImage, Cimg, DevIL, OpenImageIO, Boost GIL und SDL_image 2.0, am Testvergleich mit Windows Imaging Component (WIC) teilnehmen. Aber die letzten drei Bibliotheken, abhängig von solchen "Monstern" wie Boost und SDL, wurden von Kunden gebeten, im Notfall in Reserve zu bleiben, wenn die gewünschte Bibliothek nicht unter den ersten drei gefunden wird. Und zum Glück wurde sie gefunden. Obwohl nicht sofort.
Der folgende Bericht wurde vom Google-Benchmark erstellt und zeigt Folgendes:
- FreeImage mit einem Crushing Score verliert WIC in allen Tests und kann daher nicht mehr berücksichtigt werden.
- Cimg verliert WIC überall sauber, außer beim Laden von TIFF, wo es etwas (weniger als 5%) schneller ist. Leider muss er auch gelöscht werden. Darüber hinaus gilt dies für die direkte Verwendung des ImageMagick-Pakets.
Bleibt die DevIL-Bibliothek. Es zeigt hervorragende Ergebnisse beim Laden von bmp und tiff (3- und 2,8-mal höher als WIC!), Schwarz-Weiß-JPEG (1,75-mal besser als WIC), verlangsamt sich jedoch beim Laden eines normalen 24-Bit-JPEG etwas - es macht es um 3 % langsamer als 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) |
Benchmark | Time | CPU | Iterations |
BM_WIC8jpeg | 72 ms | 70 ms | 11 |
BM_cimg8jpeg | 562 ms | 52 ms | 10 |
BM_FreeImage8jpeg | 147 ms | 144 ms | 5 |
BM_devIL8jpeg | 41 ms | 41 ms | 17 |
|
BM_WIC24jpeg | 266 ms | 260 ms | 3 |
BM_cimg24jpeg | 656 ms | 128 ms | 6 |
BM_FreeImage24jpeg | 594 ms | 594 ms | 1 |
BM_devIL24jpeg | 276 ms | 276 ms | 3 |
|
BM_WIC24tiff | 844 ms | 844 ms | 1 |
BM_cimg24tiff | 808 ms | 131 ms | 5 |
BM_FreeImage24tiff | 953 ms | 938 ms | 1 |
BM_devIL24tiff | 305 ms | 305 ms | 2 |
|
BM_WIC32 | 3 ms | 3 ms | 236 |
BM_cimg32 | 71 ms | 7 ms | 90 |
BM_FreeImage32 | 6 ms | 5 ms | 112 |
BM_devIL32 | 1 ms | 1 ms | 747 |
Natürlich könnte DevIL zu diesem Zeitpunkt auch abgelehnt werden, aber hier erscheint eine andere Bibliothek im Rahmen -
Libjpeg-turbo .
Die Ausgabe kann leicht mit Applaus
beantwortet werden -
Libjpeg-turbo ist eine plattformübergreifende Bibliothek, die die libjpeg-Funktionalität (API) vollständig implementiert und ihre eigene Funktionalität hinzufügt (z. B. Arbeiten mit 32-Bit-Puffern). Gleichzeitig verwendet Libjpeg-turbo für die x86-Architektur aktiv Vektoranweisungen (SSE2, AVX2) und ist laut seinen Erstellern 2-6-mal schneller als libjpeg (!)
Daher besteht der nächste Schritt darin, DevIL mit Libjpeg-turbo anstelle von libjpeg zu erstellen. Libjpeg-turbo erstellt mit Hilfe von CMake problemlos Visual Studio und arbeitet dann fast sofort (mit dem Ersatz der einzigen #define, die die Version von libjpeg in der DevIL-Headerdatei bestimmt) als Teil von DevIL.
Infolgedessen sieht der Google-Benchmark-Bericht folgendermaßen aus:
Benchmark | Time | CPU | Iterations |
BM_WIC8jpeg | 72 ms | 68 ms | 9 |
BM_cimg8jpeg | 565 ms | 39 ms | 10 |
BM_FreeImage8jpeg | 148 ms | 141 ms | 5 |
BM_devIL8jpeg | 31 ms | 31 ms | 24 |
|
BM_WIC24jpeg | 269 ms | 266 ms | 2 |
BM_cimg24jpeg | 675 ms | 131 ms | 5 |
BM_FreeImage24jpeg | 604 ms | 594 ms | 1 |
BM_devIL24jpeg | 149 ms | 150 ms | 5 |
|
BM_WIC24tiff | 833 ms | 828 ms | 1 |
BM_cimg24tiff | 785 ms | 138 ms | 5 |
BM_FreeImage24tiff | 943 ms | 938 ms | 1 |
BM_devIL24tiff | 318 ms | 320 ms | 2 |
|
BM_WIC32 | 4 ms | 3 ms | 236 |
BM_cimg32 | 74 ms | 8 ms | 56 |
BM_FreeImage32 | 6 ms | 5 ms | 100 |
BM_devIL32 | 1 ms | 1 ms | 747 |
Natürlich sind Leistungsverbesserungen mit JPEG im Vergleich zu libjpeg nicht einmal doppelt so hoch, aber das sollte auch so sein - denn die Geschwindigkeitsüberlegenheit gilt nur für die JPEG-Codierung / -Decodierung, und der Test beinhaltet den Aufwand für das Lesen / Schreiben einer Datei.
Es ist jedoch ersichtlich, dass DevIL im Durchschnitt 8-Bit-JPEG
2,3- mal, 24-Bit-JPEG
1,8- mal, 24-Bit-TIFF -
2,7- mal, 32-Bit-BMP -
3,5- mal schneller als WIC ist.
Das Problem ist gelöst. Drei Sommerarbeitstage vor den Ferien wurden vollständig für die Entscheidung aufgewendet. Wenn es ein bisschen mehr gäbe, wäre es natürlich möglich, dass es eine Bibliothek mit noch beeindruckenderen Ergebnissen gibt, und wenn es viel mehr wäre, würde ich vielleicht die Bibliothek schreiben, die ich selbst gesucht habe.
Aber auch was beeindruckend ist. Wenn Sie also nach einer plattformübergreifenden Bibliothek für die Arbeit mit Grafikdateien suchen, die in jeder Hinsicht schnell und einfach ist, achten Sie auf
DevIL . Wenn Sie schnell und genau vergleichende Messungen des Codes durchführen müssen,
steht Ihnen der
Google-Benchmark zur Verfügung.