Intel ha uno specifico CRC32
instruction disponibile nel set di istruzioni SSE4.2. Come posso sfruttare questa istruzione per accelerare i calcoli CRC32?Come implementare CRC32 sfruttando le istruzioni specifiche di Intel?
risposta
Prima di tutto di istruzioni del processore Intel CRC32
serve per calcolare CRC-32C
(cioè utilizza un polinomio diverso che regolare CRC32 Guardate la voce Wikipedia CRC32.)
Per utilizzare l'accelerazione hardware di Intel per CRC32C utilizzando gcc
è possibile:
- Inline linguaggio assembly in codice C tramite la dichiarazione
asm
- Utilizzare intrinseche
_mm_crc32_u8
,_mm_crc32_u16
,_mm_crc32_u32
o_mm_crc32_u64
. Vedere Intel Intrinsics Guide per una descrizione di quelli per il compilatore Intelicc
ma anchegcc
li implementa.
Questo è come si dovrebbe farlo con __mm_crc32_u8
che prende un byte alla volta, utilizzando __mm_crc32_u64
darebbe un ulteriore miglioramento delle prestazioni visto che richiede 8 byte alla volta.
uint32_t sse42_crc32(const uint8_t *bytes, size_t len)
{
uint32_t hash = 0;
size_t i = 0;
for (i=0;i<len;i++) {
hash = _mm_crc32_u8(hash, bytes[i]);
}
return hash;
}
per compilare questo è necessario passare -msse4.2
in CFLAGS
. Come gcc -g -msse4.2 test.c
altrimenti si lamenterà di undefined reference to _mm_crc32_u8
.
Se si desidera ripristinare un'implementazione C semplice se l'istruzione non è disponibile nella piattaforma su cui è in esecuzione l'eseguibile, è possibile utilizzare l'attributo GCC ifunc
. Come
uint32_t sse42_crc32(const uint8_t *bytes, size_t len)
{
/* use _mm_crc32_u* here */
}
uint32_t default_crc32(const uint8_t *bytes, size_t len)
{
/* pure C implementation */
}
/* this will be called at load time to decide which function really use */
/* sse42_crc32 if SSE 4.2 is supported */
/* default_crc32 if not */
static void * resolve_crc32(void) {
__builtin_cpu_init();
if (__builtin_cpu_supports("sse4.2")) return sse42_crc32;
return default_crc32;
}
/* crc32() implementation will be resolved at load time to either */
/* sse42_crc32() or default_crc32() */
uint32_t crc32(const uint8_t *bytes, size_t len) __attribute__ ((ifunc ("resolve_crc32")));
Vedere this answer per le implementazioni hardware e software veloci di CRC-32C. L'implementazione hardware esegue in modo efficace tre istruzioni crc32
in parallelo per la velocità.
Se è legale leggere il codice LGPL, vedere http://code.woboq.org/qt5/qtbase/src/corelib/tools/qhash.cpp.html#95 – peppe