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

pointer and stack local storage

jimdempseyatthecove
Honored Contributor III
1,277 Views

A lot of effort is being made at Intel in the direction of multi-threaded programming. Unfortunately, advancement in compiler updates are not multi-threaded programming friendly as the should be.

Using IVF 10.0.027 broke code by making thread-safe code into thread-unsafe code. In my subroutines I typically use pointers to user defined type structures.

type(T_foo), pointer :: a_foo

Up until 10.0.027 this would creat stack local storage for the pointer. 10.0.027 made the pointer SAVE (i.e. the pointer itself stored in static memory as opposed to on stack). This was particularly annoying since it took me a week to figure this out. Code that had been working for years was now broken.

To correct for this, I now have to use

type(T_foo), automatic, pointer :: a_foo

Why, in light of multi-threaded programming,cannot the absense of SAVE imply use stack local storage?

Jim Dempsey

0 Kudos
9 Replies
Steven_L_Intel1
Employee
1,277 Views

The default is "auto_scalar" which means that scalars are automatic by default, but non-scalars (derived types and arrays) are static. If you are doing threaded programming, you must use the RECURSIVE keyword or the /auto switch as this will not only default variables to automatic storage, but will also put descriptors and other non-user-visible state on the stack. Note that if you use /Qopenmp or /parallel you get /auto along for the ride. It is not sufficient to just make individual variables automatic.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,277 Views

The default is "auto_scalar" which means that scalars are automatic by default, but non-scalars (derived types and arrays) are static. If you are doing threaded programming, you must use the RECURSIVE keyword or the /auto switch as this will not only default variables to automatic storage, but will also put descriptors and other non-user-visible state on the stack. Note that if you use /Qopenmp or /parallel you get /auto along for the ride. It is not sufficient to just make individual variables automatic.


The routines are not recursive, they are reentrant. I do not desire to use auto parallelization (/parallel) nor to use OpenMP (/Qopenmp) yet I also want the subroutines generated to be thread-safe. I will enable /Qauto and hope that future updates do not change in behavior.

0 Kudos
Steven_L_Intel1
Employee
1,277 Views

Whether or not they are recursive, I recommend the RECURSIVE keyword be used to get the behavior you want in lieu of switches. You can use the switch if you want.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,277 Views

Whether or not they are recursive, I recommend the RECURSIVE keyword be used to get the behavior you want in lieu of switches. You can use the switch if you want.


Recursive did not make the pointera stack variable, automatic did, so I would imagine /Qauto would as well. /Qauto seemed to correct the problem although I did not inspect the 100's of affected files to verify.

Jim

0 Kudos
Steven_L_Intel1
Employee
1,277 Views

RECURSIVE should have made the pointer a stack variable. If it didn't, that's a bug. I tested with 10.1.026 and 11.0.066 and it did work for me. If you have a test case that shows otherwise i'd like to see it.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,277 Views

RECURSIVE should have made the pointer a stack variable. If it didn't, that's a bug. I tested with 10.1.026 and 11.0.066 and it did work for me. If you have a test case that shows otherwise i'd like to see it.


Steve,

I ran a test with RECURSIVE, this works. (reenterant alonedoes not work)

10.0.027 WinXP x64 /Debug

Jim

0 Kudos
Steven_L_Intel1
Employee
1,277 Views

If you mean the /reentrancy option, all that does is tell the run-time library whether or not to protect itself against calls from multiple threads.

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,277 Views

If you mean the /reentrancy option, all that does is tell the run-time library whether or not to protect itself against calls from multiple threads.

Luckily, I saw this thread and recalled that something is fishy in Qsave/recursive field. Then, I discovered that we inadvertently left /Qsave for the Release configuration (heritage from prehistory, but shouldn't matter for the semantics), then I joined the pieces together... Otherwise, I don't know how I would find the problem, as the actual example was quite complex.

Steve, you do have a bug there, at least in 11.0.61 (haven't checked 11.0.66). Take a look at the following code:

[cpp]program Qsave
call foo(3)
end program Qsave

recursive subroutine foo(n)
implicit none

integer, intent(in):: n
integer::             j

write(*,"(i1)",advance="no") n
do j=1,n
   call foo(n-1)
end do

end subroutine foo

[/cpp]

It should produce:

3210102101021010

However, when it's compiled with /Qsave, it produces:

3210

Because J is SAVEd accross recursive calls, i.e. shared among all instances. In other words, RECURSIVE doesn't override /Qsave, although it should.

I reported it to Premier as 529970.

0 Kudos
Steven_L_Intel1
Employee
1,277 Views

Yes, RECURSIVE should override /Qsave. Thanks for reporting it.

0 Kudos
Reply