2009-11-14 92 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