Preliminary support for ADVX512

This commit is contained in:
Andrea Mazzoleni 2026-04-16 10:03:07 +02:00
parent cf515b82b2
commit d0fb6d2ac3
7 changed files with 157 additions and 4 deletions

View file

@ -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

View file

@ -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])

View file

@ -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);

View file

@ -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) {

View file

@ -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

View file

@ -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");

View file

@ -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