Skip to content

Commit 685525f

Browse files
authored
optimize crc32c_hw_series() (alibaba#971)
1 parent d688fb9 commit 685525f

2 files changed

Lines changed: 49 additions & 13 deletions

File tree

common/checksum/crc.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -690,23 +690,37 @@ void crc32c_series_sw(const uint8_t *buffer, uint32_t part_size, uint32_t n_part
690690
}
691691

692692
void crc32c_series_hw(const uint8_t *buffer, uint32_t part_size, uint32_t n_parts, uint32_t* crc_parts) {
693-
memset(crc_parts, 0, n_parts * sizeof(uint32_t));
694-
uint64_t i = 0;
695-
auto perf = [&](auto type) {
696-
using T = decltype(type);
697-
for (; i < part_size; i += sizeof(T)) {
698-
#pragma GCC unroll 8
699-
for (uint64_t j = 0; j < n_parts; ++j) {
700-
auto ptr = buffer + i + j * part_size;
701-
crc_parts[j] = crc32c(crc_parts[j], *(T*)ptr);
702-
}
693+
const size_t BATCH = 4;
694+
auto part_main = part_size / 8 * 8;
695+
auto part_remain = part_size % 8;
696+
auto batch_crc = [&](auto ptr, size_t batch) __attribute__((always_inline)) {
697+
#pragma GCC unroll 4
698+
for (size_t k = 0; k < batch; ++k) {
699+
crc_parts[k] = crc32c(crc_parts[k], *ptr);
700+
ptr = decltype(ptr)((char*)ptr + part_size);
703701
}
704702
};
705-
perf(i);
706-
perf(buffer[0]);
703+
auto batch_blocks_crc = [&](const uint8_t* ptr, auto batch) __attribute__((always_inline)) {
704+
for (size_t j = 0; j < batch; ++j)
705+
crc_parts[j] = 0;
706+
for (; ptr < buffer + part_main; ptr += 8) {
707+
batch_crc((uint64_t*)ptr, batch);
708+
}
709+
if (unlikely(part_main)) {
710+
if (part_remain & 4) { batch_crc((uint32_t*)ptr, batch); ptr += 4; }
711+
if (part_remain & 2) { batch_crc((uint16_t*)ptr, batch); ptr += 2; }
712+
if (part_remain & 1) { batch_crc((uint8_t*)ptr, batch); ptr += 1; }
713+
}
714+
};
715+
for (; n_parts >= BATCH; n_parts -= BATCH) {
716+
batch_blocks_crc(buffer, BATCH);
717+
buffer += part_size * BATCH;
718+
crc_parts += BATCH;
719+
}
720+
if (unlikely(n_parts))
721+
batch_blocks_crc(buffer, n_parts);
707722
}
708723

709-
710724
// rk1 ~ rk20
711725
__attribute__((aligned(16), used))
712726
const static uint64_t rk[20] = {

common/checksum/test/test_checksum.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ inline void do_perf_crc(const char* name, CRC64ECMA crc64ecma, unsigned long siz
143143
}
144144

145145
const size_t _128KB = 128 * 1024;
146+
const size_t _1MB = 1024 * 1024;
146147
const size_t _1GB = 1024 * 1024 * 1024;
147148

148149
TEST(Perf, crc32c_hw_simple) {
@@ -252,6 +253,27 @@ TEST(TestChecksum, crc32_combine) {
252253
EXPECT_EQ(crc32c_trim({x, sizeof(buf)}, {crc1, 128}, {crc3, 128}), crc2);
253254
}
254255

256+
void crc32c_series_hw_old(const uint8_t *buffer, uint32_t part_size, uint32_t n_parts, uint32_t* crc_parts);
257+
258+
TEST(Perf, crc32c_hw_series) {
259+
const uint32_t PART_SIZE = 4096;
260+
static uint32_t crc[1024*1024];
261+
auto f = [](const uint8_t *buffer, size_t nbytes, uint32_t) -> uint32_t {
262+
crc32c_series_hw(buffer, PART_SIZE, nbytes / PART_SIZE, crc);
263+
return 0;
264+
};
265+
do_perf_crc("crc32c_hw_series", f, _128KB);
266+
do_perf_crc("crc32c_hw_series", f, _1MB);
267+
268+
auto f_naive = [](const uint8_t *buffer, size_t nbytes, uint32_t) -> uint32_t {
269+
for (size_t i = 0; i < nbytes / PART_SIZE; ++i)
270+
crc[i] = crc32c_hw(buffer + i * PART_SIZE, PART_SIZE, 0);
271+
return 0;
272+
};
273+
do_perf_crc("crc32c_hw_series_naive", f_naive, _128KB);
274+
do_perf_crc("crc32c_hw_series_naive", f_naive, _1MB);
275+
}
276+
255277
int main(int argc, char **argv)
256278
{
257279
if (!photon::is_using_default_engine()) return 0;

0 commit comments

Comments
 (0)