Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Pointing to concurrent variables

zp3
Beginner
1,023 Views

Hi,

I'ld like to ask if it's save to point to concurrent variables outside a concurrent construct and use the pointer inside the concurrent construct. E.g.:

...
integer :: m,n
integer, target :: i, k
integer, pointer :: ip, kp
real :: mat(m0,n0)
...
if (something) then
   ip => i
   kp => k
   m=m0;n=n0
else
   ip => k
   kp => i
   m=n0;n=m0
end if
...
do concurrent(k=1:n)
   ...
   do i=1,m
      mat(ip,kp)=...
   end do
end do
...

I've read somewhere:


If a pointer is used in an iteration other than in the case of pointer assignment, allocation, or nullification, it must either be previously pointer associated during that iteration or must not have its pointer association changed during any other iteration. A pointer that has its pointer association changed in more than one iteration has an undefined association status when the construct terminates.

If I understood this correctly, then I do not change the association status in any iteration and so the code above should be legit. On the other hand this seems a bit strange to me, because this implicates that the compiler probably has to replicate also the pointer (even if it never changes within a iteration) and to reassign it to its newly created (also replicated), previously defined target. This would further mean, that the compiler has to check all present pointers if they may be assigned to any iteration-local variable and if so, to set them iteration-local too and to reassign them. This looks like a lot of work to me...
A solution to my understanding problem might be if the compiler would treat the pointer more like an alias and substitutes the actual variable back before expanding them into any concurrent context...

Thanks for any help!

 

0 Kudos
1 Solution
Steve_Lionel
Honored Contributor III
1,023 Views

I showed this to Malcolm Cohen, and his first reaction was "This calls out for that keyboard option that electrocutes the user..."

What we eventually concluded was that because I has TARGET and that there are pointers referenced inside the DO CONCURRENT, the DO CONCURRENT effectively has to run serially, though the iterations can be in any order. The rules of the language effectively prohibit parallelization in this case. I can't be localized so one of the pointers remains pointing to it, and that at then end of the DO CONCURRENT I has the value M+1.

Remember that DO CONCURRENT does not guarantee parallelization.

View solution in original post

0 Kudos
14 Replies
jimdempseyatthecove
Honored Contributor III
1,023 Views

Steve L may have a better answer than mine. Due to undefined behavior... IMHO

The k and i _prior_ to the do concurrent are in the scope outside that of the do concurrent, thus ip and kp will point to the memory location of the out of scope i and k or k and i as the case may be.

Inside the do concurrent, the compiler may be free to re-scope i and k:

a) construct new k(s) that are independent for use by each concurrency
b) construct new i(s)  that are independent for use by each concurrency

Note, it is of my opinion that ip and kp will be the same values for all concurrent executions. Though different implementations are free to do things differently.

Jim Dempsey

0 Kudos
Steve_Lionel
Honored Contributor III
1,023 Views

The variable K in the DO CONCURRENT has "construct scope" and is NOT the same K as used outside the DO CONCURRENT. IP and KP will be whatever they point to and are simply referenced as subscripts to MAT - neither one points to the DO CONCURRENT index.  The value of I does change, but IP and KP point to whatever storage they pointed to outside the loop, so there's really very little of interest here. Since IP and KP are from outside the DO CONCURRENT, the pointers themselves are shared across the iterations and nothing needs to be duplicated.

Am I misunderstanding the question?

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,023 Views

I think so. Our answers are in agreement.

Jim Dempsey

0 Kudos
Steve_Lionel
Honored Contributor III
1,023 Views

Almost. I is not free to be "rescoped", and K MUST be rescoped.

0 Kudos
zp3
Beginner
1,023 Views

Ok, thanks for all your answers!

I've read a bit of the F2015 working draft and found out that it's now possible to define the locality of variables explicitly in a do concurrent construct. Like in OMP it's now possible (for example), defining a variable LOCAL_INIT. To quote the standard:

a variable with LOCAL_INIT locality has the allocation, pointer association, and definition status of the outside variable with that name

If I understood this correctly, than allocatables get replicated (=locally allocated + initialized with original content) and pointers get replicated (=locally associated with all the same outside target)?

If my understanding is correct, than unlike in OMP it's not possible to associate the pointer as intended outside the iterations. In OMP I could do something like:

...
integer :: m,n
integer, target :: i, k
integer, pointer :: ip, kp
real :: mat(m0,n0)
...
if (something) then
   m=m0;n=n0
else
   m=n0;n=m0
end if
...
!$omp parallel shared(mat,m,n) private(i,k,ip,kp)
if (something) then
   ip => i
   kp => k
else
   ip => k
   kp => i
end if
!$omp do
do k=1,n
   ...
   do i=1,m
      mat(ip,kp)=...
   end do
end do
!$omp end do
!$omp end parallel
...

IMHO this would not be possible with do concurrent with its actual abilities and I'ld consider this as a weakness of the construct. The actual application of this code snippet would be to implement some kind of inline transposition (without the actual need of transposing the matrix or replicating the whole code fragment by manually switching indices).

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,023 Views

Steve Lionel (Ret.) wrote:

Almost. I is not free to be "rescoped", and K MUST be rescoped.

IMHO, I is rescoped in the sense that inside the DO I= loop (inside the DO CONCURRENT may play a part as well), the I may likely be regesterized, and as such will iterate without regard to updating the target of the pointer set in the outer scope. This said, at the end of the DO I=, the compiler is required to update the memory location referenced by I.

What I do not know, perhaps you know, is what the compiler requirements are when the loop control variable (I in this case) is aliased .OR. volatile.

The minimum requirement stated in the documentation is:

The DO variable must not be redefined or become undefined during execution of the DO range.

Which leads to the possibility that the DO variable is free of encumbrances.

Jim

0 Kudos
Steve_Lionel
Honored Contributor III
1,023 Views

In the code as supplied, the loop control variable I of the inner DO loop is NOT private to each CONCURRENT iteration and in fact gets redefined in each. This program is not legal. If you wanted to make it legal, you'd do something like this:

do concurrent(k=1:n)
   ...
   block
      integer i
      do i=1,m
         mat(ip,kp)=...
      end do
    end block
end do

Now I will be private to each concurrent iteration and the code will be legal. (Whether it does what is wanted, I am not sure.)

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,023 Views

I did not intend to indicate the inner DO loop was conforming, rather stating anticipated behavior. I should have prefaced this with non-conforming. However, the original programmer may have specifically designed a non-conforming loop. Insufficient information is provided to make this determination. Or, the loop was conforming... up until some programmer revised to code by adding a do concurrent(...), and by such, then introducing the non-conformance.

Jim Dempsey

0 Kudos
zp3
Beginner
1,023 Views

Steve Lionel (Ret.) wrote:

In the code as supplied, the loop control variable I of the inner DO loop is NOT private to each CONCURRENT iteration and in fact gets redefined in each.

Well, maybe I understood the standard the whole time wrong, but IMHO all variables that become defined in an iteration (like I in my example) are treated as local variables. This is (IMHO) the logical consequence of the following rule:

If a variable has unspecified locality, if it is referenced in an iteration it shall either be previously defined during that iteration, or shall not be defined or become undefined during any other iteration; if it is defined or becomes undefined by more than one iteration it becomes undefined when the loop terminates;

So I implicate, that when I define a variable in an iteration I may also reference this variable. Referencing a variable in an iteration that is non-local (shared) would lead to undefined behavior, as execution order is undefined. So, I conclude that such variables have to be somehow local. Together with:

execution of a DO statement causes the DO variable, if any, to become defined

I would say my code is legal.

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,023 Views

>>So I implicate, that when I define a variable in an iteration I may also reference this variable.

The point we were addressing is not the referencing of the variable I, but rather the alias to a memory/stack of I as it was outside the loop. Inside the loop, the compiler is free to manipulate/registerize the loop control variable as long as the operations within the loop are equivalent to an un-optimized loop of the same code. In the case of the loop control variable the alias and/or memory location are not necessarily updated until exit of loop.

Consider a loop generating vector instructions, I is not necessarily incremented by 1. And, for small loops, I is generally registerized.

0 Kudos
IanH
Honored Contributor II
1,023 Views

Steve Lionel (Ret.) wrote:

In the code as supplied, the loop control variable I of the inner DO loop is NOT private to each CONCURRENT iteration and in fact gets redefined in each. This program is not legal.

What is the specific restriction in the standard against such an arrangement?  I can't see one...

 

0 Kudos
Steve_Lionel
Honored Contributor III
1,023 Views

I was mistaken and confused - my apologies. 

In F2015 terms, I has "unspecified locality". The rule for this is:

"A variable that is referenced in an iteration shall either be previously defined during that iteration, or shall not be defined or become undefined during any other iteration. A variable that is defined or becomes undefined by more than one iteration becomes undefined when the loop terminates."

Since I is defined before use in each iteration, it becomes effectively private to that iteration and is separate from whatever IP or KP points to. The compiler has to recognize this. The interesting fallout from this case is that if N is more than 1, the I in the outer scope becomes undefined at the end of the DO CONCURRENT, otherwise it remains defined.

My earlier statement that K has "construct scope" and is different from whatever is pointed to by IP/KP remains true.

0 Kudos
IanH
Honored Contributor II
1,023 Views

Steve Lionel (Ret.) wrote:

Since I is defined before use in each iteration, it becomes effectively private to that iteration and is separate from whatever IP or KP points to. The compiler has to recognize this.

I'm not convinced that the standard appropriately deals with whether the pointer remains associated with the "effectively private" `i` or not.

 

 

 

0 Kudos
Steve_Lionel
Honored Contributor III
1,024 Views

I showed this to Malcolm Cohen, and his first reaction was "This calls out for that keyboard option that electrocutes the user..."

What we eventually concluded was that because I has TARGET and that there are pointers referenced inside the DO CONCURRENT, the DO CONCURRENT effectively has to run serially, though the iterations can be in any order. The rules of the language effectively prohibit parallelization in this case. I can't be localized so one of the pointers remains pointing to it, and that at then end of the DO CONCURRENT I has the value M+1.

Remember that DO CONCURRENT does not guarantee parallelization.

0 Kudos
Reply