C代码循环性能

Ric*_*cky 40 c performance assembly intel instructions

我的应用程序中有一个乘法添加内核,我想提高它的性能.

我使用英特尔酷睿i7-960(3.2 GHz时钟)并已使用SSE内在函数手动实现内核,如下所示:

 for(int i=0; i<iterations; i+=4) {
    y1 = _mm_set_ss(output[i]);
    y2 = _mm_set_ss(output[i+1]);
    y3 = _mm_set_ss(output[i+2]);
    y4 = _mm_set_ss(output[i+3]);

    for(k=0; k<ksize; k++){
        for(l=0; l<ksize; l++){
            w  = _mm_set_ss(weight[i+k+l]);

            x1 = _mm_set_ss(input[i+k+l]);
            y1 = _mm_add_ss(y1,_mm_mul_ss(w,x1));
            …
            x4 = _mm_set_ss(input[i+k+l+3]);
            y4 = _mm_add_ss(y4,_mm_mul_ss(w,x4));
        }
    }
    _mm_store_ss(&output[i],y1);
    _mm_store_ss(&output[i+1],y2);
    _mm_store_ss(&output[i+2],y3);
    _mm_store_ss(&output[i+3],y4);
 }
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用压缩的fp向量来提高性能,我已经成功完成了,但我想知道为什么单个标量代码无法满足处理器的峰值性能.

我的机器上的这个内核的性能是每个周期大约1.6个FP操作,而每个周期最大的是2个FP操作(因为FP add + FP mul可以并行执行).

如果我对研究生成的汇编代码是正确的,理想的时间表将如下所示,其中mov指令需要3个周期,从依赖指令的加载域到FP域的切换延迟需要2个周期,FP乘以4个循环,FP添加需要3个循环.(注意,乘法 - > add的依赖性不会导致任何切换延迟,因为操作属于同一个域).

时间表

根据测量的性能(最大理论性能的约80%),每8个周期有大约3个指令的开销.

我想要:

  • 摆脱这种开销,或
  • 解释它来自哪里

当然,存在缓存未命中和数据错位的问题,这可能会增加移动指令的延迟,但是还有其他因素可以在这里发挥作用吗?像寄存器读取档位或什么?

我希望我的问题很明确,在此先感谢您的回复!


更新:内循环的程序集如下所示:

...
Block 21: 
  movssl  (%rsi,%rdi,4), %xmm4 
  movssl  (%rcx,%rdi,4), %xmm0 
  movssl  0x4(%rcx,%rdi,4), %xmm1 
  movssl  0x8(%rcx,%rdi,4), %xmm2 
  movssl  0xc(%rcx,%rdi,4), %xmm3 
  inc %rdi 
  mulss %xmm4, %xmm0 
  cmp $0x32, %rdi 
  mulss %xmm4, %xmm1 
  mulss %xmm4, %xmm2 
  mulss %xmm3, %xmm4 
  addss %xmm0, %xmm5 
  addss %xmm1, %xmm6 
  addss %xmm2, %xmm7 
  addss %xmm4, %xmm8 
  jl 0x401b52 <Block 21> 
...
Run Code Online (Sandbox Code Playgroud)

Mys*_*ial 31

我在评论中注意到:

  • 循环需要5个周期才能执行.
  • 它"应该"需要4个周期.(因为有4个添加和4个mulitplies)

但是,您的程序集显示5条SSE movssl指令.根据Agner Fog的表格,Nehalem的所有浮点SSE移动指令至少为1 inst/cycle往复吞吐量.

由于你有5个,你不能比5个周期/迭代做得更好.


因此,为了达到最佳性能,您需要减少所拥有的负载数量.如何做到这一点我无法立即看到这个特例 - 但它可能是可能的.

一种常见的方法是使用平铺.在哪里添加嵌套级别以改善局部性.虽然它主要用于改进缓存访问,但它也可以用在寄存器中以减少所需的加载/存储数量.

最终,您的目标是减少负载数量,使其少于add/muls的数量.所以这可能是要走的路.

  • 你怎么能在多任务处理系统上说这个呢?真的吗?Linux的桌面调度程序和上下文切换涉及80%的理论吞吐量......我真的很想看看他是否可以通过1条指令减少循环并获得更好的速度(使用不完整的内核) (2认同)