ICON Community Interface 0.4.0
Loading...
Searching...
No Matches
mpi_handshake.c
Go to the documentation of this file.
1/*
2 * Keywords:
3 * Maintainer: Moritz Hanke <hanke@dkrz.de>
4 * URL: https://gitlab.dkrz.de/dkrz-sw/mpi-handshake
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * Redistributions of source code must retain the above copyright notice,
11 * this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * Neither the name of the DKRZ GmbH nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
22 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
25 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <limits.h>
35#include <mpi.h>
36#include <stdint.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40
41// taken from http://beige.ucs.indiana.edu/I590/node85.html
42static void mh_mpi_error(int error_code, MPI_Comm comm) {
43 int rank;
44 MPI_Comm_rank(comm, &rank);
45
46 char error_string[MPI_MAX_ERROR_STRING];
47 int length_of_error_string, error_class;
48
49 MPI_Error_class(error_code, &error_class);
50 MPI_Error_string(error_class, error_string, &length_of_error_string);
51 fprintf(stderr, "%3d: %s\n", rank, error_string);
52 MPI_Abort(comm, error_code);
53}
54
55static void mh_abort(const char *error_string, MPI_Comm comm, const char *file,
56 int line) {
57
58 int rank;
59 MPI_Comm_rank(comm, &rank);
60
61 fprintf(stderr, "%3d: %s\n", rank, error_string);
62 fprintf(stderr, "Aborting in file %s, line %i ...\n", file, line);
63 MPI_Abort(comm, EXIT_FAILURE);
64}
65
66#define mh_mpi_call(call, comm) \
67 do { \
68 int error_code = (call); \
69 if (error_code != MPI_SUCCESS) \
70 mh_mpi_error(error_code, comm); \
71 } while (0)
72
73#define mh_assert(exp, msg, comm) \
74 { \
75 if (!((exp))) \
76 mh_abort(((msg)), ((comm)), __FILE__, __LINE__); \
77 }
78
79void mpi_handshake(char const **group_names, MPI_Comm *group_comms, size_t n,
80 MPI_Comm comm) {
81
82 // check whether comm is an intercomm
83 int is_intercomm;
84 mh_mpi_call(MPI_Comm_test_inter(comm, &is_intercomm), comm);
85 mh_assert(!is_intercomm,
86 "ERROR(mpi_handshake): inter-communicators are not supported",
87 comm);
88
89 // STEP 1: Version exchange
90 enum { MPI_HANDSHAKE_VERSION = 1 };
91 int mh_version = MPI_HANDSHAKE_VERSION;
93 MPI_Allreduce(MPI_IN_PLACE, &mh_version, 1, MPI_INT, MPI_MIN, comm),
94 comm);
95 mh_assert(mh_version == MPI_HANDSHAKE_VERSION,
96 "ERROR(mpi_handshake): version mismatch."
97 "This implementation of the MPI handshake only supports version 1",
98 comm);
99
100 // generate communicators
101 int rank, size;
102 MPI_Comm_rank(comm, &rank);
103 MPI_Comm_size(comm, &size);
104 for (size_t i = 0; i < n; ++i)
105 group_comms[i] = MPI_COMM_NULL;
106
107 while (1) {
108 // STEP 2: determine broadcasting rank
109 size_t group_idx = SIZE_MAX;
110 for (size_t i = 0; (i < n) && (group_idx == SIZE_MAX); ++i)
111 if (group_comms[i] == MPI_COMM_NULL)
112 group_idx = i;
113 int broadcasting_rank = group_idx != SIZE_MAX ? rank : size;
114 mh_mpi_call(MPI_Allreduce(MPI_IN_PLACE, &broadcasting_rank, 1, MPI_INT,
115 MPI_MIN, comm),
116 comm);
117 mh_assert(broadcasting_rank >= 0 && broadcasting_rank <= size,
118 "ERROR(mpi_handshake): "
119 "broadcasting rank cannot be negativ or greater than "
120 "communicator size.",
121 comm);
122 if (broadcasting_rank == size)
123 break;
124
125 // STEP 3: broadcast group name
126 int group_name_buffer_size = 0;
127 if (broadcasting_rank == rank) {
128 size_t len = strlen(group_names[group_idx]);
129 mh_assert(len <= INT_MAX,
130 "ERROR(yac_mpi_handshake): group name is too long", comm);
131 group_name_buffer_size = (int)len;
132 }
133 MPI_Bcast(&group_name_buffer_size, 1, MPI_INT, broadcasting_rank, comm);
134 char *group_name_buffer =
135 malloc((group_name_buffer_size + 1) * sizeof(*group_name_buffer));
136 mh_assert(group_name_buffer,
137 "ERROR(mpi_handshake): failed to allocate group name buffer",
138 comm);
139 if (broadcasting_rank == rank)
140 strcpy(group_name_buffer, group_names[group_idx]);
141 mh_mpi_call(MPI_Bcast(group_name_buffer, group_name_buffer_size, MPI_CHAR,
142 broadcasting_rank, comm),
143 comm);
144 group_name_buffer[group_name_buffer_size] = '\0';
145
146 // STEP 4: split communicator
147 group_idx = SIZE_MAX;
148 for (size_t i = 0; (i < n) && (group_idx == SIZE_MAX); ++i)
149 if (!strcmp(group_name_buffer, group_names[i])) {
150 mh_assert(group_comms[i] == MPI_COMM_NULL,
151 "ERROR(yac_mpi_handshake): "
152 "Group communicator for a group that was already created "
153 "was broadcasted again.",
154 comm);
155 group_idx = i;
156 }
157 free(group_name_buffer);
158 MPI_Comm group_comm;
159 mh_mpi_call(MPI_Comm_split(comm,
160 (group_idx != SIZE_MAX) ? 0 : MPI_UNDEFINED,
161 rank, &group_comm),
162 comm);
163 if (group_idx != SIZE_MAX) {
164 group_comms[group_idx] = group_comm;
165 }
166 }
167}
168
169void mpi_handshake_c2f(int n, char const **group_names, MPI_Fint *group_comms,
170 MPI_Fint comm) {
171 MPI_Comm comm_c = MPI_Comm_f2c(comm);
172 MPI_Comm *group_comms_c = malloc(n * sizeof(*group_comms_c));
173 mpi_handshake(group_names, group_comms_c, n, comm_c);
174 for (int i = 0; i < n; ++i)
175 group_comms[i] = MPI_Comm_c2f(group_comms_c[i]);
176 free(group_comms_c);
177}
178
179void mpi_handshake_dummy(MPI_Comm comm) { mpi_handshake(NULL, NULL, 0, comm); }
static void mh_abort(const char *error_string, MPI_Comm comm, const char *file, int line)
#define mh_mpi_call(call, comm)
void mpi_handshake_c2f(int n, char const **group_names, MPI_Fint *group_comms, MPI_Fint comm)
void mpi_handshake_dummy(MPI_Comm comm)
static void mh_mpi_error(int error_code, MPI_Comm comm)
#define mh_assert(exp, msg, comm)
void mpi_handshake(char const **group_names, MPI_Comm *group_comms, size_t n, MPI_Comm comm)
int rank