2012-06-18 6 views
6

Sto lavorando con intrinsecamente SSE per la prima volta e sto riscontrando un errore di segmentazione anche dopo aver assicurato l'allineamento della memoria a 16 byte. Questo post è un'estensione alla mia precedente domanda:Errore di segmentazione mentre si lavora con gli intrinsechi SSE a causa di un allineamento errato della memoria

How to allocate 16byte memory aligned data

Ecco come ho dichiarato la mia matrice:

float *V = (float*) memalign(16,dx*sizeof(float)); 

Quando provo a fare questo:

__m128 v_i = _mm_load_ps(&V[i]); //It works 

Ma quando faccio questo:

__m128 u1 = _mm_load_ps(&V[(i-1)]); //There is a segmentation fault 

Ma se faccio:

__m128 u1 = _mm_loadu_ps(&V[(i-1)]); //It works again 

Tuttavia mi vogliono eliminare utilizzando _mm_loadu_ps e vogliono farlo funzionare utilizzando solo _mm_load_ps.

Sto lavorando con il compilatore Intel ICC.

Come posso risolvere questo problema?

UPDATE:

utilizzando entrambe le operazioni nel seguente codice:

versione
void FDTD_base (float *V, float *U, int dx, float c0, float c1, float c2, float c3,  float c4) 
    { 
     int i, j, k; 
        for (i = 4; i < dx-4; i++) 
        { 

          U[i] = (c0 * (V[i]) //center 
            + c1 * (V[(i-1)] + V[(i+1)]) 
            + c2 * (V[(i-2)] + V[(i+2)]) 
            + c3 * (V[(i-3)] + V[(i+3)]) 
            + c4 * (V[(i-4)] + V[(i+4)])); 
        } 

     } 

SSE:

  for (i=4; i < dx-4; i+=4) 
     { 
      v_i = _mm_load_ps(&V[i]); 
      __m128 center = _mm_mul_ps(v_i,c0_i); 

      __m128 u1 = _mm_loadu_ps(&V[(i-1)]); 
      u2 = _mm_loadu_ps(&V[(i+1)]); 

      u3 = _mm_loadu_ps(&V[(i-2)]); 
      u4 = _mm_loadu_ps(&V[(i+2)]); 

      u5 = _mm_loadu_ps(&V[(i-3)]); 
      u6 = _mm_loadu_ps(&V[(i+3)]); 

      u7 = _mm_load_ps(&V[(i-4)]); 
      u8 = _mm_load_ps(&V[(i+4)]); 

      __m128 tmp1 = _mm_add_ps(u1,u2); 
      __m128 tmp2 = _mm_add_ps(u3,u4); 
      __m128 tmp3 = _mm_add_ps(u5,u6); 
      __m128 tmp4 = _mm_add_ps(u7,u8); 

      __m128 tmp5 = _mm_mul_ps(tmp1,c1_i); 
      __m128 tmp6 = _mm_mul_ps(tmp2,c2_i); 
      __m128 tmp7 = _mm_mul_ps(tmp3,c3_i); 
      __m128 tmp8 = _mm_mul_ps(tmp4,c4_i); 

      __m128 tmp9 = _mm_add_ps(tmp5,tmp6); 
      __m128 tmp10 = _mm_add_ps(tmp7,tmp8); 

      __m128 tmp11 = _mm_add_ps(tmp9,tmp10); 
      __m128 tmp12 = _mm_add_ps(center,tmp11); 

      _mm_store_ps(&U[i], tmp12); 
    } 

C'è un modo più efficiente di fare questo utilizzando solo _mm_load_ps()?

+0

Che cos'è 'sizeof (float)' sulla tua architettura? – ecatmur

+0

@ecatmur: Sto lavorando su una macchina a 64 bit. – PGOnTheGo

+0

che non risponde alla domanda; ci sono molti differenti ABI a 64 bit. – ecatmur

risposta

11

Poiché sizeof(float) è 4, solo una quarta voce in V sarà allineata correttamente. Ricorda che _mm_load_ps carica quattro float alla volta. L'argomento, ovvero il puntatore al primo float, deve essere allineato a 16 byte.

Suppongo che nell'esempio i sia un multiplo di quattro, altrimenti _mm_load_ps(&V[i]) non riuscirebbe.

Aggiornamento

Questo è quanto vorrei suggerire attuare l'esempio finestra sopra scorrevole con carichi allineati e riordini:

__m128 v_im1; 
__m128 v_i = _mm_load_ps(&V[0]); 
__m128 v_ip1 = _mm_load_ps(&V[4]); 

for (i = 4 ; i < dx ; i += 4) { 

    /* Get the three vectors in this 'frame'. */ 
    v_im1 = v_i; v_i = v_ip1; v_ip1 = _mm_load_ps(&V[i+4]); 

    /* Get the u1..u8 from the example code. */ 
    __m128 u3 = _mm_shuffle_ps(v_im1 , v_i , 3 + (4<<2) + (0<<4) + (1<<6)); 
    __m128 u4 = _mm_shuffle_ps(v_i , v_ip1 , 3 + (4<<2) + (0<<4) + (1<<6)); 

    __m128 u1 = _mm_shuffle_ps(u3 , v_i , 1 + (2<<2) + (1<<4) + (2<<6)); 
    __m128 u2 = _mm_shuffle_ps(v_i , u4 , 1 + (2<<2) + (1<<4) + (2<<6)); 

    __m128 u5 = _mm_shuffle_ps(v_im1 , u3 , 1 + (2<<2) + (1<<4) + (2<<6)); 
    __m128 u6 = _mm_shuffle_ps(u4 , v_ip1 , 1 + (2<<2) + (1<<4) + (2<<6)); 

    __m128 u7 = v_im1; 
    __m128 u8 = v_ip1; 

    /* Do your computation and store. */ 
    ... 

    } 

noti che questo è un po 'complicato in quanto _mm_shuffle_ps può assumere solo due valori da ogni argomento, ecco perché dobbiamo prima creare u3 e u4 per riutilizzarli per gli altri valori con sovrapposizioni diverse.

noti inoltre che i valori u1, u3 e u5 possono anche essere recuperati da u2, u4 e u6 nell'iterazione precedente.

Nota, infine, che ho non verificato il codice sopra! Leggere la documentazione per _mm_shuffle_ps e verificare che il terzo argomento, il selettore, sia corretto per ciascun caso.

+0

Pedro: hai ragione. io sono un multiplo di 4 nel mio esempio. Ma come faccio a superare l'errore di segmentazione? – PGOnTheGo

+0

@Hello_PG: dipende da cosa vuoi fare. Devi fare operazioni SIMD su tutti gli elementi di 'V' in gruppi di quattro, ad es. 'V [0..3]', 'V [4..7]', 'V [8..11]'? O hai una finestra scorrevole di lunghezza quattro, ad es. 'v [0..3]', 'V [1..4]', 'V [2..5]'? Nel primo caso, si potrebbe semplicemente usare un ciclo 'for' su' i', incrementando 'i' di' 4' in ogni iterazione. In quest'ultimo caso, sei bloccato con il meno efficiente '_mm_loadu_ps'. – Pedro

+0

Il mio codice comprende un concetto di finestra scorrevole. Fondamentalmente si tratta di uno stencil 1D, che richiede il monitoraggio dei 4 elementi vicini. Ho aggiornato il codice utilizzando sia _mm_load_ps che _mm_loadu_ps..Per favore, trova il codice nel mio post aggiornato. È questo il modo migliore per affrontarlo? – PGOnTheGo

Problemi correlati