Skip to content

Commit 44c6391

Browse files
Nicoshevmeta-codesync[bot]
authored andcommitted
Improve aarch64 crc32 on short-input
Summary: We are introducing a specialized crc32 routine for small inputs It is a mix between v2s1x2 and s1x2 Performance improvements vary widely depending on the input size, ranging from 1% to 57% Before: crc32_8 2.75ns 363.06M crc32_16 2.78ns 360.04M crc32_32 2.73ns 365.92M crc32_64 4.10ns 243.83M crc32_128 7.59ns 131.80M crc32_256 11.23ns 89.03M crc32_384 20.35ns 49.14M crc32_512 20.96ns 47.71M crc32_1024 40.39ns 24.76M After: crc32_8 2.61ns 383.85M crc32_16 2.75ns 364.25M crc32_32 2.71ns 369.42M crc32_64 3.31ns 302.35M crc32_128 4.51ns 221.65M crc32_256 9.32ns 107.27M crc32_384 14.13ns 70.78M crc32_512 18.44ns 54.23M crc32_1024 33.94ns 29.46M Reviewed By: yfeldblum Differential Revision: D95478675 fbshipit-source-id: 4ffcc9966ebe8fd979fad15bf23508e0b97ba76e
1 parent 361e958 commit 44c6391

3 files changed

Lines changed: 81 additions & 2 deletions

File tree

third-party/folly/src/folly/external/fast-crc32/neon_eor3_crc32_v8s2x4e_s1x2.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ CRC_EXPORT uint32_t neon_eor3_crc32_v8s2x4e_s1x2(const uint8_t*, size_t, uint32_
2525
abort(); // not implemented on this platform
2626
}
2727

28+
CRC_EXPORT uint32_t neon_eor3_crc32_small(const uint8_t*, size_t, uint32_t) {
29+
abort(); // not implemented on this platform
30+
}
31+
2832
CRC_EXPORT bool has_neon_eor3_crc32_v8s2x4e_s1x2() {
2933
return false;
3034
}
@@ -85,6 +89,75 @@ CRC_EXPORT bool has_neon_eor3_crc32_v8s2x4e_s1x2() {
8589
caps.aarch64_crc32() && caps.aarch64_sha3();
8690
}
8791

92+
// Mix v2s1x2 and s1x2
93+
CRC_EXPORT uint32_t neon_eor3_crc32_small(const uint8_t* buf, size_t len, uint32_t crc0) {
94+
for (; len && ((uintptr_t)buf & 7); --len) {
95+
crc0 = __crc32b(crc0, *buf++);
96+
}
97+
if (len > 384) {
98+
if (((uintptr_t)buf & 8)) {
99+
crc0 = __crc32d(crc0, *(const uint64_t*)buf);
100+
buf += 8;
101+
len -= 8;
102+
}
103+
size_t blk = (len - 0) / 48;
104+
size_t klen = blk * 16;
105+
const uint8_t* buf2 = buf + klen;
106+
uint64x2_t vc0;
107+
uint64_t vc;
108+
/* First vector chunk. */
109+
uint64x2_t x0 = vld1q_u64((const uint64_t*)buf2), y0;
110+
uint64x2_t x1 = vld1q_u64((const uint64_t*)(buf2 + 16)), y1;
111+
uint64x2_t k;
112+
{ static const uint64_t CRC_ALIGN(16) k_[] = {0xf1da05aa, 0x81256527}; k = vld1q_u64(k_); }
113+
buf2 += 32;
114+
len -= 48;
115+
/* Main loop. */
116+
do {
117+
y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k);
118+
y1 = clmul_lo(x1, k), x1 = clmul_hi(x1, k);
119+
x0 = veor3q_u64(x0, y0, vld1q_u64((const uint64_t*)buf2));
120+
x1 = veor3q_u64(x1, y1, vld1q_u64((const uint64_t*)(buf2 + 16)));
121+
crc0 = __crc32d(crc0, *(const uint64_t*)buf);
122+
crc0 = __crc32d(crc0, *(const uint64_t*)(buf + 8));
123+
buf += 16;
124+
buf2 += 32;
125+
len -= 48;
126+
} while (len >= 48);
127+
/* Reduce x0 ... x1 to just x0. */
128+
{ static const uint64_t CRC_ALIGN(16) k_[] = {0xae689191, 0xccaa009e}; k = vld1q_u64(k_); }
129+
y0 = clmul_lo(x0, k), x0 = clmul_hi(x0, k);
130+
x0 = veor3q_u64(x0, y0, x1);
131+
/* Final scalar chunk. */
132+
crc0 = __crc32d(crc0, *(const uint64_t*)buf);
133+
crc0 = __crc32d(crc0, *(const uint64_t*)(buf + 8));
134+
vc0 = crc_shift(crc0, 0 + blk * 32);
135+
vc = vgetq_lane_u64(vc0, 0);
136+
/* Reduce 128 bits to 32 bits, and multiply by x^32. */
137+
crc0 = __crc32d(0, vgetq_lane_u64(x0, 0));
138+
crc0 = __crc32d(crc0, vc ^ vgetq_lane_u64(x0, 1));
139+
buf = buf2;
140+
}
141+
if (len >= 16) {
142+
/* Main loop. */
143+
do {
144+
crc0 = __crc32d(crc0, *(const uint64_t*)buf);
145+
crc0 = __crc32d(crc0, *(const uint64_t*)(buf + 8));
146+
buf += 16;
147+
len -= 16;
148+
} while (len >= 16);
149+
}
150+
if (len >= 8) {
151+
crc0 = __crc32d(crc0, *(const uint64_t*)buf);
152+
len -= 8;
153+
buf += 8;
154+
}
155+
for (; len; --len) {
156+
crc0 = __crc32b(crc0, *buf++);
157+
}
158+
return crc0;
159+
}
160+
88161
CRC_EXPORT uint32_t neon_eor3_crc32_v8s2x4e_s1x2(const uint8_t* buf, size_t len, uint32_t crc0) {
89162
for (; len && ((uintptr_t)buf & 7); --len) {
90163
crc0 = __crc32b(crc0, *buf++);

third-party/folly/src/folly/external/fast-crc32/neon_eor3_crc32_v8s2x4e_s1x2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44

55
namespace folly::detail {
66
uint32_t neon_eor3_crc32_v8s2x4e_s1x2(const uint8_t* buf, size_t len, uint32_t crc0);
7+
uint32_t neon_eor3_crc32_small(const uint8_t* buf, size_t len, uint32_t crc0);
78
bool has_neon_eor3_crc32_v8s2x4e_s1x2();
89
}

third-party/folly/src/folly/hash/Checksum.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,13 @@ uint32_t crc32c(const uint8_t* data, size_t nbytes, uint32_t startingChecksum) {
244244

245245
uint32_t crc32(const uint8_t* data, size_t nbytes, uint32_t startingChecksum) {
246246
#if FOLLY_AARCH64
247-
if (nbytes >= 2048 && detail::crc32_hw_supported_neon_eor3_sha3()) {
248-
return detail::neon_eor3_crc32_v8s2x4e_s1x2(data, nbytes, startingChecksum);
247+
if (detail::crc32_hw_supported_neon_eor3_sha3()) {
248+
if (nbytes < 1536) {
249+
return detail::neon_eor3_crc32_small(data, nbytes, startingChecksum);
250+
} else {
251+
return detail::neon_eor3_crc32_v8s2x4e_s1x2(
252+
data, nbytes, startingChecksum);
253+
}
249254
}
250255
#endif
251256

0 commit comments

Comments
 (0)