每次编译具有不同参数的fortran90文件

时间:2018-10-18 03:39:54

标签: shell fortran sh fortran90 intel-fortran

我最近正在研究一个fortran90程序,该程序可以计算所需的时间以及一些数学计算的结果。这是代码:

program loops 

  use omp_lib 

  implicit none 
  integer, parameter :: N=729
  integer, parameter :: reps=1000


  real(kind=8), allocatable ::  a(:,:), b(:,:), c(:) 
  integer :: jmax(N)  


  real(kind=8) :: start1,start2,end1,end2
  integer :: r

  allocate(a(N,N), b(N,N), c(N))  

  call init1()  

  start1 = omp_get_wtime()

  do r = 1,reps
     call loop1() 
  end do

  end1  = omp_get_wtime()  

  call valid1(); 

  print *, "Total time for ",reps," reps of loop 1 = ", end1-start1 

  call init2()  

  start2 = omp_get_wtime()

  do r = 1,reps
     call loop2() 
  end do

  end2  = omp_get_wtime()  

  call valid2(); 

  print *, "Total time for ",reps," reps of loop 2 = ", end2-start2 


contains 

subroutine init1()

  implicit none 

  integer ::  i,j

  do i = 1,N 
     do j = 1,N 
        a(j,i) = 0.0 
        b(j,i) = 3.142*(i+j)
     end do
  end do

end subroutine init1 


subroutine init2()

  implicit none 

  integer ::  i,j,expr

  do i = 1,N 
     expr = mod(i,3*(i/30)+1)
     if (expr == 0) then
        jmax(i) = N 
     else
        jmax(i) = 1
     end if
     c(i) = 0.0 
  end do

  do i = 1,N 
     do j = 1,N 
        b(j,i) = dble(i*j+1)/dble(N*N)
     end do
  end do

end subroutine init2


subroutine loop1() 

  implicit none 

  integer ::  i,j
  !$OMP PARALLEL DO DEFAULT(NONE), PRIVATE(i,j), SHARED(a,b), SCHEDULE(type,chunksize) 
  do i = 1,N
     do j = N,i,-1
        a(j,i) = a(j,i) + cos(b(j,i))
     end do
  end do
  !$OMP END PARALLEL DO

end subroutine loop1 



subroutine loop2() 

  implicit none 

  integer :: i,j,k
  real (kind=8) :: rN2  

  rN2 = 1.0 / dble (N*N)  

  !$OMP PARALLEL DO DEFAULT(NONE), PRIVATE(i,j,k), SHARED(rN2,c,b,jmax), SCHEDULE(type,chunksize)
  do i = 1,N
     do j = 1, jmax(i) 
        do k = 1,j 
           c(i) = c(i) + k * log(b(j,i)) *rN2
        end do
     end do
  end do
  !$OMP END PARALLEL DO

end subroutine loop2



subroutine valid1()

  implicit none 

  integer :: i,j 
  real (kind=8) :: suma 

  suma= 0.0

  do i = 1,N 
     do j = 1,N 
        suma = suma + a(j,i) 
     end do
  end do

  print *, "Loop 1 check: Sum of a is ", suma

end subroutine valid1



subroutine valid2()

  implicit none 

  integer i 
  real (kind=8) sumc 

  sumc= 0.0
  do i = 1,N 
     sumc = sumc + c(i) 
  end do

  print *, "Loop 2 check: Sum of c is ", sumc

end subroutine valid2  


end program loops

!$OMP PARALLEL DO DEFAULT(NONE), PRIVATE(i,j), SHARED(a,b), SCHEDULE(type,chunksize)!$OMP PARALLEL DO DEFAULT(NONE), PRIVATE(i,j,k), SHARED(rN2,c,b,jmax), SCHEDULE(type,chunksize)行中。

由于我想执行不同时间表情况的任务以查看不同结果,因此我需要使用不同的时间表类型和不同的块大小来更改此部分SCHEDULE(type,chunksize)。例如,在这种情况下,调度类型为静态,块大小为1。

如果我具有(静态,a,b,c)类型和块大小(1、2、3、4、5、6、7),请说。由于我是fortran的新手,所以我想知道是否可以针对所有情况一次编译并运行代码,而不必每次都必须手动更改参数,即它可以编译并运行以给出第一种情况的结果,例如( static,1),然后再次编译并运行文件,但参数会自动更改,从而产生另一个结果。例如(static,2)...(b,4)等

我听说我们可以创建一个脚本文件来执行这样的任务,但是我不确定我到底需要做什么。

非常感谢您。

1 个答案:

答案 0 :(得分:2)

您可能要研究预处理器的使用。我从gfortran的经验谈起,但是我相信这也适用于(几乎)所有其他编译器,即使它不在Fortran标准的范围之内。

如果使用后缀大写F命名源文件,即file.F,file.F90,file.F95等,则文件将在编译之前用C预处理程序进行预处理。这听起来可能很复杂,但是将其缩减为您所需的内容,这意味着如果您使用类似

的命令来编译代码
$ gfortran -DCHUNK_SIZE=1 mySource.F90

然后所有出现的CHUNK_SIZE(带有对您的问题不是必不可少的限定词)将被1代替。从技术上讲,CHUNK_SIZE成为定义为扩展为1的宏。因此,如果您在源文件中将SCHEDULE(type,chunksize)替换为SCHEDULE(type,CHUNK_SIZE),则可以用不同的值-DCHUNK_SIZE=1-DCHUNK_SIZE=2等反复调用编译器,并获得您描述的结果。对type可以这样做。

现在,您可能还希望相应地更改函数名称。一种方法是在文件顶部附近添加一些预处理器语句,以声明一些宏,即

#ifdef __GFORTRAN__
#define PASTE2(a,b) a/**/b
#define FUNC_NAME_WITH_CHUNK_SIZE(fn) PASTE2(PASTE2(fn,_),CHUNK_SIZE)
#else
#define FUNC_NAME_WITH_CHUNK_SIZE(fn) fn ## _ ## CHUNK_SIZE
#endif
#define LOOP1 FUNC_NAME_WITH_CHUNK_SIZE(loop1)
#define LOOP2 FUNC_NAME_WITH_CHUNK_SIZE(loop2)

并将loop1替换为LOOP1等。您可以像以前一样从命令行执行此操作,但是由于这些规则在编译之间不应该更改,因此将它们保留在源代码中是有意义的文件。我认为,唯一不能解释的部分是在##/**/之间使用#ifdef#endif。这就是用预处理器进行字符串连接的方式,并且由于gfortran使用C预处理器在语言标准化之前进行的方式,因此得到了特殊的待遇,请参见例如。 this answer,以获取有关这些运算符的一些信息。此操作的目的是将LOOP1替换为loop1_<CHUNK_SIZE>,其中<CHUNK_SIZE>是从命令行填写的。随意遵循其他约定命名这些功能。

如果要从另一个翻译单元调用这些函数,则当然必须以相同的方式处理这些函数名。为了使您的生活更轻松,您可能需要研究#include语句。详细说明这一点会使我们走得太远了,但是我们的想法是将所有包含内容放入一个文件(在Fortran世界中通常命名为<something>.inc,替换为<something>对您来说很有意义)并使用在所有源文件中#include "<something>.inc以获得相同的宏定义。