- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear all,
I'm have rewritten a lot of our code from fortran 77 stype to fortran 2003. I'm making quite a lot of use the the array assignment with the "Array1(1:n) = Array2(1:n)" notation but appreantly it is using the stack create a temporary which causes stack overflows on bigger test cases. The compiler fails to see that no temporary array is needed for this simple statement probably because Array1 and Array2 are pointers. Basically I need to tell the compiler there two pointers are non-overlapping (like restrict does in C). Is this possible in fortran?
P.S. I use pointers everyware instead of allocateble because I need to be fully compatible with some legacy code and I need keep track of the memory consumption using special allocator object keeps a list of allocations and deallocated on the destructor of the allocator object (final subroutine).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Perhaps this is daft for other reasons, but [I think] you get the effect of restrict if the pointer things are passed as arguments to a procedure with non-target, non-pointer dummy arguments that does the assignment.
That is, an approach would be to run around and do all the fancy pointer assignments in a top level procedure, and then pass the allocated things to worker procedures that do all the real work with non-pointers.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is nothing exactly like "restrict" but the compiler does support the option /Qansi-alias (the name really comes from the C side) that can allow some additional optimization on pointers. I am not sure if it will help here.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
/Qansi-alias is enabled by default. So basically I have it replace all these array assignment by do loops?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I see that the documentation says it is the default, but I don't think that's true. But I did an experiment and it did not seem to help in this case. Too bad you can't use allocatable.
But try this - add the CONTIGUOUS attribute to the POINTER declaration - that improves the code in my testing.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
CONTIGUOUS would not preclude overlapping regions, thus may affect optimizations, although a runtime test could fix this.
Any thoughts of adding a !DIR$ to declare following statement or loop has no aliasing issues?
!DIR$ CONTIGOUS NOALIAS
Array1(1:n) = Array2(1:n) ! arrays are pointers
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
When you add CONTIGUOUS, we call a "fast_memcpy" routine to do the assignment rather than element-by-element. This can check for overlap and do the move in the necessary direction. I am not 100% certain it avoids the tenp but it might. Is it possible to remove the (1:N) in the subscript? If you're moving the whole array, you don't need that.
I will pass on your suggestion for a NOALIAS attribute for pointers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What reason did vec-report or opt-report give for not vectorizing? How did it compare with use of !dir$ simd (which prevents the compiler from substituting fast_memcpy)?
simd implies ignoring possibility of overlap. !dir$ ivdep is a less aggressive way to assert no overlap.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Perhaps this is daft for other reasons, but [I think] you get the effect of restrict if the pointer things are passed as arguments to a procedure with non-target, non-pointer dummy arguments that does the assignment.
That is, an approach would be to run around and do all the fancy pointer assignments in a top level procedure, and then pass the allocated things to worker procedures that do all the real work with non-pointers.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I can not remove the (1:N) because the Array1 is bigger then Array2. Basically my code is increasing the size of my arrays. The CONTIGUOUS attribute nor the CONTIGUOUS NOALIAS directive do not seem to work in my case.
vec-report:2 gives me the folowing output for this single line
remark: LOOP WAS VECTORIZED
remark: loop was not vectorized: vectorization possible but seems inefficient
remark: LOOP WAS VECTORIZED
remark: loop was not vectorized: not inner loop
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Creating a subroutine VectorCopy does solver my problem. I can even pass non contiguous subarray to the subroutine call without any problem. So no copy on the stack is done for a subroutine call I hope it won't create a copy on the heap instead. Is this correct?
call VectorCopy(Array1(1:n,1:m), Array2(1:n,1:m) ! with n < size(Array1,1)
P.S. is it possible to override the intrinsic assignment operators by my functions?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Could you try something like "Array1(1:n) = Array2(1:n)" becomes "call move_vector (Array1(1), Array2(1), n)" and
[fortran] subroutine move_vector (a,b,n)
integer n
real*8 a(n), b(n)
b = a
end subroutine move_vector
[/fortran]
It is Fortran 77 style and should not use the stack. I'm not sure if the subroutine would be optimised.
I'm assuming A and B are typical contiguous arrays.
If Array1 and Array2 overlap in memory, then you could test the start address of A and B and use a reverse DO loop if LOC(A) < LOC(B)
John
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Gert,
For statements like your equate, when a call to Intel's "fast_memcpy" is substituted, the compiler will not report that the code was vectorized.
IOW do not assume lack of vectorization is lack of optimization.
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John Campbell wrote:
Could you try something like "Array1(1:n) = Array2(1:n)" becomes "call move_vector (Array1(1), Array2(1), n)" and
subroutine move_vector (a,b,n) integer n real*8 a(n), b(n) b = a end subroutine move_vector
It is Fortran 77 style and should not use the stack. I'm not sure if the subroutine would be optimised.
I'm assuming A and B are typical contiguous arrays.
If Array1 and Array2 overlap in memory, then you could test the start address of A and B and use a reverse DO loop if LOC(A) < LOC(B)John
I'm missing part of your point, since whole-array assignment surely can't be called "Fortran 77 style." Without a pointer declaration, Fortran does require that the arguments of a subroutine don't overlap. ifort has an option to discard that provision of the standard (assume:dummy_aliases).
ifort and gfortran don't support reversing loops for vectorization in presence of data overlap. Oracle Fortran, and perhaps Open64, does (probably requiring some effort with c_loc, as you suggested). ifort treats LOC and c_loc as nearly interchangeable, but as you seem to refer to capabilities of other compilers, you should adhere to f2003. memmove(), according to the C definition, is usually built so as to do that. memmove() can be called from Fortran using iso_C_binding. That won't get you the Intel library version (unless you call it by the Internal Intel name).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Tim,
I thought the problem that was identified was that a temporary copy of the array sections were being placed on the stack, causing a stack overflow. The point of my suggestion was that:
1) the call move_vector (Array1(1), Array2(1), n) should not create a temporary copy, while
2) the subroutine, using the F77 approach to transfer the array dimensions, should be sufficient to allow ifort to consider arrays a and b as sized arrays and utilise instructions suitable for efficient transfers.
My comment about using LOC was in response to the original post reference to non-overlapping, as if this was not the case then a LOC test could also easily cover this possibility and make a more robust solution.
In the past, I have found the creation of temporary copies of array sections to cause this problem and also slow down the execution, where I expected they would not be required.
John
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page