2009-11-14 93 views
2

我正在做一些SSE代码(将4个浮点数乘以4个浮点数)与传统C代码做同样的事情。我认为我的基准测试代码在某种程度上必须是不正确的,因为它似乎认为非SSE代码比SSE快2-3倍。对标SSE指令

有人能告诉我下面的基准代码有什么问题吗?也许会提出另一种准确显示SSE和非SSE代码速度的方法。

#include <time.h> 
#include <string.h> 
#include <stdio.h> 

#define ITERATIONS 100000 

#define MULT_FLOAT4(X, Y) ({ \ 
asm volatile (\ 
    "movaps (%0), %%xmm0\n\t" \ 
    "mulps (%1), %%xmm0\n\t" \ 
    "movaps %%xmm0, (%1)" \ 
    :: "r" (X), "r" (Y)); }) 

int main(void) 
{ 
    int i, j; 
    float a[4] __attribute__((aligned(16))) = { 10, 20, 30, 40 }; 
    time_t timer, sse_time, std_time; 

    timer = time(NULL); 
    for(j = 0; j < 5000; ++j) 
     for(i = 0; i < ITERATIONS; ++i) { 
      float b[4] __attribute__((aligned(16))) = { 0.1, 0.1, 0.1, 0.1 }; 

      MULT_FLOAT4(a, b); 

     } 
    sse_time = time(NULL) - timer; 

    timer = time(NULL); 
    for(j = 0; j < 5000; ++j) 
     for(i = 0; i < ITERATIONS; ++i) { 
      float b[4] __attribute__((aligned(16))) = { 0.1, 0.1, 0.1, 0.1 }; 

      b[0] *= a[0]; 
      b[1] *= a[1]; 
      b[2] *= a[2]; 
      b[3] *= a[3]; 

    } 
    std_time = time(NULL) - timer; 

    printf("sse_time %d\nstd_time %d\n", sse_time, std_time); 

    return 0; 
} 

回答

5

当您启用优化时,非SSE代码被完全消除,而SSE代码保留在那里,所以这种情况是微不足道的。更有趣的部分是关闭优化:在这种情况下,SSE代码仍然较慢,而循环的代码是相同的。最里面的循环体的

非SSE代码:

movl $0x3dcccccd, %eax 
movl %eax, -80(%rbp) 
movl $0x3dcccccd, %eax 
movl %eax, -76(%rbp) 
movl $0x3dcccccd, %eax 
movl %eax, -72(%rbp) 
movl $0x3dcccccd, %eax 
movl %eax, -68(%rbp) 
movss -80(%rbp), %xmm1 
movss -48(%rbp), %xmm0 
mulss %xmm1, %xmm0 
movss %xmm0, -80(%rbp) 
movss -76(%rbp), %xmm1 
movss -44(%rbp), %xmm0 
mulss %xmm1, %xmm0 
movss %xmm0, -76(%rbp) 
movss -72(%rbp), %xmm1 
movss -40(%rbp), %xmm0 
mulss %xmm1, %xmm0 
movss %xmm0, -72(%rbp) 
movss -68(%rbp), %xmm1 
movss -36(%rbp), %xmm0 
mulss %xmm1, %xmm0 
movss %xmm0, -68(%rbp) 
最里面的循环体的

上交所代码:

movl $0x3dcccccd, %eax 
movl %eax, -64(%rbp) 
movl $0x3dcccccd, %eax 
movl %eax, -60(%rbp) 
movl $0x3dcccccd, %eax 
movl %eax, -56(%rbp) 
movl $0x3dcccccd, %eax 
movl %eax, -52(%rbp) 
leaq -48(%rbp), %rax 
leaq -64(%rbp), %rdx 
movaps (%rax), %xmm0 
mulps (%rdx), %xmm0 
movaps %xmm0, (%rdx) 

我不知道这一点,但这里是我的猜测:

正如你所看到的,编译器只是通过4个32位存储来存储4个浮点值。然后通过16字节的加载读回。这导致存储转发失速,这在发生时是昂贵的。您可以在英特尔手册中查到这一点。它不会在标量版本中出现,这会使性能出现差异。

为了使速度更快,您需要确保不会发生此失速。如果您使用的是4个浮点数的常量数组,请将其设置为const并将结果存储在另一个对齐的数组中。这样,编译器希望在加载之前不会产生不必要的4字节mov。或者,如果您需要填充结果数组,请使用16字节的存储命令来完成。如果你无法避免这些4字节的movs,你需要在存储之后但在加载之前做其他事情(例如计算其他内容)。

+0

感谢您的回答。 :)但是,我真的需要一个使用SSE进行图像处理的非常快速的4浮点乘法器。如果我使用的方法存在缺陷,您能否提出另一种方法来利用SSE的力量,但不会导致这种减速。我读过SSE实际上是为我想到的那种图像处理而设计的,所以肯定必须成为我想要的方式吗? (我需要像alpha混合等操作的快速4float倍数) – horseyguy 2009-11-14 16:22:15

+2

我已更新帖子以包含答案。 – ypsu 2009-11-14 17:08:40

+0

谢谢,不好看起来'商店转发摊位',并试图包裹我的头在这里发生了什么 – horseyguy 2009-11-14 17:32:02