Це питання продовжується на моє питання тут (за порадою Mystical):
Продовжуючи своє запитання, коли я використовую упаковані інструкції замість скалярних інструкцій, код, що використовує внутрішні дані, буде виглядати дуже схожим:
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 операцій FP за цикл.
Беручи до уваги рух вагового коефіцієнта (спасибі, що вказали на це), графік виглядає так:
Схоже, графік не змінюється, хоча після movss
операції існує додаткова інструкція, яка переміщує значення скалярної ваги до регістра XMM, а потім використовує shufps
для копіювання цього скалярного значення у всьому векторі. Здається, вектор ваги готовий до використання протягом mulps
часу з урахуванням затримки перемикання з навантаження на домен із плаваючою точкою, тому це не повинно спричиняти додаткової затримки.
movaps
(Вирівняні, упакований хід), addps
і mulps
інструкція, які використовуються в цьому ядрі (перевірений з асемблером) має однакову затримку & пропускну здатність, як і їх скалярні версії, тому це не повинно брати на себе якісь - які додаткові затримки або.
Хто-небудь має уявлення, де витрачається цей додатковий цикл за 8 циклів, припускаючи, що максимальна продуктивність, яку може отримати це ядро, становить 6,4 FP операційних циклів за цикл, і він працює при 5,6 операційних операцій FP за цикл?
До речі ось як виглядає фактична збірка:
…
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 ітерації?" Це важко ...