Компиляция файлов fortran90 с разными параметрами каждый раз - PullRequest
0 голосов
/ 18 октября 2018

Я недавно работаю над программой 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).Поскольку я новичок в Фортране, поэтому мне интересно, можно ли скомпилировать и запустить код для всех случаев за один раз, не требуя того, чтобы мне приходилось каждый раз менять параметры вручную, то есть он компилируется и запускается, чтобы получить результат первого случая, например (static, 1), затем он снова компилирует и запускает файл, но параметры автоматически изменяются, что дает другой результат.Например, (static, 2) ... (b, 4) и т. Д.

Я слышал, что мы можем создать файл сценария для выполнения такой задачи, но я не уверен, что именно мне нужно сделать дляэто.

Большое спасибо.

1 Ответ

0 голосов
/ 18 октября 2018

Вы можете захотеть исследовать использование препроцессора.Я говорю из опыта работы с 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 делали это до стандартизации языка, он получает исключительную обработку, например, этот ответ для некоторой информации об этих операторах.Цель этой операции - заменить LOOP1 на loop1_<CHUNK_SIZE>, где <CHUNK_SIZE> заполняется из командной строки.Не стесняйтесь следовать любым другим соглашениям для именования этих функций.

Если вы хотите вызывать эти функции из другого модуля перевода, вам, конечно, придется обрабатывать имена функций таким же образом.Чтобы облегчить себе жизнь, вы можете изучить заявление #include.Детализация этого приведет нас слишком далеко, но идея состоит в том, что вы помещаете все свои включения в файл (условно названный <something>.inc в мире Фортран с заменой <something>, который имеет смысл для вас) и используете #include "<something>.inc ввсе исходные файлы для получения одинаковых определений макросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...