1

I have a 1-dimensional work array

real(8), allocatable :: work(:)

which is passed to a subroutine that operates on a 2-dimensional array

pure subroutine f(work, dim1, dim2)
  real(8), intent(out) :: work(dim1, dim2)
  integer, intent(in) :: dim1, dim2
  ...

What is the difference in the following ways of passing the array?

call f(work, dim1, dim2)
call f(work(1), dim1, dim2)

Are they the same in that they just pass the pointer to the first array element or is there some extra overhead with either call? Are there more elegant ways in modern Fortran of passing an array whose shape needs to change, without passing the dimensions explicitly, but without taking a performance hit?

I know the above looks like old Fortran but I've found it faster than declaring a two-dimensional array in the parent subroutine and passing an array section, work(:dim1,:dim2), to f.

Raul Laasner
  • 1,475
  • 1
  • 17
  • 30
  • There are two quite different questions here, in a sense. [1)](http://stackoverflow.com/q/25000321) What is the difference between `work` and `work(1)`.as arguments? [2)](http://stackoverflow.com/q/24472907) How to have an array of one shape associated with a dummy as another shape? – francescalus Jan 23 '17 at 19:06
  • For your final point, if `work` is a rank-2 array, what happens if you pass `work` as a whole array, rather than the array section `work(:dim1,:dim2)`? – francescalus Jan 23 '17 at 19:08
  • Thanks. Inside the subroutine I'm doing things like calling a `dgemm` with `work(:dim1,:dim2)` as one of the arguments. If `work` were declared as a 2-dimensional array in the calling scope and the full array were passed, this would lead to an automatic creation of a temporary array. The point is that the dimensions can be different with every call, but I'm allocating the workspace only once. – Raul Laasner Jan 23 '17 at 20:27
  • 1
    In the specific example of `dgemm`, lapack is from the days of Fortran 77 and no dynamic memory. There are the arguments like `lda` with `a(lda,*)` so that one could indeed pass the whole array (which corresponded to the largest problem expected) along with the sub-array bounds. [That's all probably off-topic for your question where there's a perfectly good answer given already, but it may be something to consider in your work.] – francescalus Jan 23 '17 at 21:01

1 Answers1

4

Both example statements are forms of sequence association. The actual argument specifies a sequence of array elements, that are then associated with the elements of the dummy argument in array element order.

If work (in the calling scope) is allocated to non-zero size and has a lower bound of one, there is unlikely to be a practical difference in implementation.

In both cases, the programmer must ensure that the size of the dummy argument must be less than or equal to the size of the actual argument element sequence.

Using the whole array reference makes it clearer to readers (and perhaps the compiler) that it was the author's intent to pass an array element sequence, potentially including all the elements of the array. It also defends against the actual argument being zero size, or perhaps having a lower bound other than one.

The author's intent is far less clear when a reference to a specific element is used to designate an array element sequence.

In this specific case, because the actual argument is allocatable the compiler knows that the element sequence of the actual argument will be contiguous, and it can arrange for the dummy argument to be associated with the element sequence appropriately. In other cases, say if the actual argument was itself an assumed shape argument without the contiguous attribute, the compiler does not know that the element sequence is contiguous, and it may have to make a copy of the element sequence ahead of the call. This can have material performance impact - it is probably the reason why you found using a non-contiguous rank two array section as an actual argument to be slower.

IanH
  • 21,026
  • 2
  • 37
  • 59