gpt4 book ai didi

memory-management - 用户定义类型的 Fortran 可分配数组成员

转载 作者:行者123 更新时间:2023-12-04 20:36:14 30 4
gpt4 key购买 nike

在以下简单程序中,我在派生类型的可分配数组成员处遇到段错误。此段错误仅发生在一台机器上(在 openSUSE 上使用 Intel Fortran 14.0.3),而不会发生在我尝试过的另一台机器上(在 Ubuntu 上使用 Intel Fortran 14.0.2)。此外,如果我更改程序中的整数参数之一,程序将正常结束。

有人可以重现这个问题吗?有人能告诉我代码有什么问题吗?

下面是三个源代码文件。
main_dbg.f90..是否发生段错误取决于n1的值和 n2在这个文件中。

PROGRAM dbg
USE tktype
USE mymodule, ONLY : MyClass, MyClass_constructor
IMPLICIT NONE

INTEGER(I4B) :: n1,n2,n3
TYPE(MyClass) :: o_MyClass

n1=23
n2=32
! .. this does not work.
! n2=31
! .. this works.
n3 = n1*n2
write(*,'(1X,A,I10)') 'n1=', n1
write(*,'(1X,A,I10)') 'n2=', n2
write(*,'(1X,A,I10)') 'n3=', n3

o_MyClass = MyClass_constructor(n1, n2, n3)

call o_MyClass%destructor()
write(*,*) '***************************'
write(*,*) ' Normal End :) '
write(*,*) '***************************'

END PROGRAM dbg
strange.f90.. 段错误发生在 forall在这个文件中构建。
!*******************************************************************
MODULE mymodule
!*******************************************************************
USE tktype
IMPLICIT NONE
PRIVATE

PUBLIC MyClass
PUBLIC MyClass_constructor

TYPE :: MyClass
PRIVATE
REAL(DP), DIMENSION(:), ALLOCATABLE :: arrA
COMPLEX(DPC), DIMENSION(:,:,:), ALLOCATABLE :: arrB
CONTAINS
PROCEDURE :: destructor
END TYPE MyClass

! ================================================================
CONTAINS
! ================================================================

! ****************************************************************
FUNCTION MyClass_constructor(n1, n2, n3) RESULT(this)
! ****************************************************************
TYPE(MyClass) :: this
INTEGER(I4B), INTENT(IN) :: n1, n2, n3
! local variables
INTEGER(I4B) :: j1, j2, j3

write(*,'(1X,A)') 'entered constructor..'

allocate(this%arrA(n2))
allocate(this%arrB(n1, n2, n3))

this%arrA = 1.0_dp

write(*,*) 'size(this%arrB,1) =', size(this%arrB,1)
write(*,*) 'n1 = ', n1
write(*,*) 'size(this%arrB,2) =', size(this%arrB,2)
write(*,*) 'n2 = ', n2
write(*,*) 'size(this%arrB,3) =', size(this%arrB,3)
write(*,*) 'n3 = ', n3

forall(j1=1:n1, j2=1:n2, j3=1:n3)
this%arrB(j1,j2,j3) = this%arrA(j2)
end forall

write(*,'(1X,A)') '..leaving constructor'

END FUNCTION MyClass_constructor


! ****************************************************************
SUBROUTINE destructor(this)
! ****************************************************************
CLASS(MyClass), INTENT(INOUT) :: this

deallocate(this%arrA)
deallocate(this%arrB)

END SUBROUTINE destructor

END MODULE mymodule
tktype.f90
! ********************************************************************
MODULE tktype
! ********************************************************************
! module tktype is an extraction of module nrtype in Numerical Recipes in
! Fortran 90.
! ********************************************************************
! Symbolic names for kind types of 4-, 2-, and 1-byte integers:
INTEGER, PARAMETER :: I4B = SELECTED_INT_KIND(9)
INTEGER, PARAMETER :: I2B = SELECTED_INT_KIND(4)
INTEGER, PARAMETER :: I1B = SELECTED_INT_KIND(2)
! Symbolic names for kind types of single- and double-precision reals:
INTEGER, PARAMETER :: SP = KIND(1.0)
INTEGER, PARAMETER :: DP = KIND(1.0D0)
! Symbolic names for kind types of single- and double-precision complex:
INTEGER, PARAMETER :: SPC = KIND((1.0,1.0))
INTEGER, PARAMETER :: DPC = KIND((1.0D0,1.0D0))
! Symbolic name for kind type of default logical:
INTEGER, PARAMETER :: LGT = KIND(.true.)
END MODULE tktype

下面是一个 shell 脚本,用于编译上面的源代码并运行生成的可执行文件。
compile_run.sh
#!/bin/bash

ifort -v
echo "compiling.."
ifort -o tktype.o -c -check -g -stand f03 tktype.f90
ifort -o strange.o -c -check -g -stand f03 strange.f90
ifort -o main_dbg.o -c -check -g -stand f03 main_dbg.f90
ifort -o baabaa strange.o tktype.o main_dbg.o
echo "..done"
echo "running.."
./baabaa
echo "..done"

标准输出如下所示。
ifort version 14.0.3
compiling..
..done
running..
n1= 23
n2= 32
n3= 736
entered constructor..
size(this%arrB,1) = 23
n1 = 23
size(this%arrB,2) = 32
n2 = 32
size(this%arrB,3) = 736
n3 = 736
./compile_run.sh: line 11: 17096 Segmentation fault ./baabaa
..done

编辑 2016-01-30

我发现添加 ulimit -s unlimited#/bin/bash 的开头(在 compile_run.sh 之后)防止段错误。 fortran 中的可分配数组是否存储在堆栈中,而不是堆中?

最佳答案

这可能是类似问题 (Segmentation fault on 2D array) 的可能重复,这里有些多维forall循环导致问题。链接问题的 OP 在 Intel 论坛 ( ifort v 14.0 / 15.0 "-g" option causes segFault ) 中提出了这个问题,最新回复如下:

Workaround #1 is to increase stack size limit. I was successful with your test case using: ulimit -s unlimited

Workaround #2 is to use DO loops instead of FORALL, as follows:


此外,根据凯西在链接问题中的评论,ifort16 不会出现此问题,因此我想这可能是特定于 ifort14/15 的编译器问题。

更多信息(只是一些实验):
通过将堆栈大小限制为 ulimit -s 4000 在我的计算机上重现了同样的问题并使用ifort14.0.1,它随着 -heap-arrays消失了选项。所以我最初认为可能存在一些大小为 n1 * n2 * n3的自动数组或数组临时文件。 ,但是原代码中好像没有这样的东西...附上 -assume realloc_lhs-check -warn也没有帮助。
所以我做了一个测试程序,使用 do 执行相同的计算。或 forall :
program main
implicit none
integer, parameter :: dp = KIND(1.0D0)
integer, parameter :: dpc = KIND((1.0D0,1.0D0))
type Mytype
real(dp), allocatable :: A(:)
complex(dpc), allocatable :: B(:,:,:)
endtype
type(Mytype) :: t
integer :: n1, n2, n3, j1, j2, j3

n1 = 23
n2 = 32
n3 = n1 * n2 !! = 736

allocate( t% A( n2 ), t% B( n1, n2, n3 ) )

t% A(:) = 1.0_dp

print *, "[1] do (3-dim)"
do j3 = 1, n3
do j2 = 1, n2
do j1 = 1, n1
t% B( j1, j2, j3 ) = t% A( j2 )
enddo
enddo
enddo

print *, "[2] do (1-dim)"
do j2 = 1, n2
t% B( :, j2, : ) = t% A( j2 )
enddo

print *, "[3] forall (1-dim)"
forall( j2 = 1:n2 )
t% B( :, j2, : ) = t% A( j2 )
end forall

print *, "[4] forall (3-dim)" ! <-- taken from the original code
forall( j1 = 1:n1, j2 = 1:n2, j3 = 1:n3 )
t% B( j1, j2, j3 ) = t% A( j2 )
end forall

print *, "all passed."
end program
其中模式 [4] 对应于 OP 使用的模式。限制堆栈大小并在没有选项的情况下编译( ulimit -s 4000 ; ifort test.f90 )给出输出
 [1] do (3-dim)
[2] do (1-dim)
[3] forall (1-dim)
[4] forall (3-dim)
Segmentation fault
这意味着只有模式 [4] 在 -heap-arrays 时失败不附加。奇怪的是,当数组 A 时问题就消失了和 B在派生类型之外声明,即以下程序不带任何选项。
program main
implicit none
integer, parameter :: dp = KIND(1.0D0)
integer, parameter :: dpc = KIND((1.0D0,1.0D0))
real(dp), allocatable :: A(:)
complex(dpc), allocatable :: B(:,:,:)
integer :: n1, n2, n3, j1, j2, j3

n1 = 23
n2 = 32
n3 = n1 * n2 !! = 736

allocate( A( n2 ), B( n1, n2, n3 ) )

A(:) = 1.0_dp

print *, "[1] do (3-dim)"
do j3 = 1, n3
do j2 = 1, n2
do j1 = 1, n1
B( j1, j2, j3 ) = A( j2 )
enddo
enddo
enddo

print *, "[2] do (1-dim)"
do j2 = 1, n2
B( :, j2, : ) = A( j2 )
enddo

print *, "[3] forall (1-dim)"
forall( j2 = 1:n2 )
B( :, j2, : ) = A( j2 )
end forall

print *, "[4] forall (3-dim)"
forall( j1 = 1:n1, j2 = 1:n2, j3 = 1:n3 )
B( j1, j2, j3 ) = A( j2 )
end forall

print *, "all passed."
end program
所以看来问题只出现在多维 forall的一些特殊情况下循环(即使没有 -g 选项),它可能正在使用堆栈上的内部临时数组(尽管 -check -warn 选项没有给出任何消息)。仅供引用,上述所有模式都适用于 gfortran 4.8/5.2 和 Oracle fortran 12.4。

关于memory-management - 用户定义类型的 Fortran 可分配数组成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35104627/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com