ошибка сегментации, вызванная memmove, если я увеличу количество записей - PullRequest
0 голосов
/ 22 января 2019

Добрый день, я получаю следующую ошибку, если нажимаю nx, ny и nz выше определенного порога, например 100.

Primary job terminated normally, but 1 process returned a non-zero exit code. 
Per user-direction, the job has been aborted.
mpiexec noticed that process rank 0 with PID 0 on node debian exited on signal 11 (Segmentation fault).

Если я остаюсь ниже порогов, все работает нормально.

Кусок кода, который генерирует ошибку, находится в следующей функции:

void dealiasing(int nx, int ny, int nz, int nxd, int nzd, FFT_SCALAR *U) {

int nz_left = 1+ (nz-1)/2 ;
int i, stride_y, stride_z, reader=0, last_index;
for ( stride_z = 0; stride_z < nz_left*ny*nxd*2; stride_z = stride_z + ny*nxd*2) {
    for ( stride_y = 0; stride_y < ny*nxd*2; stride_y = stride_y + nxd*2) {
        for ( i = 0; i < (nx)*2; i++) {
            U[reader] = U[stride_z + stride_y+i];
            reader++;
        }
    }
    last_index = stride_z + stride_y;
}

for ( stride_z = (nzd - nz_left+1)*nxd*ny*2; stride_z < nzd*ny*nxd*2; stride_z = stride_z + ny*nxd*2) {
    for ( stride_y = 0; stride_y < ny*nxd*2; stride_y = stride_y + nxd*2) { 
        for ( i = 0; i < (nx)*2; i++) {
            U[reader] = U[stride_z + stride_y+i];
            reader++;
        }
    }
    last_index = stride_z + stride_y;
}


//Save positive modes
double U_pos[2*nx*ny*(1+(nz-1)/2)];
memmove(U_pos, U, sizeof(FFT_SCALAR)*2*nx*ny*(1+(nz-1)/2)); 
memmove(U, &U[2*nx*ny*(1+(nz-1)/2)], sizeof(FFT_SCALAR)*2*nx*ny*((nz-1)/2));
memmove(&U[2*nx*ny*((nz-1)/2)], U_pos, sizeof(FFT_SCALAR)*2*nx*ny*(1+(nz-1)/2));

В частности, если я отключаю последние 4 строки функции, код работает также на nx, ny, nz вышечем 100. Цель этих строк состоит в том, чтобы переместить записи U таким образом, чтобы конечный блок значений был переназначен как начальные и наоборот.FFT_SCALAR похож на double.

Функция вызывается после серии MPI_Gatherv и MPI_Barrier, заключенных в блок

// Alloc memory for the global output
nfast=nxd;  nmid=ny; nslow=nzd;
FFT_SCALAR *UU, *UV, *VV, *VW, *WW, *UW;
UU = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
UV = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
VV = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
VW = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
WW = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));
UW = (FFT_SCALAR*) malloc( nfast*nmid*nslow*2* sizeof(FFT_SCALAR));

// Gather all data on rank 0
MPI_Gatherv( u, receive[rank], MPI_DOUBLE, U, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")

MPI_Gatherv( uu, receive[rank], MPI_DOUBLE, UU, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( uv, receive[rank], MPI_DOUBLE, UV, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( vv, receive[rank], MPI_DOUBLE, VV, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( vw, receive[rank], MPI_DOUBLE, VW, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( ww, receive[rank], MPI_DOUBLE, WW, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Gatherv( uw, receive[rank], MPI_DOUBLE, UW, scounts, displs, MPI_DOUBLE, 0, MPI_COMM_WORLD); // @suppress("Symbol is not resolved")
MPI_Barrier(MPI_COMM_WORLD); // @suppress("Symbol is not resolved")


 /**************************************** Dealias and Transpose dataset ****************************************/
 if (rank == 0) {
  dealiasing( nx, ny, nz, nxd, nzd, U);

  dealiasing( nx, ny, nz, nxd, nzd, UU);
  dealiasing( nx, ny, nz, nxd, nzd, UV);
  dealiasing( nx, ny, nz, nxd, nzd, VV);
  dealiasing( nx, ny, nz, nxd, nzd, VW);
  dealiasing( nx, ny, nz, nxd, nzd, WW);
  dealiasing( nx, ny, nz, nxd, nzd, UW);
}

1 Ответ

0 голосов
/ 22 января 2019

Если я переписываю их в строки:

double U_pos[2*nx*ny*(1+(nz-1)/2)];
memmove(U_pos, U, sizeof(FFT_SCALAR)*2*nx*ny*(1+(nz-1)/2)); 

в

#define SOME_SIZE (2*nx*ny*(1+(nz-1)/2))

double U_pos[SOME_SIZE];
memmove(U_pos, U, sizeof(FFT_SCALAR)*SOME_SIZE);

, кажется, что вы перезаписываете память - если sizeof(FFT_SCALAR) не равен 1 - потому что вы перемещаете больше байтов в U_pos, чем он может удержаться.

Другая проблема может заключаться в том, что U_pos является VLA, который (в большинстве реализаций) будет размещен в стеке.Когда nx, ny, nz становятся большими, массив U_pos становится очень большим, и у вас может быть переполнение стека.

...