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