Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
具有mpi的Fortran90派生类型,对齐问题?_Fortran_Mpi_Fortran90_Memory Alignment_Derived Types - Fatal编程技术网

具有mpi的Fortran90派生类型,对齐问题?

具有mpi的Fortran90派生类型,对齐问题?,fortran,mpi,fortran90,memory-alignment,derived-types,Fortran,Mpi,Fortran90,Memory Alignment,Derived Types,我对以下基本代码有问题: program foo use mpi implicit none type bartype real(8) :: x integer :: i end type bartype integer :: mpi_bar_type integer :: & count=2, &

我对以下基本代码有问题:

program foo

  use mpi

  implicit none

  type bartype
     real(8) :: x
     integer :: i
  end type bartype

  integer :: mpi_bar_type

  integer ::                            &
       count=2,                         &
       blocklengths(2)=(/1,1/),         &
       types(2)=(/mpi_double_precision, &
                  mpi_integer/)
  integer(kind=mpi_address_kind) :: displs(2)
  type(bartype) :: bar, bararray(4)
  integer :: rank, ierr, i, test(4), addr0


  call mpi_init(ierr)
  call mpi_comm_rank(mpi_comm_world, rank, ierr)

  call mpi_get_address(bar, addr0)
  call mpi_get_address(bar%x, displs(1))
  call mpi_get_address(bar%i, displs(2))
  do i=1,2
     displs(i)=displs(i)-addr0
  enddo

  call mpi_type_create_struct(2,blocklengths,displs,types,mpi_bar_type,ierr)
  call mpi_type_commit(mpi_bar_type,ierr)

  bararray(:)%x=rank
  bararray(:)%i=rank
  test(:)=rank
  call mpi_bcast(test, 4, mpi_integer, 0, mpi_comm_world,ierr)
  call mpi_bcast(bararray, 4, mpi_bar_type, 0, mpi_comm_world,ierr)

  call mpi_finalize(ierr)

end program foo
我在派生类型Bcast(使用intelMPI和openMPI)上得到一个segfault,在调试器(DDT)中得到一个segfault,据说这可能是一个对齐问题

我已经看到了线程,其中的问题似乎是相同的,但我仍然没有得到解决方案

谢谢你的帮助

试试这个:

program foo
  implicit none
  include 'mpif.h'

  type bartype
     real(8) :: x
     integer :: i
  end type bartype

  integer :: mpi_bar_type

  integer ::                            &
       count=4,                         &
       blocklengths(4)=(/1,1,1,1/),      &
       types(4)=(/MPI_LB,mpi_double_precision, &
                  mpi_integer,MPI_UB/)
  integer(kind=mpi_address_kind) :: displs(4)
  type(bartype) :: bararray(4)
  integer :: rank, ierr, i, test(4)


  call mpi_init(ierr)
  call mpi_comm_rank(mpi_comm_world, rank, ierr)

  call mpi_get_address(bararray(1), displs(1))
  call mpi_get_address(bararray(1)%x, displs(2))
  call mpi_get_address(bararray(1)%i, displs(3))
  call mpi_get_address(bararray(2), displs(4))

  do i=4,1,-1
     displs(i)=displs(i)-displs(1)
  enddo

  call mpi_type_create_struct(4,blocklengths,displs,types,mpi_bar_type,ierr)
  call mpi_type_commit(mpi_bar_type,ierr)

  bararray(:)%x=rank
  bararray(:)%i=rank
  test(:)=rank
  print *, "before", bararray

  call mpi_bcast(test, 4, mpi_integer, 0, mpi_comm_world,ierr)
  call mpi_bcast(bararray, 4, mpi_bar_type, 0, mpi_comm_world,ierr)

  print *, "after", bararray

  call mpi_finalize(ierr)

end program foo
注意使用
MPI_LB
MPI_UB
作为结构的附加虚拟构件。这是为了确保类型的范围正确。 我不完全确定这是按照标准推荐的方法,但它一直对我有效。 据我所知,标准要求在类型定义中添加一个
bind(C)
和一个
sequence
,但即使如此,我也不确定不设置类型的上限是否有效,因为我怀疑您会有对齐问题


编辑:在对MPI_LB和MPI_UB进行了各种评论(这些评论确实已被弃用)并仔细阅读了该标准之后,我想以下内容是可行的,应该是符合要求的

program foo
  implicit none
  include 'mpif.h'

  type bartype
     real(8) :: x
     integer :: i
  end type bartype

  integer :: tmp_type, bar_type

  integer ::                            &
       count=4,                         &
       blocklengths(2)=(/1,1/),         &
       types(2)=(/mpi_double_precision, &
                  mpi_integer/)
  integer(kind=mpi_address_kind) :: displs(2), lb, extent
  type(bartype) :: bararray(4)
  integer :: rank, ierr, i, test(4)


  call mpi_init(ierr)
  call mpi_comm_rank(mpi_comm_world, rank, ierr)

  call mpi_get_address(bararray(1)%x, displs(1))
  call mpi_get_address(bararray(1)%i, displs(2))
  call mpi_get_address(bararray(1), lb)
  call mpi_get_address(bararray(2), extent)

  do i=1,2
     displs(i)=displs(i)-lb
  enddo
  extent=extent-lb
  lb=0

  call mpi_type_create_struct(2,blocklengths,displs,types,tmp_type,ierr)
  call mpi_type_commit(tmp_type,ierr)
  call mpi_type_create_resized(tmp_type,lb,extent,bar_type,ierr)
  call mpi_type_free(tmp_type,ierr)
  call mpi_type_commit(bar_type,ierr)

  bararray(:)%x=rank
  bararray(:)%i=rank
  test(:)=rank
  print *, "before", bararray

  call mpi_bcast(test, 4, mpi_integer, 0, mpi_comm_world,ierr)
  call mpi_bcast(bararray, 4, bar_type, 0, mpi_comm_world,ierr)

  print *, "after", bararray

  call mpi_type_free(bar_type,ierr)
  call mpi_finalize(ierr)

end program foo
试试这个:

program foo
  implicit none
  include 'mpif.h'

  type bartype
     real(8) :: x
     integer :: i
  end type bartype

  integer :: mpi_bar_type

  integer ::                            &
       count=4,                         &
       blocklengths(4)=(/1,1,1,1/),      &
       types(4)=(/MPI_LB,mpi_double_precision, &
                  mpi_integer,MPI_UB/)
  integer(kind=mpi_address_kind) :: displs(4)
  type(bartype) :: bararray(4)
  integer :: rank, ierr, i, test(4)


  call mpi_init(ierr)
  call mpi_comm_rank(mpi_comm_world, rank, ierr)

  call mpi_get_address(bararray(1), displs(1))
  call mpi_get_address(bararray(1)%x, displs(2))
  call mpi_get_address(bararray(1)%i, displs(3))
  call mpi_get_address(bararray(2), displs(4))

  do i=4,1,-1
     displs(i)=displs(i)-displs(1)
  enddo

  call mpi_type_create_struct(4,blocklengths,displs,types,mpi_bar_type,ierr)
  call mpi_type_commit(mpi_bar_type,ierr)

  bararray(:)%x=rank
  bararray(:)%i=rank
  test(:)=rank
  print *, "before", bararray

  call mpi_bcast(test, 4, mpi_integer, 0, mpi_comm_world,ierr)
  call mpi_bcast(bararray, 4, mpi_bar_type, 0, mpi_comm_world,ierr)

  print *, "after", bararray

  call mpi_finalize(ierr)

end program foo
注意使用
MPI_LB
MPI_UB
作为结构的附加虚拟构件。这是为了确保类型的范围正确。 我不完全确定这是按照标准推荐的方法,但它一直对我有效。 据我所知,标准要求在类型定义中添加一个
bind(C)
和一个
sequence
,但即使如此,我也不确定不设置类型的上限是否有效,因为我怀疑您会有对齐问题


编辑:在对MPI_LB和MPI_UB进行了各种评论(这些评论确实已被弃用)并仔细阅读了该标准之后,我想以下内容是可行的,应该是符合要求的

program foo
  implicit none
  include 'mpif.h'

  type bartype
     real(8) :: x
     integer :: i
  end type bartype

  integer :: tmp_type, bar_type

  integer ::                            &
       count=4,                         &
       blocklengths(2)=(/1,1/),         &
       types(2)=(/mpi_double_precision, &
                  mpi_integer/)
  integer(kind=mpi_address_kind) :: displs(2), lb, extent
  type(bartype) :: bararray(4)
  integer :: rank, ierr, i, test(4)


  call mpi_init(ierr)
  call mpi_comm_rank(mpi_comm_world, rank, ierr)

  call mpi_get_address(bararray(1)%x, displs(1))
  call mpi_get_address(bararray(1)%i, displs(2))
  call mpi_get_address(bararray(1), lb)
  call mpi_get_address(bararray(2), extent)

  do i=1,2
     displs(i)=displs(i)-lb
  enddo
  extent=extent-lb
  lb=0

  call mpi_type_create_struct(2,blocklengths,displs,types,tmp_type,ierr)
  call mpi_type_commit(tmp_type,ierr)
  call mpi_type_create_resized(tmp_type,lb,extent,bar_type,ierr)
  call mpi_type_free(tmp_type,ierr)
  call mpi_type_commit(bar_type,ierr)

  bararray(:)%x=rank
  bararray(:)%i=rank
  test(:)=rank
  print *, "before", bararray

  call mpi_bcast(test, 4, mpi_integer, 0, mpi_comm_world,ierr)
  call mpi_bcast(bararray, 4, bar_type, 0, mpi_comm_world,ierr)

  print *, "after", bararray

  call mpi_type_free(bar_type,ierr)
  call mpi_finalize(ierr)

end program foo

(1) 通常使用
隐式无
;(2)
使用mpi
而不是
包括mpif.h
。一旦(1)和(2)完成,你会注意到(3)你没有为mpi\u cadna\u double\u st定义类型(应该是整数)和(4)显示的种类是错误的(你应该使用
integer(kind=mpi\u address\u kind)
。应该这样做。是的,我的示例代码非常糟糕。我纠正了它(并按照这个方法编辑了我的帖子),但我仍然有一个segfault…更新的代码现在几乎正确,但是
addr0
也需要是
整数(kind=mpi\u address\u kind
);如果您在创建类型之前显示
print*,您会注意到这些值是无意义的,这很容易导致segfault,因为它们描述内存访问。我真的很惊讶gfortran没有在那里发出警告。(1)通常使用
隐式无
;(2)
使用mpi
而不是
包含mpif.h
。一旦(1)和(2)完成,您会注意到(3)您没有为mpi\u cadna\u double\u st定义类型(应该是整数)和(4)dispus的类型错误(您应该使用
integer(kind=mpi\u address\u kind)
。应该这样做。是的,我的示例代码非常糟糕。我更正了它(并根据编辑了我的文章),但我仍然有一个错误…更新的代码现在几乎正确,但是
addr0
也需要是
整数(kind=mpi\u address\u kind
);如果您在创建类型之前
print*,displays
,您会注意到这些值都是无意义的,这很容易导致segfault,因为它们描述内存访问。我真的很惊讶gfortran没有在那里发出警告。@JonathanDursi我知道,但标准不是太清楚(至少对我来说)关于它们被弃用的实际原因,以及在不使用它们的情况下实现其目的的有效方法……你能告诉我这一点吗,那就太好了。你是对的,你通常需要这些信息-例如,如果OP想要创建一个数组,几乎肯定会在最后有填充-即使不是这样这里的问题。目前推荐的方法是使用。至于为什么不推荐,我真的不能说;我认为新的样式更干净,但可能有一些更强大的实现原因来进行更改。“新的”(自1998年以来)方法:不在创建结构类型时设置MPI_LB和MPI_UB,而是使用MPI_type_create_resized。您仍然创建一个具有double和int的两种类型的结构,然后根据所需的下限和(从范围派生)调整该类型的大小上限。不过,没有人会拿走MPI_LB和MPI_UB,所以你的方法至少还能工作20年。@Gilles-哦,原来有一个关于反对理由的问题:“硬编码”像这样的UB/LB对于一个单独的结构来说是非常好的,但是一旦在一个新的数据类型中使用这样定义的类型作为子类型,就会产生令人惊讶的行为。@JonathanDursi我知道它们是,但是标准不是太清楚(至少对我来说)关于它们被弃用的实际原因,以及在不使用它们的情况下实现其目的的有效方法……你能告诉我这一点吗,那就太好了。你是对的,你通常需要这些信息-例如,如果OP想要创建一个数组,几乎肯定会在最后有填充-即使不是这样这里的问题。目前推荐的方法是使用。至于为什么不推荐,我真的不能说;我认为新的样式更干净,但可能有一些更强大的实现原因来进行更改。“新的”(自1998年以来)方法:不在创建结构类型时设置MPI_LB和MPI_UB,而是使用MPI_type_create_resized。您仍然创建一个具有double和int的两种类型的结构,然后根据所需的下限和(从范围派生)调整该类型的大小上限。不过,没有人会拿走MPI_LB和MPI_UB,所以您的方法至少可以工作2年