Это не ответ на вопрос, почему вы получаете то, что вы наблюдаете, а скорее отчет о несогласии с вашими наблюдениями.Ваш код,
program matrix_multiply
implicit none
integer, parameter :: n = 1500
!real(8) :: a(n,n), b(n,n), c(n,n), aT(n,n) ! plain arrays
integer :: i, j, k, ts, te, count_rate, count_max
real(8) :: tmp
real(8), allocatable :: A(:,:), B(:,:), C(:,:), aT(:,:) ! allocatable arrays
allocate ( a(n,n), b(n,n), c(n,n), aT(n,n) )
do i = 1,n
do j = 1,n
a(i,j) = 1.d0/n/n * (i-j) * (i+j)
b(i,j) = 1.d0/n/n * (i-j) * (i+j)
end do
end do
! transpose for cache-friendliness
do i = 1,n
do j = 1,n
aT(j,i) = a(i,j)
end do
end do
call system_clock(ts, count_rate, count_max)
do i = 1,n
do j = 1,n
tmp = 0
do k = 1,n
tmp = tmp + aT(k,i) * b(k,j)
end do
c(i,j) = tmp
end do
end do
call system_clock(te)
print '(4G0)', "Elapsed time: ", real(te-ts)/count_rate,', c_(n/2+1) = ', c(n/2+1,n/2+1)
end program matrix_multiply
, скомпилированный с помощью компилятора Intel Fortran 18.0.2 для Windows и включенные флаги оптимизации,
ifort /standard-semantics /F0x1000000000 /O3 /Qip /Qipo /Qunroll /Qunroll-aggressive /inline:all /Ob2 main.f90 -o run.exe
, фактически, противоположен тому, что вы наблюдаете:
Elapsed time: 1.580000, c_(n/2+1) = -143.8334 ! plain arrays
Elapsed time: 1.560000, c_(n/2+1) = -143.8334 ! plain arrays
Elapsed time: 1.555000, c_(n/2+1) = -143.8334 ! plain arrays
Elapsed time: 1.588000, c_(n/2+1) = -143.8334 ! plain arrays
Elapsed time: 1.551000, c_(n/2+1) = -143.8334 ! plain arrays
Elapsed time: 1.566000, c_(n/2+1) = -143.8334 ! plain arrays
Elapsed time: 1.555000, c_(n/2+1) = -143.8334 ! plain arrays
Elapsed time: 1.634000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.634000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.602000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.623000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.597000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.607000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.617000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.606000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.626000, c_(n/2+1) = -143.8334 ! allocatable arrays
Elapsed time: 1.614000, c_(n/2+1) = -143.8334 ! allocatable arrays
Как видите, выделяемые массивы на самом деле немного медленнее, в среднем, что я и ожидал увидеть, что также противоречит вашим наблюдениям.Единственный источник различий, который я вижу, - это используемые флаги оптимизации, хотя я не уверен, как это может изменить ситуацию.Возможно, вы захотите запустить свои тесты в нескольких разных режимах без оптимизации и с разными уровнями оптимизации и посмотреть, получаете ли вы постоянные различия в производительности во всех режимах или нет.Чтобы получить больше информации о значении используемых флагов оптимизации, см. Справочная страница Intel .
Кроме того, не используйте real(8)
для объявлений переменных.Это нестандартный синтаксис, непереносимый и, следовательно, потенциально проблематичный.Более последовательный способ, в соответствии со стандартом Фортрана, заключается в использовании встроенного модуля iso_fortran_env
, например:
!...
use, intrinsic :: iso_fortran_env, only: real64, int32
integer(int32), parameter :: n=100
real(real64) :: a(n)
!...
Этот встроенный модуль имеет следующие виды:
int8 ! 8-bit integer
int16 ! 16-bit integer
int32 ! 32-bit integer
int64 ! 64-bit integer
real32 ! 32-bit real
real64 ! 64-bit real
real128 ! 128-bit real
Итак, дляНапример, если вы хотите объявить сложную переменную с компонентами 64-битного типа, вы можете написать:
program complex
use, intrinsic :: iso_fortran_env, only: RK => real64, output_unit
! the intrinsic attribute above is not essential, but recommended, so this would be also valid:
! use iso_fortran_env, only: RK => real64, output_unit
complex(RK) :: z = (1._RK, 2._RK)
write(output_unit,"(*(g0,:,' '))") "Hello World! This is a complex variable:", z
end program complex
, что дает:
$gfortran -std=f2008 *.f95 -o main
$main
Hello World! This is a complex variable: 1.0000000000000000 2.0000000000000000
Обратите внимание, что для этого требуется совместимость с Fortran 2008компилятор.В iso_fortran_env
также есть другие функции и объекты, например output_unit
, который является номером устройства для предварительно подключенного стандартного устройства вывода (то же самое, что используется print
или write
с спецификатором устройства *
), а также некоторые другие, такие как compiler_version()
, compiler_options()
и другие.