For my first post, I thought I’d post the results of a small experiment I ran today and ask for some help interpreting the results.
Due to the nature of the project I’m working on, I’ve been spending a fair bit of time reshaping arrays. I’m doing it enough that I thought I’d figure out if I could spend less time reshaping arrays so I thought I’d compare three ways of changing the data access topology: the reshape() intrinsic, the transfer() intrinsic, and the equivalence statement. The source is included at the end of this post.
I compiled with gfortran using only the -O3 flag (compiler optimization settings did not seem to affect the rankings here). In each case, I ran the program using the “time” command to help to give me assurance that I wasn’t hiding computing work from my cpu_time() calls.
Here are my results:
$ time ./a.out #equivalence Elapsed time: 3.0000000000030003E-006 sec real 0m0.972s user 0m0.096s sys 0m0.869s $ time ./a.out #transfer Elapsed time: 0.28676800000000002 sec real 0m1.290s user 0m0.159s sys 0m1.082s $ time ./a.out #reshape Elapsed time: 0.13298499999999999 sec real 0m1.099s user 0m0.115s sys 0m0.966s
I expected equivalence to beat the pants off the other two since it’s not a function call but a memory addressing instruction, and indeed it did. What surprised me was that even reshape was faster than transfer for this application.
This leads me to the question: WHY is transfer() preferred in modern Fortran over equivalence when equivalence is so much faster, especially on large datasets and avoids making a copy of the underlying data, which transfer() seems to do?
What’s so bad about equivalence that it is being treated as archaic, when it seems to perform a useful function that would otherwise not be available in Fortran and can avoid copying large datasets if one doesn’t want to? Shouldn’t there be room for both transfer() and equivalence in the toolbox?
EDIT: A minor update: I found some stackoverflow posts about linear indexing of multidimensional arrays using pointers, which is probably better than using equivalence for this purpose. I’d expect the pointers to work as quickly as equivalence.
program transfer_test implicit none integer :: square_array(10**4,10**4), lin_array(10**8) real(8) :: t1,t2 !! UNCOMMENT THE APPROPRIATE LINE ! equivalence (lin_array, square_array) square_array = 1 call cpu_time(t1) ! lin_array = transfer(square_array,square_array) ! lin_array = reshape(square_array,[10**8]) call cpu_time(t2) print *, "Elapsed time: ", t2-t1, " sec" ! write to make code observable open(50,file='.dummyfile',status='replace',access='stream') write(50)lin_array write(50)square_array close(50) end program transfer_test