I have a memory leak when using a "constructor"(which is just a static function) to create an initialize a derived type object.
I have two subroutines that seem to be equivalent, but one of them has a memory leak (mult_leak), while the other hasn't (mult_noleak).
I don't understand which is the difference.
program main
use lala
type(mytype) :: mt1, mt2, mt3
integer :: i
real, allocatable, dimension(:,:) :: dat
allocate(dat(1000, 1000))
dat = 1.5
do i=1,10000000
mt1 = creador(dat)
mt2 = creador(dat)
mt3 = mult_leak(mt1, mt2)
if(modulo(i,1000)==0) then
print*, i, mt3%dat(1,1)
endif
end do
end program
module lala
type mytype
integer :: nx, ny
real, allocatable, dimension(:,:) :: dat
contains
private
procedure :: init
end type
interface creador
procedure p_creador
end interface
contains
subroutine init(this, dat)
class(mytype) :: this
real, allocatable, dimension(:,:) :: dat
integer, dimension(2) :: s
s = shape(dat)
this%nx = s(1)
this%ny = s(2)
allocate(this%dat, source=dat)
end subroutine
function p_creador(dat) result(res)
type(mytype), allocatable :: res
real, allocatable, dimension(:,:) :: dat
allocate(res)
call res%init(dat)
end function
function mult_noleak(cf1, cf2) result(cfres)
class(mytype), intent(in) :: cf1, cf2
class(mytype), allocatable :: cfres
real, dimension(:,:), allocatable :: aux
allocate(cfres)
aux=cf1%dat * cf2%dat
call cfres%init(aux)
end function
function mult_leak(cf1, cf2) result(cfres)
class(mytype), intent(in) :: cf1, cf2
class(mytype), allocatable :: cfres
real, dimension(:,:), allocatable :: aux
aux=cf1%dat * cf2%dat
cfres = creador(aux)
end function
end module
I have found that the leak disappears when I change the "cfres" definition in "mult_leak" subroutine.
function mult_leak(cf1, cf2) result(cfres)
class(mytype), intent(in) :: cf1, cf2
!class(mytype), allocatable :: cfres
type(mytype), allocatable :: cfres
real, dimension(:,:), allocatable :: aux
aux=cf1%dat * cf2%dat
cfres = creador(aux)
end function
It seems that the problem is the assignment of the constructor to a polymorphic entity.
Related
I have a rather large code (>6000 lines)that with a problem that I try to illustrate with the following very simplified extract:
program TestFortran
implicit none
real, parameter :: eps = 1d-30
real :: res
real :: tmp
call TestInitialisation(res,tmp)
if (res>0 .and. res <eps) then
write(*,*) "res is small but not zero and tmp = ", tmp
res = 0d0
else
write(*,*) "res is zero and tmp = ", tmp
end if
contains
subroutine TestInitialization(output,out2)
real,intent(out) :: output
real,intent(out) :: out2
real :: origa(10,10)
real :: copya(10,10)
origa = 0d0
copya = origa
call TIS1(copya,output,out2)
end subroutine TestInitialization
subroutine TIS1(arr2d,ret,out2)
real,intent(in) :: arr2d(:,:)
real,intent(out) :: ret
real,intent(out) :: out2
integer :: ii
do ii = 1,size(arr2d,2)
call TIS2(arr2d(:,ii),ii,ret,out2)
if (ret > 0) then
exit
end if
end do
end subroutine TIS1
subroutine TIS2(arr1d,jj,ret,out2)
real,intent(in) :: arr1d(:)
real,intent(out) :: ret
real,intent(out) :: out2
integer :: ii
integer,intent(in):: jj
do ii = 1,size(arr1d)
ret = arr1d(ii)
out2 = real(jj)
if (ret > 0) then
out2 = -1d0
exit
end if
end do
end subroutine TIS2
end program TestFortran
The real program does work as expected in debug mode. However, when in release mode (visual studio 2017 with intel compiler 2017), switch /O3, the res value is just garbage (like 1.0831d-273, however I am unsure weather to trust the variable explorer when debugging optimized code). I could not recreate the situation with the example above, it just serves as illustration (thetmp variable is there for it not to just optimize the whole thing away). If I add a write(*,*) "res in TIS2 =",resin subroutine TIS2 in the real program code, the result is correct, but this it not wanted (especially because of speed degradation).
I have tested various compiler flags compbinations; i.e. the following:
/debug:full /O2 /Qinit:snan /Qinit:arrays /fpe:0 /Qipo /traceback
/check:uninit /arch:SSE3 /real_size:64 /fp:fast=2 /Qvec-threshold:60 /recursive
Does anyone have any hint's or comments on this?
I had made a mistake (bug) where an array wasn't fully populated correctly. I found this using the compiler flags: /Qinit:snan together with /Qinit:arrays in debug mode. It did not show up in release mode.
So all in all it was just a fairly simple bug in my code that went unnoticed, mostly (in 99 % of the cases) everything went well, but not always. The strange thing was that it wasn't caught in release mode.
I have written the following program in fortran90:
module constants
real*8, parameter :: zero = 0.0d0
real*8, parameter :: one = 1.0d0
real*8, parameter :: two = 2.0d0
end module constants
module common
use constants
real*8 :: a_A, a_B, e_A, e_B, b_A, b_B
end module common
module procedures
use constants
contains
function f(p)
use common
real*8, dimension(2), intent(in) :: p
real*8, dimension(2) :: f
f(1) = a_A*((two*p(1)/p(1) + p(2))**(-e_A)) - (exp(b_A*p(1)) - one)
f(2) = a_B*((two*p(2)/p(1) + p(2))**(-e_B)) - (exp(b_B*p(2)) - one)
f = f
return
end function f
subroutine wait
write(6,"('Waiting...')")
read *
return
end subroutine wait
end module procedures
program main
use constants
use common
use procedures
use toolbox
real*8, dimension(2) :: plow,phigh,pmin
a_A = one
a_B = one
e_A = one
e_B = one
b_A = 0.1d0
b_b = 0.1d0
plow(1) = 6.0d0
plow(2) = 6.0d0
phigh(1) = 8.0d0
phigh(2) = 8.0d0
pmin = one
call fminsearch(pmin,fret,plow,phigh,f)
write(6,"(3f15.8)") pmin(1),pmin(2), fret
end program main
When I run it I get the following error
call fminsearch(pmin, fret, plow, phigh, f)
1
Error: There is no specific subroutine for the generic ‘fminsearch’ at (1)
I think it is a problem with my function arguments, but could anybody give me some clarity as to what is going wrong? I am new to fortran and do not quite understand. As far as I can tell, I have declared the x with intent(in) and have declared the vector output of the function.
Thank you
I am learning correct use of subroutine, function and module, below is an simple example, no error occurs while compiling, after executing, the outcome is 4.57187637E-41 rather than pi, I have looked up several references, haven't found out the mistake yet.
module wz
implicit none
private
public :: print_out
real,parameter :: pi = 3.14159
contains
subroutine print_out
implicit none
real :: area
print *, area
end subroutine print_out
function f(x) result(area)
implicit none
real, intent(in):: x
real :: area
area = pi * x ** 2
end function f
end module wz
program test_module
use wz
implicit none
real :: x
x = 1.
call print_out
end program test_module
The value you are printing is area just after declaration and before doing anything with it. You need to pass x to f function, and you can do that via the print_out subroutine:
module wz
implicit none
private
public :: print_out
real,parameter :: pi = 3.14159
contains
subroutine print_out(x)
implicit none
real, intent(in) :: x
real :: area
area = f(x)
print *, area
end subroutine print_out
function f(x) result(area)
implicit none
real, intent(in):: x
real :: area
area = pi * x ** 2
end function f
end module wz
program test_module
use wz
implicit none
real :: x
x = 1.
call print_out(x)
end program test_module
I am often confronted with the question whether it is better to pass large arrays and subsets thereof as arguments or use modules instead. For example:
type( plant_type ), dimension( 5, 50000 ) :: plant
Note that one dimension is very long and the other much smaller.
The argument that is passed is only a subset of the array:
call plantgrowth( plant(:,icell) )
Instead of passing this argument , I could also call plantgrowth() without the argument by adding a
use md_biosphere, only: plant
inside the subroutine plantgrowth().
==> Which option works faster?
Here are the alternative Fortran examples:
Using arguments:
module md_biosphere
implicit none
private
public :: biosphere, plant_type ! only plant_type (not plant) is made public, but not instance of the type ('plant')
! the important aspect here is that ncells >> nplant
integer, parameter :: ncells = 500000
integer, parameter :: nplant = 50
type plant_type
real :: foliage
real :: roots
real :: wood
end type plant_type
type( plant_type ), dimension( nplant, ncells ) :: plant
contains
subroutine biosphere()
integer :: icell
do icell=1,ncells
call plantgrowth( plant(:,icell) )
end do
end subroutine biosphere
subroutine plantgrowth( plant )
type( plant_type ), dimension(nplant), intent(inout) :: plant
integer :: iplant
! more stuff here ...
do iplant=1,nplant
plant(iplant)%foliage = 1.0
plant(iplant)%roots = 1.0
plant(iplant)%wood = 1.0
end do
end subroutine plantgrowth
end module md_biosphere
!//////////////////////////////////////////////////////////
program example_module
use md_biosphere, only: biosphere
implicit none
call biosphere()
end program example_module
Using 'use module':
module md_biosphere
implicit none
private
public :: biosphere, plant ! instance 'plant' is made public and does not have to be passed as argument
! the important aspect here is that ncells >> nplant
integer, parameter :: ncells = 500000
integer, parameter :: nplant = 50
type plant_type
real :: foliage
real :: roots
real :: wood
end type plant_type
type( plant_type ), dimension( nplant, ncells ) :: plant
contains
subroutine biosphere()
integer :: icell
do icell=1,ncells
! no arguments are passed
call plantgrowth( icell )
end do
end subroutine biosphere
subroutine plantgrowth( icell )
integer, intent(in) :: icell
integer :: iplant
! more stuff here ...
do iplant=1,nplant
plant(iplant,icell)%foliage = 1.0
plant(iplant,icell)%roots = 1.0
plant(iplant,icell)%wood = 1.0
end do
end subroutine plantgrowth
end module md_biosphere
!//////////////////////////////////////////////////////////
program example_module
use md_biosphere, only: biosphere
implicit none
call biosphere()
end program example_module
I have a nested loop which is supposed to iterate over a an N-dim cube (line, square, cube,...)
So far I do this using nested loops, eg.
for 2D:
do i = 1,Ni
do j = 1,Nj
! do stuff with f(i,j)
enddo
enddo
or 3D:
do i = 1,Ni
do j = 1,Nj
do k = 1,Nk
! do stuff with f(i,j,k)
enddo
enddo
enddo
I would like to replace these nested loops with a construct that works for every possible N-dimensional case. How can I do this in Fortran? In C++ one can use iterators. Is there something like this in Fortran?
I am considering writing a class, which kind of works like a mechanical n-dimensional counter (i.e. if we count 3 per dimension):
0,0,0,0,0
1,0,0,0,0
2,0,0,0,0
0,1,0,0,0
1,1,0,0,0
Would this be somewhat fast, compared to nested for loops? Do you guys have better ideas?
This may be the easiest...
Also you will note that the index order for the array is reversed. Fortran in fastest in the left, so it is opposite of C.
When you call it it uses which ever one matches the array dimensions that you sent to it automagically, by checking the interface of the module.
MODULE Stuff
IMPLICIT NONE
PUBLIC MY$Work
INTERFACE MY$Work
MODULE PROCEDURE MY$Work1D, MY$Work2D, MY$Work3D
END INTERFACE
PRIVATE
CONTAINS
!~~~~~~~~~~
SUBROUTINE MY$Work1d(Array, F_of_Array)
REAL, DIMENSION(:), INTENT(IN ) :: Array
REAL, DIMENSION(:), INTENT(INOUT) :: F_of_Array
INTEGER :: I
!DIR$ DO SIMD
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i)
enddo
RETURN
END SUBROUTINE MY$Work1d
!~~~~~~~~~~
SUBROUTINE MY$Work2d(Array, F_of_Array)
REAL, DIMENSION(:,:), INTENT(IN ) :: Array
REAL, DIMENSION(:,:), INTENT(INOUT) :: F_of_Array
INTEGER :: I,J
!DEC$ UNROLL_AND_JAM
do j = LBOUND(Array,2) ,UBOUND(Array,2)
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i,j)
enddo
enddo
RETURN
END SUBROUTINE MY$Work2d
!~~~~~~~~~~
SUBROUTINE MY$Work3d(Array, F_of_Array)
REAL, DIMENSION(:,:,:), INTENT(IN ) :: Array
REAL, DIMENSION(:,:,:), INTENT(INOUT) :: F_of_Array
INTEGER :: I,J,K
!DEC$ UNROLL_AND_JAM
do k = LBOUND(Array,3) , UBOUND(Array,3)
do j = LBOUND(Array,2) ,UBOUND(Array,2)
do i = LBOUND(Array,1) ,UBOUND(Array,1)
! do stuff with f(i,j,k)
enddo
enddo
enddo
RETURN
END SUBROUTINE MY$Work3d(Array, F_of_Array)
END MODULE Stuff
PROGRAM XX
USE STUFF
...
So you could have a 3D array and do this
DO K = 1, nk
CALL MY$WORK(Array(:,:,k), ResultArray(:,:,K) )
ENDDO
That would use the 2D version and loop over it for all the K-cases...
I decided to use a super index. The size of my dimensions is limited to powers of two. This allows me to use bitshift operations and regular addition. Hopefully this is faster than a object-oriented counter.
pure function supI(j, k, n) result(vec)
implicit none
integer*8, intent(in) :: j
integer*8 :: copy
integer*4, intent(in) :: k, n
integer*4 :: vec(n), x, mask
! transforms super index j to a n-dimensional iteration,
! where each dimension has a range of 2^k
! mask to extract left most indicies
mask = ISHFT(1, k) -1
copy = j
do x = 1,n
! extract current value using mask
vec(x) = and(copy, mask)
! shift to next value
copy = ISHFT(copy, -k)
enddo
end function supI
A 3d counter with 4 in each dimension would look like this:
do j = 0,64
write(*,*) supI(j, 2, 3)
enddo
Edit: Compared to loop speed without optimization it is not to bad: ~20% more time, but If I use the optimizer it is much much slower than nested loops.