Previous Next Contents Index Doc Set Home


Porting

7


This chapter discusses the porting of programs from other dialects of Fortran to Sun compilers. VAX VMS Fortran programs compile almost exactly as is with Sun f77; this is discussed further in the chapter on VMS extensions in the Fortran 77 Language Reference.


Note - Porting issues bear mostly upon Fortran 77 programs. The Sun Fortran 90 compiler, f90, incorporates few nonstandard extensions, and these are described in the Fortran User's Guide.


Time Functions

Library functions that return the time of day or elapsed CPU time vary from system to system.

The following time functions are not supported directly in the Sun Fortran libraries, but you can write subroutines to duplicate their functions:

For example, to find the current Julian date, call TIME() to get the number of seconds since January 1, 1970, convert the result to days (divide by 86,400), and add 2,440,587 (the Julian date of December 31, 1969).

The time functions supported in the Sun Fortran library are listed in Table 7-1:

Table  7-1 Sun Fortran Time Functions

Name
Function
Man Page

time

Return the number of seconds elapsed since 1 January, 1970

time(3f)

fdate

Return the current time and date as a character string

fdate(3f)

idate

Return the current month, day, and year in an integer array

idate(3f)

itime

Return the current hour, minute, and second in an integer array

itime(3f)

ctime

Convert the time returned by the time function to a character string

ctime(3f)

ltime

Convert the time returned by the time function to the local time

ltime(3f)

gmtime

Convert the time returned by the time function to Greenwich time

gmtime(3f)

etime

Single Processor: Return elapsed user and system time for program execution
Multiple Processors: Return the wall clock time

etime(3f)

dtime

Return the elapsed user and system time since last call to dtime

dtime(3f)

For details, see Fortran Library Reference or the individual man pages for these functions.

The routines listed in
Table 7-2 provide compatibility with VMS Fortran system routines idate and time. To use these routines, you must include the -lV77 option on the f77/f90 command line, in which case you also get these VMS versions instead of the standard f77 versions.

Table  7-2 Summary: VMS Fortran System Routines

Name
Definition
Calling Sequence
Argument Type

idate

Date as day, month, year

call idate( d, m, y )

integer

time

Current time as hhmmss

call time( t )

character*8

The error condition subroutine errsns is not provided, because it is totally specific to the VMS operating system.

Here is a simple example of the use of these time functions (TestTim.f):

	subroutine startclock 
	common / myclock / mytime 
	integer mytime, time 
	mytime = time() 
	return 
	end 
	function wallclock 
	integer wallclock 
	common / myclock / mytime 
	integer mytime, time, newtime 
	newtime = time() 
	wallclock = newtime - mytime 
	mytime = newtime 
	return 
	end 
	integer wallclock, elapsed 
	character*24 greeting 
	real dtime, timediff, timearray(2) 
c	print a heading 
	call fdate( greeting ) 
	print*,  "	Hello, Time Now Is: ",  greeting 
	print*,	"See how long 'sleep 4' takes, in seconds" 
	call startclock 
	call system( 'sleep 4' ) 
	elapsed = wallclock() 
	print*, "Elapsed time for sleep 4 was: ", elapsed," seconds"
c	now test the cpu time for some trivial computing 
	timediff = dtime( timearray ) 
	q = 0.01 
	do 30 i = 1, 1000 
		q = atan( q ) 
30	continue 
	timediff = dtime( timearray ) 
	print*, "atan(q) 1000 times took: ", timediff ," seconds"
	end 

Running this program produces the following results:

demo% TimeTest
 	Hello, Time Now Is: Mon Feb 12 11:53:54 1996
 See how long 'sleep 4' takes, in seconds
 Elapsed time for sleep 4 was:   5 seconds
 atan(q) 1000 times took:     2.26550E-03 seconds
demo%


Formats

Some f77 format edit descriptors may behave differently on other systems. Here are some format specifiers that f77 treats differently than some other implementations:


Carriage-Control

Fortran carriage-control grew out of the capabilities of the equipment used when Fortran was originally developed. For similar historical reasons, an operating system derived from the UNIX operating system, does not have Fortran carriage-control, but you can simulate it in two ways.

You can use lp(1) to print a file that is opened in this manner.


Working With Files

Early Fortran systems did not use named files, but did provide a command line mechanism to equate actual file names with internal unit numbers. This facility can be emulated in a number of ways, including standard UNIX redirection:

Example: Redirecting stdin to redir.data (using csh(1)):

demo% cat redir.data            The data file 
 9 9.9 

demo% cat redir.f               The source file 
	read(*,*) i, z            The program reads standard input
	print *, i, z 
	stop 
	end 

demo% f77 -silent -o redir redir.f     The compilation step
demo% redir < redir.data      Run with redirection reads data file 
  9 9.90000
demo%

See Chapter 2, Fortran Input/Output, for more on redirection and working with files.


Data Representation

The Fortran 77 Language Reference and the Sun Numerical Computation Guide discuss in detail the hardware representation of data objects in Fortran. Differences between data representations across systems and hardware platforms usually generate the most significant portability problems.

The following issues should be noted:


Hollerith Data

Many "dusty-deck" Fortran applications store Hollerith ASCII data into numerical data objects. With the 1977 Fortran standard, the CHARACTER data type was provided for this purpose and its use is recommended. You can still initialize variables with the older Fortran Hollerith (nH) feature, but this is not standard practice. Table 7-3 indicates the maximum number of characters that will fit into certain data types. (In this table, boldfaced data types indicate default types subject to promotion by -dbl, -r8, or -xtypemap= .)

Table  7-3 Maximum Characters in Data Types 


Maximum Number of Standard ASCII Characters
Data Type
No -i2, -i4,
-r8, -dbl

-i2
-i4
-r8
-dbl

BYTE

1

1

1

1

1

COMPLEX

8

8

8

16

16

COMPLEX*16

16

16

16

16

16

COMPLEX*32

32

32

32

32

32

DOUBLE COMPLEX

16

16

16

32

32

DOUBLE PRECISION

8

8

8

16

16

INTEGER

4

2

4

4

8

INTEGER*2

2

2

2

2

2

INTEGER*4

4

4

4

4

4

INTEGER*8

8

8

8

8

8

LOGICAL

4

2

4

4

8

LOGICAL*1

1

1

1

1

1

LOGICAL*8

8

8

8

8

8

REAL

4

4

4

8

8

REAL*4

4

4

4

4

4

REAL*8

8

8

8

8

8

REAL*16

16

16

16

16

16

When storing standard ASCII characters with normal Fortran:

The storage is allocated with both options, but it is unavailable in normal Fortran with -r8.

Example: Initialize variables with Hollerith:

demo% cat FourA8.f
	double complex x(2) 
	data x /16Habcdefghijklmnop, 16Hqrstuvwxyz012345/ 
	write( 6, '(4A8, "!")' ) x 
	end 

demo% f77 -silent -o FourA8 FourA8.f
demo% FourA8
abcdefghijklmnopqrstuvwxyz012345!
demo% 

If you pass Hollerith constants as arguments, or if you use them in expressions or comparisons, they are interpreted as character-type expressions.

If needed, you can initialize a data item of a compatible type with a Hollerith and then pass it to other routines.

Example:

        program respond
        integer yes, no
        integer ask
        data yes, no / 3hyes, 2hno /

        if ( ask() .eq. yes ) then
            print *, 'You may proceed!'
        else
            print *, 'Request Rejected!'
        endif
        end

        integer function ask()
        double precision solaris, response
        integer yes, no
        data yes, no / 3hyes, 2hno /
        data solaris/ 7hSOLARIS/
10      format( "What system? ", $ )
20      format( a8 )

        write( 6, 10 )
        read ( 5, 20 ) response
        ask = no
        if ( response .eq. solaris ) ask = yes
        return
        end


Nonstandard Coding Practices

As a general rule, porting an application program from one system and compiler to another can be made easier by eliminating any nonstandard coding. Optimizations or work-arounds that were successful on one system may only serve to obscure and confuse compilers on other systems. In particular, optimized hand-tuning for one particular architecture may turn out to cause degradations in performance elsewhere. This is discussed later in the chapters on performance and tuning. However, the following issues are worth considering with regards to porting in general.

Uninitialized Variables

Some systems automatically initialize local and COMMON variables to zero or some not-a-number value. However, there is no standard practice, and programs should not make assumptions regarding the initial value of any variable. To assure maximum portability, a program should initialize all variables.

Aliasing Across Calls

Aliasing occurs when the same storage address is referenced by more than one name. This happens when actual arguments to a subprogram overlap between themselves or between COMMON variables within the subprogram. For example, arguments X and Z refer to the same storage locations, as do B and H:

  COMMON /INS/B(100)
  REAL S(100), T(100)
  ...
  CALL SUB(S,T,S,B,100)
  ...
  SUBROUTINE SUB(X,Y,Z,H,N)
  REAL X(N),Y(N),Z(N),H(N)
  COMMON /INS/B(100)
  ...

Aliasing in this manner should be avoided in all portable code. The results on some systems and with higher optimization levels could be unpredictable.

Obscure Optimizations

Legacy codes may contain source-code restructurings of ordinary computational DO loops intended to cause older vectorizing compilers to generate optimal code for a particular architecture. In most cases, these restructurings are no longer needed and may degrade the portability of a program. Two common restructurings are strip-mining and loop unrolling.

Strip-Mining

Fixed-length vector registers on some architectures led programmers to manually "strip-mine" the array computations in a loop into segments:

  REAL TX(0:63)
  ...
  DO IOUTER = 1,NX,64
     DO IINNER = 0,63
        TX(IINNER) = AX(IOUTER+IINNER) * BX(IOUTER+IINNER)/2.
        QX(IOUTER+IINNER) = TX(IINNER)**2
     END DO
  END DO

Strip-mining is no longer appropriate with modern compilers; the loop can be written much less obscurely as:

  DO IX = 1,N
    TX = AX(I)*BX(I)/2.
    QX(I) = TX**2
  END DO

Loop Unrolling

Unrolling loops by hand was a typical source-code optimization technique before compilers were available that could perform this restructuring automatically. A loop written as:

  DO       K = 1, N-5, 6
     DO    J = 1, N
        DO I = 1,N
           A(I,J) = A(I,J) + B(I,K  ) * C(K  ,J)
 *                         + B(I,K+1) * C(K+1,J)
 *                         + B(I,K+2) * C(K+2,J)
 *                         + B(I,K+3) * C(K+3,J)
 *                         + B(I,K+4) * C(K+4,J)
 *                         + B(I,K+5) * C(K+5,J)
        END DO
     END DO
  END DO
  DO       KK = K,N
     DO    J =1,N
        DO I =1,N
           A(I,J) = A(I,J) + B(I,KK) * C(KK,J)
        END DO
     END DO
  END DO

should be rewritten the way it was originally intended:

  DO       K = 1,N
     DO    J = 1,N
        DO I = 1,N
           A(I,J) = A(I,J) + B(I,K) * C(K,J)
        END DO
     END DO
  END DO


Troubleshooting

Here are a few suggestions for what to try when programs ported to Sun Fortran do not run as expected.

Results Are Close, but Not Close Enough

Try the following:

VAX math is not as good as IEEE math, and even different IEEE processors may differ. This is especially true if the mathematics involves many trigonometric functions. These functions are much more complicated than one might think, and the standard defines only the basic arithmetic functions. There can be subtle differences, even between IEEE machines. Review the chapter Floating-Point Arithmetic, in this Guide.

The output is:

99,999,990 x 10^29 = 0.99999993E+37 = 7cf0bdc1
99,999,996 x 10^29 = 0.99999993E+37 = 7cf0bdc1

In this example, the difference is 6 x 1029. The reason for this indistinguishable, wide gap is that in IEEE single-precision arithmetic, you are guaranteed only six decimal digits for any one decimal-to-binary conversion. You may be able to convert seven or eight digits correctly, but it depends on the number.

Program Fails without Warning

If the program fails without warning and runs different lengths of time between failures, then:


Previous Next Contents Index Doc Set Home