[Bug libc/32475] New: memmove_avx512_unaligned_erms performance drop 30%on AMD by commit 1a8605b6cd
luoxhu at gcc dot gnu.org
sourceware-bugzilla@sourceware.org
Wed Dec 18 02:40:28 GMT 2024
https://sourceware.org/bugzilla/show_bug.cgi?id=32475
Bug ID: 32475
Summary: memmove_avx512_unaligned_erms performance drop 30%on
AMD by commit 1a8605b6cd
Product: glibc
Version: 2.28
Status: NEW
Severity: normal
Priority: P2
Component: libc
Assignee: unassigned at sourceware dot org
Reporter: luoxhu at gcc dot gnu.org
CC: drepper.fsp at gmail dot com
Target Milestone: ---
Test code reduced:
cat reduce.c
# include <stdio.h>
# include <unistd.h>
# include <math.h>
# include <float.h>
# include <limits.h>
# include <sys/time.h>
#ifndef STREAM_ARRAY_SIZE
# define STREAM_ARRAY_SIZE 10000000
#endif
#ifdef NTIMES
#if NTIMES<=1
# define NTIMES 10
#endif
#endif
#ifndef NTIMES
# define NTIMES 10
#endif
#ifndef OFFSET
# define OFFSET 0
#endif
# define HLINE
"-------------------------------------------------------------\n"
# ifndef MIN
# define MIN(x,y) ((x)<(y)?(x):(y))
# endif
# ifndef MAX
# define MAX(x,y) ((x)>(y)?(x):(y))
# endif
#ifndef STREAM_TYPE
#define STREAM_TYPE double
#endif
static STREAM_TYPE a[STREAM_ARRAY_SIZE+OFFSET],
b[STREAM_ARRAY_SIZE+OFFSET],
c[STREAM_ARRAY_SIZE+OFFSET];
static double avgtime[4] = {0}, maxtime[4] = {0},
mintime[4] = {FLT_MAX,FLT_MAX,FLT_MAX,FLT_MAX};
static char *label[4] = {"Copy: ", "Scale: ",
"Add: ", "Triad: "};
static double bytes[4] = {
2 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE,
2 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE,
3 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE,
3 * sizeof(STREAM_TYPE) * STREAM_ARRAY_SIZE
};
extern double mysecond();
#ifdef _OPENMP
extern int omp_get_num_threads();
#endif
int
main()
{
int quantum, checktick();
int BytesPerWord;
int k;
ssize_t j;
STREAM_TYPE scalar;
double t, times[4][NTIMES];
/* --- SETUP --- determine precision and check timing --- */
printf(HLINE);
printf("STREAM version $Revision: 5.10 $\n");
printf(HLINE);
BytesPerWord = sizeof(STREAM_TYPE);
printf("This system uses %d bytes per array element.\n",
BytesPerWord);
printf(HLINE);
#ifdef N
printf("***** WARNING: ******\n");
printf(" It appears that you set the preprocessor variable N when
compiling this code.\n");
printf(" This version of the code uses the preprocesor variable
STREAM_ARRAY_SIZE to control the array size\n");
printf(" Reverting to default value of
STREAM_ARRAY_SIZE=%llu\n",(unsigned long long) STREAM_ARRAY_SIZE);
printf("***** WARNING: ******\n");
#endif
printf("Array size = %llu (elements), Offset = %d (elements)\n" , (unsigned
long long) STREAM_ARRAY_SIZE, OFFSET);
printf("Memory per array = %.1f MiB (= %.1f GiB).\n",
BytesPerWord * ( (double) STREAM_ARRAY_SIZE / 1024.0/1024.0),
BytesPerWord * ( (double) STREAM_ARRAY_SIZE / 1024.0/1024.0/1024.0));
printf("Total memory required = %.1f MiB (= %.1f GiB).\n",
(3.0 * BytesPerWord) * ( (double) STREAM_ARRAY_SIZE / 1024.0/1024.),
(3.0 * BytesPerWord) * ( (double) STREAM_ARRAY_SIZE /
1024.0/1024./1024.));
printf("Each kernel will be executed %d times.\n", NTIMES);
printf(" The *best* time for each kernel (excluding the first
iteration)\n");
printf(" will be used to compute the reported bandwidth.\n");
#ifdef _OPENMP
printf(HLINE);
#pragma omp parallel
{
#pragma omp master
{
k = omp_get_num_threads();
printf ("Number of Threads requested = %i\n",k);
}
}
#endif
#ifdef _OPENMP
k = 0;
#pragma omp parallel
#pragma omp atomic
k++;
printf ("Number of Threads counted = %i\n",k);
#endif
/* Get initial value for system clock. */
#pragma omp parallel for
for (j=0; j<STREAM_ARRAY_SIZE; j++) {
a[j] = 1.0;
b[j] = 2.0;
c[j] = 0.0;
}
printf(HLINE);
if ( (quantum = checktick()) >= 1)
printf("Your clock granularity/precision appears to be "
"%d microseconds.\n", quantum);
else {
printf("Your clock granularity appears to be "
"less than one microsecond.\n");
quantum = 1;
}
t = mysecond();
#pragma omp parallel for
for (j = 0; j < STREAM_ARRAY_SIZE; j++)
a[j] = 2.0E0 * a[j];
t = 1.0E6 * (mysecond() - t);
printf("Each test below will take on the order"
" of %d microseconds.\n", (int) t );
printf(" (= %d clock ticks)\n", (int) (t/quantum) );
printf("Increase the size of the arrays if this shows that\n");
printf("you are not getting at least 20 clock ticks per test.\n");
printf(HLINE);
printf("WARNING -- The above is only a rough guideline.\n");
printf("For best results, please be sure you know the\n");
printf("precision of your system timer.\n");
printf(HLINE);
/* --- MAIN LOOP --- repeat test cases NTIMES times --- */
scalar = 3.0;
for (k=0; k<NTIMES; k++)
{
times[0][k] = mysecond();
#pragma omp parallel for
for (j=0; j<STREAM_ARRAY_SIZE; j++)
c[j] = a[j];
times[0][k] = mysecond() - times[0][k];
}
/* --- SUMMARY --- */
for (k=1; k<NTIMES; k++) /* note -- skip first iteration */
{
for (j=0; j<1; j++)
{
avgtime[j] = avgtime[j] + times[j][k];
mintime[j] = MIN(mintime[j], times[j][k]);
maxtime[j] = MAX(maxtime[j], times[j][k]);
}
}
printf("Function Best Rate MB/s Avg time Min time Max time\n");
for (j=0; j<1; j++) {
avgtime[j] = avgtime[j]/(double)(NTIMES-1);
printf("%s%12.1f %11.6f %11.6f %11.6f\n", label[j],
1.0E-06 * bytes[j]/mintime[j],
avgtime[j],
mintime[j],
maxtime[j]);
}
#if 0
printf(HLINE);
/* --- Check Results --- */
checkSTREAMresults();
printf(HLINE);
#endif
return 0;
}
This case shows about 30% performance drops by commit
1a8605b6cd257e8a74e29b5b71c057211f5fb847 (x86: Update large memcpy case in
memmove-vec-unaligned-erms.S) on AMD machine(9K84 Genoa and 9754 Bergamo),
though 6%~7% performance improvement on Intel machines(8255C).
$ gcc -mcmodel=large -fopenmp -D_OPENMP -DSTREAM_ARRAY_SIZE=1073741824 reduce.c
-o reduce -O3
$ export OMP_NUM_THREADS=1
#glibc-2.28 WITHOUT commit 1a8605b6cd:
$ ./glibc/fast/lib64/ld-2.28.so --library-path ./glibc/fast/lib64/ ./reduce |
grep Copy -1
Function Best Rate MB/s Avg time Min time Max time
Copy: 52631.4 0.326982 0.326419 0.328695
-------------------------------------------------------------
#glibc-2.28 with commit 1a8605b6cd:
$ ./glibc/slow/lib64/ld-2.28.so --library-path ./glibc/slow/lib64/ ./reduce |
grep Copy -1
Function Best Rate MB/s Avg time Min time Max time
Copy: 38198.8 0.449934 0.449749 0.450118
-------------------------------------------------------------
Fast code:
│d3f03:┌─→prefetcht0 0x200(%rsi)
0.01 │d3f0a:│ prefetcht0 0x240(%rsi)
0.01 │d3f11:│ prefetcht0 0x280(%rsi)
0.03 │d3f18:│ prefetcht0 0x2c0(%rsi)
0.01 │d3f1f:│ prefetcht0 0x300(%rsi)
0.10 │d3f26:│ prefetcht0 0x340(%rsi)
0.01 │d3f2d:│ prefetcht0 0x380(%rsi)
0.05 │d3f34:│ prefetcht0 0x3c0(%rsi)
0.01 │d3f3b:│ vmovdqu64 (%rsi),%zmm0
0.24 │d3f41:│ vmovdqu64 0x40(%rsi),%zmm1
0.18 │d3f48:│ vmovdqu64 0x80(%rsi),%zmm2
0.18 │d3f4f:│ vmovdqu64 0xc0(%rsi),%zmm3
0.43 │d3f56:│ add $0x100,%rsi
0.07 │d3f5d:│ sub $0x100,%rdx
│d3f64:│ vmovntdq %zmm0,(%rdi)
16.83 │d3f6a:│ vmovntdq %zmm1,0x40(%rdi)
48.71 │d3f71:│ vmovntdq %zmm2,0x80(%rdi)
16.45 │d3f78:│ vmovntdq %zmm3,0xc0(%rdi)
16.59 │d3f7f:│ add $0x100,%rdi
0.09 │d3f86:│ cmp $0x100,%rdx
0.01 │d3f8d:└──ja d3f03 <__memcpy_avx512_unaligned_erms+0x363>
Slow code:
│d7105:┌─→prefetcht0 0x100(%rsi)
0.11 │d710c:│ prefetcht0 0x140(%rsi)
0.01 │d7113:│ prefetcht0 0x180(%rsi)
0.82 │d711a:│ prefetcht0 0x1c0(%rsi)
0.01 │d7121:│ prefetcht0 0x200(%rsi)
0.25 │d7128:│ prefetcht0 0x240(%rsi)
│d712f:│ prefetcht0 0x280(%rsi)
0.07 │d7136:│ prefetcht0 0x2c0(%rsi)
│d713d:│ prefetcht0 0x1100(%rsi)
0.08 │d7144:│ prefetcht0 0x1140(%rsi)
│d714b:│ prefetcht0 0x1180(%rsi)
0.69 │d7152:│ prefetcht0 0x11c0(%rsi)
0.01 │d7159:│ prefetcht0 0x1200(%rsi)
0.25 │d7160:│ prefetcht0 0x1240(%rsi)
│d7167:│ prefetcht0 0x1280(%rsi)
0.12 │d716e:│ prefetcht0 0x12c0(%rsi)
│d7175:│ vmovdqu64 (%rsi),%zmm16
0.25 │d717b:│ vmovdqu64 0x40(%rsi),%zmm17
0.18 │d7182:│ vmovdqu64 0x1000(%rsi),%zmm20
11.48 │d7189:│ vmovdqu64 0x1040(%rsi),%zmm21
7.75 │d7190:│ sub $0xffffffffffffff80,%rsi
0.04 │d7194:│ vmovntdq %zmm16,(%rdi)
11.31 │d719a:│ vmovntdq %zmm17,0x40(%rdi)
34.76 │d71a1:│ vmovntdq %zmm20,0x1000(%rdi)
23.87 │d71a8:│ vmovntdq %zmm21,0x1040(%rdi)
7.83 │d71af:│ sub $0xffffffffffffff80,%rdi
0.13 │d71b3:│ dec %ecx
│d71b5:└──jne d7105 <__memcpy_avx512_unaligned_erms+0x3f5>
contiguous copy is changed to non-contiguous copy as the commit log said,
though Intel shows better performance and commit message also mentioned this is
"ambiguous for VEC_SIZE=64", not sure whether this is valid bug for AMD
platform s only, and this performance issue still exists on glibc master, could
you please take a look?
--
You are receiving this mail because:
You are on the CC list for the bug.
More information about the Glibc-bugs
mailing list