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
Fortran 为什么具有数组作为输入的子例程比具有自动本地数组的相同子例程提供更快的性能?_Fortran_Gfortran - Fatal编程技术网

Fortran 为什么具有数组作为输入的子例程比具有自动本地数组的相同子例程提供更快的性能?

Fortran 为什么具有数组作为输入的子例程比具有自动本地数组的相同子例程提供更快的性能?,fortran,gfortran,Fortran,Gfortran,我正在重新编写一些遗留代码,以提高可读性,并希望使其更易于维护 我试图减少子例程的输入参数数量,但我发现它正在改变 子程序子网,ID->子程序子网 明显降低了性能 ID只在sub中使用,所以我认为将其作为输入是没有意义的。 是否可以在不影响性能的情况下使用subN? 对于我的使用,N

我正在重新编写一些遗留代码,以提高可读性,并希望使其更易于维护

我试图减少子例程的输入参数数量,但我发现它正在改变 子程序子网,ID->子程序子网 明显降低了性能

ID只在sub中使用,所以我认为将其作为输入是没有意义的。 是否可以在不影响性能的情况下使用subN? 对于我的使用,N<10,其中性能差5-10倍

性能比较:

附属法例1

N=4,0.9秒 N=20,1.0秒 N=200,2.1秒 次级方案2

N=4,0.07秒 N=20,0.18秒 N=200,1.3秒 我正在使用Mac OS 10.14.6和gfortran 5.2.0

program test
  integer, parameter  :: N = 1
  real, dimension(N)  :: ID


  call CPU_time(t1)

  do i = 1, 10000000
    CALL sub_1(N)
  end do

  call CPU_time(t2)
  write ( *, * ) 'Elapsed real time =', t2 - t1



  call CPU_time(t1)

  do i = 1, 10000000
    CALL sub_2(N, ID)
  end do

  call CPU_time(t2)
  write ( *, * ) 'Elapsed real time =', t2 - t1

end program test



SUBROUTINE sub_1(N)
  integer,            intent(in)      :: N
  real, dimension(N)                  :: ID

  ID = 0.0

END SUBROUTINE sub_1



SUBROUTINE sub_2(N, ID)
  integer,            intent(in)      :: N
  real, dimension(N), intent(in out)  :: ID

  ID = 0.0

END SUBROUTINE sub_2

我假设这与数组分配有关

分配内存的过程本身需要时间。当您将数组原封不动地传递到子程序sub_2中时,我认为子程序很可能不需要为数组分配内存。这可能假设数组是在堆上创建的,而不是在堆栈上创建的,但我不是100%确定

另一方面,对于子程序sub_1,它需要每次重新为数组分配空间


不幸的是,我不太擅长优化,所以我希望其他人会同意我的观点,或者告诉我我错了

我假设这与数组分配有关

分配内存的过程本身需要时间。当您将数组原封不动地传递到子程序sub_2中时,我认为子程序很可能不需要为数组分配内存。这可能假设数组是在堆上创建的,而不是在堆栈上创建的,但我不是100%确定

另一方面,对于子程序sub_1,它需要每次重新为数组分配空间


不幸的是,我不太擅长优化,所以我希望其他人会同意我的观点,或者告诉我我错了

这似乎是您正在使用的gfortran旧版本的一个功能。如果我至少在N=10的情况下使用更高版本,则时间更具可比性:

ian@eris:~/work/stack$ head s.f90
program test
  integer, parameter  :: N = 10
  real, dimension(N)  :: ID


  call CPU_time(t1)

  do i = 1, 10000000
    CALL sub_1(N)
  end do
ian@eris:~/work/stack$ gfortran-5 --version
GNU Fortran (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.

GNU Fortran comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of GNU Fortran
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING

ian@eris:~/work/stack$ gfortran-5 -O3 s.f90
ian@eris:~/work/stack$ ./a.out
 Elapsed real time =  0.149489999    
 Elapsed real time =   1.99675560E-06
ian@eris:~/work/stack$ gfortran-6 --version
GNU Fortran (Ubuntu 6.5.0-2ubuntu1~18.04) 6.5.0 20181026
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran-6 -O3 s.f90
ian@eris:~/work/stack$ ./a.out
 Elapsed real time =   7.00005330E-06
 Elapsed real time =   5.00003807E-06
ian@eris:~/work/stack$ gfortran-7 --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran-7 -O3 s.f90
ian@eris:~/work/stack$ ./a.out
 Elapsed real time =   8.00006092E-06
 Elapsed real time =   6.00004569E-06
ian@eris:~/work/stack$ gfortran-8 --version
GNU Fortran (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran-8 -O3 s.f90
ian@eris:~/work/stack$ ./a.out
 Elapsed real time =   9.00030136E-06
 Elapsed real time =   6.00004569E-06

然而,我会带着满满一桶盐来接受以上的一切。乐观主义者很可能已经发现,在这种简单的情况下,它实际上不需要做任何事情,因此刚刚摆脱了所有需要计时的操作——唯一能真正告诉你这一点的基准是你想要运行的代码。

这似乎是你正在使用的gfortran旧版本的一个功能。如果我至少在N=10的情况下使用更高版本,则时间更具可比性:

ian@eris:~/work/stack$ head s.f90
program test
  integer, parameter  :: N = 10
  real, dimension(N)  :: ID


  call CPU_time(t1)

  do i = 1, 10000000
    CALL sub_1(N)
  end do
ian@eris:~/work/stack$ gfortran-5 --version
GNU Fortran (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010
Copyright (C) 2015 Free Software Foundation, Inc.

GNU Fortran comes with NO WARRANTY, to the extent permitted by law.
You may redistribute copies of GNU Fortran
under the terms of the GNU General Public License.
For more information about these matters, see the file named COPYING

ian@eris:~/work/stack$ gfortran-5 -O3 s.f90
ian@eris:~/work/stack$ ./a.out
 Elapsed real time =  0.149489999    
 Elapsed real time =   1.99675560E-06
ian@eris:~/work/stack$ gfortran-6 --version
GNU Fortran (Ubuntu 6.5.0-2ubuntu1~18.04) 6.5.0 20181026
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran-6 -O3 s.f90
ian@eris:~/work/stack$ ./a.out
 Elapsed real time =   7.00005330E-06
 Elapsed real time =   5.00003807E-06
ian@eris:~/work/stack$ gfortran-7 --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran-7 -O3 s.f90
ian@eris:~/work/stack$ ./a.out
 Elapsed real time =   8.00006092E-06
 Elapsed real time =   6.00004569E-06
ian@eris:~/work/stack$ gfortran-8 --version
GNU Fortran (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

ian@eris:~/work/stack$ gfortran-8 -O3 s.f90
ian@eris:~/work/stack$ ./a.out
 Elapsed real time =   9.00030136E-06
 Elapsed real time =   6.00004569E-06
然而,我会带着满满一桶盐来接受以上的一切。乐观主义者很可能已经发现,在这种简单的情况下,它实际上不需要做任何事情,因此刚刚摆脱了所有需要计时的操作——唯一能真正告诉您这一点的基准是您要运行的代码。

sub_1和sub_2实际上没有可比性。在sub_1中,您分配ID,初始化所有元素,然后在子例程返回时丢弃它,因为它是子例程的本地元素

由于从未使用该ID数组,编译器可以优化它的创建和初始化。如果使用-O3编译,gfortran就是这样做的。为sub_1生成的代码只返回值

在sub_2中,它仍然必须将ID的所有元素设置为0.0。

sub_1和sub_2实际上是不可比较的。在sub_1中,您分配ID,初始化所有元素,然后在子例程返回时丢弃它,因为它是子例程的本地元素

由于从未使用该ID数组,编译器可以优化它的创建和初始化。如果使用-O3编译,gfortran就是这样做的。为sub_1生成的代码只返回值


在sub_2中,它仍然必须将ID的所有元素都设置为0.0。

您能告诉我们您是如何编译它的吗?在quest8n而不是代码中输入时间也很有用,我差点错过了them@IanBush也许这很幼稚,但我只是使用了gfortran test.f95命令,然后在终端hanks中使用./a.out执行!请将-O3标志添加到编译行并重复。您也可以显式添加-fstack数组选项。您能告诉我们您是如何编译它的吗?在任务8n而不是代码中包含时间也会很有用,我差点错过了them@IanBush也许这是幼稚的,,但是我只是使用了gfortran test.f95命令,然后在终端执行了./a.out hanks!请将-O3标志添加到编译行并重复。您也可以显式添加-fstack数组选项。谢谢。我觉得这可能是版本问题。我会更新。非常感谢您的帮助。@NickBrady请查看有关编译器o的附加注释
我刚刚添加的优化…优化器的可能性是一个非常可能的问题。有些想法是不是最好将子例程放在一个单独的文件中,这样编译器就不会有太多机会内联并添加一个输出参数来获取循环中的值,例如添加到程序变量中,不要忘记编写它,否则编译器优化器可能会再次变得聪明。。。。不幸的是,我无法测试这些想法,因为我只有一个编译器版本。谢谢。我觉得这可能是版本问题。我会更新。非常感谢您的帮助。@NickBrady请查看我刚才添加的关于编译器优化的额外注释……优化器的可能性是一个非常可能的问题。有些想法是不是最好将子例程放在一个单独的文件中,这样编译器就不会有太多机会内联并添加一个输出参数来获取循环中的值,例如添加到程序变量中,不要忘记编写它,否则编译器优化器可能会再次变得聪明。。。。不幸的是,我无法测试这些想法,因为我只有一个编译器版本。根据这个理论,sub_2是更快的子例程有意义吗?如果没有优化,sub_2可能会更快,因为它不必分配数组。通过优化,我希望sub_1更快。但更重要的一点是,它们不具有可比性,因为它们不能完成相同的任务。编译器可以抛出任何一个结果,但它永远不会打印出来。根据这一理论,sub_2是更快的子例程有意义吗?如果不进行优化,sub_2可能会更快,因为它不必分配数组。通过优化,我希望sub_1更快。但更重要的一点是,它们是不可比较的,因为它们不能完成相同的事情。编译器可以抛出任何一个结果,但它永远不会被打印出来。