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

dynamic array (pointer) allocated on the stack

luca_marsiglio
Beginner
2,314 Views

I have a problem with the following piece of code (see below). As I run it, it falls over when JBUF reach size

3.200.000.

C-------------------------------------------------

INTEGER, POINTER :: IBUF(:), JBUF(:)
INTEGER NUM, NEW

NUM=1 000 000
NEW=100 000

10 CONTINUE
ALLOCATE ( IBUF(NUM) )
ALLOCATE ( JBUF(NUM) )
JBUF=IBUF

cc DO I=1,NUM
cc JBUF(I)=IBUF(I)
cc ENDDO

DEALLOCATE (IBUF)
DEALLOCATE (JBUF)

NUM=NUM+NEW

go to 10

END

C-------------------------------------------------

Debugging with Valgrind I noticed that the problem has something to do with the stack size, and in fact if I change the stack size (eg: %> limit stacksize unlimited ) then the problem seem to be solved, or say it is postponed;) Equally, it works fine if I use the compiler flag "-heap-arrays" when compiling.

Now the question is: why is a dynamic array allocated on the stack at all?

Furthermore, if I change only JBUF from POINTER to ALLOCATABLE, and I keep the rest of the code as is, then my test run fine, even with the original stack size (=10240 kbytes). This seems to imply that the problem is in JBUF only.

IBUF seems to never overflow, and in fact I believe it is allocated on the heap. Can anyone explain me this behaviour? I mean, both JBUF and IBUF are arrays made out of a pointer, but the first is on the stack whereas the other on the heap. Why?

And finally, does anybody know why if I turn JBUF from POINTER to ALLOCATABLE, then it goes on the heap?

Apologise for the long post;)

Any help will be much appreciated! Luca

0 Kudos
8 Replies
luca_marsiglio
Beginner
2,314 Views

one more thing:

if I keep the code as is, but I uncomment the do loop and I comment out the assignment (JBUF=IBUF), then again, it run smoothly.

0 Kudos
Kevin_D_Intel
Employee
2,314 Views

Maybe others can extend/correct as needed.

With the POINTER attribute, the assignment JBUF=IBUF leads to use of an array temporary due to the compiler's concern for potential memory overlap between the arrays.

JBUF does not live on the stack, it lives on the heap, but it is the case that a very large temporary the size of NUM is created on the stack due to the array assignment. As you found, the array temporary is avoided when JBUF is declared with the ALLOCATABLE attribute or when accessing a single element at a time in the loop.

The earlier forum thread (here) contains lots of related discussion.

Hope that helps.

0 Kudos
luca_marsiglio
Beginner
2,314 Views

yes thanks Kevin!!

One more thing though. I haven't made any test yet, but I was thinking that in terms of performance, creating a temporary can probably lead to slower code (cause of course it has to copy the buffer on the temporary) and therefore i might be better off avoding that altogether.

0 Kudos
Kevin_D_Intel
Employee
2,314 Views

That's correct. There is a performance cost associated with the temporary. Guidance I've received in other similar cases and recommendations by othersthat I've read is to use the ALLOCATABLE for dynamic arrays unless there's a need for POINTER.

In the thread I cited, Steve has a nice succinct reply (here), writing:

"If you want "dynamic arrays", use ALLOCATABLE. If you want to be able to have pointers that can point to parts of other arrays, use POINTER."

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,314 Views

>>With the POINTER attribute, the assignment JBUF=IBUF leads to use of an array temporary due to the compiler's concern for potential memory overlap between the arrays.

Why not (write and) use a variant of memmove with enhancement for stride? One that performs the "copy" without use of temporary. If you look back at the number of forum posts related to problems with temporaries use in A = B copy operations you should find it well worth the effort to provide and use a Fortran analog to memmove.

Jim Dempsey

0 Kudos
Kevin_D_Intel
Employee
2,314 Views

I will put forth the suggestion Jim.

0 Kudos
luca_marsiglio
Beginner
2,313 Views

Okay thanks guys! But then I start wondering where else to expect a temporary to kick in.

I mean, is there any other situation I should be careful of?

I did some reading on both the ifort manual and the web, and it is my understanding that they are created not only when copying two arrays with pointers (see above) but also when passing a dynamic array made with pointer to a subroutine expecting an explicit array (sorry if the terminology is not exactly the correct one).

Can you briefly post me an example of the scenario i mentioned above (passing a dyn array to a routine expecting a f77 array)? as I tried to write a test and I could not see any performance penalty.

Many thanks, Luca

0 Kudos
Steven_L_Intel1
Employee
2,314 Views

In the case of passing an argument, the compiler does a run-time check to see if what you are passing is contiguous. If it is, then it doesn't need to make a copy (when the receiving dummy argument is not known to be a deferred-shape array). This is different than a test for overlap, which the compiler is doing for the assignment. In many cases the compiler can figure it out, but for POINTER it does not have enough information at compile-time to tell.

If you use ALLOCATABLE arrays you will not have this problem.

0 Kudos
Reply