Home > Archive > Fortran > March 2008 > copy behavior of a fortran array as input argument
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
copy behavior of a fortran array as input argument
|
|
| Fei Liu 2008-03-18, 7:21 pm |
| Given
real, dimension(10, 10), target :: fa
real, dimension(:,:), pointer :: fap
fap => fa
call usearray(fa(:, 3:7))
call usearray(fap(:, 3:7))
....
subroutine usearray(fa)
real, dimension(:, :), target :: fa
My understanding is that this will almost definitely cause usearray to
copy the array slices being passed in.
I know sometimes, usearray(fa(:,:)) does not cause copy, and fa is
passed to usearray as a reference.
My question is 'is there a portable way to tell if usearray%fa is a copy
or reference?'
What does the standard say about array copy/reference behavior in this
code setup?
Fei
| |
| Gordon Sande 2008-03-18, 7:21 pm |
| On 2008-03-18 14:25:22 -0300, Fei Liu <fei.liu@gmail.com> said:
> Given
>
> real, dimension(10, 10), target :: fa
> real, dimension(:,:), pointer :: fap
>
> fap => fa
>
> call usearray(fa(:, 3:7))
> call usearray(fap(:, 3:7))
> ...
>
> subroutine usearray(fa)
>
> real, dimension(:, :), target :: fa
>
> My understanding is that this will almost definitely cause usearray to
> copy the array slices being passed in.
>
> I know sometimes, usearray(fa(:,:)) does not cause copy, and fa is
> passed to usearray as a reference.
>
> My question is 'is there a portable way to tell if usearray%fa is a
> copy or reference?'
>
> What does the standard say about array copy/reference behavior in this
> code setup?
>
> Fei
The broad notion is that Fortran is structured so that the answer to
your question has no influence on the outcome of a correct Fortran program.
So there is no way within a correct Fortran to detect the difference.
It would appear that it is rather easy to construct a descriptor which
would cover the contents of what you have specified. Whether it is
done on the original array (fa) or its pointer alias (fap) makes no
difference. All that matters is that the called routine can use a descriptor
which is the case for assumed shape (the ":" version and not the "*" version).
If the called routine had used assumed (or explicit) size (the "*" version)
then the argument would noncontiguous and a copy would be generated for both
cases.
Your question has all the symptoms of getting advice from someone who has a
friend who knows somebody who claims to have met an expert. Less politely,
it sounds like bad advice.
Your statement that things get passed as a reference is the give away of
very old advice that might have made sense for F77 but is ignorent of
the techniques suitable for F90 and newer Fortrans.
Note that your example requires explicit interfaces to work. If you do not
understand why then you will need to sort that out and suddenly you will
see why your question makes so little sense.
| |
| Fei Liu 2008-03-18, 7:21 pm |
| Gordon Sande wrote:
> On 2008-03-18 14:25:22 -0300, Fei Liu <fei.liu@gmail.com> said:
>
>
> The broad notion is that Fortran is structured so that the answer to
> your question has no influence on the outcome of a correct Fortran program.
> So there is no way within a correct Fortran to detect the difference.
>
> It would appear that it is rather easy to construct a descriptor which
> would cover the contents of what you have specified. Whether it is
> done on the original array (fa) or its pointer alias (fap) makes no
> difference. All that matters is that the called routine can use a
> descriptor
> which is the case for assumed shape (the ":" version and not the "*"
> version).
>
> If the called routine had used assumed (or explicit) size (the "*" version)
> then the argument would noncontiguous and a copy would be generated for
> both
> cases.
>
> Your question has all the symptoms of getting advice from someone who has a
> friend who knows somebody who claims to have met an expert. Less politely,
> it sounds like bad advice.
>
> Your statement that things get passed as a reference is the give away of
> very old advice that might have made sense for F77 but is ignorent of
> the techniques suitable for F90 and newer Fortrans.
>
> Note that your example requires explicit interfaces to work. If you do not
> understand why then you will need to sort that out and suddenly you will
> see why your question makes so little sense.
>
>
>
Gordon, I don't disagree with you said, however the reality is quite
ugly. According to your opinion, we should not be using MPI.
The problem is sometimes we need to access the memory and we need to
know if usearray%fa is a reference or copy. There is a *need*. It's good
on paper that the programmer don't have to know and should code as
if...but the reality is we do need to code differently based on what
happened at the interface, and sometimes even reporting an error is
enough when something undesirable (copy happened) happened.
Fei
| |
| Greg Lindahl 2008-03-18, 7:21 pm |
| In article <47E00B16.9060804@gmail.com>, Fei Liu <fei.liu@gmail.com> wrote:
> According to your opinion, we should not be using MPI.
It's a huge shame that nearly 20 years after it was well known that
F90 didn't play well with MPI, there is still no way in Fortran to
efficiently specify MPI's interface, other than the silly solution of
using C interop & the C API.
You sound like you're using the F77 MPI interface. If you switch to
the F90 interface, I think that this case will be properly handled
without you having to worry about argument copies.
-- greg
| |
| Paul van Delst 2008-03-18, 7:21 pm |
| Fei Liu wrote:
> Gordon Sande wrote:
[snip]
>
> Gordon, I don't disagree with you said, however the reality is quite
> ugly. According to your opinion, we should not be using MPI.
>
> The problem is sometimes we need to access the memory and we need to
> know if usearray%fa is a reference or copy. There is a *need*. It's good
> on paper that the programmer don't have to know and should code as
> if...but the reality is we do need to code differently based on what
> happened at the interface, and sometimes even reporting an error is
> enough when something undesirable (copy happened) happened.
I was having a discussion with someone about this sort of thing just this morning. He was
of the opinion that MPI and Fortran90/95 are fundamentally incompatible (I'm not making a
statement about that either way). Apart from the pass-by-reference/value issue, he also
brought up the use of automatic or locally allocated arrays that are used in MPI calls.
Apparently he has had the situation where the Fortran routine returned (thus deallocating
the local arrays) before the MPI stuff had finished. Code that worked for 12 years had
weird things happen when a compiler (or machine, or both...can't remember) was upgraded
which had slightly different latencies.
cheers,
paulv
| |
| Gordon Sande 2008-03-18, 7:21 pm |
| On 2008-03-18 15:33:58 -0300, Fei Liu <fei.liu@gmail.com> said:
> Gordon Sande wrote:
>
> Gordon, I don't disagree with you said, however the reality is quite
> ugly. According to your opinion, we should not be using MPI.
The problem is that standard conforming Fortran and MPI make for a bad mix.
The issue has been raised here before if my memory is correct. The obvious
cure is to restict yourself to "F77 semantics" which then outlaws the features
you have used in your question. Since your users will have F90 compilers
and will have read about its new features you can not really expect then to
obey such strict rules.
> The problem is sometimes we need to access the memory and we need to
> know if usearray%fa is a reference or copy. There is a *need*. It's
> good on paper that the programmer don't have to know and should code
> as if...but the reality is we do need to code differently based on what
> happened at the interface, and sometimes even reporting an error is
> enough when something undesirable (copy happened) happened.
You make it sound like F90 is the problem. Surely the issue is that MPI assumes
"F77 semantics" and F90 has different sematics. There is a secondary
issue that the
assumed "F77 semantics" are not actually guaranteed by the F77 definition even
if many implementations met those assumptions. This is an example of the failed
logic that if it appears to work for my compiler then it must be
standard conforming.
You have not made that claim but appear to be headed for that road.
> Fei
| |
| Fei Liu 2008-03-18, 7:21 pm |
| Paul van Delst wrote:
> Fei Liu wrote:
>
> [snip]
>
>
> I was having a discussion with someone about this sort of thing just
> this morning. He was of the opinion that MPI and Fortran90/95 are
> fundamentally incompatible (I'm not making a statement about that either
> way). Apart from the pass-by-reference/value issue, he also brought up
> the use of automatic or locally allocated arrays that are used in MPI
> calls. Apparently he has had the situation where the Fortran routine
> returned (thus deallocating the local arrays) before the MPI stuff had
> finished. Code that worked for 12 years had weird things happen when a
> compiler (or machine, or both...can't remember) was upgraded which had
> slightly different latencies.
>
> cheers,
>
> paulv
I am glad you understand the problem. This is typically an issue for
library writer as I will show below.
Greg, what do you mean by using F90 MPI resolve this problem? It's not
quite clear to me. AFAIK, many MPI subroutines require arguments passed
by reference.
Here is a concrete example of what I am talking about. As a library
writer of usearray, how do I prevent things Paul described from
happening behind the user's back? It'd be great if there is a way to
test if the argument is actually a reference or it's been copied.
Fei
fa(3, 3) = 23.00000
fa(3, 3) = 23.00000
fa(5, 8) = 5.000000
fa(5, 8) = 5.000000
program copy
real, dimension(5,10) :: fa
fa = 0
fa(3, 3) = 10
fa(5, 8) = 5
call usearray(fa)
print *, 'fa(3, 3) = ', fa(3, 3)
call usearray1(fa)
print *, 'fa(3, 3) = ', fa(3, 3)
call usearray1(fa(2:4, 5:8) )
print *, 'fa(5, 8) = ', fa(5, 8)
call usearray2(fa(2:4, 5:8) )
print *, 'fa(5, 8) = ', fa(5, 8)
contains
subroutine usearray(fa)
real, dimension(5, 10) :: fa
fa(3, 3) = 23
end subroutine
subroutine usearray1(fa)
real, dimension(:, :) :: fa
fa(3, 3) = 23
end subroutine
subroutine usearray2(fa)
real, dimension(3, 4) :: fa
fa(3, 3) = 23
end subroutine
end program
| |
| glen herrmannsfeldt 2008-03-18, 7:21 pm |
| Fei Liu wrote:
> Gordon Sande wrote:
(snip)
(snip)
[color=darkred]
> Gordon, I don't disagree with you said, however the reality is quite
> ugly. According to your opinion, we should not be using MPI.
Gordon commented about the standard. You are free to write
non-standard code, but should know that it is non-standard.
I will say, though, that I agree you should not be using MPI.
If you haven't looked at languages like ZPL that allow the compiler
to figure out things for itself, likely better than a person,
then you shouldn't be using MPI.
> The problem is sometimes we need to access the memory and we need to
> know if usearray%fa is a reference or copy. There is a *need*. It's good
> on paper that the programmer don't have to know and should code as
> if...but the reality is we do need to code differently based on what
> happened at the interface, and sometimes even reporting an error is
> enough when something undesirable (copy happened) happened.
I would say that is a bug in the design of MPI, but it is a little
late now to do anything about it. Passing pointers in C
guarantees no copy. Passing pointers in Fortran should also
not cause any array copying.
In the case of assumed shape it is reasonable to expect that
the data isn't copied. For MPI programming you should know
specifically what your compiler does.
The usual case for a copy is passing a possibly non-contiguous array
(an assumed shape dummy) to another routine where the standard
requires a contiguous array. Don't do that in MPI programs.
-- glen
| |
| Fei Liu 2008-03-18, 7:21 pm |
| glen herrmannsfeldt wrote:
> Fei Liu wrote:
>
> (snip)
> (snip)
>
>
> Gordon commented about the standard. You are free to write
> non-standard code, but should know that it is non-standard.
>
> I will say, though, that I agree you should not be using MPI.
> If you haven't looked at languages like ZPL that allow the compiler
> to figure out things for itself, likely better than a person,
> then you shouldn't be using MPI.
>
>
> I would say that is a bug in the design of MPI, but it is a little
> late now to do anything about it. Passing pointers in C
> guarantees no copy. Passing pointers in Fortran should also
> not cause any array copying.
>
> In the case of assumed shape it is reasonable to expect that
> the data isn't copied. For MPI programming you should know
> specifically what your compiler does.
>
> The usual case for a copy is passing a possibly non-contiguous array
> (an assumed shape dummy) to another routine where the standard
> requires a contiguous array. Don't do that in MPI programs.
>
> -- glen
>
To sum things up, we still don't have a portable (standard conforming)
way to tell if compiler has copied data during run time or passed a
reference for a F90/95/2003 subroutine/function interface? If that's the
case, so be it.
Fei
| |
| glen herrmannsfeldt 2008-03-18, 7:21 pm |
| Fei Liu wrote:
(snip)
That is also true in C, so don't blame Fortran for it.
[color=darkred]
> I am glad you understand the problem. This is typically an issue for
> library writer as I will show below.
> Greg, what do you mean by using F90 MPI resolve this problem? It's not
> quite clear to me. AFAIK, many MPI subroutines require arguments passed
> by reference.
If you have Fortran 90 standard interface routines between
you and MPI, and those routines use the appropriate
calling methods, it should work. Note, though, that nothing
will save you if you deallocate memory while it is being used
somewhere else. This is as true in single threaded programs
as it is in MPI.
> Here is a concrete example of what I am talking about. As a library
> writer of usearray, how do I prevent things Paul described from
> happening behind the user's back? It'd be great if there is a way to
> test if the argument is actually a reference or it's been copied.
(snip)
> subroutine usearray(fa)
> real, dimension(5, 10) :: fa
> fa(3, 3) = 23
> end subroutine
In the above explicit shape array a copy will be made
if the actual argument is not contiguous, or if the
compiler can't be sure.
> subroutine usearray1(fa)
> real, dimension(:, :) :: fa
> fa(3, 3) = 23
> end subroutine
For assumed shape, as above, it is normal not to
make a copy. The standard doesn't disallow it, but
quality of implementation will.
> subroutine usearray2(fa)
> real, dimension(3, 4) :: fa
> fa(3, 3) = 23
As with the first one above, a copy might be made.
Note that this subroutine could be written as:
subroutine usearray2(fa)
real, dimension(12) :: fa
fa(9) = 23
end
That is, it will change the ninth element of the contiguous
array that is passed to it, independent of the dimensions
in the calling routine. (Though the array better have at least
nine elements.)
Do the MPI routines require contiguous arrays?
If so, and you want to pass a discontiguous array
section then either you or Fortran has to make a copy.
-- glen
| |
| James Van Buskirk 2008-03-18, 7:21 pm |
| "Fei Liu" <fei.liu@gmail.com> wrote in message
news:47E01DF6.5060409@gmail.com...
> To sum things up, we still don't have a portable (standard conforming) way
> to tell if compiler has copied data during run time or passed a reference
> for a F90/95/2003 subroutine/function interface? If that's the case, so be
> it.
We have had a way since the standard started requiring the copies.
Just declare both actual and dummy arguments to have the TARGET
attribute and point one pointer at an element of the actual argument
and another at the corresponding element of the dummy argument. Test
with the ASSOCIATED intrinsic whether the pointers are associated
with each other. If so, no copy. If not, the dummy argument is a
copy of the actual argument.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
| |
| Greg Lindahl 2008-03-18, 7:21 pm |
| In article <47E013B7.8030908@gmail.com>, Fei Liu <fei.liu@gmail.com> wrote:
>Greg, what do you mean by using F90 MPI resolve this problem? It's not
>quite clear to me. AFAIK, many MPI subroutines require arguments passed
>by reference.
F90 MPI includes a module, and if you use it, the right thing happens
in this case.
BTW, you are still using the words "passed by reference" incorrectly.
The F77 interface assumes that arrays are contiguous and are not
passed using dope vectors. The concept of "pass by reference" does not
exist in the Fortran world.
-- greg
| |
| glen herrmannsfeldt 2008-03-18, 7:21 pm |
| James Van Buskirk wrote:
(snip on copy of subprogram arguments)
> We have had a way since the standard started requiring the copies.
> Just declare both actual and dummy arguments to have the TARGET
> attribute and point one pointer at an element of the actual argument
> and another at the corresponding element of the dummy argument. Test
> with the ASSOCIATED intrinsic whether the pointers are associated
> with each other. If so, no copy. If not, the dummy argument is a
> copy of the actual argument.
You mean pass a pointer as an additional argument to the
called routine? It seems easier to just pass a pointer in
the first place. Does the standard guarantee not to make
a copy and pass a pointer to the copy?
-- glen
| |
| Dick Hendrickson 2008-03-18, 10:19 pm |
| James Van Buskirk wrote:
> "Fei Liu" <fei.liu@gmail.com> wrote in message
> news:47E01DF6.5060409@gmail.com...
>
>
> We have had a way since the standard started requiring the copies.
> Just declare both actual and dummy arguments to have the TARGET
> attribute and point one pointer at an element of the actual argument
> and another at the corresponding element of the dummy argument. Test
> with the ASSOCIATED intrinsic whether the pointers are associated
> with each other. If so, no copy. If not, the dummy argument is a
> copy of the actual argument.
>
If I'm remembering the right thing, there was an interpretation
in th 90s (that took 5 or so years to get right) that effectively
disallows copy-in/copy-out when both the actual and dummy have
the target attribute. That means that in your example, ASSOCIATED
must return true. Otherwise, it would make no sense to allow both
the actual and target to have the pointer attribute if pointers
to the same element didn't point to the same element ;).
Dick Hendrickson
| |
| James Van Buskirk 2008-03-18, 10:19 pm |
| "Dick Hendrickson" <dick.hendrickson@att.net> wrote in message
news:GbZDj.42234$cQ1.38514@bgtnsc04-news.ops.worldnet.att.net...
> If I'm remembering the right thing, there was an interpretation
> in th 90s (that took 5 or so years to get right) that effectively
> disallows copy-in/copy-out when both the actual and dummy have
> the target attribute. That means that in your example, ASSOCIATED
> must return true. Otherwise, it would make no sense to allow both
> the actual and target to have the pointer attribute if pointers
> to the same element didn't point to the same element ;).
That's not quite right. If the dummy argument is assumed shape and
both dummy and actual arguments have the TARGET attribute, then the
compiler can't do a copy due to the rules about pointer association,
unless the actual argument is an array section with a vector
subscript. See N1601.pdf, section 12.4.1.2. If the dummy argument
is explicit shape or assumed size and the actual argument is
discontiguous, then a copy must be made even if both dummy and
actual arguments have the TARGET attribute because the rules of
sequence association require the dummy to be contiguous. We see
that behavior in the following example:
C:\gfortran\clf\assoc_test>type assoc_test.f90
module mykinds
implicit none
integer, parameter :: dp = selected_real_kind(15,300)
end module mykinds
module funcs_n_stuff
use mykinds
implicit none
real(dp), pointer :: pA
real(dp), pointer :: pB
contains
subroutine test_explicit(x, n)
integer, intent(in) :: n
real(dp), target :: x(n)
pB => x(1)
write(*,'(a)') 'In subroutine test_explicit: pointers '// &
trim(merge('are ', 'are not', associated(pA, pB)))// &
' associated'
end subroutine test_explicit
subroutine test_assumed(x)
real(dp), target :: x(:)
pB => x(1)
write(*,'(a)') 'In subroutine test_assumed: pointers '// &
trim(merge('are ', 'are not', associated(pA, pB)))// &
' associated'
end subroutine test_assumed
subroutine test_contiguous(x, n)
integer, intent(in) :: n
real(dp), target :: x(n)
pA => x(1)
write(*,'(a)') 'Invoking test_explicit from test_contiguous'
call test_explicit(x, n)
write(*,'(a)') 'Invoking test_assumed from test_contiguous'
call test_assumed(x)
end subroutine test_contiguous
subroutine test_discontiguous(x)
real(dp), target :: x(:)
pA => x(1)
write(*,'(a)') 'Invoking test_explicit from test_discontiguous'
call test_explicit(x, size(x))
write(*,'(a)') 'Invoking test_assumed from test_discontiguous'
call test_assumed(x)
end subroutine test_discontiguous
end module funcs_n_stuff
program assoc_test
use mykinds
use funcs_n_stuff
implicit none
real(dp), target :: x(10)
x = 0
write(*,'(a)') 'Invoking test_contiguous with a contiguous array'
call test_contiguous(x, size(x))
write(*,'(/a)') 'Invoking test_contiguous with a discontiguous array'
call test_contiguous(x(::2), size(x(::2)))
write(*,'(/a)') 'Invoking test_discontiguous with a contiguous array'
call test_discontiguous(x)
write(*,'(/a)') 'Invoking test_discontiguous with a discontiguous array'
call test_discontiguous(x(::2))
end program assoc_test
C:\gfortran\clf\assoc_test>c:\gfortran\win64\bin\x86_64-pc-mingw32-gfortran
asso
c_test.f90 -oassoc_test
C:\gfortran\clf\assoc_test>assoc_test
Invoking test_contiguous with a contiguous array
Invoking test_explicit from test_contiguous
In subroutine test_explicit: pointers are associated
Invoking test_assumed from test_contiguous
In subroutine test_assumed: pointers are associated
Invoking test_contiguous with a discontiguous array
Invoking test_explicit from test_contiguous
In subroutine test_explicit: pointers are associated
Invoking test_assumed from test_contiguous
In subroutine test_assumed: pointers are associated
Invoking test_discontiguous with a contiguous array
Invoking test_explicit from test_discontiguous
In subroutine test_explicit: pointers are associated
Invoking test_assumed from test_discontiguous
In subroutine test_assumed: pointers are associated
Invoking test_discontiguous with a discontiguous array
Invoking test_explicit from test_discontiguous
In subroutine test_explicit: pointers are not associated
Invoking test_assumed from test_discontiguous
In subroutine test_assumed: pointers are associated
When subroutine test_discontiguous received a discontiguous dummy
argument and passed it to subroutine test_explicit as an actual
argument, it had to perform a copy. If the dummy argument is
explicit shape or assumed size and the actual argument is
contiguous, it's up to the compiler to decide, perhaps at runtime,
whether or not to make a copy.
--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end
| |
|
| > To sum things up, we still don't have a portable (standard conforming)
> way to tell if compiler has copied data during run time or passed a
> reference for a F90/95/2003 subroutine/function interface? If that's the
> case, so be it.
Looking at the code that you typed above, I can realize that all the
misunderstanding comes from you wrong idea of how the data are passed
to subroutines.
Let me rewrite a shorter version of your code, with added comments, to
explain what happens.
program copy
real, dimension(5,10) :: fa
fa = 0
fa(3, 3) = 10
fa(5, 8) = 5
! Below we pass to the contained subroutine usarray2
! a rank 2 array with shape (/ 3, 4 /), coinciding with the
section
! of fa with first index from 2 to 4 and second index from 5 to
8.
! It is up to the compiler to decide if it has to create a
temporary
! copy where usarray2 will work and then to copy the result back
into fa,
! or to decide to to pass a descriptor to access directly
! the section of fa. The final result is independent of the
choice of the
! compiler.
! Note that the compiler DOES NOT pass a pointer to a memory
location,
! but it must pass a description of the array to access exactly
the
! section fa(2:4,5:8).
!
! Instead if you want to cheat the compiler, so that the caller
believes
! to pass a (reference to) a scalar value, but the called
subroutine
! access the nearby data as if it received an array, you must use
! an implicit interface, so that the compiler cannot either
detect the
! mismatch nor it can optimize the use of the memory.
call usearray2(fa(2:4, 5:8) )
print *, 'fa(5, 8) = ', fa(5, 8)
! print fa(4,7) if you want to see what happened.
contains
subroutine usearray2(fa)
real, dimension(3, 4) :: fa
! Note: this subroutine deals with the dummy argument fa. The
dummy
! fa cannot access the component (5,8) of the original array fa,
because
! only the section fa(2:4,5:8) has been passed.
fa(3, 3) = 23
! The element (3,3) of the dummy argument fa coincides with
! the element (4:7) of the actual argument.
end subroutine
| |
| Fei Liu 2008-03-19, 7:15 pm |
| Ugo wrote:
>
> Looking at the code that you typed above, I can realize that all the
> misunderstanding comes from you wrong idea of how the data are passed
> to subroutines.
> Let me rewrite a shorter version of your code, with added comments, to
> explain what happens.
>
> program copy
>
> real, dimension(5,10) :: fa
> fa = 0
> fa(3, 3) = 10
> fa(5, 8) = 5
>
> ! Below we pass to the contained subroutine usarray2
> ! a rank 2 array with shape (/ 3, 4 /), coinciding with the
> section
> ! of fa with first index from 2 to 4 and second index from 5 to
> 8.
> ! It is up to the compiler to decide if it has to create a
> temporary
> ! copy where usarray2 will work and then to copy the result back
> into fa,
> ! or to decide to to pass a descriptor to access directly
> ! the section of fa. The final result is independent of the
> choice of the
> ! compiler.
> ! Note that the compiler DOES NOT pass a pointer to a memory
> location,
> ! but it must pass a description of the array to access exactly
> the
> ! section fa(2:4,5:8).
> !
> ! Instead if you want to cheat the compiler, so that the caller
> believes
> ! to pass a (reference to) a scalar value, but the called
> subroutine
> ! access the nearby data as if it received an array, you must use
> ! an implicit interface, so that the compiler cannot either
> detect the
> ! mismatch nor it can optimize the use of the memory.
>
> call usearray2(fa(2:4, 5:8) )
>
> print *, 'fa(5, 8) = ', fa(5, 8)
> ! print fa(4,7) if you want to see what happened.
>
> contains
>
> subroutine usearray2(fa)
> real, dimension(3, 4) :: fa
> ! Note: this subroutine deals with the dummy argument fa. The
> dummy
> ! fa cannot access the component (5,8) of the original array fa,
> because
> ! only the section fa(2:4,5:8) has been passed.
> fa(3, 3) = 23
> ! The element (3,3) of the dummy argument fa coincides with
> ! the element (4:7) of the actual argument.
> end subroutine
You are right, there was a coding error in my code sample,
I should print fa(5, 7) instead but it does not change the result. I
know copying is going to happen regardless, what I am looking for is a
portable way of detecting copy happening.
Fei
| |
| Paul van Delst 2008-03-19, 7:15 pm |
| Fei Liu wrote:
> [...] what I am looking for is a portable way of detecting copy happening.
Depending on your definition of "portable", I think those two things are mutually exclusive.
cheers,
paulv
| |
| Fei Liu 2008-03-19, 7:15 pm |
| James Van Buskirk wrote:
> "Dick Hendrickson" <dick.hendrickson@att.net> wrote in message
> news:GbZDj.42234$cQ1.38514@bgtnsc04-news.ops.worldnet.att.net...
>
>
> program assoc_test
> use mykinds
> use funcs_n_stuff
> implicit none
> real(dp), target :: x(10)
>
> x = 0
> write(*,'(a)') 'Invoking test_contiguous with a contiguous array'
> call test_contiguous(x, size(x))
> write(*,'(/a)') 'Invoking test_contiguous with a discontiguous array'
> call test_contiguous(x(::2), size(x(::2)))
> write(*,'(/a)') 'Invoking test_discontiguous with a contiguous array'
> call test_discontiguous(x)
> write(*,'(/a)') 'Invoking test_discontiguous with a discontiguous array'
> call test_discontiguous(x(::2))
> end program assoc_test
>
Hi James, what is x(::2)? I have never seen array subscript used this way.
Fei
| |
| Fei Liu 2008-03-19, 7:15 pm |
| Fei Liu wrote:
> James Van Buskirk wrote:
> Hi James, what is x(::2)? I have never seen array subscript used this way.
>
> Fei
Ok, nvm, I found it is the vector subscript (1,3,5..lb+2*k).
Fei
| |
| Richard Maine 2008-03-19, 7:15 pm |
| Fei Liu <fei.liu@gmail.com> wrote:
> Hi James, what is x(::2)? I have never seen array subscript used this way.
That's an array slice (aka section). Array slice notation is really much
like DO loops. There are 3 controlling numbers - a starting value, an
ending value, and a step. The step defaults to 1 and is often omitted
(because the default is often what you want) in both DO loops and array
slices. The start and end values for an array slice are the forst and
last index values for the array; there isn't anything comparable to that
for DO loops.
Filling in the default values, x(::2) translates into
x(lower_bound_of_x:upper_bound_of_x:2), which in turn means the slice
formed by taking every 2nd element, starting with the first element of
the array.
--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain
| |
|
| > You are right, there was a coding error in my code sample,
>
> I should print fa(5, 7) instead but it does not change the result. I
> know copying is going to happen regardless, what I am looking for is a
> portable way of detecting copy happening.
Ok, you should print fa(4,7), not fa(5,7).
Probably I was not clear enough.
Just run the following code and see.
Note that MPI does not deal with shared memory: all the parallel
calculations happen inside local images. I still cannot figure out how
can you get troubles with the serial calculations done by the
different images of MPI.
program copy
real, dimension(5,10) :: fa
fa = 0
fa(3, 3) = 10
fa(5, 8) = 5
call usearray2(fa(2:4, 5:8) )
print *, 'This must be 10.0: fa(5, 8) = ', fa(5, 8)
print *, 'This must be 23.45678: fa(4,7) = ', fa(4,7)
contains
subroutine usearray2(fa)
real, dimension(3, 4) :: fa
fa(3, 3) = 23.45678
end subroutine usearray2
end program copy
| |
| Fei Liu 2008-03-20, 7:15 pm |
| Ugo wrote:
>
> Ok, you should print fa(4,7), not fa(5,7).
> Probably I was not clear enough.
> Just run the following code and see.
>
> Note that MPI does not deal with shared memory: all the parallel
> calculations happen inside local images. I still cannot figure out how
> can you get troubles with the serial calculations done by the
> different images of MPI.
>
> program copy
> real, dimension(5,10) :: fa
> fa = 0
> fa(3, 3) = 10
> fa(5, 8) = 5
you mean fa(5, 8) = 10?
> call usearray2(fa(2:4, 5:8) )
> print *, 'This must be 10.0: fa(5, 8) = ', fa(5, 8)
> print *, 'This must be 23.45678: fa(4,7) = ', fa(4,7)
>
> contains
>
> subroutine usearray2(fa)
> real, dimension(3, 4) :: fa
> fa(3, 3) = 23.45678
> end subroutine usearray2
>
> end program copy
Yes, in this case the compiler copied the result back. But imagine
inside usearray2, fa is again passed to another subroutine and
participated in asynchronous IO. usearray2%fa could go out of scope
before IO finished. If instead a descriptor (reference) was used, there
won't be scoping problem.
Fei
| |
| glen herrmannsfeldt 2008-03-20, 7:15 pm |
| Fei Liu wrote:
(snip regarding array copies for subroutine calls)
> Yes, in this case the compiler copied the result back. But imagine
> inside usearray2, fa is again passed to another subroutine and
> participated in asynchronous IO. usearray2%fa could go out of scope
> before IO finished. If instead a descriptor (reference) was used, there
> won't be scoping problem.
I think scope is the wrong word here. Scope refers to what is visible
at any point in the program. That is often independent of what is
actually available in memory.
As I said before, Fortran 2003 has the ASYNCHRONOUS attribute to
tell the compiler which variables might be used asynchronously,
such as with Fortran 2003 ASYNCHRONOUS I/O statements. I would
expect compilers implementing that not to make a copy when it
isn't needed and to fail to compile when it is.
From your example: call usearray2(fa(2:4, 5:8) )
Unless the called routine has an assumed shape dummy the standard
pretty much requires a copy in this case. If you don't want one,
copy the array section to a contiguous array before the call.
There are cases where the compiler can't tell if an array is
contiguous, in which case many will make a copy. Others might
make the copy conditionally on the array being non-contiguous.
-- glen
| |
| Fei Liu 2008-03-21, 7:20 pm |
| glen herrmannsfeldt wrote:
> Fei Liu wrote:
>
> (snip regarding array copies for subroutine calls)
>
>
> I think scope is the wrong word here. Scope refers to what is visible
> at any point in the program. That is often independent of what is
> actually available in memory.
scope is a very formal description of variable lifetime in most high
level languages. It is not just visibility, it's also lifetime of a
variable.
>
> As I said before, Fortran 2003 has the ASYNCHRONOUS attribute to
> tell the compiler which variables might be used asynchronously,
> such as with Fortran 2003 ASYNCHRONOUS I/O statements. I would
> expect compilers implementing that not to make a copy when it
> isn't needed and to fail to compile when it is.
>
> From your example: call usearray2(fa(2:4, 5:8) )
>
> Unless the called routine has an assumed shape dummy the standard
> pretty much requires a copy in this case. If you don't want one,
> copy the array section to a contiguous array before the call.
>
> There are cases where the compiler can't tell if an array is
> contiguous, in which case many will make a copy. Others might
> make the copy conditionally on the array being non-contiguous.
>
> -- glen
>
I did try the asynchronous attribute, it worked fine and could
potentially solve my problem. Unfortunately, only 1 compiler recognizes
this F2003 keyword use, most simply bail out at compile time too. :(
Fei
| |
| Jan Vorbrüggen 2008-03-26, 8:15 am |
| > To sum things up, we still don't have a portable (standard conforming)
> way to tell if compiler has copied data during run time or passed a
> reference for a F90/95/2003 subroutine/function interface?
I thought the standard was written on the assumption that a
standard-conforming program cannot detect that difference. James's
TARGET trick seems to negate that assumption.
In any case, I believe your problem with MPI is not a problem with
Fortran, but with the asynchronous features of MPI. If you need to
enforce constraints that might be true "by magic" in other languages,
but not in Fortran, you should make them explicit in the code anyway -
in this particular case by forcing copies in the code explicitly.
Jan
| |
| glen herrmannsfeldt 2008-03-26, 7:45 pm |
| Jan Vorbrüggen wrote:
(snip)
> I thought the standard was written on the assumption that a
> standard-conforming program cannot detect that difference. James's
> TARGET trick seems to negate that assumption.
> In any case, I believe your problem with MPI is not a problem with
> Fortran, but with the asynchronous features of MPI.
It seems that ASYNCHRONOUS is a property of Fortran 2003.
-- glen
|
|
|
|
|