В чем причина разной производительности одной и той же реализации с использованием icc, gcc и clang?

Я реализовал программу для a[i]=a[i -1]+c и представляю ее. Я использую begin_rdtsc и end_rdtsc для чтения и сохраните rdtsc для измерения ускорения.

Программа следующая, я использую x86intrin.h

#define MAX1 512
#define LEN MAX1*MAX1  //array size for time measure ments
int __attribute__(( aligned(32))) a[LEN];

int main(){

    singleCore // It's a macro to assign the program to a single core of the processor
    int i, b, c;

    begin_rdtsc

    // b=1 and c=2 in this case
    b = 1;
    c = 2;
    i = 0;

    a[i++] = b;//0 --> a[0] = 1
    //step 1:
    //solving dependencies vectorization factor is 8
    a[i++] = a[0] + 1*c; //1  --> a[1] = 1 + 2  = 3
    a[i++] = a[0] + 2*c; //2  --> a[2] = 1 + 4  = 5
    a[i++] = a[0] + 3*c; //3  --> a[3] = 1 + 6  = 7
    a[i++] = a[0] + 4*c; //4  --> a[4] = 1 + 8  = 9
    a[i++] = a[0] + 5*c; //5  --> a[5] = 1 + 10 = 11
    a[i++] = a[0] + 6*c; //6  --> a[6] = 1 + 12 = 13
    a[i++] = a[0] + 7*c; //7  --> a[7] = 1 + 14 = 15
    // vectorization factor reached
    // 8 *c will work for all 
    //loading the results to an vector
    __m256i dep1;
    //__m256i  dep2; //  dep = { 1,   3,  5, 7,  9,  11, 13, 15 }
    __m256i coeff = _mm256_set1_epi32(8*c); //coeff = { 16, 16, 16, 16, 16, 16, 16, 16 }
    //step2
    for(; i<LEN-1; i+=8){

        dep1 = _mm256_load_si256((__m256i *) &a[i-8]);
        dep1 = _mm256_add_epi32(dep1, coeff);
        _mm256_store_si256((__m256i *) &a[i], dep1);    

    }
    end_rdtsc
    return 0;
}

Я компилировал эту программу разными компиляторами. Мои компиляторы: icc 18, gcc 7.2, clang 4.

ОС федора 27.

Процессор Corei7 6700HQ (Skylake).

Скалярная реализация, скомпилированная с помощью icc -D _GNU_SOURCE -O3 -no-vec -march=native, является основой для измерения ускорения.

Вывод asm для каждого компилятора выглядит следующим образом: Поскольку ICC ведет себя ненормально, я скопировал весь код для icc. Я отметил раздел в программе C ("mm...mm1/2").

  1. МУС

    # mark_description "Intel(R) C Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 18.0.1.163 Build 20171018";
    # mark_description "-D _GNU_SOURCE -O3 -no-vec -march=native -c -S -o AIC3iccnovec";
        .file "AIC3.c"
        .text
    ..TXTST0:
    .L_2__routine_start_main_0:
    # -- Begin  main
        .text
    # mark_begin;
           .align    16,0x90
        .globl main
    # --- main()
    main:
    ..B1.1:                         # Preds ..B1.0
                                    # Execution count [1.00e+00]
        .cfi_startproc
    ..___tag_value_main.1:
    ..L2:
                                                              #7.11
            pushq     %rbp                                          #7.11
        .cfi_def_cfa_offset 16
            movq      %rsp, %rbp                                    #7.11
        .cfi_def_cfa 6, 16
        .cfi_offset 6, -16
            andq      $-128, %rsp                                   #7.11
            subq      $128, %rsp                                    #7.11
            xorl      %esi, %esi                                    #7.11
            movl      $3, %edi                                      #7.11
            call      __intel_new_feature_proc_init                 #7.11
                                    # LOE rbx r12 r13 r14 r15
    ..B1.21:                        # Preds ..B1.1
                                    # Execution count [1.00e+00]
            vstmxcsr  (%rsp)                                        #7.11
            vpxor     %ymm0, %ymm0, %ymm0                           #9.2
            orl       $32832, (%rsp)                                #7.11
            vldmxcsr  (%rsp)                                        #7.11
            vmovups   %ymm0, mask(%rip)                             #9.2
            vmovups   %ymm0, 32+mask(%rip)                          #9.2
            vmovups   %ymm0, 64+mask(%rip)                          #9.2
            vmovups   %ymm0, 96+mask(%rip)                          #9.2
                                    # LOE rbx r12 r13 r14 r15
    ..B1.2:                         # Preds ..B1.21
                                    # Execution count [5.00e-01]
            xorl      %edi, %edi                                    #9.2
            movl      $128, %esi                                    #9.2
            movl      $mask, %edx                                   #9.2
            orq       $12, mask(%rip)                               #9.2
            vzeroupper                                              #9.2
    ..___tag_value_main.6:
    #       sched_setaffinity(__pid_t, size_t, const cpu_set_t *)
            call      sched_setaffinity                             #9.2
    ..___tag_value_main.7:
                                    # LOE rbx r12 r13 r14 r15
    ..B1.3:                         # Preds ..B1.2
                                    # Execution count [1.72e+00]
            movq      $0xdf84757ff, %rax                            #12.5
            movq      $.L_2__STRING.1, programName(%rip)            #10.2
            movq      $100000000, elapsed_rdtsc(%rip)               #12.5
            movq      %rax, overal_time(%rip)                       #12.5
            movq      $0, ttime(%rip)                               #12.5
            vmovdqu   .L_2il0floatpacket.2(%rip), %ymm0             #33.21
                                    # LOE rbx r12 r13 r14 r15
    ..B1.4:                         # Preds ..B1.12 ..B1.3
                                    # Execution count [2.91e+00]
    # Begin ASM
    # #mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm1
    # End ASM
                                    # LOE rbx r12 r13 r14 r15
    ..B1.23:                        # Preds ..B1.4
                                    # Execution count [2.91e+00]
            vzeroupper                                              #12.5
            rdtsc                                                   #12.5
            shlq      $32, %rdx                                     #12.5
            orq       %rdx, %rax                                    #12.5
                                    # LOE rax rbx r12 r13 r14 r15
    ..B1.5:                         # Preds ..B1.23
                                    # Execution count [2.62e+00]
            movq      %rax, t1_rdtsc(%rip)                          #12.5
            xorl      %edx, %edx                                    #35.5
            movl      $1, a(%rip)                                   #18.5
            xorl      %eax, %eax                                    #35.5
            movl      $3, 4+a(%rip)                                 #21.5
            movl      $5, 8+a(%rip)                                 #21.5
            movl      $7, 12+a(%rip)                                #21.5
            movl      $9, 16+a(%rip)                                #21.5
            movl      $11, 20+a(%rip)                               #21.5
            movl      $13, 24+a(%rip)                               #21.5
            movl      $15, 28+a(%rip)                               #21.5
            vmovdqu   .L_2il0floatpacket.2(%rip), %ymm1             #35.5
                                    # LOE rax rbx r12 r13 r14 r15 edx ymm1
    ..B1.6:                         # Preds ..B1.6 ..B1.5
                                    # Execution count [4.29e+04]
            vpaddd    a(%rax), %ymm1, %ymm0                         #38.16
            incl      %edx                                          #35.5
            vmovdqu   %ymm0, 32+a(%rax)                             #39.41
            addq      $32, %rax                                     #35.5
            cmpl      $2047, %edx                                   #35.5
            jb        ..B1.6        # Prob 99%                      #35.5
                                    # LOE rax rbx r12 r13 r14 r15 edx ymm1
    ..B1.7:                         # Preds ..B1.6
                                    # Execution count [2.91e+00]
            vzeroupper                                              #46.5
            rdtsc                                                   #46.5
            shlq      $32, %rdx                                     #46.5
            orq       %rdx, %rax                                    #46.5
                                    # LOE rax rbx r12 r13 r14 r15
    ..B1.8:                         # Preds ..B1.7
                                    # Execution count [2.91e+00]
            movq      %rax, t2_rdtsc(%rip)                          #46.5
                                    # LOE rbx r12 r13 r14 r15
    ..B1.26:                        # Preds ..B1.8
                                    # Execution count [2.91e+00]
    # Begin ASM
    # #mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm2
    # End ASM
                                    # LOE rbx r12 r13 r14 r15
    ..B1.25:                        # Preds ..B1.26
                                    # Execution count [2.91e+00]
            movq      t2_rdtsc(%rip), %rdx                          #46.5
            subq      t1_rdtsc(%rip), %rdx                          #46.5
            movq      ttbest_rdtsc(%rip), %rsi                      #46.5
            movq      %rdx, ttotal_rdtsc(%rip)                      #46.5
            cmpq      %rsi, %rdx                                    #46.5
            jge       ..B1.10       # Prob 50%                      #46.5
                                    # LOE rdx rbx rsi r12 r13 r14 r15
    ..B1.9:                         # Preds ..B1.25
                                    # Execution count [1.45e+00]
            movq      elapsed_rdtsc(%rip), %rcx                     #46.5
            movq      %rcx, %rax                                    #46.5
            negq      %rax                                          #46.5
            movq      %rdx, %rsi                                    #46.5
            addq      $100000000, %rax                              #46.5
            movq      %rdx, ttbest_rdtsc(%rip)                      #46.5
            movq      %rax, elapsed(%rip)                           #46.5
            jmp       ..B1.11       # Prob 100%                     #46.5
                                    # LOE rdx rcx rbx rsi r12 r13 r14 r15
    ..B1.10:                        # Preds ..B1.25
                                    # Execution count [1.45e+00]
            movq      elapsed_rdtsc(%rip), %rcx                     #46.5
                                    # LOE rdx rcx rbx rsi r12 r13 r14 r15
    ..B1.11:                        # Preds ..B1.9 ..B1.10
                                    # Execution count [2.91e+00]
            movq      ttime(%rip), %rax                             #46.5
            addq      %rdx, %rax                                    #46.5
            movq      %rax, ttime(%rip)                             #46.5
            testq     %rcx, %rcx                                    #46.5
            je        ..B1.14       # Prob 50%                      #46.5
                                    # LOE rax rcx rbx rsi r12 r13 r14 r15
    ..B1.12:                        # Preds ..B1.11
                                    # Execution count [1.45e+00]
            decq      %rcx                                          #46.5
            movq      %rcx, elapsed_rdtsc(%rip)                     #46.5
            cmpq      overal_time(%rip), %rax                       #46.5
            jl        ..B1.4        # Prob 82%                      #46.5
            jmp       ..B1.15       # Prob 100%                     #46.5
                                    # LOE rcx rbx rsi r12 r13 r14 r15
    ..B1.14:                        # Preds ..B1.11
                                    # Execution count [1.45e+00]
            movq      $-1, elapsed_rdtsc(%rip)                      #46.5
            movq      $-1, %rcx                                     #46.5
                                    # LOE rcx rbx rsi r12 r13 r14 r15
    ..B1.15:                        # Preds ..B1.12 ..B1.14
                                    # Execution count [1.00e+00]
            negq      %rcx                                          #46.5
            movl      $.L_2__STRING.2, %edi                         #46.5
            addq      $100000000, %rcx                              #46.5
            xorl      %eax, %eax                                    #46.5
            movq      elapsed(%rip), %rdx                           #46.5
    ..___tag_value_main.8:
    #       printf(const char *__restrict__, ...)
            call      printf                                        #46.5
    ..___tag_value_main.9:
                                    # LOE rbx r12 r13 r14 r15
    ..B1.16:                        # Preds ..B1.15
                                    # Execution count [1.00e+00]
            movl      $.L_2__STRING.3, %edi                         #46.5
            movl      $.L_2__STRING.4, %esi                         #46.5
    #       fopen(const char *__restrict__, const char *__restrict__)
            call      fopen                                         #46.5
                                    # LOE rax rbx r12 r13 r14 r15
    ..B1.17:                        # Preds ..B1.16
                                    # Execution count [1.00e+00]
            movl      $128, %ecx                                    #46.5
            movq      %rax, %rdi                                    #46.5
            movq      %rax, fileForSpeedups(%rip)                   #46.5
            movl      $.L_2__STRING.5, %esi                         #46.5
            movl      %ecx, %r8d                                    #46.5
            xorl      %eax, %eax                                    #46.5
            movq      programName(%rip), %rdx                       #46.5
            movq      ttbest_rdtsc(%rip), %r9                       #46.5
    #       fprintf(FILE *__restrict__, const char *__restrict__, ...)
            call      fprintf                                       #46.5
                                    # LOE rbx r12 r13 r14 r15
    ..B1.18:                        # Preds ..B1.17
                                    # Execution count [1.00e+00]
            xorl      %eax, %eax                                    #47.9
            movq      %rbp, %rsp                                    #47.9
            popq      %rbp                                          #47.9
        .cfi_def_cfa 7, 8
        .cfi_restore 6
            ret                                                     #47.9
            .align    16,0x90
                                    # LOE
        .cfi_endproc
    # mark_end;
        .type   main,@function
        .size   main,.-main
    ..LNmain.0:
        .data
    # -- End  main
        .bss
        .align 8
        .align 8
        .globl fileForSpeedups
    fileForSpeedups:
        .type   fileForSpeedups,@object
        .size   fileForSpeedups,8
        .space 8    # pad
        .align 8
        .globl ttime
    ttime:
        .type   ttime,@object
        .size   ttime,8
        .space 8    # pad
        .data
        .align 8
        .align 8
        .globl programName
    programName:
        .quad   .L_2__STRING.0
        .type   programName,@object
        .size   programName,8
        .align 8
        .globl ttbest_rdtsc
    ttbest_rdtsc:
        .long   0x5d89ffff,0x01634578
        .type   ttbest_rdtsc,@object
        .size   ttbest_rdtsc,8
        .align 8
        .globl elapsed_rdtsc
    elapsed_rdtsc:
        .long   0x05f5e100,0x00000000
        .type   elapsed_rdtsc,@object
        .size   elapsed_rdtsc,8
        .align 8
        .globl overal_time
    overal_time:
        .long   0xf84757ff,0x0000000d
        .type   overal_time,@object
        .size   overal_time,8
        .section .rodata, "a"
        .align 32
        .align 32
    .L_2il0floatpacket.2:
        .long   0x00000010,0x00000010,0x00000010,0x00000010,0x00000010,0x00000010,0x00000010,0x00000010
        .type   .L_2il0floatpacket.2,@object
        .size   .L_2il0floatpacket.2,32
        .section .rodata.str1.4, "aMS",@progbits,1
        .align 4
        .align 4
    .L_2__STRING.1:
        .long   860047681
        .byte   0
        .type   .L_2__STRING.1,@object
        .size   .L_2__STRING.1,5
        .space 3, 0x00  # pad
        .align 4
    .L_2__STRING.2:
        .long   1701344266
        .long   1936024096
        .long   1936269428
        .long   1819026720
        .long   1852383332
        .long   1819026720
        .long   543716452
        .long   1919251561
        .long   1869182049
        .long   1851859054
        .long   1814372452
        .long   1914725484
        .long   1952804965
        .long   1869182057
        .long   684910
        .type   .L_2__STRING.2,@object
        .size   .L_2__STRING.2,60
        .align 4
    .L_2__STRING.3:
        .long   1701603686
        .long   1400008518
        .long   1684366704
        .long   7565429
        .type   .L_2__STRING.3,@object
        .size   .L_2__STRING.3,16
        .align 4
    .L_2__STRING.4:
        .word   97
        .type   .L_2__STRING.4,@object
        .size   .L_2__STRING.4,2
        .space 2, 0x00  # pad
        .align 4
    .L_2__STRING.5:
        .long   539783973
        .long   628646949
        .long   622865508
        .long   174353516
        .byte   0
        .type   .L_2__STRING.5,@object
        .size   .L_2__STRING.5,17
        .space 3, 0x00  # pad
        .align 4
    .L_2__STRING.0:
        .word   32
        .type   .L_2__STRING.0,@object
        .size   .L_2__STRING.0,2
        .data
        .comm mask1,128,32
        .comm t1_rdtsc,8,8
        .comm t2_rdtsc,8,8
        .comm ttotal_rdtsc,8,8
        .comm elapsed,8,8
        .comm mask,128,32
        .comm a,65536,32
        .section .note.GNU-stack, ""
    // -- Begin DWARF2 SEGMENT .eh_frame
        .section .eh_frame,"a",@progbits
    .eh_frame_seg:
        .align 8
    # End
    
  2. ССАГПЗ

    //gcc  -D _GNU_SOURCE -O3 -fno-tree-vectorize -fno-tree-slp-vectorize -march=native -c -S -o "AIC3" "AIC3.c"
    rdtsc
    salq    $32, %rdx
    movq    %r10, a(%rip)
    
    
    orq %rdx, %rax
    movq    %r9, a+8(%rip)
    movq    %r8, a+16(%rip)
    movq    %rdi, a+24(%rip)
    
    
    vmovdqa a(%rip), %ymm1
    movq    %rax, t1_rdtsc(%rip)
    movl    $a+32, %eax
    .p2align 4,,10
    .p2align 3
    .L2:
        vpaddd  %ymm1, %ymm2, %ymm0
        addq    $32, %rax
        vmovdqa %ymm0, -32(%rax)
        vmovdqa %ymm0, %ymm1
        cmpq    %rax, %rcx
        jne .L2
    rdtsc
    
  3. лязг

    //clang  -D _GNU_SOURCE -O3 -fno-vectorize -fno-slp-vectorize -march=native -c -S -o "AIC3"clang "
    rdtsc
    shlq    $32, %rdx
    orq %rax, %rdx
    movq    %rdx, t1_rdtsc(%rip)
    movq    %r8, a(%rip)
    movq    %r9, a+8(%rip)
    movq    %r10, a+16(%rip)
    movq    %rcx, a+24(%rip)
    vmovdqa a(%rip), %ymm8
    movl    $64, %eax
    jmp .LBB0_2
    .p2align    4, 0x90
    .LBB0_9:                                #   in Loop: Header=BB0_2 Depth=2
        vpaddd  %ymm7, %ymm8, %ymm8
        vmovdqa %ymm8, a(,%rax,4)
        addq    $64, %rax
    .LBB0_2:                                #   Parent Loop BB0_1 Depth=1
                                        # =>  This Inner Loop Header: Depth=2
        vpaddd  %ymm0, %ymm8, %ymm9
        vmovdqa %ymm9, a-224(,%rax,4)
        vpaddd  %ymm1, %ymm8, %ymm9
        vmovdqa %ymm9, a-192(,%rax,4)
        vpaddd  %ymm2, %ymm8, %ymm9
        vmovdqa %ymm9, a-160(,%rax,4)
        vpaddd  %ymm3, %ymm8, %ymm9
        vmovdqa %ymm9, a-128(,%rax,4)
        vpaddd  %ymm4, %ymm8, %ymm9
        vmovdqa %ymm9, a-96(,%rax,4)
        vpaddd  %ymm5, %ymm8, %ymm9
        vmovdqa %ymm9, a-64(,%rax,4)
        vpaddd  %ymm6, %ymm8, %ymm9
        vmovdqa %ymm9, a-32(,%rax,4)
        cmpq    $16383, %rax            # imm = 0x3FFF
        jl  .LBB0_9
    # BB#3:                                 #   in Loop: Header=BB0_1 Depth=1
    rdtsc
    

Ускорение составляет ~ 1,30, ~ 4,10 и 4,00 при использовании icc, gcc и clang соответственно.

Как я уже говорил, я скомпилировал один и тот же код с помощью разных компиляторов и записал rdtsc. ускорение для ICC не так, как я ожидал. Я использовал IACA для просмотра внутреннего цикла, итоговый вывод:

-----------------------------------------------------
|  compilers  |    icc    |     gcc    |    clang    |
------------------------------------------------------
|  Throughput |1.49 cycle |1.00 cycle  |1.49 cycle   |
------------------------------------------------------
|  bottleneck | Front End | dependency | Front End   |
------------------------------------------------------

ОБНОВЛЕНИЕ-0: я сравнил коды, сгенерированные IACA, и без них. Причина, по которой IACA не помогает в данном случае, заключается в том, что выходы не совпадают. Кажется, что введение меток IACA заставляет компиляторы прекратить оптимизацию, GCC имеет тот же сгенерированный код, что и ICC и Clang. Но вычисление адресов в GCC более эффективно с точки зрения пропускной способности. Таким образом, IACA не может помочь с этим кодом.

ОБНОВЛЕНИЕ-1: результаты для perf следующие:

512*512
ICC:

 86.06 │loop:  vpaddd 0x604580(%rax),%ymm1,%ymm0
  0.17 │       inc    %edx
  4.73 │       vmovdq %ymm0,0x6045a0(%rax)
       │       add    $0x20,%rax
       │       cmp    $0x7fff,%edx
  8.98 │       jb     loop


GCC:

 30.62 │loop:  vpaddd %ymm1,%ymm2,%ymm0
 15.12 │       add    $0x20,%rax
 46.03 │       vmovdq %ymm0,-0x20(%rax)
  2.40 │       vmovdq %ymm0,%ymm1
  0.01 │       cmp    %rax,%rcx
  5.62 │       jne    loop


LLVM:

  3.00 │loop:  vpaddd %ymm0,%ymm7,%ymm8                                                  
  6.61 │       vmovdq %ymm8,0x6020e0(,%rax,4)                                            
 15.96 │       vpaddd %ymm1,%ymm7,%ymm8                                                  
  5.19 │       vmovdq %ymm8,0x602100(,%rax,4)                                            
  1.89 │       vpaddd %ymm2,%ymm7,%ymm8                                                  
  6.16 │       vmovdq %ymm8,0x602120(,%rax,4)                                            
 13.25 │       vpaddd %ymm3,%ymm7,%ymm8                                                 
  8.01 │       vmovdq %ymm8,0x602140(,%rax,4)                                            
  2.10 │       vpaddd %ymm4,%ymm7,%ymm8                                                  
  5.37 │       vmovdq %ymm8,0x602160(,%rax,4)                                            
 13.92 │       vpaddd %ymm5,%ymm7,%ymm8                                                  
  7.95 │       vmovdq %ymm8,0x602180(,%rax,4)                                            
  0.89 │       vpaddd %ymm6,%ymm7,%ymm7                                                  
  4.34 │       vmovdq %ymm7,0x6021a0(,%rax,4)                                            
  2.82 │       add    $0x38,%rax                                                         
       │       cmp    $0x3ffff,%rax                                                      
  2.24 │       jl     loop                                                                

Выходные данные сборки ICC показывают, что внутри файла rdtsc есть некоторые SIMD-инструкции. Если я что-то пропустил, или что-то не так, я действительно понятия не имею. Я потратил много времени, чтобы понять проблему, но ноль достижений. Пожалуйста, если кто-то знает причину, помогите мне. Заранее спасибо.


person Martin    schedule 30.12.2017    source источник
comment
Вы ожидаете, что каждый компилятор будет создавать почти оптимальный код при любых обстоятельствах? Если да, то я могу продать вам очень хороший блестящий мост, почти новый.   -  person n. 1.8e9-where's-my-share m.    schedule 30.12.2017
comment
@н.м. Я ожидаю, что ICC будет хорошим мальчиком. Что ты предлагаешь?:)   -  person Martin    schedule 30.12.2017
comment
ICC является продуктом с закрытым исходным кодом одной компании, у него нет реальных шансов против гигантов OSS, таких как gcc и clang. Единственное, что дает ему некоторое преимущество, чтобы выжить, это то, что это та же компания, которая производит целевой ЦП, поэтому они могут использовать знания HW на ранней стадии. С другой стороны, их тонкие изменения, направленные на создание довольно крошечного неоптимального кода в обмен на снижение производительности AMD, мешают им почти настолько, чтобы свести на нет их преимущество. Но gcc и clang теперь достаточно зрелые, чтобы сделать любые усилия одной компании безнадежными, вы не можете разместить такой объем знаний под одной крышей.   -  person Ped7g    schedule 31.12.2017
comment
@ Ped7g: ICC лучше справляется с автоматической векторизацией некоторых вещей, чем gcc/clang. Он нацелен только на x86, в то время как gcc векторизует в независимом от архитектуры внутреннем представлении, которое даже не знает, какие перетасовки может выполнять цель. Одним из важных примеров является то, что ICC может автоматически векторизовать циклы поиска (например, реализация memchr на чистом языке C), но gcc/clang может автоматически векторизовать циклы только с количеством поездок, которое определяется до входа в цикл. Однако Clang часто очень хорош, когда он выполняет автоматическую векторизацию.   -  person Peter Cordes    schedule 31.12.2017
comment
@PeterCordes, привет, Питер, скучал по тебе. в тестовом документе, который я читал (не могу вспомнить, где), ICC смог автоматически векторизовать 90% циклов, в то время как Clang и GCC смогли автоматически векторизовать 60% и 50%. Я думаю, что clang выиграет соревнование. Насколько я знаю, большинство исследователей пытаются реализовать свои идеи с помощью LLVM, которую использует Clang.   -  person Martin    schedule 31.12.2017
comment
По моему опыту, Clang показывает большую производительность, когда вы разворачиваете цикл в исходных кодах.   -  person Martin    schedule 31.12.2017
comment
Ну... бывает, иногда.   -  person n. 1.8e9-where's-my-share m.    schedule 31.12.2017
comment
по какой причине проголосовали? Если есть какие-либо проблемы, скажите и предоставьте решение.   -  person Martin    schedule 01.01.2018


Ответы (1)


Различные компиляторы на самом деле используют здесь довольно разные стратегии реализации.

GCC отмечает, что ему никогда не нужно повторно загружать a[i-8], который был рассчитан на предыдущей итерации и, следовательно, может быть получен из регистра. Это в некоторой степени зависит от исключения перемещения, в противном случае перемещение reg-reg все равно добавило бы некоторую задержку, хотя даже без устранения перемещения это было бы намного быстрее, чем перезагрузка каждый раз.

Codegen ICC очень наивен, он просто делает именно так, как вы его написали. Store/reload добавляет довольно большую задержку.

Clang делает примерно то же самое, что и GCC, но разворачивается на 8 (минус первая итерация). Clang часто любит разворачивать больше. Я не уверен, почему это немного хуже, чем то, что делает GCC.

Вы можете избежать перезагрузки, явно не делая этого в первую очередь: (не проверено)

dep1 = _mm256_load_si256((__m256i *) &a[0]);
for(; i<LEN-1; i+=8){

    dep1 = _mm256_add_epi32(dep1, coeff);
    _mm256_store_si256((__m256i *) &a[i], dep1);    

}
person harold    schedule 30.12.2017
comment
Я добавил выходы perf, это показывает, почему gcc быстрее, чем Clang. Я думаю, это из-за другого расчета адреса, а gcc более эффективен. - person Martin; 31.12.2017
comment
@Martin: этот вывод perf ничего не объясняет. Skylake может поддерживать микрослияние хранилищ в режиме индексированной адресации; IACA ошибается в этом и по-прежнему применяет правила Sandybridge. Мне кажется, что clang должен быть намного быстрее: развертывание с большим количеством регистров, поэтому цепочка dep, переносимая циклом, составляет только каждые 8-е vpaddd. Но это целое число, а не FP, поэтому vpaddd задержка составляет всего 1 с, и она должна ограничивать пропускную способность хранилища (1 за такт или меньше, если в L1D не жарко). 3 add/c без узкого места магазина. - person Peter Cordes; 31.12.2017
comment
Я использую IACA 3.0, он поддерживает SKL по умолчанию, и вы можете изменить его на SKLX - person Martin; 31.12.2017
comment
Однако для clang было бы разумнее использовать неиндексированный режим адресации. Но в любом случае, gcc будет узким местом во внешнем интерфейсе, а не в сохранении пропускной способности. - person Peter Cordes; 31.12.2017
comment
@Martin: Я не это имел в виду. IACA для Haswell и Skylake неверен, поскольку моделирует микрослияние для режимов индексированной адресации на SKL так же, как и на SnB. Но на реальном оборудовании все изменилось с помощью HSW, что вы можете увидеть, если используете счетчики производительности для uops_issued. - person Peter Cordes; 31.12.2017
comment
@PeterCordes, я понял. - person Martin; 31.12.2017