使用 icc、gcc 和 clang 的相同实现的不同性能的原因是什么?
What is the reason for different performance of the same implementation using icc, gcc and clang?
我已经为 a[i]=a[i-1]+c and I represent it her. I use 实现了一个程序来读取和存储 rdtsc 以测量加速比。[=21=]
程序如下,我用的是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。
OS 是 fedora 27。
CPU是Corei7 6700HQ (Skylake)
使用 icc -D _GNU_SOURCE -O3 -no-vec -march=native
编译的标量实现是加速测量的基线。
每个编译器的asm输出如下: 因为ICC的行为不正常我复制了icc的所有代码。我在 C 程序中标记了该部分 ("mm...mm1/2")。
ICC
# 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 8, %rsp #7.11
xorl %esi, %esi #7.11
movl , %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 832, (%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 8, %esi #9.2
movl $mask, %edx #9.2
orq , 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 [=11=]xdf84757ff, %rax #12.5
movq $.L_2__STRING.1, programName(%rip) #10.2
movq 0000000, elapsed_rdtsc(%rip) #12.5
movq %rax, overal_time(%rip) #12.5
movq [=11=], 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 , %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 , a(%rip) #18.5
xorl %eax, %eax #35.5
movl , 4+a(%rip) #21.5
movl , 8+a(%rip) #21.5
movl , 12+a(%rip) #21.5
movl , 16+a(%rip) #21.5
movl , 20+a(%rip) #21.5
movl , 24+a(%rip) #21.5
movl , 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 , %rax #35.5
cmpl 47, %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 , %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 0000000, %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 0000000, %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 8, %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
海湾合作委员会
//gcc -D _GNU_SOURCE -O3 -fno-tree-vectorize -fno-tree-slp-vectorize -march=native -c -S -o "AIC3" "AIC3.c"
rdtsc
salq , %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 , %rax
vmovdqa %ymm0, -32(%rax)
vmovdqa %ymm0, %ymm1
cmpq %rax, %rcx
jne .L2
rdtsc
铿锵
//clang -D _GNU_SOURCE -O3 -fno-vectorize -fno-slp-vectorize -march=native -c -S -o "AIC3"clang "
rdtsc
shlq , %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 , %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 , %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 383, %rax # imm = 0x3FFF
jl .LBB0_9
# BB#3: # in Loop: Header=BB0_1 Depth=1
rdtsc
使用 icc、gcc 和 clang 时的加速分别为 ~1.30、~4.10 和 4.00。
正如我提到的,我用不同的编译器编译了相同的代码,并记录了 rdtsc。 ICC 的加速并不像我预期的那样。
我使用 IACA 观察了内循环,总结输出为:
-----------------------------------------------------
| compilers | icc | gcc | clang |
------------------------------------------------------
| Throughput |1.49 cycle |1.00 cycle |1.49 cycle |
------------------------------------------------------
| bottleneck | Front End | dependency | Front End |
------------------------------------------------------
UPDATE-0 :我比较了有无 IACA 生成的代码。在这种情况下,IACA 没有帮助的原因是输出不一样。似乎注入 IACA 标记会强制编译器停止优化,GCC 生成的代码与 ICC 和 Clang 生成的代码相同。但是,从吞吐量的角度来看,在 GCC 中计算地址更有效。综上所述,IACA对此代码无能为力。
UPDATE-1 :perf
的输出如下:
512*512
ICC:
86.06 │loop: vpaddd 0x604580(%rax),%ymm1,%ymm0
0.17 │ inc %edx
4.73 │ vmovdq %ymm0,0x6045a0(%rax)
│ add [=15=]x20,%rax
│ cmp [=15=]x7fff,%edx
8.98 │ jb loop
GCC:
30.62 │loop: vpaddd %ymm1,%ymm2,%ymm0
15.12 │ add [=15=]x20,%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 [=15=]x38,%rax
│ cmp [=15=]x3ffff,%rax
2.24 │ jl loop
ICC 汇编输出显示 rdtsc
中有一些 SIMD 指令。如果我错过了什么,或者出了什么问题,我真的不知道。我花了很多时间来意识到这个问题,但成就为零。请,如果有人知道原因,请帮助我。
提前致谢。
不同的编译器在这里实际上使用了相当不同的实现策略。
GCC 注意到它永远不必重新加载 a[i-8]
这是在上一次迭代中计算的,因此可以从寄存器中获取。这在某种程度上依赖于 mov-elimination,否则 reg-reg 移动仍然会增加一些延迟,尽管即使没有 mov-elimination 也比每次重新加载快得多。
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);
}
我已经为 a[i]=a[i-1]+c and I represent it her. I use 程序如下,我用的是 我用不同的编译器编译了这个程序。我的编译器是:
icc 18,gcc 7.2,clang 4。 OS 是 fedora 27。 CPU是Corei7 6700HQ (Skylake) 使用 每个编译器的asm输出如下: 因为ICC的行为不正常我复制了icc的所有代码。我在 C 程序中标记了该部分 ("mm...mm1/2")。 ICC 海湾合作委员会 铿锵 使用 icc、gcc 和 clang 时的加速分别为 ~1.30、~4.10 和 4.00。 正如我提到的,我用不同的编译器编译了相同的代码,并记录了 rdtsc。 ICC 的加速并不像我预期的那样。
我使用 IACA 观察了内循环,总结输出为: UPDATE-0 :我比较了有无 IACA 生成的代码。在这种情况下,IACA 没有帮助的原因是输出不一样。似乎注入 IACA 标记会强制编译器停止优化,GCC 生成的代码与 ICC 和 Clang 生成的代码相同。但是,从吞吐量的角度来看,在 GCC 中计算地址更有效。综上所述,IACA对此代码无能为力。 UPDATE-1 : ICC 汇编输出显示 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 -D _GNU_SOURCE -O3 -no-vec -march=native
编译的标量实现是加速测量的基线。
# 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 8, %rsp #7.11
xorl %esi, %esi #7.11
movl , %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 832, (%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 8, %esi #9.2
movl $mask, %edx #9.2
orq , 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 [=11=]xdf84757ff, %rax #12.5
movq $.L_2__STRING.1, programName(%rip) #10.2
movq 0000000, elapsed_rdtsc(%rip) #12.5
movq %rax, overal_time(%rip) #12.5
movq [=11=], 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 , %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 , a(%rip) #18.5
xorl %eax, %eax #35.5
movl , 4+a(%rip) #21.5
movl , 8+a(%rip) #21.5
movl , 12+a(%rip) #21.5
movl , 16+a(%rip) #21.5
movl , 20+a(%rip) #21.5
movl , 24+a(%rip) #21.5
movl , 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 , %rax #35.5
cmpl 47, %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 , %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 0000000, %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 0000000, %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 8, %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
//gcc -D _GNU_SOURCE -O3 -fno-tree-vectorize -fno-tree-slp-vectorize -march=native -c -S -o "AIC3" "AIC3.c"
rdtsc
salq , %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 , %rax
vmovdqa %ymm0, -32(%rax)
vmovdqa %ymm0, %ymm1
cmpq %rax, %rcx
jne .L2
rdtsc
//clang -D _GNU_SOURCE -O3 -fno-vectorize -fno-slp-vectorize -march=native -c -S -o "AIC3"clang "
rdtsc
shlq , %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 , %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 , %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 383, %rax # imm = 0x3FFF
jl .LBB0_9
# BB#3: # in Loop: Header=BB0_1 Depth=1
rdtsc
-----------------------------------------------------
| compilers | icc | gcc | clang |
------------------------------------------------------
| Throughput |1.49 cycle |1.00 cycle |1.49 cycle |
------------------------------------------------------
| bottleneck | Front End | dependency | Front End |
------------------------------------------------------
perf
的输出如下:512*512
ICC:
86.06 │loop: vpaddd 0x604580(%rax),%ymm1,%ymm0
0.17 │ inc %edx
4.73 │ vmovdq %ymm0,0x6045a0(%rax)
│ add [=15=]x20,%rax
│ cmp [=15=]x7fff,%edx
8.98 │ jb loop
GCC:
30.62 │loop: vpaddd %ymm1,%ymm2,%ymm0
15.12 │ add [=15=]x20,%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 [=15=]x38,%rax
│ cmp [=15=]x3ffff,%rax
2.24 │ jl loop
rdtsc
中有一些 SIMD 指令。如果我错过了什么,或者出了什么问题,我真的不知道。我花了很多时间来意识到这个问题,但成就为零。请,如果有人知道原因,请帮助我。
提前致谢。
不同的编译器在这里实际上使用了相当不同的实现策略。
GCC 注意到它永远不必重新加载 a[i-8]
这是在上一次迭代中计算的,因此可以从寄存器中获取。这在某种程度上依赖于 mov-elimination,否则 reg-reg 移动仍然会增加一些延迟,尽管即使没有 mov-elimination 也比每次重新加载快得多。
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);
}