fortran mpi fortran90 mpi-io

fortran - Escribir varias matrices distribuidas con MPI IO



fortran90 mpi-io (1)

Estoy reescribiendo un código de simulación numérica que se paraleliza utilizando MPI en una dirección. Hasta ahora, las matrices que contienen los datos fueron guardadas por el proceso maestro MPI, que implicó transferir los datos de todos los procesos MPI a uno y asignar enormes matrices para almacenar todo. No es muy eficiente ni elegante, y es un problema para resoluciones grandes.

Por lo tanto, estoy tratando de usar MPI-IO para escribir directamente el archivo de las matrices distribuidas. Una de las limitaciones que tengo es que el archivo escrito debe respetar el formato fortran "no formateado" (es decir, un entero de 4 bytes antes y después de cada campo que indique su tamaño).

Escribí un programa de prueba simple, que funciona cuando escribo solo una matriz distribuida en el archivo. Sin embargo, cuando escribo varias matrices, el tamaño total del archivo es incorrecto y cuando se compara con el archivo fortran ''no formateado'' equivalente, los archivos son diferentes.

Aquí está el código de ejemplo :

module arrays_dim implicit none INTEGER, PARAMETER :: dp = kind(0.d0) integer, parameter :: imax = 500 integer, parameter :: jmax = 50 integer, parameter :: kmax = 10 end module arrays_dim module mpi_vars use mpi implicit none integer, save :: ierr, myID, numprocs integer, save :: i_start, i_end, i_mean, i_loc integer, save :: subArray, fileH integer(MPI_OFFSET_KIND), save :: offset, currPos end module mpi_vars program test use mpi use arrays_dim use mpi_vars real(dp), dimension(0:imax,0:jmax+1,0:kmax+1) :: v, w real(dp), dimension(:,:,:), allocatable :: v_loc, w_loc integer :: i, j, k call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, myID, ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, numprocs, ierr) i_mean = (imax+1)/numprocs i_start = myID*i_mean i_end = i_start+i_mean-1 if(i_mean*numprocs<imax+1) then if(myID == numprocs-1) i_end = imax endif i_loc = i_end - i_start + 1 allocate(v_loc(i_start:i_end,0:jmax+1,0:kmax+1)) allocate(w_loc(i_start:i_end,0:jmax+1,0:kmax+1)) print*, ''I am:'', myID, i_start, i_end, i_loc do k=0,kmax+1 do j=0,jmax+1 do i=0,imax v(i,j,k) = i+j+k w(i,j,k) = i*j*k enddo enddo enddo if(myID==0) then open(10,form=''unformatted'') write(10) v !write(10) w close(10) endif do k=0,kmax+1 do j=0,jmax+1 do i=i_start,i_end v_loc(i,j,k) = i+j+k w_loc(i,j,k) = i*j*k enddo enddo enddo call MPI_Type_create_subarray (3, [imax+1, jmax+2, kmax+2], [i_loc, jmax+2, kmax+2], & [i_start, 0, 0], & MPI_ORDER_FORTRAN, MPI_DOUBLE_PRECISION, subArray, ierr) call MPI_Type_commit(subArray, ierr) call MPI_File_open(MPI_COMM_WORLD, ''mpi.dat'', & MPI_MODE_WRONLY + MPI_MODE_CREATE + MPI_MODE_APPEND, & MPI_INFO_NULL, fileH, ierr ) call saveMPI(v_loc, (i_loc)*(jmax+2)*(kmax+2)) !call saveMPI(w_loc, (i_loc)*(jmax+2)*(kmax+2)) call MPI_File_close(fileH, ierr) deallocate(v_loc,w_loc) call MPI_FINALIZE(ierr) end program test ! subroutine saveMPI(array, n) use mpi use arrays_dim use mpi_vars implicit none real(dp), dimension(n) :: array integer :: n offset = (imax+1)*(jmax+2)*(kmax+2)*8 if(myID==0) then call MPI_File_seek(fileH, int(0,MPI_OFFSET_KIND), MPI_SEEK_CUR, ierr) call MPI_File_write(fileH, [(imax+1)*(jmax+2)*(kmax+2)*8], 1, MPI_INTEGER, MPI_STATUS_IGNORE, ierr) call MPI_File_seek(fileH, offset, MPI_SEEK_CUR, ierr) call MPI_File_write(fileH, [(imax+1)*(jmax+2)*(kmax+2)*8], 1, MPI_INTEGER, MPI_STATUS_IGNORE, ierr) endif call MPI_File_set_view(fileH, int(4,MPI_OFFSET_KIND), MPI_DOUBLE_PRECISION, subArray, ''native'', MPI_INFO_NULL, ierr) call MPI_File_write_all(fileH, array, (i_loc)*(jmax+2)*(kmax+2), MPI_DOUBLE_PRECISION, MPI_STATUS_IGNORE, ierr) end subroutine saveMPI

cuando se !write(10) w las líneas !write(10) w !call saveMPI(w_loc, (i_loc)*(jmax+2)*(kmax+2)) (es decir, solo escribo la matriz v), el código funciona bien:

mpif90.openmpi -O3 -o prog main.f90 mpirun.openmpi -np 4 ./prog cmp mpi.dat fort.10

cmp no genera una salida, por lo que los archivos son idénticos. Sin embargo, si descomenta estas líneas, los archivos resultantes (mpi.dat y fort.10) son diferentes. Estoy seguro de que el problema radica en la forma en que defino el desplazamiento que utilizo para escribir los datos en la posición correcta en el archivo, pero no sé cómo indicar a la segunda llamada de saveMPI que la posición inicial debería ser el final del archivo. Qué me estoy perdiendo ?


Solo la primera llamada a saveMPI está funcionando como esperabas. Todo se estropea desde la segunda llamada. Aquí hay algunas indicaciones de lo que está sucediendo:

  • MPI_File_set_view restablece los punteros de archivo independientes y el puntero de archivo compartido a cero. Ver MPI_File_set_view para más detalles. Así que en realidad está sobrescribiendo datos v con datos w cuando llama a MPI_File_set_view en saveMPI .
  • con MPI_File_write , los datos se escriben en las partes del archivo especificadas por la vista actual. Esto significa que la forma en que agrega la información de tamaño en el archivo no es realmente compatible con la vista previamente configurada para v .
  • llamando a MPI_File_seek con MPI_SEEK_CUR establece la posición relativa a la posición actual del puntero individual. Entonces, para la segunda llamada, es relativa al puntero individual del proceso 0

No uso tanto el IO paralelo, así que no puedo evitarlo a menos que entre en los documentos, a los que no tengo tiempo. La pista que puedo dar es:

  • agregue un parámetro adicional a saveMPI que contendrá el desplazamiento absoluto de los datos para escribir; esto puede ser un [in out] arg. Para la primera llamada, será cero y para llamadas posteriores, será el tamaño de todos los datos ya escritos en el archivo, incluida la información de tamaño. Se puede actualizar en saveMPI .
  • antes de escribir la información de tamaño (por proceso 0), llame a MPI_File_set_view para restablecer la vista a la transmisión lineal de bytes como originalmente fue dada por MPI_File_open . Esto se puede hacer estableciendo el etype filetype y el filetype de filetype en MPI_BYTE al llamar a MPI_File_set_view . mira en el documento de MPI_File_open para más información. A continuación, tendrá que realizar llamadas a MPI_File_set_view en saveMPI .

Su subrutina saveMPI podría verse como

subroutine saveMPI(array, n, disp) use mpi use arrays_dim use mpi_vars implicit none real(dp), dimension(n) :: array integer :: n, disp offset = (imax+1)*(jmax+2)*(kmax+2)*8 call MPI_File_set_view(fileH, int(disp,MPI_OFFSET_KIND), MPI_BYTE, MPI_BYTE, ''native'', MPI_INFO_NULL, ierr) if(myID==0) then call MPI_File_seek(fileH, int(0,MPI_OFFSET_KIND), MPI_SEEK_END, ierr) call MPI_File_write(fileH, [(imax+1)*(jmax+2)*(kmax+2)*8], 1, MPI_INTEGER, MPI_STATUS_IGNORE, ierr) call MPI_File_seek(fileH, int(offset,MPI_OFFSET_KIND), MPI_SEEK_CUR, ierr) call MPI_File_write(fileH, [(imax+1)*(jmax+2)*(kmax+2)*8], 1, MPI_INTEGER, MPI_STATUS_IGNORE, ierr) endif call MPI_File_set_view(fileH, int(disp+4,MPI_OFFSET_KIND), MPI_DOUBLE_PRECISION, subArray, ''native'', MPI_INFO_NULL, ierr) call MPI_File_write_all(fileH, array, (i_loc)*(jmax+2)*(kmax+2), MPI_DOUBLE_PRECISION, MPI_STATUS_IGNORE, ierr) disp = disp+offset+8 end subroutine saveMPI

y llamado como:

disp = 0 call saveMPI(v_loc, (i_loc)*(jmax+2)*(kmax+2), disp) call saveMPI(w_loc, (i_loc)*(jmax+2)*(kmax+2), disp)

Finalmente, asegúrese de eliminar el archivo entre dos llamadas porque está usando MPI_MODE_APPEND .