mpi.c revision 1.1.1.3 1 1.1 mrg /* MPI implementation of GNU Fortran Coarray Library
2 1.1.1.3 mrg Copyright (C) 2011-2022 Free Software Foundation, Inc.
3 1.1 mrg Contributed by Tobias Burnus <burnus (at) net-b.de>
4 1.1 mrg
5 1.1 mrg This file is part of the GNU Fortran Coarray Runtime Library (libcaf).
6 1.1 mrg
7 1.1 mrg Libcaf is free software; you can redistribute it and/or modify
8 1.1 mrg it under the terms of the GNU General Public License as published by
9 1.1 mrg the Free Software Foundation; either version 3, or (at your option)
10 1.1 mrg any later version.
11 1.1 mrg
12 1.1 mrg Libcaf is distributed in the hope that it will be useful,
13 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 1.1 mrg GNU General Public License for more details.
16 1.1 mrg
17 1.1 mrg Under Section 7 of GPL version 3, you are granted additional
18 1.1 mrg permissions described in the GCC Runtime Library Exception, version
19 1.1 mrg 3.1, as published by the Free Software Foundation.
20 1.1 mrg
21 1.1 mrg You should have received a copy of the GNU General Public License and
22 1.1 mrg a copy of the GCC Runtime Library Exception along with this program;
23 1.1 mrg see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 1.1 mrg <http://www.gnu.org/licenses/>. */
25 1.1 mrg
26 1.1 mrg #include "libcaf.h"
27 1.1 mrg #include <stdio.h>
28 1.1 mrg #include <stdlib.h>
29 1.1 mrg #include <string.h> /* For memcpy. */
30 1.1 mrg #include <stdarg.h> /* For variadic arguments. */
31 1.1 mrg #include <mpi.h>
32 1.1 mrg
33 1.1 mrg
34 1.1 mrg /* Define GFC_CAF_CHECK to enable run-time checking. */
35 1.1 mrg /* #define GFC_CAF_CHECK 1 */
36 1.1 mrg
37 1.1 mrg typedef void ** mpi_token_t;
38 1.1 mrg #define TOKEN(X) ((mpi_token_t) (X))
39 1.1 mrg
40 1.1 mrg static void error_stop (int error) __attribute__ ((noreturn));
41 1.1 mrg
42 1.1 mrg /* Global variables. */
43 1.1 mrg static int caf_mpi_initialized;
44 1.1 mrg static int caf_this_image;
45 1.1 mrg static int caf_num_images;
46 1.1 mrg static int caf_is_finalized;
47 1.1 mrg
48 1.1 mrg caf_static_t *caf_static_list = NULL;
49 1.1 mrg
50 1.1 mrg
51 1.1 mrg /* Keep in sync with single.c. */
52 1.1 mrg static void
53 1.1 mrg caf_runtime_error (const char *message, ...)
54 1.1 mrg {
55 1.1 mrg va_list ap;
56 1.1 mrg fprintf (stderr, "Fortran runtime error on image %d: ", caf_this_image);
57 1.1 mrg va_start (ap, message);
58 1.1 mrg vfprintf (stderr, message, ap);
59 1.1 mrg va_end (ap);
60 1.1 mrg fprintf (stderr, "\n");
61 1.1 mrg
62 1.1 mrg /* FIXME: Shutdown the Fortran RTL to flush the buffer. PR 43849. */
63 1.1 mrg /* FIXME: Do some more effort than just MPI_ABORT. */
64 1.1 mrg MPI_Abort (MPI_COMM_WORLD, EXIT_FAILURE);
65 1.1 mrg
66 1.1 mrg /* Should be unreachable, but to make sure also call exit. */
67 1.1 mrg exit (EXIT_FAILURE);
68 1.1 mrg }
69 1.1 mrg
70 1.1 mrg
71 1.1 mrg /* Initialize coarray program. This routine assumes that no other
72 1.1 mrg MPI initialization happened before; otherwise MPI_Initialized
73 1.1 mrg had to be used. As the MPI library might modify the command-line
74 1.1 mrg arguments, the routine should be called before the run-time
75 1.1 mrg libaray is initialized. */
76 1.1 mrg
77 1.1 mrg void
78 1.1 mrg _gfortran_caf_init (int *argc, char ***argv)
79 1.1 mrg {
80 1.1 mrg if (caf_num_images == 0)
81 1.1 mrg {
82 1.1 mrg /* caf_mpi_initialized is only true if the main program is
83 1.1 mrg not written in Fortran. */
84 1.1 mrg MPI_Initialized (&caf_mpi_initialized);
85 1.1 mrg if (!caf_mpi_initialized)
86 1.1 mrg MPI_Init (argc, argv);
87 1.1 mrg
88 1.1 mrg MPI_Comm_size (MPI_COMM_WORLD, &caf_num_images);
89 1.1 mrg MPI_Comm_rank (MPI_COMM_WORLD, &caf_this_image);
90 1.1 mrg caf_this_image++;
91 1.1 mrg }
92 1.1 mrg }
93 1.1 mrg
94 1.1 mrg
95 1.1 mrg /* Finalize coarray program. */
96 1.1 mrg
97 1.1 mrg void
98 1.1 mrg _gfortran_caf_finalize (void)
99 1.1 mrg {
100 1.1 mrg while (caf_static_list != NULL)
101 1.1 mrg {
102 1.1 mrg caf_static_t *tmp = caf_static_list->prev;
103 1.1 mrg
104 1.1 mrg free (TOKEN (caf_static_list->token)[caf_this_image-1]);
105 1.1 mrg free (TOKEN (caf_static_list->token));
106 1.1 mrg free (caf_static_list);
107 1.1 mrg caf_static_list = tmp;
108 1.1 mrg }
109 1.1 mrg
110 1.1 mrg if (!caf_mpi_initialized)
111 1.1 mrg MPI_Finalize ();
112 1.1 mrg
113 1.1 mrg caf_is_finalized = 1;
114 1.1 mrg }
115 1.1 mrg
116 1.1 mrg
117 1.1 mrg int
118 1.1 mrg _gfortran_caf_this_image (int distance __attribute__ ((unused)))
119 1.1 mrg {
120 1.1 mrg return caf_this_image;
121 1.1 mrg }
122 1.1 mrg
123 1.1 mrg
124 1.1 mrg int
125 1.1 mrg _gfortran_caf_num_images (int distance __attribute__ ((unused)),
126 1.1 mrg int failed __attribute__ ((unused)))
127 1.1 mrg {
128 1.1 mrg return caf_num_images;
129 1.1 mrg }
130 1.1 mrg
131 1.1 mrg
132 1.1 mrg void *
133 1.1 mrg _gfortran_caf_register (size_t size, caf_register_t type, caf_token_t *token,
134 1.1 mrg int *stat, char *errmsg, size_t errmsg_len,
135 1.1 mrg int num_alloc_comps __attribute__ ((unused)))
136 1.1 mrg {
137 1.1 mrg void *local;
138 1.1 mrg int err;
139 1.1 mrg
140 1.1 mrg if (unlikely (caf_is_finalized))
141 1.1 mrg goto error;
142 1.1 mrg
143 1.1 mrg /* Start MPI if not already started. */
144 1.1 mrg if (caf_num_images == 0)
145 1.1 mrg _gfortran_caf_init (NULL, NULL);
146 1.1 mrg
147 1.1 mrg /* Token contains only a list of pointers. */
148 1.1 mrg local = malloc (size);
149 1.1 mrg *token = malloc (sizeof (mpi_token_t) * caf_num_images);
150 1.1 mrg
151 1.1 mrg if (unlikely (local == NULL || *token == NULL))
152 1.1 mrg goto error;
153 1.1 mrg
154 1.1 mrg /* token[img-1] is the address of the token in image "img". */
155 1.1 mrg err = MPI_Allgather (&local, sizeof (void*), MPI_BYTE, TOKEN (*token),
156 1.1 mrg sizeof (void*), MPI_BYTE, MPI_COMM_WORLD);
157 1.1 mrg
158 1.1 mrg if (unlikely (err))
159 1.1 mrg {
160 1.1 mrg free (local);
161 1.1 mrg free (*token);
162 1.1 mrg goto error;
163 1.1 mrg }
164 1.1 mrg
165 1.1 mrg if (type == CAF_REGTYPE_COARRAY_STATIC)
166 1.1 mrg {
167 1.1 mrg caf_static_t *tmp = malloc (sizeof (caf_static_t));
168 1.1 mrg tmp->prev = caf_static_list;
169 1.1 mrg tmp->token = *token;
170 1.1 mrg caf_static_list = tmp;
171 1.1 mrg }
172 1.1 mrg
173 1.1 mrg if (stat)
174 1.1 mrg *stat = 0;
175 1.1 mrg
176 1.1 mrg return local;
177 1.1 mrg
178 1.1 mrg error:
179 1.1 mrg {
180 1.1 mrg char *msg;
181 1.1 mrg
182 1.1 mrg if (caf_is_finalized)
183 1.1 mrg msg = "Failed to allocate coarray - there are stopped images";
184 1.1 mrg else
185 1.1 mrg msg = "Failed to allocate coarray";
186 1.1 mrg
187 1.1 mrg if (stat)
188 1.1 mrg {
189 1.1 mrg *stat = caf_is_finalized ? STAT_STOPPED_IMAGE : 1;
190 1.1 mrg if (errmsg_len > 0)
191 1.1 mrg {
192 1.1 mrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
193 1.1 mrg : strlen (msg);
194 1.1 mrg memcpy (errmsg, msg, len);
195 1.1 mrg if (errmsg_len > len)
196 1.1 mrg memset (&errmsg[len], ' ', errmsg_len-len);
197 1.1 mrg }
198 1.1 mrg }
199 1.1 mrg else
200 1.1 mrg caf_runtime_error (msg);
201 1.1 mrg }
202 1.1 mrg
203 1.1 mrg return NULL;
204 1.1 mrg }
205 1.1 mrg
206 1.1 mrg
207 1.1 mrg void
208 1.1 mrg _gfortran_caf_deregister (caf_token_t *token, int *stat, char *errmsg, size_t errmsg_len)
209 1.1 mrg {
210 1.1 mrg if (unlikely (caf_is_finalized))
211 1.1 mrg {
212 1.1 mrg const char msg[] = "Failed to deallocate coarray - "
213 1.1 mrg "there are stopped images";
214 1.1 mrg if (stat)
215 1.1 mrg {
216 1.1 mrg *stat = STAT_STOPPED_IMAGE;
217 1.1 mrg
218 1.1 mrg if (errmsg_len > 0)
219 1.1 mrg {
220 1.1 mrg size_t len = (sizeof (msg) - 1 > errmsg_len)
221 1.1 mrg ? errmsg_len : sizeof (msg) - 1;
222 1.1 mrg memcpy (errmsg, msg, len);
223 1.1 mrg if (errmsg_len > len)
224 1.1 mrg memset (&errmsg[len], ' ', errmsg_len-len);
225 1.1 mrg }
226 1.1 mrg return;
227 1.1 mrg }
228 1.1 mrg caf_runtime_error (msg);
229 1.1 mrg }
230 1.1 mrg
231 1.1 mrg _gfortran_caf_sync_all (NULL, NULL, 0);
232 1.1 mrg
233 1.1 mrg if (stat)
234 1.1 mrg *stat = 0;
235 1.1 mrg
236 1.1 mrg free (TOKEN (*token)[caf_this_image-1]);
237 1.1 mrg free (*token);
238 1.1 mrg }
239 1.1 mrg
240 1.1 mrg
241 1.1 mrg void
242 1.1 mrg _gfortran_caf_sync_all (int *stat, char *errmsg, size_t errmsg_len)
243 1.1 mrg {
244 1.1 mrg int ierr;
245 1.1 mrg
246 1.1 mrg if (unlikely (caf_is_finalized))
247 1.1 mrg ierr = STAT_STOPPED_IMAGE;
248 1.1 mrg else
249 1.1 mrg ierr = MPI_Barrier (MPI_COMM_WORLD);
250 1.1 mrg
251 1.1 mrg if (stat)
252 1.1 mrg *stat = ierr;
253 1.1 mrg
254 1.1 mrg if (ierr)
255 1.1 mrg {
256 1.1 mrg char *msg;
257 1.1 mrg if (caf_is_finalized)
258 1.1 mrg msg = "SYNC ALL failed - there are stopped images";
259 1.1 mrg else
260 1.1 mrg msg = "SYNC ALL failed";
261 1.1 mrg
262 1.1 mrg if (errmsg_len > 0)
263 1.1 mrg {
264 1.1 mrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
265 1.1 mrg : strlen (msg);
266 1.1 mrg memcpy (errmsg, msg, len);
267 1.1 mrg if (errmsg_len > len)
268 1.1 mrg memset (&errmsg[len], ' ', errmsg_len-len);
269 1.1 mrg }
270 1.1 mrg else
271 1.1 mrg caf_runtime_error (msg);
272 1.1 mrg }
273 1.1 mrg }
274 1.1 mrg
275 1.1 mrg
276 1.1 mrg /* SYNC IMAGES. Note: SYNC IMAGES(*) is passed as count == -1 while
277 1.1 mrg SYNC IMAGES([]) has count == 0. Note further that SYNC IMAGES(*)
278 1.1 mrg is not equivalent to SYNC ALL. */
279 1.1 mrg void
280 1.1 mrg _gfortran_caf_sync_images (int count, int images[], int *stat, char *errmsg,
281 1.1 mrg size_t errmsg_len)
282 1.1 mrg {
283 1.1 mrg int ierr;
284 1.1 mrg if (count == 0 || (count == 1 && images[0] == caf_this_image))
285 1.1 mrg {
286 1.1 mrg if (stat)
287 1.1 mrg *stat = 0;
288 1.1 mrg return;
289 1.1 mrg }
290 1.1 mrg
291 1.1 mrg #ifdef GFC_CAF_CHECK
292 1.1 mrg {
293 1.1 mrg int i;
294 1.1 mrg
295 1.1 mrg for (i = 0; i < count; i++)
296 1.1 mrg if (images[i] < 1 || images[i] > caf_num_images)
297 1.1 mrg {
298 1.1 mrg fprintf (stderr, "COARRAY ERROR: Invalid image index %d to SYNC "
299 1.1 mrg "IMAGES", images[i]);
300 1.1 mrg error_stop (1);
301 1.1 mrg }
302 1.1 mrg }
303 1.1 mrg #endif
304 1.1 mrg
305 1.1 mrg /* FIXME: SYNC IMAGES with a nontrivial argument cannot easily be
306 1.1 mrg mapped to MPI communicators. Thus, exist early with an error message. */
307 1.1 mrg if (count > 0)
308 1.1 mrg {
309 1.1 mrg fprintf (stderr, "COARRAY ERROR: SYNC IMAGES not yet implemented");
310 1.1 mrg error_stop (1);
311 1.1 mrg }
312 1.1 mrg
313 1.1 mrg /* Handle SYNC IMAGES(*). */
314 1.1 mrg if (unlikely (caf_is_finalized))
315 1.1 mrg ierr = STAT_STOPPED_IMAGE;
316 1.1 mrg else
317 1.1 mrg ierr = MPI_Barrier (MPI_COMM_WORLD);
318 1.1 mrg
319 1.1 mrg if (stat)
320 1.1 mrg *stat = ierr;
321 1.1 mrg
322 1.1 mrg if (ierr)
323 1.1 mrg {
324 1.1 mrg char *msg;
325 1.1 mrg if (caf_is_finalized)
326 1.1 mrg msg = "SYNC IMAGES failed - there are stopped images";
327 1.1 mrg else
328 1.1 mrg msg = "SYNC IMAGES failed";
329 1.1 mrg
330 1.1 mrg if (errmsg_len > 0)
331 1.1 mrg {
332 1.1 mrg size_t len = (strlen (msg) > errmsg_len) ? errmsg_len
333 1.1 mrg : strlen (msg);
334 1.1 mrg memcpy (errmsg, msg, len);
335 1.1 mrg if (errmsg_len > len)
336 1.1 mrg memset (&errmsg[len], ' ', errmsg_len-len);
337 1.1 mrg }
338 1.1 mrg else
339 1.1 mrg caf_runtime_error (msg);
340 1.1 mrg }
341 1.1 mrg }
342 1.1 mrg
343 1.1 mrg
344 1.1 mrg /* ERROR STOP the other images. */
345 1.1 mrg
346 1.1 mrg static void
347 1.1 mrg error_stop (int error)
348 1.1 mrg {
349 1.1 mrg /* FIXME: Shutdown the Fortran RTL to flush the buffer. PR 43849. */
350 1.1 mrg /* FIXME: Do some more effort than just MPI_ABORT. */
351 1.1 mrg MPI_Abort (MPI_COMM_WORLD, error);
352 1.1 mrg
353 1.1 mrg /* Should be unreachable, but to make sure also call exit. */
354 1.1 mrg exit (error);
355 1.1 mrg }
356 1.1 mrg
357 1.1 mrg
358 1.1 mrg /* ERROR STOP function for string arguments. */
359 1.1 mrg
360 1.1 mrg void
361 1.1 mrg _gfortran_caf_error_stop_str (const char *string, size_t len, bool quiet)
362 1.1 mrg {
363 1.1 mrg if (!quiet)
364 1.1 mrg {
365 1.1 mrg fputs ("ERROR STOP ", stderr);
366 1.1 mrg while (len--)
367 1.1 mrg fputc (*(string++), stderr);
368 1.1 mrg fputs ("\n", stderr);
369 1.1 mrg }
370 1.1 mrg error_stop (1);
371 1.1 mrg }
372 1.1 mrg
373 1.1 mrg
374 1.1 mrg /* ERROR STOP function for numerical arguments. */
375 1.1 mrg
376 1.1 mrg void
377 1.1 mrg _gfortran_caf_error_stop (int error, bool quiet)
378 1.1 mrg {
379 1.1 mrg if (!quiet)
380 1.1 mrg fprintf (stderr, "ERROR STOP %d\n", error);
381 1.1 mrg error_stop (error);
382 1.1 mrg }
383