- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This is something that confused me greatly during my first few months with F90, many moons ago. It was a feature that I had been desperately anxious to use for years, but my attempts to use it with Compaq VF 6.0 proved futile. In fact, I was left with such a reflexive flinch that since then I retreat to older, more cumbersome ways to solve the problem when I encounter a situation that it seemed suited to.
Perhaps now enough time has passed that I can try again.
I want to create functions that return array results. To do so, I have to declare the returned value as a pointer of the correct type and rank and allocate memory for use within the routine. Clearly, I cannot DeAllocate that memory before return, so it seems that every use of this pattern would create a memory leak.
How and when should the memory be returned to heap? Should I declare the returned variable "Save" and test it's rank on next entry, then ReAllocate when necessary?
Is the prefered approach compiler version dependent?
I currently use CVF6.6c since despite paying for and early version of IVF and MSVS, the installation and configuration issues scared me off.
On another topic...
Does IVF support Allocatable arrays within derived types?
Thanks, Cliff
Perhaps now enough time has passed that I can try again.
I want to create functions that return array results. To do so, I have to declare the returned value as a pointer of the correct type and rank and allocate memory for use within the routine. Clearly, I cannot DeAllocate that memory before return, so it seems that every use of this pattern would create a memory leak.
How and when should the memory be returned to heap? Should I declare the returned variable "Save" and test it's rank on next entry, then ReAllocate when necessary?
Is the prefered approach compiler version dependent?
I currently use CVF6.6c since despite paying for and early version of IVF and MSVS, the installation and configuration issues scared me off.
On another topic...
Does IVF support Allocatable arrays within derived types?
Thanks, Cliff
Link Copied
7 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Cliff,
The preferable way of doing this is to have the function return an ALLOCATABLE array, not a POINTER. The function result will always start out unalliocated. Barring compiler bugs, it is impossible to have allocatable arrays leak memory. If you are assigning the result to another allocatable array where you do not know the shape of the function result, you may want to use the /assume:realloc_lhs option to have the left side automatically realliocated as needed. (I will caution that there are some bugs in this feature at present.)
Yes, IVF supports allocatable components of derived types as well as allocatable function results.
Do you know that you can also have functions return arrays that have bounds dependent on arguments without making them POINTER or ALLOCATABLE?
The preferable way of doing this is to have the function return an ALLOCATABLE array, not a POINTER. The function result will always start out unalliocated. Barring compiler bugs, it is impossible to have allocatable arrays leak memory. If you are assigning the result to another allocatable array where you do not know the shape of the function result, you may want to use the /assume:realloc_lhs option to have the left side automatically realliocated as needed. (I will caution that there are some bugs in this feature at present.)
Yes, IVF supports allocatable components of derived types as well as allocatable function results.
Do you know that you can also have functions return arrays that have bounds dependent on arguments without making them POINTER or ALLOCATABLE?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The popular channel benchmark:
http://www.polyhedron.co.uk/pb05-win32-f90bench_p40html
is an example with internal array valued functions. This does not yet work efficiently with ifort, but it's not at all complicated at the source code level. You would have to use one of the f90 mechanisms: CONTAINS, MODULE, INTERFACE
According to the results returned by forum search, the allocatable derived type arrays have been supported for 4 years.
Since ifort began including the PPE option for installation without a separately obtained Microsoft component, installation is less complicated than CVF with updates, particularly on recent Windows versions.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Tim,
That example shows the internal function results being dimensioned with Size() evaluations of the input argument. I didn't think that this was possible, because i thought everything in a declaration had to be evaluatable at compile time. I have read the words "defered dimensions" but obviously never understood the implications.
If you could explain the mechanism to me, I would have a better chance of understanding and remembering the details. Obviously memory for the return is allocated at entry. Is it allocated on the stack, or on the heap? How long does it persist?
Are the size and rank limitations the same as any other variable?
Thanks, Cliff
That example shows the internal function results being dimensioned with Size() evaluations of the input argument. I didn't think that this was possible, because i thought everything in a declaration had to be evaluatable at compile time. I have read the words "defered dimensions" but obviously never understood the implications.
If you could explain the mechanism to me, I would have a better chance of understanding and remembering the details. Obviously memory for the return is allocated at entry. Is it allocated on the stack, or on the heap? How long does it persist?
Are the size and rank limitations the same as any other variable?
Thanks, Cliff
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This is a new feature in Fortran 90 where the function return variable can be declared using a "specification expression". This is a run-time expression with restrictions - the most important is that variables in the expression be actual arguments, COMMON variables or use or host-associated. There are limits on which intrinsic functions can be used in such expressions, though these limits got lifted some in Fortran 95 and much more in Fortran 2003.
A key point is that an explicit interface for the function MUST be visible to the caller, hence Tim's reference to MODULE/USE/INTERFACE. This provides the compiler the information it needs to create space for the return value before the call is made. By default, this goes on the stack and it persists to the end of the statement that calls the function. There are no limits on size or rank, though if you have a very large array, it may not fit on the stack. The option /heap-arrays will cause the value to be allocated on the heap (and automatically deallocated).
A key point is that an explicit interface for the function MUST be visible to the caller, hence Tim's reference to MODULE/USE/INTERFACE. This provides the compiler the information it needs to create space for the return value before the call is made. By default, this goes on the stack and it persists to the end of the statement that calls the function. There are no limits on size or rank, though if you have a very large array, it may not fit on the stack. The option /heap-arrays will cause the value to be allocated on the heap (and automatically deallocated).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
As all the declarations of the containing function are available by definition when the internal function is compiled, the sizes are compile time evaluations inthis example. There need not be any run-time allocation, unless it were to be
compiled with a multi-thread option, such as /Qopenmp, which changes the default to putting local arrays on stack.
If such an internal function were in a subroutine rather than a main program, I
imagine its data allocation would be handled as part of the containing subroutine, but I'm not an expert on such things. I think it's clear the calling subroutine is responsible for supplying the memory allocation for a vector valued function return, and the available f90 interface mechanisms permit that evaluation before the function call. As gfortran handles this case well, and some of the experts who frequent fortran@gcc.gnu.org are familiar with it, you could ask how that compiler does it, if you are interested. Subscribe to that list at gcc.gnu.org mailing list link.
compiled with a multi-thread option, such as /Qopenmp, which changes the default to putting local arrays on stack.
If such an internal function were in a subroutine rather than a main program, I
imagine its data allocation would be handled as part of the containing subroutine, but I'm not an expert on such things. I think it's clear the calling subroutine is responsible for supplying the memory allocation for a vector valued function return, and the available f90 interface mechanisms permit that evaluation before the function call. As gfortran handles this case well, and some of the experts who frequent fortran@gcc.gnu.org are familiar with it, you could ask how that compiler does it, if you are interested. Subscribe to that list at gcc.gnu.org mailing list link.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Tim,
In the specific example you brought up, the host routine variables that are used as arguments are indeed explicitely dimensioned. But nothing in Steve's discussion of the usage requires this, does it? Those aruments could just as easily have been Allocatable and runtime dimensioned themselves, breaking my paradigm of "Declaration" implies "compile time evaluatable". Which is OK, that was nothing more than a constraint that helped me remember many program organization specifics (circa F77) in one simple rule.
Steve,
If a compiler were sufficiently sophisticated, it could look at a specific usage of the array valued function, and if it was an assignment it could avoid an allocation, a copy and the terminating deallocation. Any chance CVF or IVF do that?
I guess that if Tim's suggestion about the allocation occurring in the calling routine prior to the call is correct, this would be an obvious optimization.
What I'm getting at is... I like the syntax of using vector valued functions, but I'm worried that there may be hidden performance penalties I should be aware of. Anything come to mind?
Thanks to both of you for this enlightening discussion, Cliff
In the specific example you brought up, the host routine variables that are used as arguments are indeed explicitely dimensioned. But nothing in Steve's discussion of the usage requires this, does it? Those aruments could just as easily have been Allocatable and runtime dimensioned themselves, breaking my paradigm of "Declaration" implies "compile time evaluatable". Which is OK, that was nothing more than a constraint that helped me remember many program organization specifics (circa F77) in one simple rule.
Steve,
If a compiler were sufficiently sophisticated, it could look at a specific usage of the array valued function, and if it was an assignment it could avoid an allocation, a copy and the terminating deallocation. Any chance CVF or IVF do that?
I guess that if Tim's suggestion about the allocation occurring in the calling routine prior to the call is correct, this would be an obvious optimization.
What I'm getting at is... I like the syntax of using vector valued functions, but I'm worried that there may be hidden performance penalties I should be aware of. Anything come to mind?
Thanks to both of you for this enlightening discussion, Cliff
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Tim's description of compile-time allocation is not applicable here. I explained how it works. The "specification expression" is evaluated at the time of the call and can be run-time variable.
Fortran semantics, in general, don't allow for the sort of pointer-copying you describe, except for POINTER arrays in which case that's what you get when you assign one POINTER to another, but as you noted earlier, that leaves management of the memory to you. Theoretically, if you enabled the "realloc_lhs" feature and the right-side was an allocatable function result the compiler could just "transfer the allocation". The compiler does try to be quite clever in this situation, but I am not sure just how clever it is.
My advice, as always, is to write clear and understandable code using the language features as they were intended to be used. Let the compiler worry about optimization. IF and only if the application performance is not what you need, and you have used a performance analyzer such as Intel VTune to identify a "copy" as a bottleneck, then you should look at alternatives.
Fortran semantics, in general, don't allow for the sort of pointer-copying you describe, except for POINTER arrays in which case that's what you get when you assign one POINTER to another, but as you noted earlier, that leaves management of the memory to you. Theoretically, if you enabled the "realloc_lhs" feature and the right-side was an allocatable function result the compiler could just "transfer the allocation". The compiler does try to be quite clever in this situation, but I am not sure just how clever it is.
My advice, as always, is to write clear and understandable code using the language features as they were intended to be used. Let the compiler worry about optimization. IF and only if the application performance is not what you need, and you have used a performance analyzer such as Intel VTune to identify a "copy" as a bottleneck, then you should look at alternatives.

Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page