Die SIMDComp-Bibliothek
Eine einfache C-Bibliothek zum Komprimieren von Ganzzahllisten mithilfe von Binärpackungs- und SIMD-Anweisungen. Die Annahme ist entweder, dass Sie eine Liste von 32-Bit-Ganzzahlen haben, von denen die meisten klein sind, oder eine Liste von 32-Bit-Ganzzahlen, in denen die Unterschiede zwischen aufeinanderfolgenden Ganzzahlen gering sind. Keine Software ist in der Lage, ein Array von 32-Bit-Zufallszahlen zuverlässig zu komprimieren.
Diese Bibliothek kann auf den meisten Desktop- oder Laptop-Prozessoren mindestens 4 Milliarden komprimierte Ganzzahlen pro Sekunde dekodieren. Das heißt, es kann Daten mit einer Rate von 15 GB/s dekomprimieren. Dies ist deutlich schneller als generische Codecs wie gzip, LZO, Snappy oder LZ4.
Auf einem Skylake-Intel-Prozessor kann er Ganzzahlen mit einer Rate von 0,3 Zyklen pro Ganzzahl dekodieren, was sich problemlos in mehr als 8 dekodierte Milliarden Ganzzahlen pro Sekunde umsetzen lässt.
Diese Bibliothek ist Teil der Awesome C-Liste der C-Ressourcen.
Mitwirkende: Daniel Lemire, Nathan Kurz, Christoph Rupp, Anatol Belski, Nick White und andere
Wozu dient es?
Dies ist eine Low-Level-Bibliothek für die schnelle Ganzzahlkomprimierung. Es definiert konstruktionsbedingt kein komprimiertes Format. Es ist Sache des (erfahrenen) Benutzers, ein komprimiertes Format zu erstellen.
Es wird verwendet von:
- upscaledb
- EventQL
- ManticoreSearch
Anforderungen
- Ihr Prozessor sollte SSE4.1 unterstützen (Es wird von den meisten seit 2008 veröffentlichten Intel- und AMD-Prozessoren unterstützt.)
- Es ist möglich, den Kernteil des Codes zu erstellen, wenn Ihr Prozessor SSE2 (Pentium4 oder besser) unterstützt.
- C99-kompatibler Compiler (GCC wird vorausgesetzt)
- Das Makefile geht von einer Linux-ähnlichen Distribution aus
Eine einfache C-Version, die keine SIMD-Anweisungen verwendet, finden Sie unter https://github.com/lemire/LittleIntPacker
Verwendung
Die Komprimierung funktioniert über Blöcke mit 128 Ganzzahlen.
Ein vollständiges Arbeitsbeispiel finden Sie unter example.c (Sie können es erstellen und mit „make example; ./example“ ausführen).
- Listen von ganzen Zahlen in zufälliger Reihenfolge.
const uint32_t b = maxbits ( datain ); // computes bit width
simdpackwithoutmask ( datain , buffer , b ); //compressed to buffer, compressing 128 32-bit integers down to b*32 bytes
simdunpack ( buffer , backbuffer , b ); //uncompressed to backbuffer
Während 128 32-Bit-Ganzzahlen gelesen werden, werden nur b 128-Bit-Wörter geschrieben. Somit beträgt das Kompressionsverhältnis 32/b.
- Sortierte Listen von ganzen Zahlen.
Wir haben Differentialkodierung verwendet: Wir speichern die Differenz zwischen aufeinanderfolgenden ganzen Zahlen. Dazu benötigen wir einen Anfangswert (Offset genannt).
uint32_t offset = 0 ;
uint32_t b1 = simdmaxbitsd1 ( offset , datain ); // bit width
simdpackwithoutmaskd1 ( offset , datain , buffer , b1 ); //compressing 128 32-bit integers down to b1*32 bytes
simdunpackd1 ( offset , buffer , backbuffer , b1 ); //uncompressed
Allgemeines Beispiel für Arrays beliebiger Länge:
int compress_decompress_demo () {
size_t k , N = 9999 ;
__m128i * endofbuf ;
uint32_t * datain = malloc ( N * sizeof ( uint32_t ));
uint8_t * buffer ;
uint32_t * backbuffer = malloc ( N * sizeof ( uint32_t ));
uint32_t b ;
for ( k = 0 ; k < N ; ++ k ){ /* start with k=0, not k=1! */
datain [ k ] = k ;
}
b = maxbits_length ( datain , N );
buffer = malloc ( simdpack_compressedbytes ( N , b )); // allocate just enough memory
endofbuf = simdpack_length ( datain , N , ( __m128i * ) buffer , b );
/* compressed data is stored between buffer and endofbuf using (endofbuf-buffer)*sizeof(__m128i) bytes */
/* would be safe to do : buffer = realloc(buffer,(endofbuf-(__m128i *)buffer)*sizeof(__m128i)); */
simdunpack_length (( const __m128i * ) buffer , N , backbuffer , b );
for ( k = 0 ; k < N ; ++ k ){
if ( datain [ k ] != backbuffer [ k ]) {
printf ( "bugn" );
return -1 ;
}
}
return 0 ;
}
- Referenzrahmen
Wir haben auch Frame-of-Reference (FOR)-Funktionen (siehe simdfor.h-Header). Sie funktionieren wie die Bitpacking-Routinen, verwenden jedoch keine Differenzcodierung, sodass sie in einigen Fällen eine schnellere Suche auf Kosten der Komprimierung ermöglichen.
Aufstellen
machen, machen, testen
Und wenn Sie sich trauen:
make installieren
Gehen
Wenn Sie ein Go-Benutzer sind, gibt es einen „Go“-Ordner, in dem Sie eine einfache Demo finden.
Andere Bibliotheken
- Schnelle Ganzzahlkomprimierung in Go: https://github.com/ronanh/intcomp
- Schnelle Bitpacking-Algorithmen: Rust-Port von simdcomp https://github.com/quickwit-oss/bitpacking
- SIMDCompressionAndIntersection: Eine C++-Bibliothek zum Komprimieren und Schneiden sortierter Listen von Ganzzahlen mithilfe von SIMD-Anweisungen https://github.com/lemire/SIMDCompressionAndIntersection
- Die FastPFOR C++-Bibliothek: Schnelle Ganzzahlkomprimierung https://github.com/lemire/FastPFor
- Leistungsstarke Wörterbuchcodierung https://github.com/lemire/dictionary
- LittleIntPacker: C-Bibliothek zum schnellstmöglichen Packen und Entpacken kurzer Arrays von Ganzzahlen https://github.com/lemire/LittleIntPacker
- StreamVByte: Schnelle Ganzzahlkomprimierung in C mit dem StreamVByte-Codec https://github.com/lemire/streamvbyte
- MaskedVByte: Schneller Decoder für VByte-komprimierte Ganzzahlen https://github.com/lemire/MaskedVByte
- CSharpFastPFOR: AC#-Integer-Komprimierungsbibliothek https://github.com/Genbox/CSharpFastPFOR
- JavaFastPFOR: Eine Java-Integer-Komprimierungsbibliothek https://github.com/lemire/JavaFastPFOR
- Kodierung: Ganzzahlkomprimierungsbibliotheken für Go https://github.com/zhenjl/encoding
- FrameOfReference ist eine C++-Bibliothek speziell für die Frame-of-Reference-Komprimierung (FOR): https://github.com/lemire/FrameOfReference
- libvbyte: Eine schnelle Implementierung für Varbyte 32bit/64bit Integer-Komprimierung https://github.com/cruppstahl/libvbyte
- TurboPFor ist eine C-Bibliothek, die viele interessante Optimierungen bietet. Es lohnt sich, einen Blick darauf zu werfen! (GPL-Lizenz) https://github.com/powturbo/TurboPFor
- Oroch ist eine C++-Bibliothek, die eine nutzbare API (MIT-Lizenz) https://github.com/ademakov/Oroch bietet
Andere Programmiersprachen
- Für Julia gibt es eine Hülle.
- Es gibt einen Rust-Port.
Referenzen
- Daniel Lemire, Nathan Kurz, Christoph Rupp, Stream VByte: Schnellere byteorientierte Ganzzahlkomprimierung, Informationsverarbeitungsbriefe, Informationsverarbeitungsbriefe 130, Februar 2018, Seiten 1–6https://arxiv.org/abs/1709.08990
- Jianguo Wang, Chunbin Lin, Yannis Papakonstantinou, Steven Swanson, Eine experimentelle Studie zur Bitmap-Komprimierung im Vergleich zur Komprimierung invertierter Listen, SIGMOD 2017 http://db.ucsd.edu/wp-content/uploads/2017/03/sidm338-wangA. pdf
- P. Damme, D. Habich, J. Hildebrandt, W. Lehner, Lightweight Data Compression Algorithms: An Experimental Survey (Experimente und Analysen), EDBT 2017 http://openproceedings.org/2017/conf/edbt/paper-146. pdf
- P. Damme, D. Habich, J. Hildebrandt, W. Lehner, Insights into the Comparative Evaluation of Lightweight Data Compression Algorithms, EDBT 2017 http://openproceedings.org/2017/conf/edbt/paper-414.pdf
- Daniel Lemire, Leonid Boytsov, Nathan Kurz, SIMD Compression and the Intersection of Sorted Integers, Software Practice & Experience 46 (6) 2016. http://arxiv.org/abs/1401.6399
- Daniel Lemire und Leonid Boytsov, Decoding billions of integers per second through vectorization, Software Practice & Experience 45 (1), 2015. http://arxiv.org/abs/1209.2137 http://onlinelibrary.wiley.com/doi/10.1002 /spe.2203/abstract
- Jeff Plaisance, Nathan Kurz, Daniel Lemire, Vectorized VByte Decoding, International Symposium on Web Algorithms 2015, 2015. http://arxiv.org/abs/1503.07387
- Wayne Xin Zhao, ://arxiv.org/abs/1502.01916
- TD Wu, Bitpacking-Techniken zur Indexierung von Genomen: I. Hash-Tabellen, Algorithms for Molecular Biology 11 (5), 2016. http://almob.biomedcentral.com/articles/10.1186/s13015-016-0069-5