Use coarrays with a C main program

I am experimenting a bit with the combination C and coarrays, in particular:

  • The main program is C
  • This calls a simple Fortran routine compiled with the coarray option (I use ifort on Windows for now)

I can build the program without any complaints, but it does not print anything from the Fortran routine and actually seems to stop.

I attach the code.
run.txt (618 Bytes)

I checked with Dependency Walker if any DLLs were missing, but that was not the case.

Should I perhaps start it in a different way or add a call in the main (C) program to make sure that the coarray environment is started correctly?

1 Like

Found something here: CoarrayLib - GCC Wiki; not sure how up to date it is.

You may also like to (re-)read: Using coarrays in a shared library (OpenCoarrays) - #3 by themos

Aha, thanks! I will check these two.

At least to get a single image version working with the Intel compiler, you can try,

// Routines from libifcore
extern void for_rtl_init_(int *, char **);
extern int for_rtl_finish_();

extern void some_caf_subroutine(); // Fortran procedure using coarrays

int main(int argc, char **argv) {
  for_rtl_init_(&argc, argv);
  some_caf_subroutine();
  for_rtl_finish_(); // ignore status
  return 0;
}

When compiling with your C compiler, you’ll need to add the path of the Intel Fortran runtime libraries:

LDFLAGS=-L/opt/intel/oneapi/compiler/2024.0/lib
LDLIBS=-lifcore -licaf -ldl

main: main.c some_caf_subroutine.o
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LDLIBS)

I don’t think this is intended to work. Something has to initialise the images and whatever runtime library is used for the communication. If the main program isn’t Fortran then nothing knows to do so, let alone how.

1 Like

Using a Fortran main program of course does solve it. In my experiment the program simply calls the C routine which then calls the Fortran print routine. The C routine is clearly run by each image.

(By the way, I use ifort to link the program, so I do not have to worry about the libraries.)

TL;DR: …what @everythingfunctional said.

:warning: unportable internals exposed below :warning:

Inspecting the symbols using nm from binutils, it wasn’t hard to find a routine responsible for launching multiple images:

// WARNING: may be incorrect!
int for_rtl_ICAF_LAUNCH(int /*num_images*/, char* /*config*/, void * /* ??? */);

The first argument is the number of images corresponding to the flag -coarray-num-images= (no flag results in -1, giving as many images as available cores). The second argument corresponds to the argument of the flag -coarray-config-file=. I don’t know what the third argument is for; values other than NULL would crash the entire process :bomb:.

If you compile a coarray program with ifx in compiler explorer, another procedure appears:

caflaunch$MAIN$blk:
        push    rax
        mov     edi, -1
        xor     esi, esi
        xor     edx, edx
        call    for_rtl_ICAF_LAUNCH@PLT
        test    al, 1
        jne     .LBB1_1
        mov     edi, offset __unnamed_3
        pop     rax
        jmp     for_exit@PLT
.LBB1_1:
        pop     rax
        ret

which can be roughly decompiled to:

// "fake" caflaunch$MAIN$blk
extern "C" int caflaunch(void) {
	int result = for_rtl_ICAF_LAUNCH(-1,nullptr,nullptr);
	if ((result & 1) != 0) {
		return result;
	}
	return for_exit(0);
}

What is weird is that I couldn’t find any reference to this procedure (or it’s address) in the object file, so it remains unclear when or how this procedure is invoked and why it is there in the first place.

Empirically, calling the routine seems to fork the process and create multiple images:

int main(int argc, char **argv) {
  for_rtl_init_(&argc, argv);
  caflaunch();
// vvv  multiple images running  vvv
  some_caf_subroutine();
  for_rtl_finish_(); // ignore status
  return 0;
}

No matter what I tried, I couldn’t find a way to join the images back together and this behavior essentially matches the MPI model (upon which the Intel Coarray Fortran implementation is based). After a call to MPI_Finalize the number of processes (images) remains undefined, and the expectation is the program will exit.

So my suggestion for anyone trying to incorporate a coarray section into a non-Fortran program, would be to either:

  • launch a separate process and read/write whatever values needed using an external file
  • launch a separate process and communicate using IPC (this could be as simple as reading and writing to stdin/stdout)
  • invoke the non-Fortran program from the coarray Fortran program as suggested in the other thread

Hm, interesting. The reason I asked about this is that the intended use is something along these lines:

In a loop (configurable via a C++ program via some user-defined input file):

  • Let program 1 (or rather the main routine from a shared library) calculate one step.
  • At the end of the step, results are passed on to program 2 and there is an exchange between other instances of the same program.
  • Let program 2 pick up the results and do its own step (again exchanges between other instances of program 2 may happen).
  • Repeat until the end of the calculation.

The C++ program currently is responsible for managing the parallel instances (which all works via MPI), but I would like to be able to use coarrays instead of MPI.

At least that is the most complicated scenario I can foresee.