This chapter documents your control of Power Fortran using driver options, directives, and assertions.
You use f90 driver options to control the operations of Power Fortran. This topic discusses the options that are unique to Power Fortran. (For other driver options, see the MIPSpro Fortran 90 Programmer's Guide.) This chapter discusses the driver options in functional groups. For a summary ordered alphabetically, see Appendix C, “Power Fortran Driver Options.”
The –concurrentize option (or –conc) directs Power Fortran to convert eligible loops to run in parallel. This option is assumed when the -pfa option is used to enable Power Fortran.
Use –noconcurrentize option (or –nconc) to prevent Power Fortran from converting loops, while still applying scalar optimizations.
You can use the C*$*NOCONCURRENTIZE directive to prevent transformation of a particular loop (see “C*$*[NO]CONCURRENTIZE”).
The –minconcurrent=n option (or –mc=n) specifies the minimum amount of work that must be found inside any loop in order for it to be profitable to execute the loop in parallel. The positive integer n is a count of the number of operations (for example, add, multiply, load, store) in the loop, multiplied by the number of times the loop will be executed.
The default value is 500 or more operation. The higher the value for n, the larger (more iterations, more statements, or both) the loop body must be, to be run in parallel. You can set the threshold for a particular loop using the C*$* MINCONCURRENT(n) directive.
When the loop bounds are known at compile time (that is, when they are constants), Power Fortran can compute the exact iteration count and decide whether to run the loop in parallel. Loops that are too small are not parallelized.
When the loop bounds are undefined at compile time, Power Fortran adds an IF clause to the generated parallel directive. This clause tests at run-time if sufficient work exists. If not, the loop runs serially.
To disable testing the work threshold throughout the program, specify –minconcurrent=0. You can disable the threshold for a specific loop using the C*$* MINCONCURRENT(0) directive.
The loop in Example 3-1 executes an unpredictable amount of work.
subroutine minc(x,y,z,n)
integer n
real x(n),y(n),z(n)
do i = 1,n
x(i) = y(i)*z(i)
end do
end
|
Power Fortran generates the transformed loop shown in Example 3-2.
DIR 1 # 1 "pfa7.f90"
1 subroutine MINC ( X, Y, Z, N )
I 1 integer N, I
I 1 real X(N), Y(N), Z(N)
I 4 C$PAR parallel if (N .gt. 200) shared (N,X,Y,Z) local (I)
I 4 CSGI$ startloop 3
I 4 C$PAR pdo
LM I C +--------- 4 do 2 I=1,N
* 5 X(I) = Y(I) * Z(I)
I *_________ 6 2 continue
I 6 C$PAR end pdo nowait
I 6 CSGI$ endloop 3
I 6 C$PAR end parallel
7 end
|
The IF clause in the C$PAR directive at line 4 is executed at runtime. It tests whether there are the default 500 operations in the loop body (apparently Power Fortran counts 2.5 operations in statement 5). Each time this subroutine is entered the test is made and, when n>200, the loop executes in parallel. Otherwise, it runs serially
The –parallelio option (or –pio) enables the parallelization of loops that contain I/O statements. The -parallelio=no is the default. Use this option only on systems with parallel I/O capabilities or where you are sure that I/O statements in a parallelized loop are not executed.
The –limit=n option (or –lm=n) controls the amount of time Power Fortran can spend trying to determine whether a loop is safe to run in parallel. The limit n does not correspond to the DO loop nest level. It is an estimate of the number of loop orderings that Power Fortran could generate from a loop nest.
Power Fortran estimates how much time is required to analyze each nest of loops. If an outer loop looks as if it would take too much time to analyze, Power Fortran ignores the outer loop and recursively visits the inner loops.
Larger limits can allow Power Fortran to generate parallel code for deeply nested loop structures that it might not otherwise be able to run safely in parallel. However, with larger limits Power Fortran can also take more time to analyze a program.
You can set the same limit either globally or for a particular part of the source module using the C*$* LIMIT(n) directive.
The –optimize=n option (or –o=n) sets the optimization level. The higher you set the optimization level, the more code is optimized and the longer compilation takes Valid values for n are:
0 | Disables optimization; no loops are converted. |
1 | Converts loops to run in parallel without using advanced data dependence tests. Enables loop interchanging. |
2 | Determines when scalars need last-value assignment using lifetime analysis. Also uses more powerful data dependence tests to find loops that can run safely in parallel. This level allows reductions in loops that execute concurrently but only if the –roundoff option is set to 2 (see “Reductions” for discussion of –roundoff.) |
3 | Recognizes triangular loops and attempts loop interchanging to improve memory referencing. Uses special case data dependence tests. Also, recognizes special index sets called wraparound variables. |
4 | Generates two versions of a loop, if necessary, to break a data dependence arc. This level also implements more-exact data dependence tests and allows special index sets (called wraparound variables) to convert more code to run in parallel. |
5 | Fuses two adjacent loops if it is legal to do so (that is, there are no data dependencies) and if the loops have the same control values. In certain limited cases, this level recognizes arrays as local variables. This level is the default. |
The same option is supported when Power Fortran is not invoked, to control scalar optimizations (refer to Chapter 4 of the MIPSpro Fortran 90 Programmer's Guide). You can set the optimization level with global use of the C*$* OPTIMIZE(n) directive.
The –roundoff=n option (or –r=n) controls the amount of variation in round off that Power Fortran will allow as a result of the different order of execution between parallel and serial loops. Valid values for n are the following integers:
0, 1 | Suppresses any round-off transformations. This is the default. |
2 | Allows reductions to be performed in parallel.This value is one of the most commonly-specified user options. |
3 | Recognizes REAL induction variables. Permits memory management transformations (refer to the MIPSpro Fortran 90 Programmer's Guide for details.) |
See “Reductions” for an example.
Function and subroutine calls create an obstacle to parallelization. Power Fortran provides three ways of dealing with this obstacle:
Assert that the external routine is safe for concurrent execution (see “C*$* ASSERT CONCURRENT CALL”).
Inline the routine by replacing the call to the external routine with the actual code.
Perform interprocedural analysis (IPA) by analyzing the external routine ahead of time and using the results of that analysis when a reference to the routine is encountered.
Inlining and IPA tend to be slow, memory-intensive operations. Attempting to inline all routines everywhere they occur can take a lot of time. Inlining should usually be restricted to a few time-critical places. For details about inlining and IPA, and the related directives and command line options, refer to the MIPSpro Fortran 90 Programmer's Guide.
Power Fortran does not check the correctness of assertions. Directives inserted into a source module and then forgotten can cause unexpected results that contradict the driver options you employ. If you specify that an untrue assertion or unwanted directive is causing problems, you can control the interpretation of directives and assertions in three ways.
Use the –nodirectives driver option to cause all directives to be treated as comments.
Use the -directives=list driver option to selectively prevent or allow the interpretation of Cray, VAST, and SGI directives (refer to the pfa(1) reference page).
Place the C*$* NO ASSERTIONS directive to tell Power Fortran to ignore all following assertions.
After you run a Fortran source program through Power Fortran once, you can use directives and assertions to fine-tune program execution. (Driver options apply to the program as a whole.) The listing file will show where and why Power Fortran did not parallelize the code. You can also use WorkShop Pro MPF to review Power Fortran's analysis of your program.
You use directives and assertions to force Power Fortran to process portions of code in various ways. You can also use directives and assertions to keep Power Fortran from converting code to run in parallel. In other cases you might want to explicitly force Power Fortran to run segments of code in parallel even though it normally would not.
Often you know of parts of your program that should not be parallelized, typically because you know that these parts contribute little to the execution time of the program. You can insert directives or assertions (called assertions, actually they have the effect of directives) to prevent Power Fortran from parallelizing specific loops.
The assertion C*$* ASSERT DO (SERIAL) tells Power Fortran to run the loop immediately following it serially. Power Fortran also does not try to run any enclosing loop in parallel. However, it can still convert any loops nested inside the serial loop to run in parallel. For example, consider the code shown in Example 3-3.
subroutine nest(x,y,z,n)
real x(n,n,n), y(n,n), z(n,n)
do i=1,n
do j = 1,n
do k = 1,n
x(i,j,k) = x(i,j,k) * y(i,j)
end do
do k = 1,n
X(i,j,k) = X(i,j,k) + Z(i,k)
end do
end do
end do
end
|
As written, Power Fortran will interchange loop variables to invert the order of the three loops, and parallelizes the outermost loop. Adding an assertion as shown in Example 3-4 makes a dramatic change.
subroutine nest(x,y,z,n)
real x(n,n,n), y(n,n), z(n,n)
do i=1,n
do j = 1,n
!*$* ASSERT DO(SERIAL)
do k = 1,n
x(i,j,k) = x(i,j,k) * y(i,j)
end do
do k = 1,n
X(i,j,k) = X(i,j,k) + Z(i,k)
end do
end do
end do
end
|
The assertion forces the loop on I, the loop on J, and the first loop on K to be serial. Power Fortran still executes the second loop on K in parallel.
Silicon Graphics Power Fortran supports the Cray directive, CDIR$ NEXT SCALAR as a synonym for the C*$* ASSERT DO (SERIAL) assertion.
The C*$* ASSERT DO PREFER (SERIAL) assertion tells the compiler to prefer any ordering in which the loop following the assertion remains serial. Unlike C*$* ASSERT DO (SERIAL), this assertion does not inhibit optimization of outer loops. This assertion directs Power Fortran to leave the loop alone, regardless of the setting of the optimization level. You can use this assertion to control which loop in a nest of loops Power Fortran chooses to run in parallel. The code fragment in Example 3-5 is an example of how to use the assertion.
DO I = 1, N
C*$*ASSERT DO PREFER (SERIAL)
DO J = 1, M
A(I,J) = B(I,J)
END DO
END DO
|
The assertion requests that the loop on J be serial. In this construction, Power Fortran tries to run the loop on I in parallel. This capability is useful when you know the value of M to be very small or less than N.
If the assertion in Example 3-4 is changed from DO (SERIAL) to DO PREFER (SERIAL), Power Fortran makes remarkable alterations in the transformed program, producing two copies of the outer loop, each containing just one of the inner loops on K.
Sometimes you might need to hand-tune a loop so that it will run in parallel. You can use the C$ DOACROSS directive, or the PCF directives, to explictly mark a section of code for parallel execution. These directives are discussed in detail in Chapter 7 of the MIPSpro Fortran 90 Programmer's Guide.
The C*$*[NO]CONCURRENTIZE directive enables or disables Power Fortran from transforming eligible loops to run in parallel to the end of the current program unit.
Used locally, these directives override the –[no]concurrentize driver option. Used globally, these directives have the same effect as the –[no]concurrentize driver option. (See “Enabling Parallelization of Loops”)
Power Fortran supports the VAST directive CVD$CONCUR. Power Fortran interprets this directive as if it were the C*$*CONCURRENTIZE directive.
The C*$* ASSERT DO PREFER (CONCURRENT) assertion directs Power Fortran to run a particular nested loop in parallel if possible. Power Fortran runs another of the nested loops in parallel only if a condition prevents running the selected loop in parallel. This assertion applies only to the loop immediately after it.
Consider the code in Example 3-6.
!*$* ASSERT DO PREFER (CONCURRENT)
DO I = 1, N
DO 100 J = 1, M
A (I, J) = B (I, J)
END DO
END DO
|
The assertion directs Power Fortran to prefer to run the loop on I in parallel. However, if a data dependence conflict prevents running that loop in parallel, Power Fortran might run the loop on J in parallel.
The –noconcurrentize command line option and the C*$* NO CONCURRENTIZE directive prevent Power Fortran from generating concurrent code, even if you specify the C*$* ASSERT DO PREFER (CONCURRENT) assertion.
The C*$* ASSERT DO (CONCURRENT) assertion tells Power Fortran to ignore assumed data dependencies.
Normally, Power Fortran is conservative about converting loops to run in parallel. When Power Fortran analyzes a loop, it categorizes the loop into one of three groups:
yes (loop is safe to run in parallel)
no (definite data dependency)
not sure (assumed data dependency)
Normally, Power Fortran does not run in parallel a loop with an assumed data dependency. C*$* ASSERT DO (CONCURRENT) tells Power Fortran to go ahead and run “not sure” loops in parallel.
Power Fortran interprets the Cray directive CDIR$ IVDEP as if it were a C*$* ASSERT DO (CONCURRENT) assertion. Some dependencies that are safe to run on Cray hardware are not safe to run on Silicon Graphics hardware. Therefore, to avoid incorrect parallelization of loops recognition of this assertion is turned off by default.
With assertions, you can give Power Fortran information about the use of data in the program. This allows Power Fortran to parallelize more loops or to do so more efficiently.
The C*$* ASSERT RELATION(name.xx.name) assertion specifies that a particular logical relation always holds between two variables, or between a variable and a constant. name is the variable or constant, and xx is any of the logical relations GT, GE, EQ, NE, LT, or LE. Used locally, this assertion applies only to the following DO statement.
C*$* ASSERT RELATION can be specified globally when the variable names appear in COMMON blocks or are dummy arguments to a subprogram. You cannot use global assertions to make relational assertions about variables that are local to a subprogram.
The code in Example 3-7 illustrates the use of C*$* ASSERT RELATION.
subroutine sumdown(a,b,m,n)
integer m,n,j
real a,b
dimension a(:),b(:)
do j=1,n
a(j) = a(j+m) + b(j)
end do
end
|
When Power Fortran analyzes this code, it detects that a data dependence would exist if M were less than or equal to N, because in that case different instances of a concurrent loop could store into the same elements of A. Power Fortran parallelizes the loop by generating this IF statement:
if (M .ge. 1 .and. N .ge. M .or. M .le. (-1)) then |
The THEN branch of the IF contains a serial version of the loop as originally written. The ELSE branch, executed when no data dependency can exist, contains a parallel version of the loop.
When you know that M is always greater than N, there is no need for this duplication of code. You can use C*$* ASSERT RELATION to inform Power Fortran, as shown in Example 3-8. When you do this, Power Fortran generates only the parallel form of the loop.
subroutine sumdown(a,b,m,n)
integer m,n,j
real a,b
dimension a(:),b(:)
!*$* assert relation (m.gt.n)
do j=1,n
a(j) = a(j+m) + b(j)
end do
end
|
The C*$* ASSERT NO RECURRENCE(variable) assertion tells the compiler to ignore all data dependence conflicts caused by variable in the loop that follows it. For example, the following code tells the compiler to ignore all dependence arcs caused by the variable X in the loop:
!*$* assert no recurrence (x)
do i= 1,m,5
x(k) = x(k) + x(i)
end do
|
Not only does the compiler ignore the assumed dependence, it also ignores the real dependence caused by X(k) appearing on both sides of the assignment.
The C*$* ASSERT NO RECURRENCE assertion applies only to the following loop. It cannot be specified as a global assertion.
The C*$* ASSERT PERMUTATION(array) assertion tells Power Fortran that array contains no repeated values. This assertion permits Power Fortran to run in parallel certain kinds of loops that use indirect addressing. For a detailed example of the use of this assertion, see “Indirect Indexing”.
C*$* ASSERT CONCURRENT CALL tells Power Fortran to ignore assumed dependencies that are caused by a subroutine call or a function reference. You must ensure that the subroutines and referenced functions have no side effects and are safe for parallel execution. This assertion applies to all subroutine and function references in the following loop. For detailed examples of the use of this assertions, see “Function Call” and “Procedure Parameters”.