Intelには特定の CRC32
命令 SSE4.2命令セットで使用できます。この命令を利用してCRC32計算を高速化するにはどうすればよいですか?
まず、IntelのCRC32
命令はCRC-32C
を計算するのに役立ちます(つまり、通常のCRC32とは異なる多項式を使用します。 WikipediaCRC32 エントリを見てください)
gcc
を使用してCRC32Cにインテルのハードウェアアクセラレーションを使用するには、次のことができます。
asm
ステートメントによるCコードのインラインアセンブリ言語_mm_crc32_u8
、_mm_crc32_u16
、_mm_crc32_u32
または_mm_crc32_u64
を使用します。インテルのコンパイラーicc
の説明については、 インテル組み込み関数ガイド を参照してください。ただし、gcc
もそれらを実装しています。これは、一度に1バイトかかる__mm_crc32_u8
でそれを行う方法です。__mm_crc32_u64
を使用すると、一度に8バイトかかるため、パフォーマンスがさらに向上します。
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;
}
これをコンパイルするには、CFLAGS
に-msse4.2
を渡す必要があります。 gcc -g -msse4.2 test.c
と同様に、それ以外の場合はundefined reference to _mm_crc32_u8
について文句を言います。
実行可能ファイルが実行されているプラットフォームで命令が使用できない場合にプレーンC実装に戻したい場合は、GCCのifunc
属性を使用できます。お気に入り
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")));
CRC-32Cの高速ハードウェアおよびソフトウェア実装については、 この回答 を参照してください。ハードウェア実装は、速度のために3つのcrc32
命令を並行して効果的に実行します。