Porting serial Fortran 77 numerical computation code for OpenMP applications
Matteo Ainardi Vittorio Giovara Alberto Grand July 21, 2008
1 Introduction 2 Porting to standards 2.1 VMS debris . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Setting up the compilation environment . . . . . . . . . . . . 2.3 Generating Makeﬁles . . . . . . . . . . . . . . . . . . . . . . . 3 Test case - Sally3D 3.1 Code standardization . . . . . . . . . . . . . . . . . . . . . . . 2 3 3 5 6 7 8
The aim of this document is to provide an introduction to porting nonstandard Fortran 77 programs to standard Fortran in order to be able to perform compilation optimization, parallel programming and use of modern numerical libraries. A sample test case will be analyzed and prepared for parallel execution through the OpenMP standard library, using the GNU Compiler Collection (GCC) and GNU Fortran (GFortran) version 4.3 implementation. The use of standard tools and standard code has become increasily popular during the years in every programming language, as it allowed easily portable code and a high level of documentability.
Porting to standards
2.1 VMS debris
Most Fortran software is written using old-fashioned code, as it was often written when standard procedures didn’t yet exist or were poorly followed. Sometimes the production machines on which the code was written implemented in diﬀerent ways equivalent functions, taking advantage of nonstandard features available to that machine only. The VAX/VMS, now called OpenVMS, is one of such machines: here is presented a list of possible statements that need to be revised before proceeding with the compilation. • DATE and TIME functions are broken, even in the VMS implementation; they must be substituted with DATE AND TIME • The vector size must be declared along with the vector type; for example the following string CHARACTER VALMAP*10(NQUAN_MX),NOMMAP*30 must be corrected in CHARACTER*10 VALMAP(NQUAN_MX),NOMMAP*30 • Operands of an equivalence statement must be explicitly deﬁned: for example IF (ANS.EQ.’N’.OR.ANS.EQ.’n’) THEN must be preceeded by CHARACTER ANS*1 3
• Procedure calling with vectors as arguments must use $ instead of <>: so 100 101 format(1x,’.subckt ’,a30,1x,<nmors>a10,’ sub_gnd ’) format(1x,’.subckt ’,a30,1x,<nmors>a10)
becomes 100 101 format(1x,’.subckt ’,a30,1x,$a10,’ sub_gnd ’) format(1x,’.subckt ’,a30,1x,$a10)
• The above applies also for multi line statements: WRITE(LW,’(1X,’’Quantity: ’’,(<IRECORD>1X,A))’) + (VALMAP(K)(1:3),K=1,IRECORD) becomes WRITE(LW,’(1X,’’Quantity: ’’,($1X,A))’) + (VALMAP(K)(1:3),K=1,IRECORD) • Intrinsic arguments are not allowed, must be explicit: strings like INDX(1) = IFIX( RAND(DUMMY)*N ) + 1 need to have arguments declared before with INTEGER DUMMY • Reading variables with READ doesn’t need the round parenthesis: READ(LR,*) (AREAFAC3(NFA)) are just READ(LR,*) AREAFAC3(NFA) • Opening ﬁle functions have strict speciﬁc argument; for example the following string OPEN(UNIT=L_HLP,FILE=FILEHLP,SHARED,READONLY,STATUS=’OLD’) uses SHARED and READONLY which are VMS-only keywords. The correct structure for these functions is OPEN(UNIT=L_HLP,FILE=’FILEHLP’,STATUS=’OLD’) 4
Setting up the compilation environment
Now that the code is clean, it can be compiled from a variety of standardcompliant compilers, like in this case with the gcc, with support to OpenMP. OpenMP is a relatively new library oﬀering advanced system calls for C, C++ and Fortran for parallelizing the execution of the code, using very simple interface level; support for OpenMP is oﬀered in gcc only from version 4.3 which is still considered unstable (even though it works perfectly). So setting up the environment can be particularly tricky, depending on the distribution of Linux or Mac version. Debian/Ubuntu For example in Ubuntu Linux 8.04 and Debian there are two ways for obtaining gcc-4.3 1. using the gcc-snapshot package, which contains a development version of gcc, and installs it in /usr/lib/gcc-snapshot/ sudo apt-get install gcc-snapshot 2. installing the experimentantal repository https://launchpad.net/ ~ubuntu-toolchain/+archive in /etc/apt/sources.list sudo apt-get update sudo apt-get upgrade gcc In both cases particular attention should be paid with symlink generation as by default they are not updated. Gentoo Linux In Gentoo it is possible to compile and install gcc-4.3 simply by putting a token in /etc/portage/package.keywords: >=sys-devel/gcc-4.3.1-rc1 ~* and then updating the compiler with emerge -u gcc Mac OS X As for Mac OS X it is possible to downoload and install gcc-4.3 using Fink or MacPorts programs, which fetch the source and compile and install the code on the machine.
sudo port install gcc43 or fink install gcc43
One last possible step is to optimize the compilation using the Makeﬁle: with this tool project parameters can be easily updated, incremental compilation is automatically activated (so source ﬁles not modiﬁed are not recompiled) and parallel compilation is achieved with the -j ﬂag. Usually libraries are compiled ﬁrst, building a .a ﬁle containg all symbols included with this code ar rvu *.o ranlib *.o On the other hand the base programs need to be linked against those libraries, so with retiqua: retiqua.o $(LIBS) $(CC) -o $(BIN)/$@.out $@.o $(LIB)/work.a meaning The program retiqua depends on the object retiqua.o and on all the libraries; when they ﬁnish compiling, link them and produce the output ﬁle retiqua.out.
Test case - Sally3D
The test program used as example is Sally3D a numerical software for solving electro-magnetic problems, producing 3D models. It was written using VMS Fortran implementation but now it has been successfully ported to standard GNU Fortran and is ready for parallelization with OpenMP. Several steps were made in order to have a clean code, and more in particular ﬁles have been moved in a more organized structure: • All the ﬁles .for and .FOR were renamed lowercase; • All the ﬁles .dat, .cmm, .DAT and .CMM were renamed uppercase; • All the ﬁles .a, .out, .sh, .new and .bat were removed; • All the libraries were moved in the /src folder; • For each library a bare Makeﬁle was created; • Using the Makeﬁles, useless ﬁles were removed in every library; • The main Makeﬁle was created, using advanced optimization ﬂag and architecture-dependant compilation; • Files with name equal to libraries have been renamed appending a src at the end of the name (applies to sol micromag.for, sol pint.for, sol bem.for); • Fortran standardization.
Several ﬁles suﬀered issues from porting to standard Fortran, but they have been deeply analyzed and corrected. • in / netlist.for: line 56 used illegal characters in calling procedures; • in / sol slap.for: line 607 used an intrinsic argument; • in /src/work/ util.for:28 and plotta.for:812 contained the DATE and TIME incompatibility; • in /src/work saveread.for:776 and in / build source.for:62 contained a function with wrong syntax; • in / calc hsn.for:18 calc fmmsdua.for:18 calc res.for:24 calc fmms.for:18 assigncur.for:17 spice2sally3.for:19 spice2sally4.for:20 sol pint.for:59 sol pmat.for:41 sol mumag1.for:46 pre mutet.for:44 sally3dpost.for:55 sally3dpost.for:66 didn’t declare the vector size in variable declarations; • in / spice2sally3.for:46 spice2sally4.for:50 sol pbem.for:167 sol pmat.for:168 sally3dpre.for:22 sally3dpost.for:66 didn’t explicitly declare the comparison operands; • in / sol tontss.for:871 sol tontss.for:904 sally3dpost:2835 sally3dpost.for:2832 and in /src/work/ plotta.for:32 saveread map.for:100 saveread map.for:134 used illegal characters in multi line statements.