Does using Assumed-Shape Arrays slow down a function/subroutine?

Dear all,

I have a question,
Does using Assumed-Shape Arrays slow down a function/subroutine?

Say I have an function f1

function f1(a)
real :: a(:)
xxxxx
end

Will this function f1 be slower than the function f2 below which put size n of a in the argument, or vice versa?

   function f2(a,n)
   real :: a(n)
   xxxxx
   end

Again, my function is just for illustration and by no mean it is accurate.

I actually just wanted to ask, guys, in your experiences,
which function/subroutine do you prefer from performance point of view, f1 or f2?
Especially consider that f1 and f2 may be in a big loop and will be called many many times, in such cases f1 and f2 which is better?
Or something else?

Thank you very much in advance!

2 Likes

This is an excellent question and also a long standing question and design in Fortran where opinions (still) differ. Read this discussion starting from roughly this comment: Fortran Best Practice Minibook - #8 by certik.

To answer which is faster, the traditional answer is that in the assumed shape (a(:)) case the compiler passes in an array descriptor, while in the explicit shape (a(n)) the compiler passes just a pointer and dimension n as an argument. Depending on how you call it, things might or might not be faster. Also in tight loops the compiler would inline the function so there shouldn’t be any difference.

Conclusion: if performance matters, then the function should be inlined in the loop, in which case both are probably equivalent. If performance does not matter, then the performance might slightly differ, e.g., if you are passing strided arrays, then explicit shape might be faster, if you are passing contiguous arrays that somehow do not have an array descriptor in the caller (such as another subroutine with explicit shape), then the explicit shape might be slightly faster.

Our plan with LFortran is to do things like function inlining at the ASR level, and be able to print it as Fortran source code, so that one can check what exactly the compiler is doing and ensure optimal code is generated (inlined in this case). Currently we decided to pass an array descriptor for all arrays, including explicit shape. We will experiment with different approaches later.

4 Likes

@CRquantum ,

The situation is really YMMV depending on the processor, any attempt at any generalization can be legitimately challenged.

But my experience suggests any performance difference in terms of assumed-shape vis-a-vis other options (assumed size, explicit shape, etc,) is likely going to be small, so much so that overlooking the benefits of assumed-shape for such gains will be akin to penny wise, pound foolish.

4 Likes

Yes. And for that reason it seems we mostly agree to recommend assumed shape arrays by default: Arrays - Fortran Programming Language.

1 Like

@certik Thank you very much!
Just a stupid question, I took an example from
https://fortran-lang.org/learn/best_practices/arrays

subroutine f(r)
  real(dp), intent(out) :: r(:)
  integer :: n, i
  n = size(r)
  do i = 1, n
    r(i) = 1.0_dp / i**2
  end do
end subroutine f

If an array A, start from, say, index -100. Then I put A into f(A), will f(A) crash?
Or, is it that, no matter what A’s index begins from, whenever we do f(A), f automatically convert A into r, such that r’s index is from 1, so the actual index A does not matter?
Sorry this is really a lazy question and I should actually try it myself. Just curious :sweat_smile:

for the

do i = 1, n 

I may write things like,

do i = lbound(r),  lbound(r) + n -1 

Anyway, I believe you have explained it somewhere in
https://fortran-lang.org/learn/best_practices/arrays
and I will check out.