2012-06-18 9 views
6

Po raz pierwszy współpracuję z wewnętrzną specyfikacją SSE i napotykam błąd segmentacji, nawet po zapewnieniu wyrównania pamięci 16-bajtowej. Ten post jest rozszerzeniem do mojego wcześniejszego pytania:Błąd segmentacji podczas pracy ze specyfiką SSE z powodu nieprawidłowego wyrównania pamięci

How to allocate 16byte memory aligned data

To jak ja zadeklarowały moje tablicy:

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

Kiedy próbuję to zrobić:

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

Ale kiedy to zrobię:

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

Ale jeśli to zrobię:

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

Jednak chcę wyeliminować stosując _mm_loadu_ps i chcą, aby pracować przy użyciu _mm_load_ps tylko.

Pracuję z kompilatorem Intel icc.

Jak rozwiązać ten problem?

UPDATE:

użyciu zarówno operacje w poniższym kodzie:

wersję
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); 
    } 

Czy jest bardziej efektywny sposób to zrobić używając tylko _mm_load_ps()?

+0

Co to jest "sizeof (float)" w twojej architekturze? – ecatmur

+0

@ecatmur: Pracuję na komputerze 64-bitowym. – PGOnTheGo

+0

który nie odpowiada na pytanie; istnieje wiele różnych 64-bitowych ABI. – ecatmur

Odpowiedz

11

Ponieważ ma wartość 4, tylko co czwarty wpis w pozycji V zostanie poprawnie wyrównany. Pamiętaj, że _mm_load_ps ładuje cztery pływaki na raz. Argument, tj. Wskaźnik do pierwszego elementu pływającego, musi zostać wyrównany do 16 bajtów.

Zakładam, że w twoim przykładzie i jest wielokrotnością czterech, w przeciwnym wypadku _mm_load_ps(&V[i]) może zawieść.

Aktualizacja

ten sposób chciałbym zaproponować wdrożenie powyżej przesuwne przykład okna za pomocą dopasowanych obciążenia i przetasowań:

__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. */ 
    ... 

    } 

pamiętać, że jest to trochę skomplikowane, ponieważ _mm_shuffle_ps może trwać tylko dwie wartości z każdego argumentu, dlatego najpierw musimy wykonać u3 i u4, aby ponownie wykorzystać je dla innych wartości z różnymi nakładającymi się.

Należy również zauważyć, że wartości u1, u3 i u5 może być również odzyskiwane z u2, u4 i u6 w poprzedniej iteracji.

Uwaga, w końcu, mam nie zweryfikowałem powyższego kodu! Przeczytaj dokumentację dla _mm_shuffle_ps i sprawdź, czy trzeci argument, selektor, jest poprawny dla każdego przypadku.

+0

Pedro: masz rację. i jest wielokrotnością 4 w moim przykładzie. Ale jak pokonać problem segmentacji? – PGOnTheGo

+0

@Hello_PG: To zależy od tego, co chcesz zrobić. Czy musisz wykonywać operacje SIMD na wszystkich elementach 'V' w grupach po cztery, np. 'V [0..3]', 'V [4..7]', 'V [8..11]'? Czy masz okno przesuwne o długości czterech, np. 'v [0..3]', 'V [1..4]', 'V [2..5]'? W pierwszym przypadku możesz po prostu użyć pętli 'for' zamiast' i', zwiększając 'i' o' 4' w każdej iteracji. W tym drugim przypadku utkniesz w mniej wydajnym, niepodpisanym "_mm_loadu_ps". – Pedro

+0

Mój kod obejmuje koncepcję przesuwanego okna. Zasadniczo jest to szablon 1D, który wymaga mi śledzenia sąsiednich 4 elementów. Zaktualizowałem kod, używając zarówno _mm_load_ps, jak i _mm_loadu_ps .. Proszę znaleźć kod w moim zaktualizowanym wpisie. Czy to najlepszy sposób, aby temu zaradzić? – PGOnTheGo

Powiązane problemy