代码之家  ›  专栏  ›  技术社区  ›  horseyguy

基准测试SSE指令

  •  2
  • horseyguy  · 技术社区  · 15 年前

    SSE 代码(4个浮点数乘以4个浮点数)与执行相同操作的传统C代码相比。我认为我的基准代码在某种程度上肯定是不正确的,因为它似乎说非苏格兰和南方能源公司代码比苏格兰和南方能源公司代码快2-3倍。

    有人能告诉我下面的基准代码有什么问题吗?或许可以提出另一种方法,准确显示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;
    }
    
    1 回复  |  直到 15 年前
        1
  •  5
  •   ypsu    15 年前

    当您启用优化时,非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)
    

    最内层循环体的SSE代码:

    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字节的加载将其读回。这会导致商店转发暂停,发生这种情况时成本高昂。您可以在英特尔手册中查找。标量版本中不会出现这种情况,这会导致性能差异。