调试gfortran:4.8.4确定性/预期性能,5.3.0非确定性/ NaN

时间:2016-09-01 04:33:33

标签: debugging fortran runtime-error gfortran

我一直无法在gfortran下构建一个明显的编译器错误的MWE,因为我编写了一个涉及的代码。 (该代码是ODE的通用集成器,它依赖于通过显式接口传递多个函数的虚拟过程名称。)我正在寻找调试方面的帮助 - 您可以将其视为尝试调试代码或编译器,I我不知道原因。在生成“工作”可执行文件的编译器(4.8.4,见下文)中,我会称之为“预期行为”并且可以检查这一点,因为它成功地解决了几个可以通过其他方法独立检查的ODE (代码或分析结果)。

我在两台机器上编译了相同的源代码。以下是在linux框(4.8.4)和Mac(5.3.0)上使用的gfortran版本:

$ gfortran -v 
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.8/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04.3' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)

Mac: ~ $ gfortran -v
Using built-in specs.
COLLECT_GCC=gfortran
COLLECT_LTO_WRAPPER=/opt/local/libexec/gcc/x86_64-apple-darwin15/5.3.0/lto-wrapper
Target: x86_64-apple-darwin15
Configured with: /opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_tarballs_ports_lang_gcc5/gcc5/work/gcc-5.3.0/configure --prefix=/opt/local --build=x86_64-apple-darwin15 --enable-languages=c,c++,objc,obj-c++,lto,fortran,java --libdir=/opt/local/lib/gcc5 --includedir=/opt/local/include/gcc5 --infodir=/opt/local/share/info --mandir=/opt/local/share/man --datarootdir=/opt/local/share/gcc-5 --with-local-prefix=/opt/local --with-system-zlib --disable-nls --program-suffix=-mp-5 --with-gxx-include-dir=/opt/local/include/gcc5/c++/ --with-gmp=/opt/local --with-mpfr=/opt/local --with-mpc=/opt/local --with-isl=/opt/local --enable-stage1-checking --disable-multilib --enable-lto --enable-libstdcxx-time --with-as=/opt/local/bin/as --with-ld=/opt/local/bin/ld --with-ar=/opt/local/bin/ar --with-bugurl=https://trac.macports.org/newticket --with-pkgversion='MacPorts gcc5 5.3.0_0'
Thread model: posix
gcc version 5.3.0 (MacPorts gcc5 5.3.0_0)

版本4.8.4(linux)完全按预期运行。版本5.3.0(mac)给出NaN结果并且行为不确定。 (NaN发生在运行中的不同点。)

我使用以下选项(而没有其他选项)编译了相同的源:

-fdump-fortran-original

来自4.8.4和5.3.0编译的编译器stdout的sdiff时,唯一的差异,其中有20次出现,都是类型:

Array spec:(1 [0] AS_EXPLICIT 1 size[((drvdha:y(FULL)) ((arg not-present)) ((arg not-present)))] )                      |       Array spec:(1 [0] AS_EXPLICIT 1 [[((drvdha:y(FULL)) ((arg not-present)) ((arg not-present)))]] )

请注意,关键字size出现在工作4.8.4(最左侧)-fdump-fortran-original上,但不出现在5.3.0(最右侧)上。除了这种确切的差异sdiff是沉默的。

顺便说一下,英特尔Fortran编译器ifort也失败了:

$ ifort --version
ifort (IFORT) 16.0.3 20160415

第一个问题:这可能是两个系统上不同代码行为的原因吗?

第二个问题:如果没有,关于如何调试这些代码/编译器组合的建议?

1 个答案:

答案 0 :(得分:3)

-fdump-...的输出似乎来自像

这样的代码
module mymod
contains
    function myfunc( a )
        integer :: a(:)
        integer :: myfunc( size(a) )
        myfunc = a * 2
    endfunction
end module

program main
    use mymod
    implicit none
    integer a(5)
    a = 100
    print *, myfunc( a )
end program

对于此代码,OSX10.9上的gfortran-6.1.0给出了

procedure name = mymod
  symtree: 'myfunc'      || symbol: 'myfunc'       
    type spec : (INTEGER 4)
    attributes: (PROCEDURE MODULE-PROC  DIMENSION FUNCTION)
    Array spec:(1 [0] AS_EXPLICIT 1 size[((myfunc:a(FULL)) ((arg not-present)) ((arg not-present)))] )
...
procedure name = main
    ...
  symtree: 'myfunc'      || symbol: 'myfunc'       
    type spec : (INTEGER 4)
    attributes: (PROCEDURE MODULE-PROC  DIMENSION USE-ASSOC(mymod) FUNCTION)
    Array spec:(1 [0] AS_EXPLICIT 1 size[((myfunc:a(FULL)) ((arg not-present)) ((arg not-present)))] )

而Linux机器上的gfortran-4.8.2(使用ScientificLinux-6,x86_64)给出了

procedure name = mymod
  symtree: 'myfunc'      || symbol: 'myfunc'       
    type spec : (INTEGER 4)
    attributes: (PROCEDURE MODULE-PROC  DIMENSION FUNCTION)
    Array spec:(1 [0] AS_EXPLICIT 1 size[((myfunc:a(FULL)) ((arg not-present)) ((arg not-present)))] )
    ...
procedure name = main
   symtree: 'myfunc'      || symbol: 'myfunc'       
    type spec : (INTEGER 4)
    attributes: (PROCEDURE MODULE-PROC  DIMENSION USE-ASSOC(mymod) FUNCTION)
    Array spec:(1 [0] AS_EXPLICIT 1 [[((myfunc:a(FULL)) ((arg not-present)) ((arg not-present)))]] )

也就是说,使用gfortran-4.8编译时,最后一行中的size丢失了。但是因为两个编译器都给出了相同的结果

   200         200         200         200         200

这可能不是很重要(只是中间代码格式略有不同?)

相反,似乎更重要的是

gfortran -g -ffpe-trap=invalid,zero,overflow,underflow -fbacktrace ...

给出运行时错误消息(根据上面的评论)

Program received signal SIGFPE: Floating-point exception 
- erroneous arithmetic operation.

Backtrace for this error:
#0 0x10684f692
#1 0x10684fe5e
#2 0x7fff98b3e529
#3 0x10683c2ec
#4 0x106841811
#5 0x106841e1b
#6 0x10682c6d4
#7 0x10682cb73
Floating point exception: 8

似乎有各种页面讨论此错误(例如,Getting the error floating point exception: 8)。例如,此代码

program main
    implicit none
    integer m, n
    print *, "Please input m and n:"
    read(*,*) m, n
    print *, mod( m, n )
end 

也给出相同的消息(当涉及整数除以零时)

 Please input m and n:
5 0

Program received signal SIGFPE: Floating-point exception - erroneous arithmetic operation.

Backtrace for this error:
#0  0x10d9d6879
#1  0x10d9d5c45
#2  0x7fff880bf5a9
#3  0x10d9cae01
#4  0x10d9cae6a
Floating point exception: 8

但即使没有-ffpe-trap=...,也会打印此错误消息,因此代码中的实际问题可能会有所不同。无论如何,重要的是以某种方式找到此错误的原因,并确保程序运行时没有这样的错误(如果有的话)。