Chapter 3. Working With Power Fortran 90

This chapter documents your control of Power Fortran using driver options, directives, and assertions.

Using Driver Options

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.”

Enabling Parallelization of Loops

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”).

Specifying a Work Threshold

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.

Example 3-1. Loop With Unknown 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.

Example 3-2. Transformed Loop With Unknown Amount of Work


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

Enabling Parallel I/O

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.

Specifying a Complexity Limit

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.

Setting the Optimization Level

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.

Controlling Variations in Round Off

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.

Performing Inlining and Interprocedural Analysis

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.

Preventing Use of Directives and Assertions

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.

Using Directives and 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.

Preventing Parallelization

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.

C*$* ASSERT DO (SERIAL)

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.

Example 3-3. Nested Loop


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.

Example 3-4. Nested Loop With Serial Assertion


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.

CDIR$ NEXT SCALAR

Silicon Graphics Power Fortran supports the Cray directive, CDIR$ NEXT SCALAR as a synonym for the C*$* ASSERT DO (SERIAL) assertion.

C*$* ASSERT DO PREFER (SERIAL)

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.

Example 3-5. Inner Loop Preferred Serial


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.

Explicit Parallelization

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.

C*$*[NO]CONCURRENTIZE

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”)

CVD$ CONCUR

Power Fortran supports the VAST directive CVD$CONCUR. Power Fortran interprets this directive as if it were the C*$*CONCURRENTIZE directive.

C*$* ASSERT DO PREFER (CONCURRENT)

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.

Example 3-6. Nested Loop With Preferred Loop


!*$* 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.

C*$* ASSERT DO (CONCURRENT)

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.

CDIR$ IVDEP

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.

Clarifying Dependencies

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.

C*$* ASSERT RELATION

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.

Example 3-7. Loop With Implied 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.

Example 3-8. Loop With Asserted Relation


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

C*$* ASSERT NO RECURRENCE

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.

C*$* ASSERT PERMUTATION

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

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”.

CVD$ CNCALL

Power Fortran interprets the VAST directive CDIR$ CNCALL as if it were a C*$* ASSERT CONCURRENT CALL assertion. Some dependencies that are safe to run on Cray hardware are not safe to run on Silicon Graphics hardware. Therefore, recognition of this assertion is turned off by default.