Questa domanda continua sulla mia domanda qui (su consiglio di Mystical):C prestazioni codice di ciclo [continua]
Proseguendo la mia domanda, quando uso istruzioni fornite, invece di scalare istruzioni per il codice utilizzando intrinseche sarebbe molto simile:
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);
}
le prestazioni misurata di questo kernel è di circa 5,6 operazioni FP per ciclo, anche se avrei aspettarsi che corrisponda esattamente alle prestazioni 4x della versione scalare, ovvero 4,1,6 = 6,4 FP op per ciclo.
Prendendo la mossa del fattore di peso in considerazione (grazie per la segnalazione), il programma si presenta come:
Sembra che il programma non cambia, anche se c'è un extra istruzioni dopo l'operazione movss
che sposta il valore di peso scalare nel registro XMM e quindi utilizza shufps
per copiare questo valore scalare nell'intero vettore. Sembra che il vettore del peso sia pronto per essere utilizzato per lo mulps
in tempo, tenendo in considerazione la latenza di commutazione dal carico al dominio in virgola mobile, pertanto non dovrebbe verificarsi alcuna latenza aggiuntiva.
Il movaps
(allineato, spostare al sacco), addps
& mulps
istruzioni che vengono utilizzati in questo kernel (verificato con il codice assembly) hanno la stessa latenza & il throughput come le loro versioni scalari, quindi questo non dovrebbe essere soggetto alcuna latenza più o .
Qualcuno ha un'idea su dove viene speso questo ciclo extra per 8 cicli, supponendo che le prestazioni massime ottenibili da questo kernel siano 6.4 FP ops per ciclo ed è in esecuzione a 5.6 FP ops per ciclo?
A proposito qui è ciò che il gruppo attuale si presenta come:
…
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>
…
Quindi immagino che la domanda ora sia: "Perché l'istruzione' shufps' aggiunge 1 ciclo ogni 1,6 iterazioni? " È una cosa tosta ... – Mysticial
mi aspetterei che non abbia overhead visto che l'output di 'shufps' dovrebbe essere direttamente disponibile all'opzione' multps' dato che è sia il dominio FP – Ricky
Facile da scoprire. Assicurarsi che il vettore del peso non contenga valori di valori denormalizzati. Prova il loop senza le istruzioni shuffle.Non produrrà risultati utili, ma forse troverai le istruzioni che ti costano cicli addizionali (sospetto che lo shuffle, ovviamente). – hirschhornsalz