fortran mpi mpi-io

fortran - MPI-IO: escribir subcampo



(1)

Estoy comenzando a usar MPI-IO e intenté escribir un ejemplo muy simple de las cosas que me gustaría hacer con él; Sin embargo, a pesar de que es un código simple y me inspiré en los ejemplos que leo aquí y allá, recibo una falla de segmentación que no entiendo.

La lógica de la pieza de código es muy simple: cada hilo manejará una matriz local que es parte de una matriz globlal que quiero escribir. Creo un tipo de MPI_Type_Create_Subarray usando MPI_Type_Create_Subarray para hacerlo. Luego solo abro el archivo, establezco una vista e intento escribir los datos. Obtengo el error de segmentación durante MPI_File_Write_All .

Aquí está el código:

program test implicit none include "mpif.h" integer :: myrank, nproc, fhandle, ierr integer :: xpos, ypos integer, parameter :: loc_x=10, loc_y=10 integer :: loc_dim integer :: nx=2, ny=2 real(8), dimension(loc_x, loc_y) :: data integer :: written_arr integer, dimension(2) :: wa_size, wa_subsize, wa_start call MPI_Init(ierr) call MPI_Comm_Rank(MPI_COMM_WORLD, myrank, ierr) call MPI_Comm_Size(MPI_COMM_WORLD, nproc, ierr) xpos = mod(myrank, nx) ypos = mod(myrank/nx, ny) data = myrank loc_dim = loc_x*loc_y wa_size = (/ nx*loc_x, ny*loc_y /) wa_subsize = (/ loc_x, loc_y /) wa_start = (/ xpos, ypos /)*wa_subsize call MPI_Type_Create_Subarray(2, wa_size, wa_subsize, wa_start & , MPI_ORDER_FORTRAN, MPI_DOUBLE_PRECISION, written_arr, ierr) call MPI_Type_Commit(written_arr, ierr) call MPI_File_Open(MPI_COMM_WORLD, "file.dat" & & , MPI_MODE_WRONLY + MPI_MODE_CREATE, MPI_INFO_NULL, fhandle, ierr) call MPI_File_Set_View(fhandle, 0, MPI_DOUBLE_PRECISION, written_arr & , "native", MPI_INFO_NULL, ierr) call MPI_File_Write_All(fhandle, data, loc_dim, MPI_DOUBLE_PRECISION & , MPI_INFO_NULL, ierr) call MPI_File_Close(fhandle, ierr) call MPI_Finalize(ierr) end program test

¡Cualquier ayuda sería muy apreciada!


El último argumento para MPI_FILE_WRITE_ALL antes del argumento de salida de error es un objeto de estado MPI y no un objeto de información MPI. Hacer la llamada con MPI_INFO_NULL es, por lo tanto, erróneo. Si no está interesado en el estado de la operación de escritura, debe pasar MPI_STATUS_IGNORE en MPI_STATUS_IGNORE lugar. Hacer la llamada con MPI_INFO_NULL podría funcionar en algunas implementaciones de MPI debido a los detalles de cómo se definen ambas constantes, pero luego fallan en otras.

Por ejemplo, en Open MPI, MPI_INFO_NULL se declara como:

parameter (MPI_INFO_NULL=0)

Cuando se pasa en lugar de MPI_STATUS_IGNORE provoca que se MPI_STATUS_IGNORE la implementación C de MPI_File_write_all con el argumento de estado apuntando a una ubicación de memoria constante (de solo lectura) que contiene el valor de MPI_INFO_NULL (que es como Fortran implementa las constantes de paso por dirección). Cuando la función C está a punto de finalizar, intenta llenar el objeto de estado, lo que da como resultado un intento de escribir en la memoria constante y, finalmente, conduce a la falla de segmentación.

Al escribir nuevos programas Fortran, es aconsejable no utilizar la antigua interfaz mpif.h , ya que no proporciona ninguna comprobación de errores. Más bien, uno debería usar el módulo mpi o incluso mpi_f08 cuando más implementaciones de MPI se vuelven compatibles con MPI-3.0. El comienzo de su programa debería por lo tanto verse así:

program test use mpi implicit none ... end program test

Una vez que utiliza el módulo mpi lugar de mpif.h , el compilador puede realizar la comprobación del tipo de parámetro para algunas llamadas MPI, incluido MPI_FILE_SET_VIEW , y detectar un error:

test.f90(34): error #6285: There is no matching specific subroutine for this generic subroutine call. [MPI_FILE_SET_VIEW] call MPI_File_Set_View(fhandle, 0, MPI_DOUBLE_PRECISION, written_arr & -------^ compilation aborted for test.f90 (code 1)

La razón es que el segundo argumento para MPI_FILE_SET_VIEW es de tipo INTEGER(KIND=MPI_OFFSET_KIND) , que es de 64 bits en la mayoría de las plataformas modernas. La constante 0 simplemente es del tipo INTEGER y, por lo tanto, es de 32 bits en la mayoría de las plataformas. Lo que sucede es que con mpif.h el compilador pasa un puntero a una constante INTEGER con valor de 0 , pero la subrutina lo interpreta como un puntero a un entero más grande e interpreta los valores vecinos como parte del valor constante. Por lo tanto, el cero que pasa como un desplazamiento dentro del archivo termina siendo un valor distinto de cero.

Reemplace el 0 en la llamada MPI_FILE_SET_VIEW con 0_MPI_OFFSET_KIND o declare una constante de tipo INTEGER(KIND=MPI_OFFSET_KIND) y un valor de cero y luego páselo.

call MPI_File_Set_View(fhandle, 0_MPI_OFFSET_KIND, MPI_DOUBLE_PRECISION, ...

o

integer(kind=MPI_OFFSET_KIND), parameter :: zero_off = 0 ... call MPI_File_Set_View(fhandle, zero_off, MPI_DOUBLE_PRECISION, ...

Ambos métodos conducen a un archivo de salida de 3200 bytes de tamaño (como se esperaba).