Этот вопрос продолжает на мой вопрос здесь (по совету мистического):C производительность кода цикла [продолжение]
Продолжая мой вопрос, когда я использовать упакованные инструкции вместо скалярных инструкции кода с помощью встроенных средств будет выглядеть очень похоже:
for(int i=0; i<size; i+=16) {
y1 = _mm_load_ps(output[i]);
…
y4 = _mm_load_ps(output[i+12]);
for(k=0; k<ksize; k++){
for(l=0; l<ksize; l++){
w = _mm_set_ps1(weight[i+k+l]);
x1 = _mm_load_ps(input[i+k+l]);
y1 = _mm_add_ps(y1,_mm_mul_ps(w,x1));
…
x4 = _mm_load_ps(input[i+k+l+12]);
y4 = _mm_add_ps(y4,_mm_mul_ps(w,x4));
}
}
_mm_store_ps(&output[i],y1);
…
_mm_store_ps(&output[i+12],y4);
}
измеренная производительность этого ядра составляет около 5,6 операций FP за цикл, хотя я бы ожидайте, что это будет ровно 4 раза производительность скалярной версии, т. е. 4,1,6 = 6,4 ОПП за цикл.
Принимая движение фактора веса во внимание (спасибо за указание, что выход), график выглядит следующим образом:
Похоже, что график не меняется, хотя есть дополнительный после операции movss
, которая перемещает значение скалярного веса в регистр XMM, а затем использует shufps
для копирования этого скалярного значения во всем векторе. Похоже, что вектор веса готов к использованию для mulps
во времени, принимая во внимание задержку переключения от нагрузки до домена с плавающей запятой, поэтому это не должно вызывать дополнительной задержки.
movaps
(выровнены, упакованный ход), addps
& mulps
инструкции, которые используются в этом ядре (проверено с ассемблере) имеют одинаковую латентность & пропускную способность как их скалярных версии, поэтому это не должно брать на себя какие-либо дополнительные задержки либо ,
Есть ли у кого-нибудь идеи, где этот дополнительный цикл на 8 циклов расходуется, при условии, что максимальная производительность, которую может получить это ядро, составляет 6.4 FP ops за цикл и работает на 5.6 FP ops за цикл?
Кстати, вот что фактическая сборка выглядит следующим образом:
…
Block x:
movapsx (%rax,%rcx,4), %xmm0
movapsx 0x10(%rax,%rcx,4), %xmm1
movapsx 0x20(%rax,%rcx,4), %xmm2
movapsx 0x30(%rax,%rcx,4), %xmm3
movssl (%rdx,%rcx,4), %xmm4
inc %rcx
shufps $0x0, %xmm4, %xmm4 {fill weight vector}
cmp $0x32, %rcx
mulps %xmm4, %xmm0
mulps %xmm4, %xmm1
mulps %xmm4, %xmm2
mulps %xmm3, %xmm4
addps %xmm0, %xmm5
addps %xmm1, %xmm6
addps %xmm2, %xmm7
addps %xmm4, %xmm8
jl 0x401ad6 <Block x>
…
Итак, теперь я задаю вопрос: «Почему инструкция' shufps »добавляет 1 цикл каждые 1.6 итерации?» Это сложно ... – Mysticial
Я бы ожидал, что у него не будет накладных расходов, так как вывод 'shufps' должен быть непосредственно доступен для' multps' op, так как он является доменом FP – Ricky
Легко узнать. Убедитесь, что вектор весов не содержит значений денормализованных значений. Попробуйте цикл без инструкции перетасовки.Это не принесет каких-либо полезных результатов, но, может быть, ваша находка, какая инструкция требует дополнительных циклов (я подозреваю, что тасовка, конечно). – hirschhornsalz