From d0fb6d2ac331380386aa61beaa823769a5926e8f Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Thu, 16 Apr 2026 10:03:07 +0200 Subject: [PATCH] Preliminary support for ADVX512 --- Makefile.am | 5 ++- configure.ac | 21 ++++++++++- raid/internal.h | 7 ++++ raid/test.c | 7 ++++ raid/test/Makefile | 7 +++- raid/test/speedtest.c | 29 +++++++++++++++ raid/x86.c | 85 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 157 insertions(+), 4 deletions(-) diff --git a/Makefile.am b/Makefile.am index f9870665..53a99d99 100644 --- a/Makefile.am +++ b/Makefile.am @@ -382,13 +382,14 @@ else if !HAVE_MEMORY_CHECKER if HAVE_EMULATOR $(MSG) Speed -# Run the self test in AVX2 - $(TESTENV_AVX2) $(SNAPRAID) --test-skip-device -c $(CONF) status +# Run the self test in AVX512 + $(TESTENV_AVX512) $(SNAPRAID) --test-skip-device -c $(CONF) status # Run the speed test in different architectures $(TESTENV_SSE2) $(SNAPRAID) --test-skip-device -T $(TESTENV_SSSE3) $(SNAPRAID) --test-skip-device -T $(TESTENV_SSE42) $(SNAPRAID) --test-skip-device -T $(TESTENV_AVX2) $(SNAPRAID) --test-skip-device -T + $(TESTENV_AVX512) $(SNAPRAID) --test-skip-device -T else # Run the self test natively $(TESTENV) $(SNAPRAID) --test-skip-device -c $(CONF) status diff --git a/configure.ac b/configure.ac index 3bc9ae32..b2937f3a 100644 --- a/configure.ac +++ b/configure.ac @@ -242,6 +242,22 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ [AC_DEFINE([HAVE_AVX2], [1], [Define to 1 if avx2 is supported by the assembler.]) asmavx2=yes]) AC_MSG_RESULT([$asmavx2]) +dnl Checks for AS supporting the AVX512BW instructions. +AC_MSG_CHECKING([for avx512bw]) +asmavx512bw=no +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#if defined(__i386__) || defined(__x86_64__) + void f(void* ptr) + { + asm volatile("vpshufb %0, %%zmm0, %%zmm1" : : "m" (ptr)); + } +#else +#error not x86 +#endif +]])], +[AC_DEFINE([HAVE_AVX512BW], [1], [Define to 1 if avx512bw is supported by the assembler.]) asmavx512bw=yes]) +AC_MSG_RESULT([$asmavx512bw]) + dnl AS_IF(HAVE_ASSEMBLY) closed here ) @@ -353,12 +369,14 @@ dnl p4p -> Pentium4 Prescott with SSE2 dnl mrm -> Merom with SSSE3 dnl nhm -> Nehalem with SSE4.2 dnl hsw -> Haswell with AVX2 -dnl knl -> Knights Landing with AVX512 +dnl knl -> Knights Landing with AVX512F +dnl skx -> Skylake Xeon with AVX512BW [ TESTENV_SSE2="$SDE -chip-check-exe-only -p4p --" TESTENV_SSSE3="$SDE -chip-check-exe-only -mrm --" TESTENV_SSE42="$SDE -nhm --" TESTENV_AVX2="$SDE -hsw --" + TESTENV_AVX512="$SDE -skx --" EMULATOR=1 # Target CPU compatible with P4 Prescott CFLAGS="$CFLAGS -march=athlon64" @@ -402,6 +420,7 @@ AC_ARG_VAR([TESTENV_SSE2], [Test environment for SSE2]) AC_ARG_VAR([TESTENV_SSSE3], [Test environment for SSSE3]) AC_ARG_VAR([TESTENV_SSE42], [Test environment for SSE42]) AC_ARG_VAR([TESTENV_AVX2], [Test environment for AVX2]) +AC_ARG_VAR([TESTENV_AVX512], [Test environment for AVX512]) AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([pkg/snapraid.info pkg/control pkg/snapraid.spec pkg/.PKGINFO pkg/PKGBUILD pkg/.SRCINFO]) diff --git a/raid/internal.h b/raid/internal.h index 36d61528..61907b82 100644 --- a/raid/internal.h +++ b/raid/internal.h @@ -43,6 +43,10 @@ #define CONFIG_AVX2 1 #endif +#if HAVE_AVX512BW /* Enables AVX2512BW only if the assembler supports it */ +#define CONFIG_AVX512BW 1 +#endif + #else /* if HAVE_CONFIG_H is not defined */ /* Assume that assembly is always supported */ @@ -61,6 +65,7 @@ #define CONFIG_SSE2 1 #define CONFIG_SSSE3 1 #define CONFIG_AVX2 1 +#define CONFIG_AVX512BW 1 #endif #endif @@ -123,11 +128,13 @@ void raid_gen1_int32(int nd, size_t size, void **vv); void raid_gen1_int64(int nd, size_t size, void **vv); void raid_gen1_sse2(int nd, size_t size, void **vv); void raid_gen1_avx2(int nd, size_t size, void **vv); +void raid_gen1_avx512bw(int nd, size_t size, void **vv); void raid_gen2_int32(int nd, size_t size, void **vv); void raid_gen2_int64(int nd, size_t size, void **vv); void raid_gen2_sse2(int nd, size_t size, void **vv); void raid_gen2_avx2(int nd, size_t size, void **vv); void raid_gen2_sse2ext(int nd, size_t size, void **vv); +void raid_gen2_avx512bw(int nd, size_t size, void **vv); void raid_genz_int32(int nd, size_t size, void **vv); void raid_genz_int64(int nd, size_t size, void **vv); void raid_genz_sse2(int nd, size_t size, void **vv); diff --git a/raid/test.c b/raid/test.c index 93a76c4f..2bc4e2d0 100644 --- a/raid/test.c +++ b/raid/test.c @@ -354,6 +354,13 @@ int raid_test_par(int mode, int nd, size_t size) f[nf++] = raid_gen2_avx2; } #endif + +#ifdef CONFIG_AVX512BW + if (raid_cpu_has_avx512bw()) { + f[nf++] = raid_gen1_avx512bw; + f[nf++] = raid_gen2_avx512bw; + } +#endif #endif /* CONFIG_X86 */ if (mode == RAID_MODE_CAUCHY) { diff --git a/raid/test/Makefile b/raid/test/Makefile index 5d77fd90..e1381db0 100644 --- a/raid/test/Makefile +++ b/raid/test/Makefile @@ -73,10 +73,15 @@ sdecovtest: $(SDE) -mrm -- ./selftest $(SDE) -nhm -- ./selftest $(SDE) -hsw -- ./selftest - $(SDE) -hsw -- ./speedtest + $(SDE) -skx -- ./selftest + $(SDE) -icl -- ./selftest + $(SDE) -icl -- ./speedtest $(MAKE) lcov_capture $(MAKE) lcov_html +sde: + $(SDE) -icl -- ./speedtest + lcov_reset: lcov --directory . -z rm -f lcov.info diff --git a/raid/test/speedtest.c b/raid/test/speedtest.c index 927c7ebe..7b11892e 100644 --- a/raid/test/speedtest.c +++ b/raid/test/speedtest.c @@ -137,6 +137,7 @@ void speed(void) printf("%8s", "avx2"); #ifdef CONFIG_X86_64 printf("%8s", "avx2e"); + printf("%8s", "avx512"); #endif #endif printf("\n"); @@ -191,6 +192,18 @@ void speed(void) fflush(stdout); } #endif +#ifdef CONFIG_AVX512BW + if (raid_cpu_has_avx512bw()) { + printf("%8s", ""); + + SPEED_START { + raid_gen1_avx512bw(nd, size, v); + } SPEED_STOP + + printf("%8" PRIu64, ds / dt); + fflush(stdout); + } +#endif #endif printf("\n"); @@ -250,6 +263,18 @@ void speed(void) fflush(stdout); } #endif +#ifdef CONFIG_AVX512BW + if (raid_cpu_has_avx512bw()) { + printf("%8s", ""); + + SPEED_START { + raid_gen2_avx512bw(nd, size, v); + } SPEED_STOP + + printf("%8" PRIu64, ds / dt); + fflush(stdout); + } +#endif #endif printf("\n"); @@ -858,6 +883,10 @@ int main(void) printf("Including x86 SSSE3 functions\n"); if (raid_cpu_has_avx2()) printf("Including x86 AVX2 functions\n"); + if (raid_cpu_has_avx512bw()) + printf("Including x86 AVX512bw functions\n"); + if (raid_cpu_has_avx512gfni()) + printf("Including x86 AVX512gfni functions\n"); #endif #ifdef CONFIG_X86_64 printf("Including x64 extended SSE register set\n"); diff --git a/raid/x86.c b/raid/x86.c index 5bce4f4c..bb51cbb8 100644 --- a/raid/x86.c +++ b/raid/x86.c @@ -91,6 +91,42 @@ void raid_gen1_avx2(int nd, size_t size, void **vv) } #endif +#if defined(CONFIG_X86) && defined(CONFIG_AVX512BW) +/* + * GEN1 (RAID5 with xor) AVX512BW implementation + * + * Note that in true AVX512F would suffice, but we don't want to add + * specific support for AVX512F because this would be the only function + * to benefit from that. + * + * Intentionally don't process more than 64 bytes because 64 is the typical + * cache block, and processing 128 bytes doesn't increase performance, and in + * some cases it even decreases it. + */ +void raid_gen1_avx512bw(int nd, size_t size, void **vv) +{ + uint8_t **v = (uint8_t**)vv; + uint8_t *p; + int d, l; + size_t i; + + l = nd - 1; + p = v[nd]; + + raid_avx_begin(); + + for (i = 0; i < size; i += 64) { + asm volatile ("vmovdqa64 %0,%%zmm0" : : "m" (v[l][i])); + for (d = l - 1; d >= 0; --d) { + asm volatile ("vpxorq %0,%%zmm0,%%zmm0" : : "m" (v[d][i])); + } + asm volatile ("vmovntdq %%zmm0,%0" : "=m" (p[i])); + } + + raid_avx_end(); +} +#endif + #if defined(CONFIG_X86) && defined(CONFIG_SSE2) static const struct gfconst16 { uint8_t poly[16]; @@ -214,6 +250,48 @@ void raid_gen2_avx2(int nd, size_t size, void **vv) } #endif +#if defined(CONFIG_X86) && defined(CONFIG_AVX512BW) +/* + * GEN2 (RAID6 with powers of 2) AVX512BW implementation + */ +void raid_gen2_avx512bw(int nd, size_t size, void **vv) +{ + uint8_t **v = (uint8_t**)vv; + uint8_t *p; + uint8_t *q; + int d, l; + size_t i; + + l = nd - 1; + p = v[nd]; + q = v[nd + 1]; + + raid_avx_begin(); + + asm volatile ("vbroadcasti32x4 %0, %%zmm7" : : "m" (gfconst16.poly[0])); + asm volatile ("vpxorq %zmm6,%zmm6,%zmm6"); + + for (i = 0; i < size; i += 64) { + asm volatile ("vmovdqa64 %0,%%zmm0" : : "m" (v[l][i])); + asm volatile ("vmovdqa64 %zmm0,%zmm2"); + for (d = l - 1; d >= 0; --d) { + asm volatile ("vpcmpgtb %zmm2,%zmm6,%k1"); + asm volatile ("vpaddb %zmm2,%zmm2,%zmm2"); + asm volatile ("vmovdqu8 %zmm7,%zmm4{%k1}{z}"); + asm volatile ("vpxorq %zmm4,%zmm2,%zmm2"); + + asm volatile ("vmovdqa64 %0,%%zmm4" : : "m" (v[d][i])); + asm volatile ("vpxorq %zmm4,%zmm0,%zmm0"); + asm volatile ("vpxorq %zmm4,%zmm2,%zmm2"); + } + asm volatile ("vmovntdq %%zmm0,%0" : "=m" (p[i])); + asm volatile ("vmovntdq %%zmm2,%0" : "=m" (q[i])); + } + + raid_avx_end(); +} +#endif + #if defined(CONFIG_X86_64) && defined(CONFIG_SSE2) /* * GEN2 (RAID6 with powers of 2) SSE2 implementation @@ -2502,5 +2580,12 @@ void raid_register_x86(void) raid_rec_register(RAID_ALGO_CAUCHY_PAR6, "avx2", raid_recX_avx2); } #endif + +#ifdef CONFIG_AVX512BW + if (raid_cpu_has_avx512bw()) { + raid_gen_register(RAID_ALGO_CAUCHY_PAR1, "avx512bw", raid_gen1_avx512bw); + raid_gen_register(RAID_ALGO_CAUCHY_PAR2, "avx512bw", raid_gen2_avx512bw); + } +#endif } #endif