Производительность циклов кода C

В моем приложении есть ядро ​​с множественным добавлением, и я хочу повысить его производительность.

Я использую Intel Core i7-960 (тактовая частота 3,2 ГГц) и уже вручную внедрил ядро ​​с использованием встроенных функций 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);
 }

Я знаю, что могу использовать упакованные векторы fp для повышения производительности, и я уже сделал это успешно. , но я хочу знать, почему один скалярный код не соответствует пиковой производительности процессора.

Производительность этого ядра на моей машине составляет ~1,6 операций FP за цикл, в то время как максимум может быть 2 операции FP за цикл (поскольку FP add + FP mul могут выполняться параллельно).

Если я прав из изучения сгенерированного ассемблерного кода, идеальное расписание будет выглядеть следующим образом, где инструкция movзанимает 3 такта, задержка переключения из домена нагрузки в домен FP для зависимые инструкции занимают 2 такта, умножение FP занимает 4 цикла, а сложение FP занимает 3 цикла. (Обратите внимание, что зависимость от умножения -> добавить не приводит к задержке переключения, поскольку операции принадлежат одному и тому же домену).

schedule

Согласно измеренной производительности (~80% от максимальной теоретической производительности) накладные расходы составляют ~3 инструкции на 8 циклов.

Я пытаюсь либо:

  • избавиться от этих накладных расходов, либо
  • объяснить, откуда они берутся

Конечно, существует проблема с промахами кеша и несовпадением данных, которые могут увеличить задержку перемещения инструкции, но есть ли какие-то другие факторы, которые могли бы сыграть здесь роль? Например, киоски чтения регистров или что-то в этом роде?

Надеюсь, моя проблема ясна, заранее спасибо за ответы!


Обновление: сборка внутреннего цикла выглядит следующим образом:

...
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> 
...
40
задан Ryan Tenney 1 May 2012 в 04:17
поделиться