xref: /netbsd-src/external/gpl3/gcc.old/dist/libgfortran/caf/mpi.c (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1627f7eb2Smrg /* MPI implementation of GNU Fortran Coarray Library
2*4c3eb207Smrg    Copyright (C) 2011-2020 Free Software Foundation, Inc.
3627f7eb2Smrg    Contributed by Tobias Burnus <burnus@net-b.de>
4627f7eb2Smrg 
5627f7eb2Smrg This file is part of the GNU Fortran Coarray Runtime Library (libcaf).
6627f7eb2Smrg 
7627f7eb2Smrg Libcaf is free software; you can redistribute it and/or modify
8627f7eb2Smrg it under the terms of the GNU General Public License as published by
9627f7eb2Smrg the Free Software Foundation; either version 3, or (at your option)
10627f7eb2Smrg any later version.
11627f7eb2Smrg 
12627f7eb2Smrg Libcaf is distributed in the hope that it will be useful,
13627f7eb2Smrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14627f7eb2Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15627f7eb2Smrg GNU General Public License for more details.
16627f7eb2Smrg 
17627f7eb2Smrg Under Section 7 of GPL version 3, you are granted additional
18627f7eb2Smrg permissions described in the GCC Runtime Library Exception, version
19627f7eb2Smrg 3.1, as published by the Free Software Foundation.
20627f7eb2Smrg 
21627f7eb2Smrg You should have received a copy of the GNU General Public License and
22627f7eb2Smrg a copy of the GCC Runtime Library Exception along with this program;
23627f7eb2Smrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24627f7eb2Smrg <http://www.gnu.org/licenses/>.  */
25627f7eb2Smrg 
26627f7eb2Smrg #include "libcaf.h"
27627f7eb2Smrg #include <stdio.h>
28627f7eb2Smrg #include <stdlib.h>
29627f7eb2Smrg #include <string.h>	/* For memcpy.  */
30627f7eb2Smrg #include <stdarg.h>	/* For variadic arguments.  */
31627f7eb2Smrg #include <mpi.h>
32627f7eb2Smrg 
33627f7eb2Smrg 
34627f7eb2Smrg /* Define GFC_CAF_CHECK to enable run-time checking.  */
35627f7eb2Smrg /* #define GFC_CAF_CHECK  1  */
36627f7eb2Smrg 
37627f7eb2Smrg typedef void ** mpi_token_t;
38627f7eb2Smrg #define TOKEN(X) ((mpi_token_t) (X))
39627f7eb2Smrg 
40627f7eb2Smrg static void error_stop (int error) __attribute__ ((noreturn));
41627f7eb2Smrg 
42627f7eb2Smrg /* Global variables.  */
43627f7eb2Smrg static int caf_mpi_initialized;
44627f7eb2Smrg static int caf_this_image;
45627f7eb2Smrg static int caf_num_images;
46627f7eb2Smrg static int caf_is_finalized;
47627f7eb2Smrg 
48627f7eb2Smrg caf_static_t *caf_static_list = NULL;
49627f7eb2Smrg 
50627f7eb2Smrg 
51627f7eb2Smrg /* Keep in sync with single.c.  */
52627f7eb2Smrg static void
caf_runtime_error(const char * message,...)53627f7eb2Smrg caf_runtime_error (const char *message, ...)
54627f7eb2Smrg {
55627f7eb2Smrg   va_list ap;
56627f7eb2Smrg   fprintf (stderr, "Fortran runtime error on image %d: ", caf_this_image);
57627f7eb2Smrg   va_start (ap, message);
58627f7eb2Smrg   vfprintf (stderr, message, ap);
59627f7eb2Smrg   va_end (ap);
60627f7eb2Smrg   fprintf (stderr, "\n");
61627f7eb2Smrg 
62627f7eb2Smrg   /* FIXME: Shutdown the Fortran RTL to flush the buffer.  PR 43849.  */
63627f7eb2Smrg   /* FIXME: Do some more effort than just MPI_ABORT.  */
64627f7eb2Smrg   MPI_Abort (MPI_COMM_WORLD, EXIT_FAILURE);
65627f7eb2Smrg 
66627f7eb2Smrg   /* Should be unreachable, but to make sure also call exit.  */
67627f7eb2Smrg   exit (EXIT_FAILURE);
68627f7eb2Smrg }
69627f7eb2Smrg 
70627f7eb2Smrg 
71627f7eb2Smrg /* Initialize coarray program.  This routine assumes that no other
72627f7eb2Smrg    MPI initialization happened before; otherwise MPI_Initialized
73627f7eb2Smrg    had to be used.  As the MPI library might modify the command-line
74627f7eb2Smrg    arguments, the routine should be called before the run-time
75627f7eb2Smrg    libaray is initialized.  */
76627f7eb2Smrg 
77627f7eb2Smrg void
_gfortran_caf_init(int * argc,char *** argv)78627f7eb2Smrg _gfortran_caf_init (int *argc, char ***argv)
79627f7eb2Smrg {
80627f7eb2Smrg   if (caf_num_images == 0)
81627f7eb2Smrg     {
82627f7eb2Smrg       /* caf_mpi_initialized is only true if the main program is
83627f7eb2Smrg        not written in Fortran.  */
84627f7eb2Smrg       MPI_Initialized (&caf_mpi_initialized);
85627f7eb2Smrg       if (!caf_mpi_initialized)
86627f7eb2Smrg 	MPI_Init (argc, argv);
87627f7eb2Smrg 
88627f7eb2Smrg       MPI_Comm_size (MPI_COMM_WORLD, &caf_num_images);
89627f7eb2Smrg       MPI_Comm_rank (MPI_COMM_WORLD, &caf_this_image);
90627f7eb2Smrg       caf_this_image++;
91627f7eb2Smrg     }
92627f7eb2Smrg }
93627f7eb2Smrg 
94627f7eb2Smrg 
95627f7eb2Smrg /* Finalize coarray program.   */
96627f7eb2Smrg 
97627f7eb2Smrg void
_gfortran_caf_finalize(void)98627f7eb2Smrg _gfortran_caf_finalize (void)
99627f7eb2Smrg {
100627f7eb2Smrg   while (caf_static_list != NULL)
101627f7eb2Smrg     {
102627f7eb2Smrg       caf_static_t *tmp = caf_static_list->prev;
103627f7eb2Smrg 
104627f7eb2Smrg       free (TOKEN (caf_static_list->token)[caf_this_image-1]);
105627f7eb2Smrg       free (TOKEN (caf_static_list->token));
106627f7eb2Smrg       free (caf_static_list);
107627f7eb2Smrg       caf_static_list = tmp;
108627f7eb2Smrg     }
109627f7eb2Smrg 
110627f7eb2Smrg   if (!caf_mpi_initialized)
111627f7eb2Smrg     MPI_Finalize ();
112627f7eb2Smrg 
113627f7eb2Smrg   caf_is_finalized = 1;
114627f7eb2Smrg }
115627f7eb2Smrg 
116627f7eb2Smrg 
117627f7eb2Smrg int
_gfortran_caf_this_image(int distance)118627f7eb2Smrg _gfortran_caf_this_image (int distance __attribute__ ((unused)))
119627f7eb2Smrg {
120627f7eb2Smrg   return caf_this_image;
121627f7eb2Smrg }
122627f7eb2Smrg 
123627f7eb2Smrg 
124627f7eb2Smrg int
_gfortran_caf_num_images(int distance,int failed)125627f7eb2Smrg _gfortran_caf_num_images (int distance __attribute__ ((unused)),
126627f7eb2Smrg 			  int failed __attribute__ ((unused)))
127627f7eb2Smrg {
128627f7eb2Smrg   return caf_num_images;
129627f7eb2Smrg }
130627f7eb2Smrg 
131627f7eb2Smrg 
132627f7eb2Smrg void *
_gfortran_caf_register(size_t size,caf_register_t type,caf_token_t * token,int * stat,char * errmsg,size_t errmsg_len,int num_alloc_comps)133627f7eb2Smrg _gfortran_caf_register (size_t size, caf_register_t type, caf_token_t *token,
134627f7eb2Smrg 			int *stat, char *errmsg, size_t errmsg_len,
135627f7eb2Smrg 			int num_alloc_comps __attribute__ ((unused)))
136627f7eb2Smrg {
137627f7eb2Smrg   void *local;
138627f7eb2Smrg   int err;
139627f7eb2Smrg 
140627f7eb2Smrg   if (unlikely (caf_is_finalized))
141627f7eb2Smrg     goto error;
142627f7eb2Smrg 
143627f7eb2Smrg   /* Start MPI if not already started.  */
144627f7eb2Smrg   if (caf_num_images == 0)
145627f7eb2Smrg     _gfortran_caf_init (NULL, NULL);
146627f7eb2Smrg 
147627f7eb2Smrg   /* Token contains only a list of pointers.  */
148627f7eb2Smrg   local = malloc (size);
149627f7eb2Smrg   *token = malloc (sizeof (mpi_token_t) * caf_num_images);
150627f7eb2Smrg 
151627f7eb2Smrg   if (unlikely (local == NULL || *token == NULL))
152627f7eb2Smrg     goto error;
153627f7eb2Smrg 
154627f7eb2Smrg   /* token[img-1] is the address of the token in image "img".  */
155627f7eb2Smrg   err = MPI_Allgather (&local, sizeof (void*), MPI_BYTE, TOKEN (*token),
156627f7eb2Smrg 		       sizeof (void*), MPI_BYTE, MPI_COMM_WORLD);
157627f7eb2Smrg 
158627f7eb2Smrg   if (unlikely (err))
159627f7eb2Smrg     {
160627f7eb2Smrg       free (local);
161627f7eb2Smrg       free (*token);
162627f7eb2Smrg       goto error;
163627f7eb2Smrg     }
164627f7eb2Smrg 
165627f7eb2Smrg   if (type == CAF_REGTYPE_COARRAY_STATIC)
166627f7eb2Smrg     {
167627f7eb2Smrg       caf_static_t *tmp = malloc (sizeof (caf_static_t));
168627f7eb2Smrg       tmp->prev  = caf_static_list;
169627f7eb2Smrg       tmp->token = *token;
170627f7eb2Smrg       caf_static_list = tmp;
171627f7eb2Smrg     }
172627f7eb2Smrg 
173627f7eb2Smrg   if (stat)
174627f7eb2Smrg     *stat = 0;
175627f7eb2Smrg 
176627f7eb2Smrg   return local;
177627f7eb2Smrg 
178627f7eb2Smrg error:
179627f7eb2Smrg   {
180627f7eb2Smrg     char *msg;
181627f7eb2Smrg 
182627f7eb2Smrg     if (caf_is_finalized)
183627f7eb2Smrg       msg = "Failed to allocate coarray - there are stopped images";
184627f7eb2Smrg     else
185627f7eb2Smrg       msg = "Failed to allocate coarray";
186627f7eb2Smrg 
187627f7eb2Smrg     if (stat)
188627f7eb2Smrg       {
189627f7eb2Smrg 	*stat = caf_is_finalized ? STAT_STOPPED_IMAGE : 1;
190627f7eb2Smrg 	if (errmsg_len > 0)
191627f7eb2Smrg 	  {
192627f7eb2Smrg 	    size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
193627f7eb2Smrg 	      : strlen (msg);
194627f7eb2Smrg 	    memcpy (errmsg, msg, len);
195627f7eb2Smrg 	    if (errmsg_len > len)
196627f7eb2Smrg 	      memset (&errmsg[len], ' ', errmsg_len-len);
197627f7eb2Smrg 	  }
198627f7eb2Smrg       }
199627f7eb2Smrg     else
200627f7eb2Smrg       caf_runtime_error (msg);
201627f7eb2Smrg   }
202627f7eb2Smrg 
203627f7eb2Smrg   return NULL;
204627f7eb2Smrg }
205627f7eb2Smrg 
206627f7eb2Smrg 
207627f7eb2Smrg void
_gfortran_caf_deregister(caf_token_t * token,int * stat,char * errmsg,size_t errmsg_len)208627f7eb2Smrg _gfortran_caf_deregister (caf_token_t *token, int *stat, char *errmsg, size_t errmsg_len)
209627f7eb2Smrg {
210627f7eb2Smrg   if (unlikely (caf_is_finalized))
211627f7eb2Smrg     {
212627f7eb2Smrg       const char msg[] = "Failed to deallocate coarray - "
213627f7eb2Smrg 			  "there are stopped images";
214627f7eb2Smrg       if (stat)
215627f7eb2Smrg 	{
216627f7eb2Smrg 	  *stat = STAT_STOPPED_IMAGE;
217627f7eb2Smrg 
218627f7eb2Smrg 	  if (errmsg_len > 0)
219627f7eb2Smrg 	    {
220627f7eb2Smrg 	      size_t len = (sizeof (msg) - 1 > errmsg_len)
221627f7eb2Smrg 		? errmsg_len : sizeof (msg) - 1;
222627f7eb2Smrg 	      memcpy (errmsg, msg, len);
223627f7eb2Smrg 	      if (errmsg_len > len)
224627f7eb2Smrg 		memset (&errmsg[len], ' ', errmsg_len-len);
225627f7eb2Smrg 	    }
226627f7eb2Smrg 	  return;
227627f7eb2Smrg 	}
228627f7eb2Smrg       caf_runtime_error (msg);
229627f7eb2Smrg     }
230627f7eb2Smrg 
231627f7eb2Smrg   _gfortran_caf_sync_all (NULL, NULL, 0);
232627f7eb2Smrg 
233627f7eb2Smrg   if (stat)
234627f7eb2Smrg     *stat = 0;
235627f7eb2Smrg 
236627f7eb2Smrg   free (TOKEN (*token)[caf_this_image-1]);
237627f7eb2Smrg   free (*token);
238627f7eb2Smrg }
239627f7eb2Smrg 
240627f7eb2Smrg 
241627f7eb2Smrg void
_gfortran_caf_sync_all(int * stat,char * errmsg,size_t errmsg_len)242627f7eb2Smrg _gfortran_caf_sync_all (int *stat, char *errmsg, size_t errmsg_len)
243627f7eb2Smrg {
244627f7eb2Smrg   int ierr;
245627f7eb2Smrg 
246627f7eb2Smrg   if (unlikely (caf_is_finalized))
247627f7eb2Smrg     ierr = STAT_STOPPED_IMAGE;
248627f7eb2Smrg   else
249627f7eb2Smrg     ierr = MPI_Barrier (MPI_COMM_WORLD);
250627f7eb2Smrg 
251627f7eb2Smrg   if (stat)
252627f7eb2Smrg     *stat = ierr;
253627f7eb2Smrg 
254627f7eb2Smrg   if (ierr)
255627f7eb2Smrg     {
256627f7eb2Smrg       char *msg;
257627f7eb2Smrg       if (caf_is_finalized)
258627f7eb2Smrg 	msg = "SYNC ALL failed - there are stopped images";
259627f7eb2Smrg       else
260627f7eb2Smrg 	msg = "SYNC ALL failed";
261627f7eb2Smrg 
262627f7eb2Smrg       if (errmsg_len > 0)
263627f7eb2Smrg 	{
264627f7eb2Smrg 	  size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
265627f7eb2Smrg 	    : strlen (msg);
266627f7eb2Smrg 	  memcpy (errmsg, msg, len);
267627f7eb2Smrg 	  if (errmsg_len > len)
268627f7eb2Smrg 	    memset (&errmsg[len], ' ', errmsg_len-len);
269627f7eb2Smrg 	}
270627f7eb2Smrg       else
271627f7eb2Smrg 	caf_runtime_error (msg);
272627f7eb2Smrg     }
273627f7eb2Smrg }
274627f7eb2Smrg 
275627f7eb2Smrg 
276627f7eb2Smrg /* SYNC IMAGES. Note: SYNC IMAGES(*) is passed as count == -1 while
277627f7eb2Smrg    SYNC IMAGES([]) has count == 0. Note further that SYNC IMAGES(*)
278627f7eb2Smrg    is not equivalent to SYNC ALL. */
279627f7eb2Smrg void
_gfortran_caf_sync_images(int count,int images[],int * stat,char * errmsg,size_t errmsg_len)280627f7eb2Smrg _gfortran_caf_sync_images (int count, int images[], int *stat, char *errmsg,
281627f7eb2Smrg 			   size_t errmsg_len)
282627f7eb2Smrg {
283627f7eb2Smrg   int ierr;
284627f7eb2Smrg   if (count == 0 || (count == 1 && images[0] == caf_this_image))
285627f7eb2Smrg     {
286627f7eb2Smrg       if (stat)
287627f7eb2Smrg 	*stat = 0;
288627f7eb2Smrg       return;
289627f7eb2Smrg     }
290627f7eb2Smrg 
291627f7eb2Smrg #ifdef GFC_CAF_CHECK
292627f7eb2Smrg   {
293627f7eb2Smrg     int i;
294627f7eb2Smrg 
295627f7eb2Smrg     for (i = 0; i < count; i++)
296627f7eb2Smrg       if (images[i] < 1 || images[i] > caf_num_images)
297627f7eb2Smrg 	{
298627f7eb2Smrg 	  fprintf (stderr, "COARRAY ERROR: Invalid image index %d to SYNC "
299627f7eb2Smrg 		   "IMAGES", images[i]);
300627f7eb2Smrg 	  error_stop (1);
301627f7eb2Smrg 	}
302627f7eb2Smrg   }
303627f7eb2Smrg #endif
304627f7eb2Smrg 
305627f7eb2Smrg   /* FIXME: SYNC IMAGES with a nontrivial argument cannot easily be
306627f7eb2Smrg      mapped to MPI communicators. Thus, exist early with an error message.  */
307627f7eb2Smrg   if (count > 0)
308627f7eb2Smrg     {
309627f7eb2Smrg       fprintf (stderr, "COARRAY ERROR: SYNC IMAGES not yet implemented");
310627f7eb2Smrg       error_stop (1);
311627f7eb2Smrg     }
312627f7eb2Smrg 
313627f7eb2Smrg   /* Handle SYNC IMAGES(*).  */
314627f7eb2Smrg   if (unlikely (caf_is_finalized))
315627f7eb2Smrg     ierr = STAT_STOPPED_IMAGE;
316627f7eb2Smrg   else
317627f7eb2Smrg     ierr = MPI_Barrier (MPI_COMM_WORLD);
318627f7eb2Smrg 
319627f7eb2Smrg   if (stat)
320627f7eb2Smrg     *stat = ierr;
321627f7eb2Smrg 
322627f7eb2Smrg   if (ierr)
323627f7eb2Smrg     {
324627f7eb2Smrg       char *msg;
325627f7eb2Smrg       if (caf_is_finalized)
326627f7eb2Smrg 	msg = "SYNC IMAGES failed - there are stopped images";
327627f7eb2Smrg       else
328627f7eb2Smrg 	msg = "SYNC IMAGES failed";
329627f7eb2Smrg 
330627f7eb2Smrg       if (errmsg_len > 0)
331627f7eb2Smrg 	{
332627f7eb2Smrg 	  size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
333627f7eb2Smrg 	    : strlen (msg);
334627f7eb2Smrg 	  memcpy (errmsg, msg, len);
335627f7eb2Smrg 	  if (errmsg_len > len)
336627f7eb2Smrg 	    memset (&errmsg[len], ' ', errmsg_len-len);
337627f7eb2Smrg 	}
338627f7eb2Smrg       else
339627f7eb2Smrg 	caf_runtime_error (msg);
340627f7eb2Smrg     }
341627f7eb2Smrg }
342627f7eb2Smrg 
343627f7eb2Smrg 
344627f7eb2Smrg /* ERROR STOP the other images.  */
345627f7eb2Smrg 
346627f7eb2Smrg static void
error_stop(int error)347627f7eb2Smrg error_stop (int error)
348627f7eb2Smrg {
349627f7eb2Smrg   /* FIXME: Shutdown the Fortran RTL to flush the buffer.  PR 43849.  */
350627f7eb2Smrg   /* FIXME: Do some more effort than just MPI_ABORT.  */
351627f7eb2Smrg   MPI_Abort (MPI_COMM_WORLD, error);
352627f7eb2Smrg 
353627f7eb2Smrg   /* Should be unreachable, but to make sure also call exit.  */
354627f7eb2Smrg   exit (error);
355627f7eb2Smrg }
356627f7eb2Smrg 
357627f7eb2Smrg 
358627f7eb2Smrg /* ERROR STOP function for string arguments.  */
359627f7eb2Smrg 
360627f7eb2Smrg void
_gfortran_caf_error_stop_str(const char * string,size_t len,bool quiet)361627f7eb2Smrg _gfortran_caf_error_stop_str (const char *string, size_t len, bool quiet)
362627f7eb2Smrg {
363627f7eb2Smrg   if (!quiet)
364627f7eb2Smrg     {
365627f7eb2Smrg       fputs ("ERROR STOP ", stderr);
366627f7eb2Smrg       while (len--)
367627f7eb2Smrg 	fputc (*(string++), stderr);
368627f7eb2Smrg       fputs ("\n", stderr);
369627f7eb2Smrg     }
370627f7eb2Smrg   error_stop (1);
371627f7eb2Smrg }
372627f7eb2Smrg 
373627f7eb2Smrg 
374627f7eb2Smrg /* ERROR STOP function for numerical arguments.  */
375627f7eb2Smrg 
376627f7eb2Smrg void
_gfortran_caf_error_stop(int error,bool quiet)377627f7eb2Smrg _gfortran_caf_error_stop (int error, bool quiet)
378627f7eb2Smrg {
379627f7eb2Smrg   if (!quiet)
380627f7eb2Smrg     fprintf (stderr, "ERROR STOP %d\n", error);
381627f7eb2Smrg   error_stop (error);
382627f7eb2Smrg }
383