Evaluation of Fortran90 compilers for Linux/Intel

Gerry Murray ,
Forecast Systems Lab,
5/2000

Hewlett Packard is discontinuing their Fortran77 compiler.  To encourage their customers to migrate to their Fortran90 product, they are offering a free upgrade for a limited time.  Thus, the SwEG is considering mandating the use of Fortran90 compilers for AWIPS Fortran development.  Currently, the Linux port of AWIPS uses the same source code that runs on the HPs.  This has been a goal since the beginning of the port.  G77, which comes with the GCC freeware, has been compiling most of the Fortran code on Linux, except for the code that relies on structures and dynamic memory allocation.  If Fortran90 is adopted, the amount of Fortran code that is buildable will reduce substantially over time if we continue to use G77 with Linux.

My task over this last month has been to evaluate the various Fortran90 compilers available for the Linux/Intel PC platform.  I first made a list of what I thought were the important and/or nice to have features.  Through the Internet, I got a list of all Fortran compilers that were available for Linux.  Fortunately, most of those compilers had free evaluation licenses so I was able to take most of them out for a test drive.  For the first round, I eliminated a bunch that did not satisfy the "must have" requirements at first glance and was left with three compilers.  Before moving on to the final round, I decided to port all the display and localization executables to Fortran90.  I had to make numerous modifications but they all fit into four categories.  For the final evaluation, I compared the three compilers using various quantifiable and subjective comparisons.  Here's the contents of this document.

Requirements for an AWIPS Fortran90 Compiler
       Must Have
       Wish List
Internet Resources
First Round Elimination
Porting the Display and Localization Executables to Fortran90
       Logical Comparison Operators
       Byte Variables as Arguments to Logical Operators
       Equivalences between Byte and Character Arrays
       Open Statement Specifiers
       Name Mangling
       Summary of File Changes
The Big Showdown!
        General Statistics
        Usability with a Source Debugger
                Portland Group
                Fujitsu
                Absoft
         Readability and Accuracy of Diagnostic Messages
                g77
                Absoft
                Fujitsu
                Portland Group
         Quality of Documentation
Evaluation Summary
        Strengths of the Portland Group Compiler
        Weaknesses of the Portland Group Compiler
         Strengths of the Absoft Compiler
        Weaknesses of the Absoft Compiler
         Strengths of the Fujitsu Compiler
        Weaknesses of the Fujitsu Compiler
And the Winner is ...

Requirements for an AWIPS Fortran90 Compiler

I came up with these from the perspective of a software developer.  It's possible this list is incomplete or misguided; other perspectives might offer other requirements.
Must Have!

Internet Resources

This evaluation would have been much harder without the Internet at my fingertips.  Here are some of the more valuable sites used to gather much of information presented in this document. Of course, each compiler developer has its web site laden with marketing facts and figures.  Here are the compilers that I initially considered.

First Round Elimination

After doing some preliminary investigation and using the requirements as a criteria, I eliminated 6 of the 9 contestants.  Here's why.

Porting the Display and Localization Executables to Fortran90

Before preceding on evaluating the remaining three compilers (Absoft, Fujitsu, and Portland Group), I wanted to make sure I could build a complete workstation with a Fortran90 compiler.  I knew this was going to be a big job, and I was right; it took several weeks.  Yet, I feel it was time well spent rather than using benchmark programs downloaded from the Internet to do the evaluation.  Not only is it much better to do benchmarks on our own code, the lessons learned can be applied to other code that still needs to be ported, or code that has yet to be written.  Many of the changes fell into one of these five categories.

Logical Comparison Operators

We were using the .eq. and .ne. operators to compare logical variables while the f77 standard states that logical comparisons should be done with the .eqv. and .neqv. operators.  For example:
logical foo, bar
if (foo .eqv. bar) then
    ...

instead of

logical foo, bar
if (foo .eq. bar) then
    ...

Even though this appears to be the standard, our f77 compilers (g77 and HP f77) seemed to be lax on this.

Byte Variables as Arguments to Logical Operators

Consider this code from D-2D/src/depict/fortcon.f:
byte b
If ((bbb.and.1).eq.1) Goto 10011
Looking at this code, it's obvious that the programmer intended ".and." to be a bit-wise operator rather than a logical operator.  However, its not so obvious to the f90 compiler.   I think most f77 compilers allow the overloading of the .and., .or., etc...  depending on the type of the argument.  However, its not clear whether a byte variable should be treated like an integer or  a logical.  In fact, HP compiler has a +e switch to tell the compiler how to treat byte variables.  I fixed the code by explicitly specifying the bit-wise operator.  In the above example, I changed the .and. to .iand..

Equivalences between Byte and Character Arrays

I have no idea why, but all three f90 compilers I tried complains loudly about this kind of equivalence:
Character TextLine*256
Byte      ByteLine(256)
Equivalence (TextLine,ByteLine)
What's strange is that this workaround is OK.
Character TextLine*256
Integer*4 IntLine(64)
Byte      ByteLine(256)
Equivalence (TextLine,IntLine)
Equivalence (IntLine,ByteLine)
I'm sure there is somebody out there that can explain this.  If so, I'd be curious.

Open Statement Specifiers

Some of the specifiers to the open statement (which establishes a connection between a unit number and a file) have changed in Fortran90. This is the only category of modifications that is not compilable under both f77 and f90.

Name Mangling

Check out this email to TDL and FSL Fortran developers describing this issue in detail.  I haven't received much feedback whether this solution is palatable or not.

Summary of File Changes

The following 30 Fortran source code files were modified in order to compile under f90.
D-2D/src/depict/asc2int.f
D-2D/src/depict/df_dcdredmis.f
D-2D/src/depict/dualarrows.f
D-2D/src/depict/erasure.f
D-2D/src/depict/fortUAplot.f
D-2D/src/depict/fortarrow.f
D-2D/src/depict/fortbarb.f
D-2D/src/depict/fortcon.f
D-2D/src/depict/getword.f
D-2D/src/depict/gridarrows.f
D-2D/src/depict/gridbarbs.f
D-2D/src/depict/iconplot.f
D-2D/src/depict/strmpak.f
D-2D/src/geoLib/str_c2f.f
D-2D/src/geoLib/str_f2c.f
D-2D/src/geoTables/fortpoly.f
D-2D/src/meteoLib/fortconbuf.f
D-2D/src/meteoLib/matsln.f
D-2D/src/meteoLib/qvector.f
D-2D/src/meteoLib/slqvect.f
D-2D/src/meteoLib/tsoar.f
D-2D/src/util/IntrinsicFunctions.f
D-2D/src/util/RMIroutines.f
awips_common/src/lamplib/flopn.f
awips_common/src/lamplib/grdidn.f
awips_common/src/lamplib/oplamp.f
awips_common/src/lamplib/propen.f
awips_common/src/lamplib/rdarg.f
awips_common/src/lamplib/rdide.f
awips_common/src/lamplib/rdidg.f
The following C/C++ header/source files were modified for the purpose to support name mangling required by the Fujitsu and the Portland Group compilers.
D-2D/src/applications/caseArchive/ArchiveInterface_wrap.C
D-2D/src/dataMgmt/DepictableInventory.C
D-2D/src/dataMgmt/GridSliceAccessor.C
D-2D/src/dataMgmt/GridSliceWrapper.C
D-2D/src/dataMgmt/GridSliceWrapper.h
D-2D/src/depict/FortranGraphics.C
D-2D/src/depict/FortranGraphics.H
D-2D/src/depict/GridPVWindBarbDepict.C
D-2D/src/depict/SoundingDepict.C
D-2D/src/depict/SoundingParams.C
D-2D/src/depict/SoundingParams.H
D-2D/src/depict/dualarrows.h
D-2D/src/depict/fortUAplot.h
D-2D/src/depict/fortarrow.h
D-2D/src/depict/fortbarb.h
D-2D/src/depict/fortcirc.h
D-2D/src/depict/fortcon.h
D-2D/src/depict/gridarrows.h
D-2D/src/depict/gridbarbs.h
D-2D/src/depict/iconplot.h
D-2D/src/depict/strmpak.h
D-2D/src/dm/grid/GridRoutines.C
D-2D/src/dm/grid/gridFlatFile.C
D-2D/src/dm/grid/press2Theta.h
D-2D/src/dm/gridLAMP/read_grid.h
D-2D/src/dm/lamp/get_latest_lamp_run.h
D-2D/src/dm/lamp/read_elmf.h
D-2D/src/dm/mos/MOS_PlotFile.C
D-2D/src/dm/mos/closef.h
D-2D/src/dm/mos/rdcntrl.h
D-2D/src/dm/profiler/ProfilerLapsAccessor.C
D-2D/src/dm/profiler/ProfilerLapsAccessor.H
D-2D/src/dm/scan/ScanDBase.c
D-2D/src/dm/shapefile/shp2bcd.C
D-2D/src/dm/taf/dmTAF_DBCalls.c
D-2D/src/dm/taf/dmTAF_buildMxMnTree.c
D-2D/src/dm/taf/dmTAF_buildValTrees.c
D-2D/src/dm/taf/dmTAF_getWxElements.c
D-2D/src/extensions/azRanOverlay/AzRanOverlayFile.C
D-2D/src/extensions/azRanOverlay/AzRanOverlayFile.H
D-2D/src/extensions/distanceSpeed/disSpeedWish.C
D-2D/src/extensions/home/HomeFile.C
D-2D/src/extensions/home/HomeFile.H
D-2D/src/extensions/solidfill/SolidfillFile.C
D-2D/src/extensions/solidfill/SolidfillFile.H
D-2D/src/ffmp/processor/FFMPglobal.C
D-2D/src/geoLib/bcd_file.c
D-2D/src/geoLib/g2iremapper.c
D-2D/src/geoLib/geoLib.h
D-2D/src/geoLib/getarealim.c
D-2D/src/geoLib/grhiremapper.c
D-2D/src/geoLib/gridremapper.c
D-2D/src/geoLib/imageremaper.c
D-2D/src/geoLib/initgeofile.c
D-2D/src/geoLib/ll_to_xy.c
D-2D/src/geoLib/points_file.c
D-2D/src/geoLib/rangeAzimuth.c
D-2D/src/geoLib/setsup.c
D-2D/src/geoLib/windremapper.c
D-2D/src/geoLib/xy_to_ll.c
D-2D/src/hmMonitor/Monitor_DBCalls.c
D-2D/src/ipc/radar/ProductRequestEntry.H
D-2D/src/meteoLib/adiabatic_te.c
D-2D/src/meteoLib/calcHeatIndex.c
D-2D/src/meteoLib/calcWindChill.c
D-2D/src/meteoLib/calckidx.c
D-2D/src/meteoLib/calctotidx.c
D-2D/src/meteoLib/dist_filter.c
D-2D/src/meteoLib/interp.c
D-2D/src/meteoLib/meteoLib.h
D-2D/src/meteoLib/temp_mixratio.c
D-2D/src/meteoLib/temp_of_te.c
D-2D/src/meteoLib/thermoRtns.c
D-2D/src/scan/localize/createLocalHrapFile.C
D-2D/src/scan/model_data_acq/getModelData.H
D-2D/src/scan/processor/SCANglobal.C
D-2D/src/scan/processor/getMiscCellData.C
D-2D/src/textBulletinLAMP/elmdta.h
awips_common/src/common_incs/AC_dbaccess.h

The Big Showdown!

Here's how the three finalists compared head to head and against g77.  I compared the following compiler attributes/features/stats:

General Statistics

The lighter shades of green denotes better results across the row.
 

 G77  Fujitsu  Absoft   Portland Group
Executable Size (bytes)  28432398  28844930  28481252  28990428
Size of a single object with debug info (bytes)  121772  220236  148532  152548
Time to compile a single object with debug info (seconds)  2.88  1.44  4.62  2.90
Size of a single object with optimization (bytes)  72136  147872  92840  93992
Time to compile a single object with optimization (seconds)  6.82  6.13  6.03  2.72
Execution time of a single routine with debug info (seconds)  0.00486  0.00668   0.01206  0.01314
Execution time of a single routine optimized (seconds)  0.00477  0.00597  0.00665  0.00408
Cost of license without support (dollars)  free  195  NA  499
Cost of license with support (dollars)  free  275  899  674

Usability with a Source Debugger

For these tests, I tried basic debugging operations such as printing variables, arrays and expressions, stack traces, moving to different stack frames, setting breakpoints, stepping through and around statements.
Portland Group
This was the only compiler out of the three that worked with gdb.  It seems to work as well as g77 does with gdb.  Using gdb to debug Fortran code seems to work for the most part except for one notable limitation.  Printing out values of arrays is clumsy.  Using the print command doesn't seem to work well.  The workaround is to use the examine memory command which is not an easy command for a novice user of gdb to maneuver around.

I did try their native debugger on IGC_Process and it core dumped while trying to read the symbol table.

Fujitsu
Using gdb with this compiler is not practical since it can't read the symbol information completely.  Setting breakpoints worked, but it couldn't print out variables.

The compiler ships with its own debugger (fdb) which seems to be strongly based on gdb.  Like gdb, it is a command line tool; don't know of any GUI's for fdb.  This tool does debug Fortran well, better than gdb.  Printing elements of multidimensional arrays is a snap but I couldn't figure out how to print a slice of an array.

Since gdb doesn't debug Fujitsu Fortran and fdb doesn't debug gcc C/C++, you would have to use two debuggers to debug a C/C++/Fortran application.  It could be done, but could be quite aggravating.

Absoft
With this compiler, you may have to resort to print statements to do your debugging.  It doesn't work at all with GDB since the object code has a different debugging format.  (DWARF style.)

The debugger that came with their product wasn't much better.  It was difficult to use, and I couldn't get it to print out variables.  Quite possible, I was using the tool wrong.  However doing simple things like displaying source code was a major chore; thus my frustration level quickly exceeded any patience I had.

Readability and Accuracy of Diagnostic Messages

I wrote this silly Fortran function:
      1    subroutine arraydump(data, data2, nx,ny)
      2    implicit none
          4    integer*4 nx,ny
          5    real*4  data(nx,ny),k,l,data2(nx)
          6    integer i,j
 

          9    do 16 i=1,nx
         10       do 15 j=1,ny
         11         k = data(i,j) * 10.0
         12         l = data2(i,j) - k
         13         if (l.eq.3) then
         14            print "(a)", "L is 3"
         15       continue
         16    continue

         18    return
         19    end

with two trivial compiler errors:

  1. On line 12, it's using two subscripts to dereference a single dimensional array
  2. On line 13, the "if" does not have a matching "endif"
Here's what the compilers had to say:
g77
arraydump.f: In subroutine `arraydump':
arraydump.f:12:
               l = data2(i,j) - k
                   1       2
Too many elements as of (2) for array reference at (1)
arraydump.f:10:
            do 200 j=1,ny
               1
arraydump.f:13: (continued):
               if (l.eq.3) then
               2
arraydump.f:15: (continued):
    200     continue
    3
DO-statement reference to label at (1) and label definition at (3)
separated by unterminated block starting at (2)
arraydump.f:9:
         do 100 i=1,nx
            1
arraydump.f:13: (continued):
               if (l.eq.3) then
               2
arraydump.f:16: (continued):
    100  continue
    3
DO-statement reference to label at (1) and label definition at (3)
separated by unterminated block starting at (2)
arraydump.f:13:
               if (l.eq.3) then
               1
arraydump.f:19: (continued):
         end
         2
Statement at (2) invalid in context established by statement at (1)
arraydump.f:13:
               if (l.eq.3) then
               ^
End of source file before end of block started at (^)

Accurate, and understandable but very verbose.

Absoft
            l = data2(i,j) - k
                ^
cf90-204 f90fe: ERROR ARRAY DUMP, File = arraydump.f, Line = 12, Column = 17
  The number of subscripts is greater than the number of declared dimensions.

            if (l.eq.3) then
            ^
cf90-291 f90fe: ERROR ARRAY DUMP, File = arraydump.f, Line = 13, Column = 13
  An END statement is missing for this IF statement.

Accurate, clear and concise.  Very nice diagnostics!

Fujitsu
Fortran diagnostic messages: program name(arraydump)
  jwd2219i-s  "arraydump.f", line 12: Rank of array reference must be the same as the declared rank of array data.
  jwd1131i-s  "arraydump.f", line 13: The program unit contains unmatched nest in DO construct, IF construct, or CASE construct.

Technically correct but somewhat cryptic diagnostics.

Portland Group
PGF90-S-0078-Wrong number of subscripts specified for data (arraydump.f: 12)
PGF90-S-0104-Illegal control structure - unterminated DO (arraydump.f: 9)

First diagnostic is fine.  Second however is very misleading.  The code has an unbalanced if on line 13, the do on line 9 is fine.

Quality of Documentation

All three compilers have extensive on-line documentation.  The Portland Group's is in HTML while the other two are in PDF (readable by Adobe's Acrobat Reader).

In the Portland Group package I got, there was a manual for the f77 and the HPF compiler (High Performance Fortran) but the f90 manual was missing.  The user's guide does cover the f90 compiler and is well written and structured.  This guide also documents the profiler and debugger with plenty of screen shots.

Absoft's documentation set is quite impressive.  It seems to be very thorough although the user's guide was a little on the skimpy side.  The set contains a nice Fortran90 reference which could be used to learn the new features that have been added since f77.  The set also included an entire document on the debugger which could definitely be useful, since my experience with the Absoft debugger was less than favorable.

I thought the Fujitsu documentation set was adequate but not as well written as the other two sets.  I used the document of compile time messages to get clarification of a diagnostic, and the explanation in the manual was just rehashing the compiler diagnostic and offered no furthur information.

Evaluation Summary

For what its worth, here's my spin on what I learned.

Strengths of the Portland Group Compiler

Weaknesses of the Portland Group Compiler

Strengths of the Absoft Compiler

Weaknesses of the Absoft Compiler

Strengths of the Fujitsu Compiler

Weaknesses of the Fujitsu Compiler

And the Winner is ...

Beats me.  That decision is left as an exercise for the reader.