[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