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

CVF pointer question

rahzan
New Contributor I
1,784 Views

Treating a module like an object, I allow a "constructor" called setInput to receive the necessary data (such as an array), so that other methods in the module can operate on it. However, I do not wish to duplicate the memory usage by having an array input and acopy which is the property of the module. So I tried to use F90 pointers.

TWO questions:

1. Do these f90 pointer arrays need to be deallocated?

2. Similar to the input, I thought I canavoid duplicating an output array. But pointer and intent cannot mix. So I allocated an module pointer array for output. Does this need to be deallocated somehow, since it was explicitly allocated? if so how?

This routine works in console mode, but I can't be sure if it leaves memory leaks behind in a windows or com-dll project type.

module test
real,pointer:: inputX(:,:)
real,pointer:: Row1(:),Row2(:),Output(:)
integer:: nout
contains
subroutine SetInput(xin,n,m)
implicit none
integer,intent(in)::n,m
real, intent(in):: xin(n,m)
inputX=>xin
nout=n
end subroutine SetInput

subroutine run
implicit none
Row1=>inputX(:,1)
Row2=>inputX(:,2)
allocate(output(nout))
Output=3*Row1
write(*,*)inputX

write(*,*)"Row1";write(*,*)Row1
write(*,*)'Row2';write(*,*)Row2
end subroutine run

subroutine GetOutput(xout,n)
implicit none
integer,intent(in)::n
real, intent(out):: xout(n)
xout=Output
end subroutine GetOutput

end module


program main
use test
implicit none
real,allocatable:: xin(:,:),xout(:)
allocate(xin(5,2),xout(5))
xin(:,1)=1
xin(:,2)=2
write(*,*)xin
call setinput(xin,5,2)
call run
call getoutput(xout,5)
write(*,*)xout
pause
end

0 Kudos
11 Replies
Jugoslav_Dujic
Valued Contributor II
1,784 Views
Only the pointers that are explicitly ALLOCATEd must be explicitly DEALLOCATEd. Strictly speaking, when youallocate(output(nout)), you aren't "allocating a pointer", but you're "allocating an unnamed target and associating a pointer with it" -- I think it helpsif you think that way. Since the target is unnamed, the only means to reference/deallocate it is through the pointer output. If you forget to DEALLOCATE(output), you get a memory leak (which won't be a problem in one-time run in a console app, of course).
So, I think you're doing fine with input arrays (xin, inputX, Row1, etc.) -- you aren't duplicating any memory, but just associating pointers with existing target(s), already allocated in the main program.
Btw, are you still on 6.6B? I'm asking because in:
subroutine SetInput(xin,n,m)
implicit none
integer,intent(in)::n,m
real, intent(in):: xin(n,m)
inputX=>xin
xin must have TARGET attribute, but a bug in 6.6B lets you go without it. 6.6C will complain.
On the other hand, I don't like your output schema. I don't see why output array has POINTER attribute (since it is used only to allocate memory). Plus, you're doing a copy in GetOutput. Why not using something like:
module test
real, allocatable, target:: Output(:)
...
!Allocate output in SetInput as before
subroutine GetOutput(xout,n)
real, pointer:: xout(:)
xout => Output
Alternatively, don't allocate output at all, but let the main program take care of it and use xout to fill in the results directly.
Jugoslav
0 Kudos
rahzan
New Contributor I
1,784 Views

Thanks Jugoslav,

1. I tried downloading the link for the 6.6C upgrade but it leads nowhere.

I manually went to the cvf ftp site and found something called cvf-66-66cX.exe

But I'm not sure if it the right file. can you or steve confirm?

2. It is true that I do not need the xout to be a pointer it can simply be the unnnamed array you referred to. But I need to experiment to see what the caller has to do so that it gets back a pointer to xout the way you outline it. Unless you care to show me that part too!!
(So until I figure that part out, it is not even clear that, in the end, this notionsaves any memory duplication.)
3. If I understand your very last commentcorrectly, you say to make the xout public and let the USEr simply share it. I would like to do that, except that it is not possible, at least as of v 6.6A. You see, the module is in a DLL by itself and the caller is canned in another project. Due to some problem in cvf6.6, I was not able to simlyUSE the module which was in a separate DLL. So I ended up with a module in the caller project which contains only the interface to the DLL. SteveL had stated that this might be fixed at some point, but I have not followed up on that.
Your furhter comments will be appreciated.
Tim
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,784 Views
1) I guess that's the one... but I'm not sure
2) The caller has to declare a POINTER of appropriate type & shape and pass it as the argument of GetOutput. Of course, GetOutput has to have explicit interface, but that's supposed to be already solved because it's in a MODULE.
3) I didn't mean it. I mean, do you really have to keep output array around or you can simply rely on the caller to provide a sufficient buffer and pass it to get the results, i.e:
subroutine GetOutput(xout, ierr)
real, intent(out):: xout(:)
integer, intent(out):: ierr
if (size(xout).lt.nItems) then
ierr = MYERR_INSUFFICIENT_SPACE
else
do i=1,nItems
xout(i) = ALengthyExpressionWhichDependsOnInputs
end do
ierr=0
end if
end subroutine
This may be suitable or not, depending on what the nature of calculation is, i.e. whether ALengthyExpression can be calculated here, does the results need to be persistent for a latter reuse etc.
Jugoslav
0 Kudos
rahzan
New Contributor I
1,784 Views

Thanks for the quick reply,

Item 3 is not suitable since I intend for the computation and the getoutput to be in different routines.

But while I have your attention, . Instead of the MAIN, above, the caller is a routine in a com-module, and it gets xin from the outside. Is it ok/safe/reliable to add the pointer attribute to the interface of the com-module eventhough it was not something the com-wizard generated? I suspect the answer is no.

Alternatively, I assume it is also NOT ok to simply pass the loc(Xin) from the caller to a routine which expects a cvf pointer?

lastly, assuming the answer is NO to both of the options above, is it possible to use loc(xin) in the module to "define" an array which is "equivalent" to xin?

Tim

0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,784 Views

Having in mind the restrictions you just mentioned, I retreat and I state the opposite :-). Youroriginal design (with data copy) looks simplest & cleanest in such setup (apart from IMO unnecessary POINTER attribute -- why not using an ALLOCATABLE instead).

(Your both assumptions are correct and no, it's not possible to convert a non-pointer original xin (wherever it comes from) into a pointer).

Jugoslav

Message Edited by jugoslavdujic on 12-23-2003 07:50 AM

0 Kudos
rahzan
New Contributor I
1,784 Views

Ok,. we've comefull circle to the origianl question which I should have asked:

Does creating an allocatable array and copying a passed array (with intent(in)) double the memory usage?

If yes, then I prefer the Pointer method which I assumeuses only one copy of the data.

Thanks again for your patience.

Tim

0 Kudos
Steven_L_Intel1
Employee
1,784 Views
If the receiving routine is declared as accepting a deferred-shape array, no extra copy is made. If the compiler can't tell that what you're passing is contiguous, and the receiving routine is not known to receive a deferred-shape array, then a copy may be passed. You can specify /check:arg_temp_created to give a run-time informational when that happens.
0 Kudos
rahzan
New Contributor I
1,784 Views
in dll1 (FYI a com server project):
subroutine x(A)
use interfaceto_mod_dll2
real,intent(inout):: A(1:) !this is from the com server wiz'd
call Y(A)
...
in dll2 (another project):
subroutine Y(A1)
real,intent(inout):: A1(:)
n=size(A,1)
...
beacuse all of the interfaces use deferred shape, Is there only one copy of A existing? does the intent setting make any diffference?
Also can youconfirm that the 66c upgrade is called 66-66CX.exe?
thanks, Tim
0 Kudos
Steven_L_Intel1
Employee
1,784 Views
In your example, there would be only one copy. Intent does not matter.
No, the 6.6C update is not the 66CX. That WAS the 6.6C update, but I "pulled" it because of some problems that were reported. (And there's a new one I haven't investigated yet.) You can install that if you want, but I would recommend holding off for the revised version (probably not until after the new year).
0 Kudos
Jugoslav_Dujic
Valued Contributor II
1,784 Views

To Tim: depends on what youmean by"double the memory usage". As Steve said, you're guaranteed to get no temporaries which carry extra overhead. But by design, you have an output allocatable/pointer (doesn't really matter) array, whichstores the results, and you have a xin array which comes somewhere from deep space and whose size must be >= size(output). At the end, you copy from output array to xin.

In theory, you could avoid it by using only the storage provided by the shell, but that leads to certain design limitations, i.e. that storage must be known to you from the beginning and the original caller should provide enough space, I mean:

voidDeepSpace{
//written in another language somewhere unknown to you
float* Results;
int nSize; //Assumed that size of results is known
Results = new float[nSize];
TimsCOMServer(someInputs, Results, nSize);}

subroutine TimsCOMServer(someInputs, xout, nSize)
real xout(nSize);
call SetInput(someInputs, xout)
call NumberCrunch()
!call GetOutput() when NumberCrunch is done, you don't need
!GetOutput, as xout will be filed OK

end subroutine TimsCOMServer

module TimsCalculations
real, pointer:: Output(:)
contains
subroutine SetInput(someInputs, xout)
real, target:: xout(:)
Output => xout
!Now you use the storage provided by DeepSpace
...
end subroutine SetInput
subroutine NumberCrunch()
!Fill in the Output array here
end subroutine
end module

This uses only one storage for output data, but it may not be possible for some reasons in your setup (e.g. nSize is not known in advance, or there are multithreading issues, or you can't guarantee that Results willremain allocated during the process).

Jugoslav

0 Kudos
rahzan
New Contributor I
1,784 Views

Thanks Jugoslav,

This is just the way I had intended to do things. I think that I was not aware that the line

real, target:: xout(:)
is all that I need, as opposed to

real, target:: xout(nsize)

which (I understand) creates another copy.

Tim


0 Kudos
Reply