From a68cbb532ab1dd47d9167f2f5278c3ad7ebada4d Mon Sep 17 00:00:00 2001 From: z00347042 Date: Thu, 11 Jun 2020 15:53:11 +0800 Subject: [PATCH] =?UTF-8?q?MYSQL=20BINLOG=20CRC32=20ARM=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E5=8A=A0=E9=80=9F=EF=BC=9BINNOBASE=20CRC32C=20ARM=E6=8C=87?= =?UTF-8?q?=E4=BB=A4=E5=8A=A0=E9=80=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mysys/checksum.cc | 80 ++++++++++++++++++++++++++++++++++++++++++-- storage/innobase/ut/crc32.cc | 36 ++++++++++++++++++-- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/mysys/checksum.cc b/mysys/checksum.cc index 4478431..21e0ca3 100644 --- a/mysys/checksum.cc +++ b/mysys/checksum.cc @@ -31,11 +31,84 @@ #include #include -#include #include "my_inttypes.h" #include "my_sys.h" +#if defined(__aarch64__) +#include +#else +#include +#endif +#define POINTER_IS_ALIGNED(ptr, type) ((reinterpret_cast(buf) & (sizeof (type) - 1)) == 0) +/* + Calculate a long checksum for a memoryblock by cpu instructions. + + SYNOPSIS + crc32_hw() + crc start value for crc + pos pointer to memory block + length length of the block + RETURN + crc32(polynomial 0x04C11DB7) +*/ +#if defined(__aarch64__) +MY_ATTRIBUTE((target("arch=armv8-a+crc"))) +static ha_checksum crc32_hw(ha_checksum crc, const uchar *buf, size_t len) +{ + if (buf == nullptr) return 0UL; + crc = crc ^ 0xffffffffUL; + + /* calculate one byte crc32 result if the pointer of the buf is not aligned with half word */ + if (!POINTER_IS_ALIGNED(buf, uint16_t) && len >= 1) { + crc = __crc32b(crc, *buf); + len -= 1; + buf += 1; + } + + /* calculate half word crc32 result if the pointer of the buf is not aligned with word */ + if (!POINTER_IS_ALIGNED(buf, uint32_t) && len >= 2) { + uint16_t *ptr = reinterpret_cast(const_cast(buf)); + crc = __crc32h(crc, *ptr); + len -= 2; + buf += 2; + } + + /* calculate word crc32 result if the pointer of the buf is not aligned with doulbe word */ + if (!POINTER_IS_ALIGNED(buf, uint64_t) && len >= 4) { + uint32_t *ptr = reinterpret_cast(const_cast(buf)); + crc = __crc32w(crc, *ptr); + len -= 4; + buf += 4; + } + + /* use instruction to caclualte 8 bytes crc32 result every loop */ + while (len >= 8) { + uint64_t *ptr = reinterpret_cast(const_cast(buf)); + crc = __crc32d(crc, *ptr); + len -= 8; + buf += 8; + } + + /* use instruction to caclualte 4 bytes crc32 result at once */ + if (len >= 4) { + uint32_t *ptr = reinterpret_cast(const_cast(buf)); + crc = __crc32w(crc, *ptr); + len -= 4; + buf += 4; + } + + /* use instruction to caclualte 1 bytes crc32 result every loop*/ + if (len) { + do { + crc = __crc32b(crc, *buf); + buf++; + } while (--len); + } + return crc ^ 0xffffffffUL; +} +#endif + /* Calculate a long checksum for a memoryblock. @@ -45,7 +118,10 @@ pos pointer to memory block length length of the block */ - ha_checksum my_checksum(ha_checksum crc, const uchar *pos, size_t length) { +#if defined(__aarch64__) + return (ha_checksum)crc32_hw((uint)crc, pos, (uint)length); +#else return (ha_checksum)crc32((uint)crc, pos, (uint)length); +#endif } diff --git a/storage/innobase/ut/crc32.cc b/storage/innobase/ut/crc32.cc index b0c5569..ec05b10 100644 --- a/storage/innobase/ut/crc32.cc +++ b/storage/innobase/ut/crc32.cc @@ -99,6 +99,9 @@ external tools. */ #define gnuc64 #endif +#if defined(__aarch64__) +#include +#else #if defined(gnuc64) || defined(_WIN32) /* GCC 4.8 can't include intrinsic headers without -msse4.2. @@ -121,6 +124,7 @@ ALWAYS_INLINE uint64_t _mm_crc32_u64(uint64_t __C, uint64_t __V) { } #endif #endif // defined(gnuc64) || defined(_WIN32) +#endif // defined(__aarch64__) #include "univ.i" #include "ut0crc32.h" @@ -155,7 +159,7 @@ bool ut_crc32_cpu_enabled = false; #if defined(_WIN32) #include #endif -#if defined(gnuc64) || defined(_WIN32) +#if defined(gnuc64) || defined(_WIN32) || defined(__aarch64__) /** Checks whether the CPU has the CRC32 instructions (part of the SSE4.2 instruction set). @return true if CRC32 is available */ @@ -180,6 +184,9 @@ static bool ut_crc32_check_cpu() { return false; #else +#if defined(__aarch64__) + return true; +#else uint32_t features_ecx; #if defined(gnuc64) @@ -201,6 +208,7 @@ static bool ut_crc32_check_cpu() { #endif return features_ecx & (1 << 20); // SSE4.2 +#endif /* __aarch64__ */ #endif /* UNIV_DEBUG_VALGRIND */ } @@ -210,9 +218,17 @@ when the function ends it will contain the new checksum @param[in,out] data data to be checksummed, the pointer will be advanced with 1 byte @param[in,out] len remaining bytes, it will be decremented with 1 */ +#if defined(__aarch64__) +MY_ATTRIBUTE((target("arch=armv8-a+crc"))) +#else MY_ATTRIBUTE((target("sse4.2"))) +#endif inline void ut_crc32_8_hw(uint64_t *crc, const byte **data, ulint *len) { +#if defined(__aarch64__) + *crc = __crc32cb(static_cast(*crc), (*data)[0]); +#else *crc = _mm_crc32_u8(static_cast(*crc), (*data)[0]); +#endif (*data)++; (*len)--; } @@ -221,10 +237,18 @@ inline void ut_crc32_8_hw(uint64_t *crc, const byte **data, ulint *len) { @param[in] crc crc32 checksum so far @param[in] data data to be checksummed @return resulting checksum of crc + crc(data) */ +#if defined(__aarch64__) +MY_ATTRIBUTE((target("arch=armv8-a+crc"))) +#else MY_ATTRIBUTE((target("sse4.2"))) +#endif inline uint64_t ut_crc32_64_low_hw(uint64_t crc, uint64_t data) { uint64_t crc_64bit = crc; +#if defined(__aarch64__) + crc_64bit = __crc32cd(crc_64bit, data); +#else crc_64bit = _mm_crc32_u64(crc_64bit, data); +#endif return (crc_64bit); } @@ -234,7 +258,11 @@ when the function ends it will contain the new checksum @param[in,out] data data to be checksummed, the pointer will be advanced with 8 bytes @param[in,out] len remaining bytes, it will be decremented with 8 */ +#if defined(__aarch64__) +MY_ATTRIBUTE((target("arch=armv8-a+crc"))) +#else MY_ATTRIBUTE((target("sse4.2"))) +#endif inline void ut_crc32_64_hw(uint64_t *crc, const byte **data, ulint *len) { uint64_t data_int = *reinterpret_cast(*data); @@ -284,7 +312,11 @@ inline void ut_crc32_64_legacy_big_endian_hw(uint64_t *crc, const byte **data, @param[in] buf data over which to calculate CRC32 @param[in] len data length @return CRC-32C (polynomial 0x11EDC6F41) */ +#if defined(__aarch64__) +MY_ATTRIBUTE((target("arch=armv8-a+crc"))) +#else MY_ATTRIBUTE((target("sse4.2"))) +#endif static uint32_t ut_crc32_hw(const byte *buf, ulint len) { uint64_t crc = 0xFFFFFFFFU; @@ -660,7 +692,7 @@ static uint32_t ut_crc32_byte_by_byte_sw(const byte *buf, ulint len) { /** Initializes the data structures used by ut_crc32*(). Does not do any allocations, would not hurt if called twice, but would be pointless. */ void ut_crc32_init() { -#if defined(gnuc64) || defined(_WIN32) +#if defined(gnuc64) || defined(_WIN32) || defined(__aarch64__) ut_crc32_cpu_enabled = ut_crc32_check_cpu(); if (ut_crc32_cpu_enabled) { -- 1.8.3.1