Yet Another eXchange Tool 0.11.4
Loading...
Searching...
No Matches
xt_exchanger_neigh_alltoall.c
Go to the documentation of this file.
1
12/*
13 * Keywords:
14 * Maintainer: Jörg Behrens <behrens@dkrz.de>
15 * Moritz Hanke <hanke@dkrz.de>
16 * Thomas Jahns <jahns@dkrz.de>
17 * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yaxt/
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met:
22 *
23 * Redistributions of source code must retain the above copyright notice,
24 * this list of conditions and the following disclaimer.
25 *
26 * Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 *
30 * Neither the name of the DKRZ GmbH nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
38 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 */
46#ifdef HAVE_CONFIG_H
47#include <config.h>
48#endif
49
50#include <assert.h>
51#include <string.h>
52
53#include <mpi.h>
54
55#include "core/core.h"
56#include "core/ppm_xfuncs.h"
57#include "xt_config_internal.h"
58#include "xt/xt_mpi.h"
59#include "xt_mpi_internal.h"
60#include "xt_redist_internal.h"
61#include "xt/xt_xmap.h"
62#include "xt/xt_idxlist.h"
63#include "xt/xt_request.h"
64#include "xt/xt_request_msgs.h"
65#include "xt_exchanger.h"
67
68static const char filename[] = "xt_exchanger_neigh_alltoall.c";
69
70#define MAX(a,b) ((a) >= (b) ? (a) : (b))
71
72static Xt_exchanger
74 MPI_Comm newComm, int new_tag_offset);
77 const void * src_data,
78 void * dst_data);
80 const void * src_data,
81 void * dst_data,
82 Xt_request *request);
83static int
85 enum xt_msg_direction direction,
86 int *restrict *ranks);
87
88static MPI_Datatype
90 int rank,
91 enum xt_msg_direction direction,
92 bool do_dup);
93
102
104{
105 struct xt_exchanger_neigh_alltoall_team_share *team_share = share;
106 team_share->ranks = NULL;
107 team_share->one_counts = NULL;
108 team_share->displs = NULL;
109 team_share->nb_comm = MPI_COMM_NULL;
110}
111
113{
114 struct xt_exchanger_neigh_alltoall_team_share *team_share = share;
115 if (team_share->nb_comm != MPI_COMM_NULL)
116 xt_mpi_call(MPI_Comm_free(&team_share->nb_comm), Xt_default_comm);
117 free(team_share->one_counts);
118 free(team_share->displs);
119 free(team_share->ranks);
120}
121
134
136
145
147xt_exchanger_neigh_alltoall_alloc(size_t nsend, size_t nrecv,
148 void *exchanger_team_share)
149{
150 size_t nmsg = nsend + nrecv;
151 bool need_team_share_alloc = exchanger_team_share == NULL;
153 = xmalloc(sizeof(*exchanger)
154 + (need_team_share_alloc ? sizeof (*exchanger->team_share) : 0));
155 exchanger->datatypes = xmalloc(nmsg * sizeof(*exchanger->datatypes));
157 if (need_team_share_alloc) {
158 exchanger->team_share = exchanger->team_share_;
160 } else
161 exchanger->team_share = exchanger_team_share;
162 return exchanger;
163}
164
165static void copy_dt(size_t n,
166 const struct Xt_redist_msg *restrict msgs,
167 MPI_Datatype *restrict datatypes,
168 MPI_Comm comm, bool dt_dup) {
169
170 for (size_t i = 0; i < n; ++i)
171 if (dt_dup)
172 xt_mpi_call(MPI_Type_dup(msgs[i].datatype, datatypes + i), comm);
173 else
174 datatypes[i] = msgs[i].datatype;
175}
176
177static void copy_ranks(size_t n,
178 const struct Xt_redist_msg *restrict msgs,
179 int *restrict ranks)
180{
181 for (size_t i = 0; i < n; ++i)
182 ranks[i] = msgs[i].rank;
183}
184
187 const struct Xt_redist_msg *send_msgs,
188 const struct Xt_redist_msg *recv_msgs,
189 MPI_Comm comm, int tag_offset, Xt_config config)
190{
195 (void)tag_offset;
196 int flag;
197 xt_mpi_call(MPI_Comm_test_inter(comm, &flag), comm);
198 if (flag)
199 Xt_abort(comm, "ERROR(xt_exchanger_neigh_alltoall_new): "
200 "inter-communicator's are not defined for virtual topologies",
201 filename, __LINE__);
202
203 assert((nsend >= 0) & (nrecv >= 0));
205 = xt_exchanger_neigh_alltoall_alloc((size_t)nsend, (size_t)nrecv,
206 config->exchanger_team_share);
207 bool dt_dup = !(config->flags & exch_no_dt_dup);
208 copy_dt((size_t)nsend, send_msgs, exchanger->datatypes, comm, dt_dup);
209 copy_dt((size_t)nrecv, recv_msgs, exchanger->datatypes + nsend, comm, dt_dup);
211 = exchanger->team_share;
212 if (team_share->nb_comm == MPI_COMM_NULL) {
213 size_t nmsg = (size_t)nsend + (size_t)nrecv;
214 size_t max_msgs = MAX((size_t)nsend, (size_t)nrecv);
215 team_share->nmsg[RECV] = nrecv;
216 team_share->nmsg[SEND] = nsend;
217 team_share->ranks = xmalloc(nmsg * sizeof(*team_share->ranks));
218 team_share->one_counts
219 = xmalloc(max_msgs * sizeof(*team_share->one_counts));
220 team_share->displs = xmalloc(max_msgs * sizeof(*team_share->displs));
221 copy_ranks((size_t)nsend, send_msgs, team_share->ranks);
222 copy_ranks((size_t)nrecv, recv_msgs, team_share->ranks+nsend);
223 for (size_t i = 0; i < max_msgs; ++i) {
224 team_share->one_counts[i] = 1;
225 team_share->displs[i] = 0;
226 }
227 enum { no_reorder = 0 }; // no reordering of ranks in new comm
228#if __GNUC__ >= 11 && __GNUC__ <= 13
229 /* GCC 11 has no means to specify that the special value pointer
230 * MPI_UNWEIGHTED does not need to point to something of size > 0 */
231#pragma GCC diagnostic push
232#pragma GCC diagnostic ignored "-Wstringop-overread"
233#endif
235 MPI_Dist_graph_create_adjacent(
236 comm, nrecv, team_share->ranks + nsend, MPI_UNWEIGHTED, nsend,
237 team_share->ranks, MPI_UNWEIGHTED, MPI_INFO_NULL, no_reorder,
238 &team_share->nb_comm), comm);
239#if __GNUC__ >= 11 && __GNUC__ <= 13
240#pragma GCC diagnostic pop
241#endif
242 }
243 return (Xt_exchanger)exchanger;
244}
245
246static Xt_exchanger
248 MPI_Comm new_comm, int new_tag_offset)
249{
250 (void)new_tag_offset;
251 Xt_exchanger_neigh_alltoall exchanger_na =
254 *team_share = exchanger_na->team_share;
255 size_t nsend = (size_t)team_share->nmsg[SEND],
256 nrecv = (size_t)team_share->nmsg[RECV];
257
259 exchanger_copy = xt_exchanger_neigh_alltoall_alloc(nsend, nrecv, NULL);
260
262 *team_share_copy = exchanger_copy->team_share;
263 size_t nmsg = nsend + nrecv;
264 size_t max_msgs = MAX(nsend, nrecv);
265 team_share_copy->nmsg[SEND] = (int)nsend;
266 team_share_copy->nmsg[RECV] = (int)nrecv;
267 team_share_copy->ranks = xmalloc(nmsg * sizeof(*team_share_copy->ranks));
268 team_share_copy->one_counts
269 = xmalloc(max_msgs * sizeof(*team_share_copy->one_counts));
270 team_share_copy->displs
271 = xmalloc(max_msgs * sizeof(*team_share_copy->displs));
272 memcpy(team_share_copy->ranks, team_share->ranks,
273 nmsg * sizeof(*team_share_copy->ranks));
274 for (size_t i = 0; i < max_msgs; ++i) {
275 team_share_copy->one_counts[i] = 1;
276 team_share_copy->displs[i] = 0;
277 }
278#ifndef NEED_MPICH_UNWEIGHTED_COMM_DUP_WORKAROUND
279 xt_mpi_call(MPI_Comm_dup(team_share->nb_comm, &team_share_copy->nb_comm),
280 new_comm);
281#else
282 /* MPICH up to version 3.4.2 at least cannot do MPI_Comm_dup
283 * for topology communicators */
284 enum { no_reorder = 0 }; // no reordering of ranks in new comm
285#if __GNUC__ >= 11 && __GNUC__ <= 13
286 /* GCC 11 has no means to specify that the special value pointer
287 * MPI_UNWEIGHTED does not need to point to something of size > 0 */
288#pragma GCC diagnostic push
289#pragma GCC diagnostic ignored "-Wstringop-overread"
290#endif
292 MPI_Dist_graph_create_adjacent(
293 new_comm, (int)nrecv, team_share_copy->ranks + nsend, MPI_UNWEIGHTED,
294 (int)nsend, team_share_copy->ranks, MPI_UNWEIGHTED, MPI_INFO_NULL,
295 no_reorder, &team_share_copy->nb_comm), new_comm);
296#if __GNUC__ >= 11 && __GNUC__ <= 13
297#pragma GCC diagnostic pop
298#endif
299#endif
300 for (size_t i = 0; i < nmsg; ++i)
301 xt_mpi_call(MPI_Type_dup(exchanger_na->datatypes[i],
302 exchanger_copy->datatypes + i), new_comm);
303
304 return (Xt_exchanger)exchanger_copy;
305}
306
308
309 Xt_exchanger_neigh_alltoall exchanger_na =
312 *team_share_na = exchanger_na->team_share;
313
314 size_t nmsg = (size_t)team_share_na->nmsg[SEND]
315 + (size_t)team_share_na->nmsg[RECV];
316
317 for (size_t i = 0; i < nmsg; ++i)
318 xt_mpi_call(MPI_Type_free(exchanger_na->datatypes + i),
319 team_share_na->nb_comm);
320 free(exchanger_na->datatypes);
321 if (exchanger_na->team_share == exchanger_na->team_share_)
323 free(exchanger_na);
324}
325
327 const void * src_data,
328 void * dst_data) {
329
330 Xt_exchanger_neigh_alltoall exchanger_na =
333 *team_share = exchanger_na->team_share;
334
336 MPI_Neighbor_alltoallw(src_data, team_share->one_counts,
337 team_share->displs, exchanger_na->datatypes,
338 dst_data, team_share->one_counts,
339 team_share->displs, exchanger_na->datatypes +
340 (size_t)team_share->nmsg[SEND],
341 team_share->nb_comm),
342 team_share->nb_comm);
343}
344
346 const void * src_data,
347 void * dst_data,
348 Xt_request *request) {
349
350 Xt_exchanger_neigh_alltoall exchanger_na =
353 *team_share = exchanger_na->team_share;
354
355#if defined OMPI_MAJOR_VERSION && OMPI_MAJOR_VERSION == 4 \
356 && OMPI_MINOR_VERSION == 0 && OMPI_RELEASE_VERSION == 2
357 /* ugly work-around: Open MPI retains pointers to arguments
358 * of MPI_Ineighbor_alltoallw, but the exchanger might have
359 * been destroyed by the time Open MPI starts to use it.
360 * Therefore, this work-around resizes the request object and
361 * stores copies of some arguments in the request object tail.
362 * Not pretty, I know, but Open MPI 4.0.x is too recent to ignore. */
363 struct Xt_request_msgs_ {
364 const struct Xt_request_vtable *vtable;
365 int n;
367 MPI_Request requests[];
368 };
369 size_t nmsg = (size_t)team_share->nmsg[SEND] + (size_t)team_share->nmsg[RECV],
370 header_size = sizeof (struct Xt_request_msgs_),
371 body_size = sizeof (MPI_Datatype) * nmsg + sizeof (int) * nmsg,
372 dt_size = nmsg * sizeof (MPI_Datatype);
373 body_size = (body_size + sizeof (MPI_Datatype) - 1)
374 / sizeof (MPI_Datatype) * sizeof (MPI_Datatype);
375 struct Xt_request_msgs_ *request_
376 = xrealloc(xt_request_msgs_new(1, (MPI_Request[]){ MPI_REQUEST_NULL},
377 team_share->nb_comm),
378 header_size + body_size + dt_size);
379 *request = (Xt_request)request_;
380 MPI_Datatype *dt_copy
381 = (MPI_Datatype *)(void *)((unsigned char *)request_ + header_size + body_size);
382 memcpy(dt_copy, exchanger_na->datatypes, dt_size);
384 MPI_Ineighbor_alltoallw(src_data, team_share->one_counts,
385 team_share->displs, dt_copy,
386 dst_data, team_share->one_counts,
387 team_share->displs, dt_copy +
388 (size_t)team_share->nmsg[SEND],
389 team_share->nb_comm, request_->requests),
390 team_share->nb_comm);
391#else
392 MPI_Request tmp_request;
394 MPI_Ineighbor_alltoallw(src_data, team_share->one_counts,
395 team_share->displs, exchanger_na->datatypes,
396 dst_data, team_share->one_counts,
397 team_share->displs, exchanger_na->datatypes +
398 (size_t)team_share->nmsg[SEND],
399 team_share->nb_comm, &tmp_request),
400 team_share->nb_comm);
401
402 *request = xt_request_msgs_new(1, &tmp_request, team_share->nb_comm);
403#endif
404}
405
406static MPI_Datatype
408 int rank,
409 enum xt_msg_direction direction,
410 bool do_dup)
411{
412 Xt_exchanger_neigh_alltoall exchanger_na =
415 *team_share = exchanger_na->team_share;
416 size_t nsend = (size_t)team_share->nmsg[SEND],
417 nmsg = (size_t)team_share->nmsg[direction],
418 ofs = direction == SEND ? 0 : nsend;
419 int *restrict ranks = team_share->ranks + ofs;
420 MPI_Datatype datatype_copy = MPI_DATATYPE_NULL;
421 for (size_t i = 0; i < nmsg; ++i) {
422 if (ranks[i] == rank) {
423 if (do_dup)
424 xt_mpi_call(MPI_Type_dup(exchanger_na->datatypes[i+ofs],
425 &datatype_copy), team_share->nb_comm);
426 else
427 datatype_copy = exchanger_na->datatypes[i+ofs];
428 break;
429 }
430 }
431 return datatype_copy;
432}
433
434static int
436 enum xt_msg_direction direction,
437 int *restrict *ranks)
438{
439 Xt_exchanger_neigh_alltoall exchanger_na =
442 *team_share = exchanger_na->team_share;
443 size_t nsend = (size_t)team_share->nmsg[SEND],
444 nmsg = (size_t)team_share->nmsg[direction],
445 ofs = direction == SEND ? 0 : nsend;
446 int *ranks_ = *ranks;
447 if (!ranks_)
448 ranks_ = *ranks = xmalloc(nmsg * sizeof(**ranks));
449 memcpy(ranks_, team_share->ranks + ofs, nmsg * sizeof(**ranks));
450 return (int)nmsg;
451}
452
453/*
454 * Local Variables:
455 * c-basic-offset: 2
456 * coding: utf-8
457 * indent-tabs-mode: nil
458 * show-trailing-whitespace: t
459 * require-trailing-newline: t
460 * End:
461 */
@ MPI_COMM_NULL
Definition core.h:74
int MPI_Comm
Definition core.h:64
add versions of standard API functions not returning on error
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:71
#define xmalloc(size)
Definition ppm_xfuncs.h:70
void * exchanger_team_share
struct xt_exchanger_neigh_alltoall_team_share * team_share
struct xt_exchanger_neigh_alltoall_team_share team_share_[]
const struct xt_exchanger_vtable * vtable
MPI_Request requests[]
const struct Xt_request_vtable * vtable
int MPI_Type_free(MPI_Datatype *datatype)
int MPI_Type_dup(MPI_Datatype oldtype, MPI_Datatype *newtype)
implementation of configuration object
@ exch_no_dt_dup
exchanging of data based on information provided by redist's
static void copy_ranks(size_t n, const struct Xt_redist_msg *restrict msgs, int *restrict ranks)
static const char filename[]
static int xt_exchanger_neigh_alltoall_get_msg_ranks(Xt_exchanger exchanger, enum xt_msg_direction direction, int *restrict *ranks)
Xt_exchanger xt_exchanger_neigh_alltoall_new(int nsend, int nrecv, const struct Xt_redist_msg *send_msgs, const struct Xt_redist_msg *recv_msgs, MPI_Comm comm, int tag_offset, Xt_config config)
struct Xt_exchanger_neigh_alltoall_ * Xt_exchanger_neigh_alltoall
static void xt_exchanger_neigh_alltoall_a_exchange(Xt_exchanger exchanger, const void *src_data, void *dst_data, Xt_request *request)
static MPI_Datatype xt_exchanger_neigh_alltoall_get_MPI_Datatype(Xt_exchanger exchanger, int rank, enum xt_msg_direction direction, bool do_dup)
static void xt_exchanger_neigh_alltoall_delete(Xt_exchanger exchanger)
static void xt_exchanger_neigh_alltoall_team_share_destroy(void *share)
static Xt_exchanger xt_exchanger_neigh_alltoall_copy(Xt_exchanger exchanger, MPI_Comm newComm, int new_tag_offset)
static void xt_exchanger_neigh_alltoall_team_share_default_init(void *share)
static void copy_dt(size_t n, const struct Xt_redist_msg *restrict msgs, MPI_Datatype *restrict datatypes, MPI_Comm comm, bool dt_dup)
static void xt_exchanger_neigh_alltoall_s_exchange(Xt_exchanger exchanger, const void *src_data, void *dst_data)
const struct xt_exchanger_vtable xt_exchanger_neigh_alltoall_vtable
static Xt_exchanger_neigh_alltoall xt_exchanger_neigh_alltoall_alloc(size_t nsend, size_t nrecv, void *exchanger_team_share)
#define MAX(a, b)
index list declaration
utility routines for MPI
#define xt_mpi_call(call, comm)
Definition xt_mpi.h:68
redistribution of data, non-public declarations
xt_msg_direction
struct Xt_request_ * Xt_request
Definition xt_request.h:51
Xt_request xt_request_msgs_new(int n, const MPI_Request requests[n], MPI_Comm comm)
exchange map declarations