Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29273 Discussions

Release/Re-initialization of variables after retrun from subroutine - c/FORTRAN mixed

Yong_Tang
Beginner
2,518 Views

My c code is repeatedly calling a FORTRAN subroutine. The being called FORTRAN subroutine also calls many other FORTRAN subroutines. Those subroutines have "SAVE" statement which are used to retain the variable values after return (useful for the FORTRAN calculations). But now I need to clear up those save values after it returns from the main FORTRAN subroutine to C program so that it will be ready for next call.

I hope my description is clear enough. Is there an easy way to do this? There are way too many FORTRAN subroutines and variables involved. Any help is appreciated.

0 Kudos
5 Replies
Steven_L_Intel1
Employee
2,518 Views
Nope. You will have to "clear" the variables in code you write.
0 Kudos
Yong_Tang
Beginner
2,518 Views
Steve:

thanks for the quick response! but it is so sad to hear that:)
0 Kudos
jimdempseyatthecove
Honored Contributor III
2,518 Views
Tang,

This suggestion will require some experimentation on your part and what works today may not necessarily work after the next update (IOW you may need to run a verification program when you upgrade your compiler/linker).

In the first FORTRAN program (or module) you link into your image add a static variable named "integer :: ZeroBegin" (or integer, SAVE :: ZeroBegin), and in the last file linked (SAVE or module static variable) as last variable "integer :: ZeroEnd" (or integer, SAVE :: ZeroEnd). Then at the point in your code where you want to initialize you can make a call to memset(LOC(ZeroBegin), 0, LOC(ZeroEnd)-LOC(ZeroBegin)).

** the experimentation you need to do is to examine the Dissassembly code for the load segment name for SAVE variables and for MODULE static variables and for COMMON variables and for PROGRAM global variables. If these are all in .BSS (or other same named load segment name) then you can (may be able to) use one memset to zero out the "static/saved) data. If there are multiple named segments then you may require multiple zeroing code sections.

I use a similar technique for wiping allocated thread local storage. In place of one generalized wipe (e.g. memset) I use per-type wipes

[fortran]! subroutine to wipe a list of n real variables starting at p
! This is typicaly used to wipe allocated memory of various
! structures. See MOD_TOSS for an example of use.
subroutine WipeReals(p, n)
  integer :: n
  real, dimension(1:n) :: p
  p = 0.0
end subroutine WipeReals

subroutine Wipe_Reals1D(A)
  real :: A(:)
  call WipeReals(A, size(A))
end subroutine Wipe_Reals1D

subroutine Wipe_Reals2D(A)
  real :: A(:,:)
  call WipeReals(A, size(A))
end subroutine Wipe_Reals2D

! subroutine to wipe a list of n integer variables starting at p
subroutine WipeIntegers(p, n)
  integer :: n
  integer, dimension(1:n) :: p
  p = 0
end subroutine WipeIntegers

subroutine Wipe_Integers1D(A)
  integer :: A(:)
  call WipeIntegers(A, size(A))
end subroutine Wipe_Integers1D

subroutine Wipe_Integers2D(A)
  integer :: A(:,:)
  call WipeIntegers(A, size(A))
end subroutine Wipe_Integers2D
[/fortran]
...
[bash]subroutine WipeFiniteSolution(s)
    use MOD_TOSS
    type(TypeFiniteSolution) :: s
    integer :: n, nb, ni, nr
    nb = loc(s.LastReal)-loc(s.FirstReal)
    nr = (nb / sizeof(s.FirstReal)) + 1
    call WipeReals(s.FirstReal, nr)
    nb = loc(s.LastInteger)-loc(s.FirstInteger)
    ni = (nb / sizeof(s.FirstInteger)) + 1
    call WipeIntegers(s.FirstInteger, ni)
    call WipeBeads(s)
end subroutine WipeFiniteSolution

subroutine InitFiniteSolution(s)
    use MOD_TOSS
    type(TypeFiniteSolution) :: s
    nb = loc(s.LastPointer)-loc(s.FirstPointer)
    ni = (nb / sizeof(s.FirstPointer)) + 1
    ! use WipeIntegers for pointers
    call WipeIntegers(s.FirstPointer, ni)
    call WipeFiniteSolution(s)
end subroutine InitFiniteSolution
...[/bash]


Jim Dempsey
0 Kudos
bmchenry
New Contributor II
2,518 Views

One other idea:
Create a 'global module' into which you insert all the variables you need to 'save'.
So lets call it 'My_Local_Save' module.
Next,get rid of all your'save' options!! (messy! inefficieint! you're saving stuff you don't need)
Now, in the 'My local_save' module add all the variables you feel you need to save from the various fortran subroutines.
Then in each you simply Use My_Local_Save
you can even use the 'only' option to just access the variables you need from each routine.
(For convenience you might consider a prefix on each variable with the routine name to quickly remind you which routineuses which variable and to keep them all named different).
Then when you need to, from the C routine you call a subroutine which simply re-zero's all the 'local saved variables' in your module 'my_local_save'


0 Kudos
jimdempseyatthecove
Honored Contributor III
2,518 Views
bmchenry's suggestion is cleaner (clearer to understand by the next reader of your code), my suggestion was obscure (although less effort).

I might add an additional piece of information. In non-recursive, non-OpenMP subroutine any function array declaration defaults to SAVE. Therefore, when you hunt down SAVE's to port into the module, also look for arrays to port as well. You can then insert as first and last variable the dummy variable for the wipe. You can wipe everything to NULL or some magic number like 0xcacacaca (as does Debug build on Windows).

Jim Dempsey
0 Kudos
Reply