我想知道在Core 2和Westmere之间的英特尔处理器上的一系列指令的最佳顺序是什么。这是AT& T语法,因此pxor
指令是内存读取,movdqa
是内存写入:
movdqa %xmm0, -128+64(%rbx)
movdqa %xmm1, -128+80(%rbx)
movdqa %xmm2, -128+96(%rbx)
movdqa %xmm3, -128+112(%rbx)
pxor -128(%rsp), %xmm0
pxor -112(%rsp), %xmm1
pxor -96(%rsp), %xmm2
pxor -80(%rsp), %xmm3
movdqa %xmm8, 64(%rbx)
movdqa %xmm9, 80(%rbx)
movdqa %xmm10, 96(%rbx)
movdqa %xmm11, 112(%rbx)
pxor -128(%r14), %xmm8
pxor -112(%r14), %xmm9
pxor -96(%r14), %xmm10
pxor -80(%r14), %xmm11
movdqa %xmm12, 64(%rdx)
movdqa %xmm13, 80(%rdx)
movdqa %xmm14, 96(%rdx)
movdqa %xmm15, 112(%rdx)
pxor 0(%r14), %xmm12
pxor 16(%r14), %xmm13
pxor 32(%r14), %xmm14
pxor 48(%r14), %xmm15
%r14
,%rsp
,%rdx
和%rbx
是256的不同倍数。换句话说,上面的说明中没有非明显的别名和数据已经布局了对大型数据块的对齐访问。正在访问的所有内存行都在L1缓存中。
一方面,我对Agner Fog的optimization guides的理解让我相信,有可能按照下面的顺序逐个接近两个指令:
movdqa %xmm0, -128+64(%rbx)
movdqa %xmm1, -128+80(%rbx)
pxor -128(%rsp), %xmm0
movdqa %xmm2, -128+96(%rbx)
pxor -112(%rsp), %xmm1
movdqa %xmm3, -128+112(%rbx)
pxor -96(%rsp), %xmm2
movdqa %xmm8, 64(%rbx)
pxor -80(%rsp), %xmm3
movdqa %xmm9, 80(%rbx)
pxor -128(%r14), %xmm8
movdqa %xmm10, 96(%rbx)
pxor -112(%r14), %xmm9
movdqa %xmm11, 112(%rbx)
pxor -96(%r14), %xmm10
movdqa %xmm12, 64(%rdx)
pxor -80(%r14), %xmm11
movdqa %xmm13, 80(%rdx)
pxor 0(%r14), %xmm12
movdqa %xmm14, 96(%rdx)
pxor 16(%r14), %xmm13
movdqa %xmm15, 112(%rdx)
pxor 32(%r14), %xmm14
pxor 48(%r14), %xmm15
这种排序试图通过在读取和写入之间留下偏移来考虑Agner Fog的microachitecture.pdf中描述的“缓存库冲突”。
另一方面,另一个问题是虽然程序员知道上面的代码中没有别名,但是他们无法将这些信息传达给处理器。由于处理器必须考虑读取值是否被上述指令中的写入修改的可能性,因此读取和写入的交错会引入延迟?在这种情况下,显然最好先进行所有读操作,但由于这对于特定的指令序列是不可能的,因此首先完成所有写操作都是有意义的。
简而言之,这里似乎有很多可能性,而我的直觉并不足以让人感觉到每一种可能发生的事情。
编辑:如果这很重要,那么在所考虑的序列之前的代码就是从内存加载xmm
寄存器或者用算术指令计算它们,然后使用这些寄存器写入的代码写入它们作为记忆或作为算术指令的输入。已写入的内存位置不会立即重用。 rbx
,rsp
,r14
和rdx
是长期存在的寄存器,必须来自寄存器文件。
答案 0 :(得分:2)
我检测了我感兴趣的指令和周围的指令,如下所示,以便测量在使用指令的上下文中不同排序选项所采用的周期数:
#ifdef M
push %rdx
push %rax
push %rbx
push %rcx
xorq %rax, %rax
cpuid
rdtsc
movl %eax, 256+32+UNUSED_64b
movl %edx, 256+32+4+UNUSED_64b
pop %rcx
pop %rbx
pop %rax
pop %rdx
#endif
movdqa %xmm0, -128+64(%rbx)
movdqa %xmm1, -128+80(%rbx)
movdqa %xmm2, -128+96(%rbx)
movdqa %xmm3, -128+112(%rbx)
movdqa %xmm8, 64(%rbx)
movdqa %xmm9, 80(%rbx)
movdqa %xmm10, 96(%rbx)
movdqa %xmm11, 112(%rbx)
pxor -128(%rsp), %xmm0
pxor -112(%rsp), %xmm1
pxor -96(%rsp), %xmm2
pxor -80(%rsp), %xmm3
movdqa %xmm12, 64(%rdx)
movdqa %xmm13, 80(%rdx)
movdqa %xmm14, 96(%rdx)
movdqa %xmm15, 112(%rdx)
pxor -128(%r14), %xmm8
pxor -112(%r14), %xmm9
pxor -96(%r14), %xmm10
pxor -80(%r14), %xmm11
movdqa %xmm0, -128+0(%rbx)
movdqa %xmm1, -128+16(%rbx)
movdqa %xmm2, -128+32(%rbx)
movdqa %xmm3, -128+48(%rbx)
pxor 0(%r14), %xmm12
pxor 16(%r14), %xmm13
pxor 32(%r14), %xmm14
pxor 48(%r14), %xmm15
movdqa %xmm8, 0(%rbx)
movdqa %xmm9, 16(%rbx)
movdqa %xmm10, 32(%rbx)
movdqa %xmm11, 48(%rbx)
movdqa %xmm12, 0(%rdx)
movdqa %xmm13, 16(%rdx)
movdqa %xmm14, 32(%rdx)
movdqa %xmm15, 48(%rdx)
#ifdef M
push %rdx
push %rax
push %rbx
push %rcx
xorq %rax, %rax
cpuid
rdtsc
shlq $32, %rdx
orq %rdx, %rax
subq 256+32+UNUSED_64b, %rax
movq %rax, 256+32+UNUSED_64b
pop %rcx
pop %rbx
pop %rax
pop %rdx
#endif
…
// safe place
call do_debug
…
#ifdef M
.cstring
measure:
.ascii "%15lu\12\0"
.section __DATA,__data
.align 2
count:
.word 30000
.text
do_measure:
decb count(%rip)
jnz done_measure
pushq %rax
pushq %rax
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rsi
pushq %rdi
pushq %rbp
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq 16*8+UNUSED_64b, %rsi
leaq measure(%rip), %rdi
xorl %eax, %eax
call _applog
popq %r15
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %rbp
popq %rdi
popq %rsi
popq %rdx
popq %rcx
popq %rbx
popq %rax
popq %rax
done_measure:
ret
#endif
上面的序列是我发现的对于我正在开发的处理器,Westmere Xeon W3680更快的序列。我在问题中提出的序列结果证明是可怕的,例如,可能是因为它在使用xmm
寄存器的下面的指令和它们最后设置的指令之间放置了太多的距离,迫使它们去通过寄存器文件,并导致寄存器读取停顿。
UNUSED_64b
是由于对齐约束而在堆栈上可用的空插槽的名称。它必须在堆栈上,因为程序使用线程:
#define UNUSED_64b 16(%rsp)
256+32+
补偿了在设置探测点的堆栈的特殊用法。
此汇编代码适用于Mac OS X.某些类似Unix系统的细节会有所不同。