【发布时间】:2019-02-23 17:05:24
【问题描述】:
我试图让下面的代码更快地将两个变量(我们需要重用的变量)保存在寄存器中或比缓存更近的任何位置。该代码将数组中位置idx 的三个相邻元素相加。
void stencil(double * input, double * output){
unsigned int idx = 1;
output[0] = input[0] + input[1];
for(; idx < SIZE - 1; idx++){
output[idx] = input[idx-1] + input[idx] + input[idx+1];
}
output[idx] = input[idx-1] + input[idx];
}
我的实现如下所示:
void stencil(double * input, double * output){
unsigned int idx = 0;
double x , y = 0, z;
z = input[idx];
for(; idx < SIZE - 1; idx++){
x = y;
y = z;
z = input[idx + 1];
output[idx] = x + y + z;
}
output[idx] = y + z;
}
想法是重用之前操作的变量,让程序更快。
但是,该程序在速度和性能方面似乎没有提高。我在AMD Opteron(tm) Processor 6320 CPU 上使用 gcc,并且正在使用以下标志编译代码:-march=native -O3 -Wall -std=c99。
我尝试了使用和不使用本机,生成的程序集不同,但我无法获得更好的性能。生成的没有-march=native 标志的程序集如下所示:
stencil:
.LFB7:
.cfi_startproc
subl $1, %edx
movsd (%rdi), %xmm1
je .L4
movq %rsi, %rcx
xorpd %xmm0, %xmm0
xorl %eax, %eax
jmp .L3
.p2align 4,,10
.p2align 3
.L6:
movapd %xmm1, %xmm0
movapd %xmm2, %xmm1
.L3:
addl $1, %eax
addsd %xmm1, %xmm0
addq $8, %rcx
movl %eax, %r8d
movsd (%rdi,%r8,8), %xmm2
leaq 0(,%r8,8), %r9
addsd %xmm2, %xmm0
movsd %xmm0, -8(%rcx)
cmpl %edx, %eax
jne .L6
.L2:
addsd %xmm2, %xmm1
movsd %xmm1, (%rsi,%r9)
ret
.L4:
movapd %xmm1, %xmm2
xorl %r9d, %r9d
xorpd %xmm1, %xmm1
jmp .L2
加上-march=native 标志看起来像这样:
stencil:
.LFB20:
.cfi_startproc
vmovsd (%rdi), %xmm1
vxorpd %xmm0, %xmm0, %xmm0
leaq 144(%rdi), %rdx
leaq 136(%rsi), %rax
xorl %ecx, %ecx
.p2align 4,,10
.p2align 3
.L2:
vaddsd %xmm1, %xmm0, %xmm0
vmovsd -136(%rdx), %xmm4
prefetcht0 (%rdx)
addl $8, %ecx
prefetchw (%rax)
addq $64, %rdx
addq $64, %rax
vaddsd %xmm1, %xmm4, %xmm1
vaddsd %xmm4, %xmm0, %xmm0
vmovsd %xmm0, -200(%rax)
vmovsd -192(%rdx), %xmm3
vaddsd %xmm3, %xmm1, %xmm1
vaddsd %xmm3, %xmm4, %xmm4
vmovsd %xmm1, -192(%rax)
vmovsd -184(%rdx), %xmm2
vaddsd %xmm2, %xmm4, %xmm4
vaddsd %xmm2, %xmm3, %xmm3
vmovsd %xmm4, -184(%rax)
vmovsd %xmm4, -184(%rax)
vmovsd -176(%rdx), %xmm0
vaddsd %xmm0, %xmm3, %xmm3
vaddsd %xmm0, %xmm2, %xmm2
vmovsd %xmm3, -176(%rax)
vmovsd -168(%rdx), %xmm1
vaddsd %xmm1, %xmm2, %xmm2
vaddsd %xmm1, %xmm0, %xmm0
vmovsd %xmm2, -168(%rax)
vmovsd -160(%rdx), %xmm2
vaddsd %xmm2, %xmm0, %xmm0
vaddsd %xmm2, %xmm1, %xmm1
vmovsd %xmm0, -160(%rax)
vmovsd -152(%rdx), %xmm0
vaddsd %xmm0, %xmm1, %xmm1
vaddsd %xmm0, %xmm2, %xmm2
vmovsd %xmm1, -152(%rax)
vmovsd -144(%rdx), %xmm1
vaddsd %xmm1, %xmm2, %xmm2
vmovsd %xmm2, -144(%rax)
cmpl $1399999992, %ecx
jne .L2
movabsq $11199999944, %rdx
movabsq $11199999936, %rcx
addq %rdi, %rdx
addq %rsi, %rcx
xorl %eax, %eax
jmp .L3
.p2align 4,,7
.p2align 3
.L4:
vmovaps %xmm2, %xmm1
.L3:
vaddsd %xmm0, %xmm1, %xmm0
vmovsd (%rdx,%rax), %xmm2
vaddsd %xmm2, %xmm0, %xmm0
vmovsd %xmm0, (%rcx,%rax)
addq $8, %rax
vmovaps %xmm1, %xmm0
cmpq $56, %rax
jne .L4
vaddsd %xmm2, %xmm1, %xmm1
movabsq $11199999992, %rax
vmovsd %xmm1, (%rsi,%rax)
ret
有人对如何让 GCC 将变量保存到寄存器中以使代码更快有任何建议吗?或者任何其他方式让我的代码有效绕过缓存?
【问题讨论】:
-
@OliverCharlesworth 已编辑
-
你试过
restrict吗? -
限制 x、y 和 z?但它们应该是使用限制关键字的指针吗?我认为这会使整个事情变慢。 @OliverCharlesworth
-
不,当然是
double *restrict input和output,所以编译器知道输出不会与输入重叠,并且对output的赋值不会修改input[idx-1]。除非调用者为输入和输出传递相同的指针,否则您的函数需要就地工作?但这似乎没有意义。 -
对不起,这不是英特尔 CPU,我之前用过。我在大学集群上,cpu 是
AMD Opteron(tm) Processor 6320。使用 GCC 编译器。我也会编辑这个问题。但是,如果可以帮助我进行优化,我也可以使用Intel(R) Xeon(R) CPU E5-2698 v4 @ 2.20GHz。 @PeterCordes
标签: c optimization x86 cpu-registers cpu-cache