The Fortran -> C Route

In this approach, we investigated converting the problematic Fortran code to C (which we can trace). Obviously, a hand conversion is out of the question for a number of reasons:

Fortunately, automated Fortran to C conversion tools do exist, such as f2c, hosted at netlib. Generally speaking, such tools give very mixed results and often incomprehensible output. f2c is no exception in this regard; this is mitigated, however, by the very light external dependencies of these benchmarks. The basic steps for a conversion are as follows:

The Method

  1. Download f2c and libf2c. Compile both, keeping f2c.h, libf2c.a, and f2c itself handy.
  2. Copy <NASDIR>/common/randi8.o to wherever you put libf2c.a.
  3. Create a local copy of the benchmark; from the root of the NPB distribution, a command similar to the following works:

    cat common/timers.f common/print_results.f CG/cg.f > /tmp/cg.f

    This simplifies the linking process later (adding in randi8.f is possible but requires some fixing up of the Fortran code; it is easier just to link in the already compiled object code).
  4. The actual conversion is performed with a command like the following:

    f2c -I/opt/mpich-1.2.4..8/include cg.f

    This produces cg.c.
  5. The resulting C program can then be compiled with a Makefile like the following (directories will have to change, depending on circumstances, of course):
    CC=mpicc
    LINK=mpicc
    
    CFLAGS=-g -I./ 
    
    LIBDIRS=-L/home/travitc/lib -L./
    LIBS=randi8.o -lf2c -lumpire -lm 
    
    cg.A.4: cg/4/cg.c
    	$(CC) $(CFLAGS) -o cg.A.4 cg/4/cg.c $(LIBDIRS) $(LIBS)
    					
  6. Now comes the interesting part: converting the MPI calls to their C counterparts. Converting the standard calls (ie MPI_Send) is mechanical: remove the ierr argument from each call and remove extraneous address-of operators that do not make sense in the C context (but maintain Fortran semantics); this is most of them.

    The difficult call is, of course, MPI_Init; the C version expects to be passed argc and argv, but these two variables are not available in the stub main function (MAIN__) created by f2c. This can be addressed by declaring:

    extern int xargc
    extern char** xargv

    These two symbols are provided by libf2c.a for just this purpose, and the call can look like MPI_Init(&xargc, &xargv).

Generally speaking, just this and a few more spot modifications that are apparent from compiler errors are sufficient to make the benchmark compile in C.

Initial Results

The initial results of this method are fairly promising; the resulting C program compiles and executes; when linked with the umpire library, the recorded_ops directory is even created and filled with output files.

Unfortunately, this does not appear to be quite sufficient; the conversion process retains many artifacts of Fortran semantics (every argument is passed via reference by default, for example). The resulting program begins to execute but does not finish (or even seem to start any useful computation). The addresses of some function parameters are taken in inappropriate contexts for several calls, and function calls (especially to external functions) need to be analyzed for such occurences. If such an analysis is completed, the results should be very acceptable.

Final Results

We won't per pursuing this direction any further (as the real solution was much more pertinent); the experience was, however, invaluable. Without attempting the f2c conversion and encountering the problem of converting Fortran's mpi_init to C's MPI_Init and seeing the problems of passing junk data to MPICH's implementation of PMPI_Init, we would not have paid any mind to that practice in umpire/record.

Valid XHTML 1.0 Strict