Próbuję nauczyć się sznurków SSE w C. Mam fragment kodu, w którym ładuję dwukomponentowy wektor podwójnych danych, dodam do niego coś, a następnie próbuję go zapisać z powrotem do pamięci. Wszystko działa: mogę załadować moje dane do rejestrów SEE, mogę operować na moich danych w tych rejestrach SSE, ale w chwili, gdy spróbuję zapisać te przetworzone dane z powrotem do oryginalnej tablicy (gdzie czytam moje dane z pierwsze miejsce!) Otrzymuję błąd segmentacji.SSE _mm_load_pd działa przy _mm_store_pd segfaults
Czy ktoś może mi doradzić w tej sprawie - to doprowadza mnie do szaleństwa.
double res[2] __attribute__((aligned(16)));
for(int k=0; k<n; k++){
int i=0;
for(; i+1<n; i+=2)
{
__m128d cik = _mm_load_pd(&C[i+k*n]);
int j = 0;
for(; j+1<n; j+=2)
{
__m128d aTij = _mm_load_pd(&A_T[j+i*n]);
__m128d bjk = _mm_load_pd(&B[j+k*n]);
__m128d dotpr = _mm_dp_pd(aTij, bjk,2);
cik = _mm_add_pd(cik, dotpr);
}
_mm_store_pd(res, cik);
//C[i+k*n] = res[0];
}
}
Jak powiedziałem wyżej, wszystko działa w tym kodzie wyjątkiem gdzie przechowywać moje wyniki z powrotem do tej jednowymiarowej tablicy „C” gdzie mogę czytać dane ze w pierwszej kolejności. Oznacza to, że kiedy usunąć znaki komentarza przed
//C[i+k*n] = res[0];
otrzymuję winy segmentacji.
Jak to jest możliwe, że mogę odczytać z C z wyrównaną wersją pamięci _mm_load_pd (więc C musi być wyrównane w pamięci!) Podczas pisania z powrotem do niego nie działa? "C" musi być wyrównane, a jak widać "res" musi być wyrównany.
Zastrzeżenie: Mój oryginalny kod odczytać
_mm_store_pd(&C[i+k*n], cik);
który wyprodukował także usterki segmentacji i zacząłem wprowadzania „RES” z wyraźną wyrównania w moim próba rozwiązania problemu.
Uzupełnienie
A, B, C są zadeklarowane w następujący sposób:
buf = (double*) malloc (3 * nmax * nmax * sizeof(double));
double* A = buf + 0;
double* B = A + nmax*nmax;
double* C = B + nmax*nmax;
Próba rozwiązania z posix_memalign
Starając się rozwiązać problem błędu segmentacji pisząc do oryginalna tablica jednowymiarowa, teraz używam buforów dla odpowiednich macierzy. Jednak wciąż się odkłada podczas próby zapisu z powrotem na C_buff!
double res[2] __attribute__((aligned(16)));
double * A_T;
posix_memalign((void**)&A_T, 16, n*n*sizeof(double));
double * B_buff;
posix_memalign((void**)&B_buff, 16, n*n*sizeof(double));
double * C_buff;
posix_memalign((void**)&C_buff, 16, n*n*sizeof(double));
for(int y=0; y<n; y++)
for(int x=0; x<n; x++)
A_T[x+y*n] = A[y+x*n];
for(int x=0; x<n; x++)
for(int y=0; y<n; y++)
B_buff[y+x*n] = B[y+x*n];
for(int x=0; x<n; x++)
for(int y=0; y<n; y++)
C_buff[y+x*n] = C[y+x*n];
for(int k=0; k<n; k++){
int i=0;
for(; i+1<n; i+=2)
{
__m128d cik = _mm_load_pd(&C_buff[i+k*n]);
int j = 0;
for(; j+1<n; j+=2)
{
__m128d aTij = _mm_load_pd(&A_T[j+i*n]);
__m128d bjk = _mm_load_pd(&B_buff[j+k*n]);
__m128d dotpr = _mm_dp_pd(aTij, bjk,2);
cik = _mm_add_pd(cik, dotpr);
}
_mm_store_pd(&C_buff[i+k*n], cik);
//_mm_store_pd(res, cik);
//C_buff[i+k*n] = res[0];
//C_buff[i+1+k*n] = res[1];
}
}
W jaki sposób zadeklarowano "C"? –
@TonyTheLion patrz dodatek w pytaniu. O ile rozumiem, malloc próbuje wyrównać fragment pamięci, który przydziela, ale nie zawsze kończy się sukcesem dla wszystkich celów. Moja główna uwaga odnośnie powyższego jest taka, że mogę czytać z tej konkretnej lokalizacji w "C", ale nie mogę do niej pisać. A więc "C" wydaje się wyrównane w celu czytania, ale nie pisania? –
Myślę, że wychodząc z założenia, że 'malloc' wyrówna wszystko, jest niepewne, możesz chcieć użyć [' aligned_alloc'] (http://man7.org/linux/man-pages/man3/posix_memalign.3.html) jeśli używasz GCC lub ['_aligned_malloc'] (http://msdn.microsoft.com/en-us/library/8z34s9c6%28VS.80%29.aspx) jeśli używasz MSVC. –