util/crc32c: add SSE 4.2 CRC32 instruction support
Use the CRC32 CPU instruction, if available, to optimize the iSCSI CRC-32C calculation. Change-Id: Ifb706528c28f5e6921ebf525274b959d8cac85a0 Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com> Reviewed-on: https://review.gerrithub.io/370766 Tested-by: SPDK Automated Test System <sys_sgsw@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
parent
ae60710ab8
commit
b483027aca
@ -33,6 +33,45 @@
|
||||
|
||||
#include "spdk/crc32.h"
|
||||
|
||||
#if defined(__x86_64__) && defined(__SSE4_2__)
|
||||
#include <x86intrin.h>
|
||||
|
||||
uint32_t
|
||||
spdk_crc32c_update(const void *buf, size_t len, uint32_t crc)
|
||||
{
|
||||
uint64_t crc_tmp64;
|
||||
size_t count;
|
||||
|
||||
/* _mm_crc32_u64() needs a 64-bit intermediate value */
|
||||
crc_tmp64 = crc;
|
||||
|
||||
/* Process as much of the buffer as possible in 64-bit blocks. */
|
||||
count = len / 8;
|
||||
while (count--) {
|
||||
uint64_t block;
|
||||
|
||||
/*
|
||||
* Use memcpy() to avoid unaligned loads, which are undefined behavior in C.
|
||||
* The compiler will optimize out the memcpy() in release builds.
|
||||
*/
|
||||
memcpy(&block, buf, sizeof(block));
|
||||
crc_tmp64 = _mm_crc32_u64(crc_tmp64, block);
|
||||
buf += sizeof(block);
|
||||
}
|
||||
crc = (uint32_t)crc_tmp64;
|
||||
|
||||
/* Handle any trailing bytes. */
|
||||
count = len & 7;
|
||||
while (count--) {
|
||||
crc = _mm_crc32_u8(crc, *(const uint8_t *)buf);
|
||||
buf++;
|
||||
}
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
#else /* SSE 4.2 (CRC32 instruction) not available */
|
||||
|
||||
static struct spdk_crc32_table g_crc32c_table;
|
||||
|
||||
__attribute__((constructor)) static void
|
||||
@ -46,3 +85,5 @@ spdk_crc32c_update(const void *buf, size_t len, uint32_t crc)
|
||||
{
|
||||
return spdk_crc32_update(&g_crc32c_table, buf, len, crc);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -42,12 +42,83 @@ static void
|
||||
test_crc32c(void)
|
||||
{
|
||||
uint32_t crc;
|
||||
char buf[] = "Hello world!";
|
||||
char buf[1024];
|
||||
|
||||
/* Verify a string's CRC32-C value against the known correct result. */
|
||||
snprintf(buf, sizeof(buf), "%s", "Hello world!");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0x7b98e751);
|
||||
|
||||
/*
|
||||
* The main loop of the optimized CRC32-C implementation processes data in 8-byte blocks,
|
||||
* followed by a loop to handle the 0-7 trailing bytes.
|
||||
* Test all buffer sizes from 0 to 7 in order to hit all possible trailing byte counts.
|
||||
*/
|
||||
|
||||
/* 0-byte buffer should not modify CRC at all, so final result should be ~0 ^ ~0 == 0 */
|
||||
snprintf(buf, sizeof(buf), "%s", "");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0);
|
||||
|
||||
/* 1-byte buffer */
|
||||
snprintf(buf, sizeof(buf), "%s", "1");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0x90F599E3);
|
||||
|
||||
/* 2-byte buffer */
|
||||
snprintf(buf, sizeof(buf), "%s", "12");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0x7355C460);
|
||||
|
||||
/* 3-byte buffer */
|
||||
snprintf(buf, sizeof(buf), "%s", "123");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0x107B2FB2);
|
||||
|
||||
/* 4-byte buffer */
|
||||
snprintf(buf, sizeof(buf), "%s", "1234");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0xF63AF4EE);
|
||||
|
||||
/* 5-byte buffer */
|
||||
snprintf(buf, sizeof(buf), "%s", "12345");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0x18D12335);
|
||||
|
||||
/* 6-byte buffer */
|
||||
snprintf(buf, sizeof(buf), "%s", "123456");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0x41357186);
|
||||
|
||||
/* 7-byte buffer */
|
||||
snprintf(buf, sizeof(buf), "%s", "1234567");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0x124297EA);
|
||||
|
||||
/* Test a buffer of exactly 8 bytes (one block in the main CRC32-C loop). */
|
||||
snprintf(buf, sizeof(buf), "%s", "12345678");
|
||||
crc = 0xFFFFFFFFu;
|
||||
crc = spdk_crc32c_update(buf, strlen(buf), crc);
|
||||
crc ^= 0xFFFFFFFFu;
|
||||
CU_ASSERT(crc == 0x6087809A);
|
||||
}
|
||||
|
||||
int
|
||||
|
Loading…
Reference in New Issue
Block a user