Intel® Fortran Compiler 17.0 Developer Guide and Reference
OpenMP* Fortran Compiler Directive: Specifies that the iterations of the immediately following DO loop must be executed in parallel.
!$OMP DO [clause[[,] clause] ... ]
do_loop
[!$OMP END DO [NOWAIT]]
clause |
Is one of the following:
|
||||||||||||||||||||||||
do_loop |
Is a DO iteration (an iterative DO loop). It cannot be a DO WHILE or a DO loop without loop control. The DO loop iteration variable must be of type integer. The iterations of the DO loop are distributed across the existing team of threads. The values of the loop control parameters of the DO loop associated with a DO directive must be the same for all the threads in the team. You cannot branch out of a DO loop associated with a DO directive. |
The binding thread set for a DO construct is the current team. A DO loop region binds to the innermost enclosing parallel region.
If used, the END DO directive must appear immediately after the end of the loop. If you do not specify an END DO directive, an END DO directive is assumed at the end of the DO loop.
If you specify NOWAIT in the END DO directive, threads do not synchronize at the end of the parallel loop. Threads that finish early proceed straight to the instruction following the loop without waiting for the other members of the team to finish the DO directive.
Parallel DO loop control variables are block-level entities within the DO loop. If the loop control variable also appears in the LASTPRIVATE list of the parallel DO, it is copied out to a variable of the same name in the enclosing PARALLEL region. The variable in the enclosing PARALLEL region must be SHARED if it is specified in the LASTPRIVATE list of a DO directive.
Only a single SCHEDULE, COLLAPSE, or ORDERED clause can appear in a DO directive.
ORDERED (n) specifies how many loops are associated with the DO directive and it specifies that those associated loops form a doacross loop nest. n does not affect how the logical iteration space is divided.
If you specify COLLAPSE (M) ORDERED (N) for loops nested K deep, the following rules apply:
If either M > K or N > K, the behavior is unspecified.
N must be greater than M
A LINEAR clause or an ORDERED (n) clause can be specified on a DO directive but not both.
DO directives must be encountered by all threads in a team or by none at all. It must also be encountered in the same order by all threads in a team.
In the following example, the loop iteration variable is private by default, and it is not necessary to explicitly declare it. The END DO directive is optional:
!$OMP PARALLEL
!$OMP DO
DO I=1,N
B(I) = (A(I) + A(I-1)) / 2.0
END DO
!$OMP END DO
!$OMP END PARALLEL
If there are multiple independent loops within a parallel region, you can use the NOWAIT option to avoid the implied BARRIER at the end of the DO directive, as follows:
!$OMP PARALLEL
!$OMP DO
DO I=2,N
B(I) = (A(I) + A(I-1)) / 2.0
END DO
!$OMP END DO NOWAIT
!$OMP DO
DO I=1,M
Y(I) = SQRT(Z(I))
END DO
!$OMP END DO NOWAIT
!$OMP END PARALLEL
Correct execution sometimes depends on the value that the last iteration of a loop assigns to a variable. Such programs must list all such variables as arguments to a LASTPRIVATE clause so that the values of the variables are the same as when the loop is executed sequentially, as follows:
!$OMP PARALLEL
!$OMP DO LASTPRIVATE(I)
DO I=1,N
A(I) = B(I) + C(I)
END DO
!$OMP END PARALLEL
CALL REVERSE(I)
In this case, the value of I at the end of the parallel region equals N+1, as in the sequential case.
Ordered sections are useful for sequentially ordering the output from work that is done in parallel. Assuming that a reentrant I/O library exists, the following program prints out the indexes in sequential order:
!$OMP DO ORDERED SCHEDULE(DYNAMIC)
DO I=LB,UB,ST
CALL WORK(I)
END DO
...
SUBROUTINE WORK(K)
!$OMP ORDERED
WRITE(*,*) K
!$OMP END ORDERED
In the next example, the loops over J1 and J2 are collapsed and their iteration space is executed by all threads of the current team:
!$OMP DO COLLAPSE(2) PRIVATE(J1, J2, J3)
DO J1 = J1_L, J1_U, J1_S
DO J2 = J2_L, J2_U, J2_S
DO J3 = J3_L, J3_U, J3_S
CALL BAR(A, J1, J2, J3)
ENDDO
ENDDO
ENDDO
!$OMP END DO