Yet Another eXchange Tool 0.11.2
Loading...
Searching...
No Matches
xt_xmap_intersection.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 <stdlib.h>
51#include <stdio.h>
52#include <string.h>
53#include <assert.h>
54#include <limits.h>
55
56#include <mpi.h>
57
58#include "xt/xt_idxlist.h"
59#include "xt_idxlist_internal.h"
60#include "xt/xt_idxvec.h"
61#include "xt/xt_xmap.h"
62#include "xt_xmap_internal.h"
63#include "xt/xt_mpi.h"
64#include "xt_mpi_internal.h"
65#include "core/core.h"
66#include "core/ppm_xfuncs.h"
69#include "ensure_array_size.h"
70#include "xt_arithmetic_util.h"
71#include "xt_config_internal.h"
72
73
74
75static const char filename[] = "xt_xmap_intersection.c";
76
77/* unfortunately GCC 11 cannot handle the literal constants used for
78 * MPI_STATUSES_IGNORE by MPICH */
79#if __GNUC__ >= 11 && __GNUC__ <= 13 && defined MPICH
80#pragma GCC diagnostic push
81#pragma GCC diagnostic ignored "-Wstringop-overread"
82#pragma GCC diagnostic ignored "-Wstringop-overflow"
83#endif
84
88static void
90static void
95static void xmap_intersection_delete(Xt_xmap xmap);
98static int const *
100static int
102static const struct Xt_pos_ext *
104static int
109static Xt_xmap
111 Xt_config config);
112static Xt_xmap
114 const int * src_positions,
115 const int * dst_positions);
116static Xt_xmap
117xmap_intersection_spread(Xt_xmap xmap, int num_repetitions,
118 const int src_displacements[num_repetitions],
119 const int dst_displacements[num_repetitions]);
120
121
122static const struct Xt_xmap_iter_vtable
132
134
136
137 const struct Xt_xmap_iter_vtable * vtable;
138
139 struct exchange_data * msg;
141};
142
143static inline Xt_xmap_iter_intersection
144xmii(void *iter)
145{
146 return (Xt_xmap_iter_intersection)iter;
147}
148
149
151 .get_communicator = xmap_intersection_get_communicator,
152 .get_num_destinations = xmap_intersection_get_num_destinations,
153 .get_num_sources = xmap_intersection_get_num_sources,
154 .get_destination_ranks = xmap_intersection_get_destination_ranks,
155 .get_source_ranks = xmap_intersection_get_source_ranks,
156 .get_out_iterator = xmap_intersection_get_out_iterator,
157 .get_in_iterator = xmap_intersection_get_in_iterator,
159 .delete = xmap_intersection_delete,
160 .get_max_src_pos = xmap_intersection_get_max_src_pos,
161 .get_max_dst_pos = xmap_intersection_get_max_dst_pos,
162 .reorder = xmap_intersection_reorder,
164 .spread = xmap_intersection_spread};
165
167 // list of relative positions in memory to send or receive
169 struct Xt_pos_ext *transfer_pos_ext_cache;
171 int rank;
172};
173
175
176 const struct Xt_xmap_vtable * vtable;
177
179
180 // we need the max position in order to enable quick range-checks
181 // for xmap-users like redist
182 int max_src_pos; // max possible pos over all src transfer_pos (always >= 0)
183 int max_dst_pos; // same for dst
184 int tag_offset; /* add to make tags on same communicator non-overlapping */
185
187 struct exchange_data msg[];
188};
189
191
192static inline Xt_xmap_intersection
193xmi(void *xmap)
194{
195 return (Xt_xmap_intersection)xmap;
196}
197
199
200 Xt_xmap_intersection xmap_intersection = xmi(xmap);
201
202 return xmap_intersection->comm;
203}
204
206
207 Xt_xmap_intersection xmap_intersection = xmi(xmap);
208
209 // the number of destinations equals the number of source messages
210 return xmap_intersection->n_out;
211}
212
214
215 Xt_xmap_intersection xmap_intersection = xmi(xmap);
216
217 // the number of sources equals the number of destination messages
218 return xmap_intersection->n_in;
219}
220
221static void xmap_intersection_get_destination_ranks(Xt_xmap xmap, int * ranks) {
222
223 Xt_xmap_intersection xmap_intersection = xmi(xmap);
224 struct exchange_data *restrict out_msg
225 = xmap_intersection->msg + xmap_intersection->n_in;
226 for (int i = 0; i < xmap_intersection->n_out; ++i)
227 ranks[i] = out_msg[i].rank;
228}
229
230static void xmap_intersection_get_source_ranks(Xt_xmap xmap, int * ranks) {
231
232 Xt_xmap_intersection xmap_intersection = xmi(xmap);
233 struct exchange_data *restrict in_msg = xmap_intersection->msg;
234 for (int i = 0; i < xmap_intersection->n_in; ++i)
235 ranks[i] = in_msg[i].rank;
236}
237
238enum {
239 bitsPerCoverageElement = sizeof (unsigned long) * CHAR_BIT,
240};
241
247
248/* compute list positions for recv direction */
249static struct tpd_result
251 int num_intersections,
252 const struct Xt_com_list intersections[num_intersections],
253 Xt_idxlist mypart_idxlist,
254 struct exchange_data *restrict resSets,
255 int *restrict num_indices_to_remove_per_intersection)
256{
257 int mypart_num_indices = xt_idxlist_get_num_indices(mypart_idxlist);
258 size_t coverage_size = (size_t)mypart_num_indices;
259 coverage_size = (coverage_size + bitsPerCoverageElement - 1)
261 unsigned long *restrict coverage = xcalloc(coverage_size, sizeof(*coverage));
262 /* set uncovered top-most bits to ease later comparison */
263 if (mypart_num_indices%bitsPerCoverageElement)
264 coverage[coverage_size-1]
265 = ~((1UL << (mypart_num_indices%bitsPerCoverageElement)) - 1UL);
266
267 int new_num_intersections = 0;
268 size_t total_num_indices_to_remove = 0;
269 size_t curr_indices_to_remove_size = 0;
270 Xt_int *restrict indices_to_remove = NULL;
271 int *restrict intersection_pos = NULL;
272
273 for (int i = 0; i < num_intersections; ++i) {
274
275 const Xt_int *restrict intersection_idxvec
276 = xt_idxlist_get_indices_const(intersections[i].list);
277 int max_intersection_size
278 = xt_idxlist_get_num_indices(intersections[i].list);
279 intersection_pos
280 = xrealloc(intersection_pos,
281 (size_t)max_intersection_size * sizeof(*intersection_pos));
282
283#ifndef NDEBUG
284 int retval =
285#endif
287 mypart_idxlist, intersection_idxvec, max_intersection_size,
288 intersection_pos, 1);
289 assert(retval == 0);
290
291 // we have to enforce single_match_only not only within a single
292 // intersection, but also between all intersections
293
294 int intersection_size = 0;
295 int num_indices_to_remove_isect = 0;
296
297 /* at most max_intersection_size many indices need to be removed */
298 ENSURE_ARRAY_SIZE(indices_to_remove, curr_indices_to_remove_size,
299 total_num_indices_to_remove
300 + (size_t)max_intersection_size);
301
302 for (int j = 0; j < max_intersection_size; ++j) {
303
304 int pos = intersection_pos[j];
305 /* the predicate effectively conditionalizes adding of either
306 * the position to intersection_pos
307 * if the current value was NOT already in another intersection
308 * or
309 * the index to indices_to_remove_
310 * if the current value was already in another intersection
311 */
312 unsigned long mask = 1UL << (pos % bitsPerCoverageElement);
313 int is_duplicate = (coverage[pos/bitsPerCoverageElement] & mask) != 0UL;
314 intersection_pos[intersection_size] = pos;
315 indices_to_remove[total_num_indices_to_remove
316 + (size_t)num_indices_to_remove_isect]
317 = intersection_idxvec[j];
318 intersection_size += is_duplicate ^ 1;
319 num_indices_to_remove_isect += is_duplicate;
320 coverage[pos/bitsPerCoverageElement] |= mask;
321 }
322
323 total_num_indices_to_remove += (size_t)num_indices_to_remove_isect;
324 num_indices_to_remove_per_intersection[i] = num_indices_to_remove_isect;
325
326 if (intersection_size > 0) {
327 resSets[new_num_intersections].transfer_pos = intersection_pos;
328 resSets[new_num_intersections].num_transfer_pos = intersection_size;
329 resSets[new_num_intersections].transfer_pos_ext_cache = NULL;
330 resSets[new_num_intersections].num_transfer_pos_ext
331 = (int)count_pos_ext((size_t)intersection_size, intersection_pos);
332 resSets[new_num_intersections].rank = intersections[i].rank;
333 new_num_intersections++;
334 intersection_pos = NULL;
335 }
336 }
337 free(intersection_pos);
338
340 = xrealloc(indices_to_remove, total_num_indices_to_remove
341 * sizeof (*indices_to_remove));
342
343 // check resulting bit map
344 unsigned long all_bits_set = ~0UL;
345 for (size_t i = 0; i < coverage_size; ++i)
346 all_bits_set &= coverage[i];
347
348 free(coverage);
349 return (struct tpd_result){
350 .indices_to_remove = indices_to_remove,
351 .resCount = new_num_intersections,
352 .all_dst_covered = all_bits_set == ~0UL };
353}
354
355
358};
359
360/* compute list positions for send direction */
361static struct pos_count_max
362generate_dir_transfer_pos_src(int num_intersections,
363 const struct Xt_com_list
364 intersections[num_intersections],
365 Xt_idxlist mypart_idxlist,
366 struct exchange_data *restrict resSets,
367 const Xt_int *indices_to_remove,
368 const int *num_indices_to_remove_per_intersection)
369{
370 int new_num_intersections = 0;
371 int offset = 0;
372
373 Xt_int * new_intersection_idxvec = NULL;
374 size_t curr_new_intersection_idxvec_size = 0;
375 int *restrict intersection_pos = NULL;
376 int max_pos_ = -1;
377
378 for (int i = 0; i < num_intersections; ++i) {
379
380 const Xt_int *restrict intersection_idxvec
381 = xt_idxlist_get_indices_const(intersections[i].list);
382 int intersection_size
383 = xt_idxlist_get_num_indices(intersections[i].list);
384 intersection_pos = xrealloc(intersection_pos,
385 (size_t)intersection_size
386 * sizeof(*intersection_pos));
387
388 int num_indices_to_remove = num_indices_to_remove_per_intersection[i];
389 if (num_indices_to_remove > 0) {
390
392 new_intersection_idxvec, curr_new_intersection_idxvec_size,
393 intersection_size - num_indices_to_remove + 1);
394 int new_intersection_size = 0;
395
396 for (int j = 0; j < intersection_size; ++j) {
397
398 int discard = 0;
399
400 Xt_int idx = intersection_idxvec[j];
401 /* could be improved with BLOOM-filter if
402 * num_indices_to_remove was sufficiently large */
403 for (int k = 0; k < num_indices_to_remove; ++k)
404 discard |= (idx == indices_to_remove[offset + k]);
405
406 new_intersection_idxvec[new_intersection_size] = idx;
407 new_intersection_size += !discard;
408 }
409
410 intersection_idxvec = new_intersection_idxvec;
411 intersection_size = new_intersection_size;
412 offset = offset + num_indices_to_remove;
413 }
414
415#ifndef NDEBUG
416 int retval =
417#endif
419 mypart_idxlist, intersection_idxvec, intersection_size,
420 intersection_pos, 0);
421 assert(retval == 0);
422
423 if (intersection_size > 0) {
424 resSets[new_num_intersections].transfer_pos = intersection_pos;
425 resSets[new_num_intersections].num_transfer_pos = intersection_size;
426 for (int j = 0; j < intersection_size; ++j)
427 if (intersection_pos[j] > max_pos_) max_pos_ = intersection_pos[j];
428 resSets[new_num_intersections].transfer_pos_ext_cache = NULL;
429 resSets[new_num_intersections].num_transfer_pos_ext
430 = (int)count_pos_ext((size_t)intersection_size, intersection_pos);
431 resSets[new_num_intersections].rank = intersections[i].rank;
432 new_num_intersections++;
433 intersection_pos = NULL;
434 }
435 }
436
437 free(new_intersection_idxvec);
438 free(intersection_pos);
439
440 return (struct pos_count_max){ .max_pos = max_pos_,
441 .count = new_num_intersections };
442}
443
444static Xt_int *
445exchange_points_to_remove(int num_src_intersections,
446 const struct Xt_com_list
447 src_com[num_src_intersections],
448 int num_dst_intersections,
449 const struct Xt_com_list
450 dst_com[num_dst_intersections],
451 int *restrict num_src_indices_to_remove_per_intersection,
452 Xt_int *dst_indices_to_remove,
453 const int *restrict
454 num_dst_indices_to_remove_per_intersection,
455 int tag_offset,
456 MPI_Comm comm) {
457
458 MPI_Request * requests
459 = xmalloc((size_t)(num_src_intersections + 2 * num_dst_intersections) *
460 sizeof(*requests));
461 MPI_Request *send_header_requests = requests,
462 *recv_requests = requests + num_dst_intersections,
463 *send_data_requests = recv_requests + num_src_intersections;
464
465 // set up receives for indices that need to be removed from the send messages
466 for (int i = 0; i < num_src_intersections; ++i)
467 xt_mpi_call(MPI_Irecv(
468 num_src_indices_to_remove_per_intersection + i, 1, MPI_INT,
469 src_com[i].rank,
471 comm, recv_requests+i), comm);
472
473 // send indices that need to be removed on the target side due to duplicated
474 // receives
475 int offset = 0;
476 unsigned num_nonempty_dst_intersections = 0;
477 for (int i = 0; i < num_dst_intersections; ++i) {
478 xt_mpi_call(MPI_Isend(
479 CAST_MPI_SEND_BUF(
480 num_dst_indices_to_remove_per_intersection + i), 1, MPI_INT,
481 dst_com[i].rank,
483 comm, send_header_requests + i), comm);
484
485 if (num_dst_indices_to_remove_per_intersection[i] > 0) {
486
487 xt_mpi_call(MPI_Isend(
488 dst_indices_to_remove + offset,
489 num_dst_indices_to_remove_per_intersection[i], Xt_int_dt,
490 dst_com[i].rank,
492 comm, send_data_requests + num_nonempty_dst_intersections),
493 comm);
494 offset += num_dst_indices_to_remove_per_intersection[i];
495 ++num_nonempty_dst_intersections;
496 }
497 }
498
499 // wait for the receiving of headers to complete
500 xt_mpi_call(MPI_Waitall(num_src_intersections + num_dst_intersections,
501 send_header_requests, MPI_STATUSES_IGNORE), comm);
502
503 size_t total_num_src_indices_to_recv = 0;
504
505 for (int i = 0; i < num_src_intersections; ++i)
506 total_num_src_indices_to_recv
507 += (size_t)num_src_indices_to_remove_per_intersection[i];
508
509 unsigned num_nonempty_src_intersections = 0;
510 Xt_int *src_indices_to_remove;
511 if (total_num_src_indices_to_recv > 0) {
512
513 src_indices_to_remove = xmalloc(total_num_src_indices_to_recv
514 * sizeof(*src_indices_to_remove));
515
516 // set up receive for indices that need to be removed
517 offset = 0;
518 for (int i = 0; i < num_src_intersections; ++i)
519 if (num_src_indices_to_remove_per_intersection[i] > 0) {
520 ++num_nonempty_src_intersections;
521 xt_mpi_call(MPI_Irecv(
522 src_indices_to_remove + offset,
523 num_src_indices_to_remove_per_intersection[i],
524 Xt_int_dt, src_com[i].rank,
526 comm,
527 send_data_requests - num_nonempty_src_intersections),
528 comm);
529
530 offset += num_src_indices_to_remove_per_intersection[i];
531 }
532
533 } else {
534 src_indices_to_remove = NULL;
535 }
536
537 // wait until all communication is completed
538 xt_mpi_call(MPI_Waitall((int)num_nonempty_src_intersections
539 + (int)num_nonempty_dst_intersections,
540 send_data_requests-num_nonempty_src_intersections,
541 MPI_STATUSES_IGNORE), comm);
542 free(requests);
543 return src_indices_to_remove;
544}
545
546static int
548 int num_src_intersections,
549 const struct Xt_com_list src_com[num_src_intersections],
550 int num_dst_intersections,
551 const struct Xt_com_list dst_com[num_dst_intersections],
552 Xt_idxlist src_idxlist_local,
553 Xt_idxlist dst_idxlist_local,
554 MPI_Comm comm) {
555
556 int *num_src_indices_to_remove_per_intersection =
557 xmalloc(((size_t)num_src_intersections + (size_t)num_dst_intersections)
558 * sizeof(int)),
559 *num_dst_indices_to_remove_per_intersection =
560 num_src_indices_to_remove_per_intersection + num_src_intersections;
561
562 struct tpd_result tpdr
564 num_dst_intersections, dst_com, dst_idxlist_local, xmap->msg,
565 num_dst_indices_to_remove_per_intersection);
567 xmap->n_in = tpdr.resCount;
568 Xt_int *dst_indices_to_remove = tpdr.indices_to_remove;
569 // exchange the points that need to be removed
570 Xt_int *src_indices_to_remove
572 num_src_intersections, src_com, num_dst_intersections, dst_com,
573 num_src_indices_to_remove_per_intersection,
574 dst_indices_to_remove, num_dst_indices_to_remove_per_intersection,
575 xmap->tag_offset, comm);
576
577 free(dst_indices_to_remove);
578 num_src_indices_to_remove_per_intersection
579 = xrealloc(num_src_indices_to_remove_per_intersection,
580 (size_t)num_src_intersections * sizeof(int));
581
582 struct pos_count_max tpsr
584 num_src_intersections, src_com, src_idxlist_local, xmap->msg + xmap->n_in,
585 src_indices_to_remove, num_src_indices_to_remove_per_intersection);
586 xmap->max_src_pos = tpsr.max_pos;
587 xmap->n_out = tpsr.count;
588
589 free(src_indices_to_remove);
590 free(num_src_indices_to_remove_per_intersection);
591 return all_dst_covered;
592}
593
595xt_xmap_intersection_new(int num_src_intersections,
596 const struct Xt_com_list
597 src_com[num_src_intersections],
598 int num_dst_intersections,
599 const struct Xt_com_list
600 dst_com[num_dst_intersections],
601 Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist,
602 MPI_Comm comm)
603{
605 num_src_intersections, src_com,
606 num_dst_intersections, dst_com,
607 src_idxlist, dst_idxlist, comm, &xt_default_config);
608}
609
612 int num_src_intersections,
613 const struct Xt_com_list src_com[num_src_intersections],
614 int num_dst_intersections,
615 const struct Xt_com_list dst_com[num_dst_intersections],
616 Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist,
617 MPI_Comm comm,
618 Xt_config XT_UNUSED(config))
619{
620 // ensure that yaxt is initialized
621 assert(xt_initialized());
622
623 size_t num_isect
624 = (size_t)num_dst_intersections + (size_t)num_src_intersections;
626 = xmalloc(sizeof (*xmap) + num_isect * sizeof (struct exchange_data));
627
629
630 xmap->comm = comm = xt_mpi_comm_smart_dup(comm, &xmap->tag_offset);
631
632 // generate exchange lists
633 if (!generate_transfer_pos(xmap,
634 num_src_intersections, src_com,
635 num_dst_intersections, dst_com,
636 src_idxlist, dst_idxlist, comm)) {
637
638 int num_dst_indices = xt_idxlist_get_num_indices(dst_idxlist);
639 const Xt_int *dst_indices = xt_idxlist_get_indices_const(dst_idxlist);
640 int * found_index_mask = xcalloc((size_t)num_dst_indices,
641 sizeof(*found_index_mask));
642 int * index_positions = xmalloc((size_t)num_dst_indices
643 * sizeof(*index_positions));
644
645 for (size_t i = 0; i < (size_t)num_dst_intersections; ++i) {
646 xt_idxlist_get_positions_of_indices(dst_com[i].list, dst_indices,
647 num_dst_indices, index_positions, 0);
648 for (size_t j = 0; j < (size_t)num_dst_indices; ++j)
649 found_index_mask[j] |= index_positions[j] != -1;
650 }
651
652 int first_missing_pos = 0;
653 while ((first_missing_pos < (num_dst_indices - 1)) &&
654 (found_index_mask[first_missing_pos])) ++first_missing_pos;
655 free(found_index_mask);
656 free(index_positions);
658 print_miss_msg(dst_idxlist, first_missing_pos, comm, filename, __LINE__);
659 }
660
661 int n_in = xmap->n_in, n_out = xmap->n_out;
662 size_t new_num_isect = (size_t)n_in + (size_t)n_out;
663 if (new_num_isect != num_isect)
664 xmap = xrealloc(xmap, sizeof (*xmap) + (new_num_isect
665 * sizeof(struct exchange_data)));
666
667 xmap->max_dst_pos = xt_idxlist_get_num_indices(dst_idxlist) - 1;
668
669 return (Xt_xmap)xmap;
670}
671
673 return xmi(xmap)->max_src_pos;
674}
675
677 return xmi(xmap)->max_dst_pos;
678}
679
680
681typedef int (*Xt_pos_copy)(size_t num_pos,
682 int *pos, const int *orig_pos,
683 const void *state);
684
685static int
686pos_copy_verbatim(size_t num_pos,
687 int *pos, const int *orig_pos, const void *state)
688{
689 (void)state;
690 memcpy(pos, orig_pos, sizeof (*pos) * num_pos);
691 return -1;
692}
693
694static void
696 const struct exchange_data *restrict msg,
697 int *nmsg_copy,
698 struct exchange_data *restrict msg_copy,
699 int *max_pos_, int num_repetitions,
700 Xt_pos_copy pos_copy, const void *pos_copy_state) {
701 *nmsg_copy = (int)nmsg;
702 int max_pos = 0;
703 for (size_t i = 0; i < nmsg; ++i) {
704 size_t num_transfer_pos
705 = (size_t)(msg_copy[i].num_transfer_pos
706 = num_repetitions * msg[i].num_transfer_pos);
707 msg_copy[i].rank = msg[i].rank;
708 msg_copy[i].transfer_pos_ext_cache = NULL;
709 size_t size_transfer_pos
710 = num_transfer_pos * sizeof (*(msg[i].transfer_pos));
711 msg_copy[i].transfer_pos = xmalloc(size_transfer_pos);
712 int new_max_pos
713 = pos_copy(num_transfer_pos,
714 msg_copy[i].transfer_pos, msg[i].transfer_pos,
715 pos_copy_state);
716 if (new_max_pos > max_pos)
717 max_pos = new_max_pos;
718 if (pos_copy == pos_copy_verbatim)
719 msg_copy[i].num_transfer_pos_ext = msg[i].num_transfer_pos_ext;
720 else
721 msg_copy[i].num_transfer_pos_ext =
722 (int)(count_pos_ext(num_transfer_pos, msg_copy[i].transfer_pos));
723 }
724 if (pos_copy != pos_copy_verbatim)
725 *max_pos_ = max_pos;
726}
727
728static Xt_xmap
730 int num_repetitions,
731 Xt_pos_copy pos_copy_in, const void *pci_state,
732 Xt_pos_copy pos_copy_out, const void *pco_state)
733{
734 Xt_xmap_intersection xmap_intersection = xmi(xmap), xmap_intersection_new;
735 size_t n_in = (size_t)xmap_intersection->n_in,
736 n_out = (size_t)xmap_intersection->n_out,
737 num_isect = n_in + n_out;
738 xmap_intersection_new
739 = xmalloc(sizeof (*xmap_intersection_new)
740 + num_isect * sizeof (struct exchange_data));
741 xmap_intersection_new->vtable = xmap_intersection->vtable;
742 xmap_intersection_new->n_in = (int)n_in;
743 xmap_intersection_new->n_out = (int)n_out;
744 xmap_intersection_new->max_src_pos = xmap_intersection->max_src_pos;
745 xmap_intersection_new->max_dst_pos = xmap_intersection->max_dst_pos;
746 xmap_intersection_msg_copy(n_in, xmap_intersection->msg,
747 &xmap_intersection_new->n_in,
748 xmap_intersection_new->msg,
749 &xmap_intersection_new->max_dst_pos,
750 num_repetitions,
751 pos_copy_in, pci_state);
752 xmap_intersection_msg_copy(n_out, xmap_intersection->msg + n_in,
753 &xmap_intersection_new->n_out,
754 xmap_intersection_new->msg+n_in,
755 &xmap_intersection_new->max_src_pos,
756 num_repetitions,
757 pos_copy_out, pco_state);
758 xmap_intersection_new->comm
759 = xt_mpi_comm_smart_dup(xmap_intersection->comm,
760 &xmap_intersection_new->tag_offset);
761 return (Xt_xmap)xmap_intersection_new;
762}
763
764static Xt_xmap
766{
767 return xmap_intersection_copy_(xmap, 1,
768 pos_copy_verbatim, NULL,
769 pos_copy_verbatim, NULL);
770}
771
772static void
774 for (int i = 0; i < nmsg; ++i) {
775 free(msg[i].transfer_pos_ext_cache);
776 free(msg[i].transfer_pos);
777 }
778}
779
781
782 Xt_xmap_intersection xmap_intersection = xmi(xmap);
783
784 int num_isect = xmap_intersection->n_in + xmap_intersection->n_out;
785 xmap_intersection_msg_delete(num_isect, xmap_intersection->msg);
786 xt_mpi_comm_smart_dedup(&xmap_intersection->comm,
787 xmap_intersection->tag_offset);
788 free(xmap_intersection);
789}
790
792
793 Xt_xmap_intersection xmap_intersection = xmi(xmap);
794
795 if (xmap_intersection->n_in == 0)
796 return NULL;
797
798 Xt_xmap_iter_intersection iter = xmalloc(sizeof (*iter));
799
801 iter->msg = xmap_intersection->msg;
802 iter->msgs_left = xmap_intersection->n_in - 1;
803
804 return (Xt_xmap_iter)iter;
805}
806
808
809 Xt_xmap_intersection xmap_intersection = xmi(xmap);
810
811 if (xmap_intersection->n_out == 0)
812 return NULL;
813
814 Xt_xmap_iter_intersection iter = xmalloc(sizeof (*iter));
815
817 iter->msg = xmap_intersection->msg + xmap_intersection->n_in;
818 iter->msgs_left = xmap_intersection->n_out - 1;
819
820 return (Xt_xmap_iter)iter;
821}
822
823struct a2abuf
824{
826};
827
828static inline struct a2abuf
829setup_buffer(int comm_size, int n, const struct exchange_data *msgs)
830{
831 size_t buffer_size = 0;
832 for (int i = 0; i < n; ++i)
833 buffer_size += (size_t)msgs[i].num_transfer_pos;
834
835 int *restrict counts = xmalloc((2 * (size_t)comm_size + buffer_size)
836 * sizeof(*counts)),
837 *restrict displs = counts + comm_size,
838 *restrict buffer = counts + 2 * comm_size;
839 for (int i = 0; i < comm_size; ++i)
840 counts[i] = 0;
841
842 for (int i = 0; i < n; ++i)
843 counts[msgs[i].rank] = msgs[i].num_transfer_pos;
844
845 for (int i = 0, accu = 0; i < comm_size; ++i) {
846 displs[i] = accu;
847 accu += counts[i];
848 }
849 return (struct a2abuf){ .buffer=buffer, .counts=counts, .displs=displs };
850}
851
853 int n_out, int n_in, struct exchange_data * out_msg,
854 struct exchange_data * in_msg, MPI_Comm comm, Xt_config config) {
855
856 int comm_size;
857 xt_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
858
859 struct a2abuf
860 out = setup_buffer(comm_size, n_out, out_msg),
861 in = setup_buffer(comm_size, n_in, in_msg);
862
863 void (*sort_int)(int a[], size_t n) = config->sort_funcs->sort_int;
864 for (int i = 0; i < n_out; ++i) {
865 const struct exchange_data * curr_msg = out_msg + i;
866 int count = curr_msg->num_transfer_pos;
867 if (count > 0) {
868 // pack local out transfer_pos into out buffer
869 memcpy(out.buffer + out.displs[curr_msg->rank],
870 curr_msg->transfer_pos, (size_t)count * sizeof(*out.buffer));
871 // sort local out transfer_pos
872 sort_int(curr_msg->transfer_pos, (size_t)count);
873 }
874 }
875
876 // exchange local out transfer_pos
877 xt_mpi_call(MPI_Alltoallv(out.buffer, out.counts, out.displs, MPI_INT,
878 in.buffer, in.counts, in.displs, MPI_INT,
879 comm), comm);
880
881 void (*sort_int_permutation)(int a[], size_t n, int permutation[])
883 for (int i = 0; i < n_in; ++i) {
884 const struct exchange_data * curr_msg = in_msg + i;
885 int count = curr_msg->num_transfer_pos;
886 if (count > 0)
887 // reorder local receive transfer_pos (curr_msg->transfer_pos) based
888 // on remote out transfer_pos (in_buffer + in_displs[curr_msg->rank])
889 sort_int_permutation(
890 in.buffer + in.displs[curr_msg->rank], (size_t)count,
891 curr_msg->transfer_pos);
892 }
893
894 free(out.counts);
895 free(in.counts);
896
897 for (int i = 0; i < n_out; ++i) {
898 free(out_msg[i].transfer_pos_ext_cache);
899 out_msg[i].transfer_pos_ext_cache = NULL;
900 out_msg[i].num_transfer_pos_ext =
901 (int)count_pos_ext(
902 (size_t)out_msg[i].num_transfer_pos, out_msg[i].transfer_pos);
903 }
904 for (int i = 0; i < n_in; ++i) {
905 free(in_msg[i].transfer_pos_ext_cache);
906 in_msg[i].transfer_pos_ext_cache = NULL;
907 in_msg[i].num_transfer_pos_ext =
908 (int)count_pos_ext(
909 (size_t)in_msg[i].num_transfer_pos, in_msg[i].transfer_pos);
910 }
911}
912
913static Xt_xmap
915 Xt_config config) {
916
917 Xt_xmap_intersection xmap_intersection_new =
919
920 int n_out = xmap_intersection_new->n_out,
921 n_in = xmap_intersection_new->n_in;
922 struct exchange_data *in_msg = xmap_intersection_new->msg,
923 *out_msg = in_msg+n_in;
924 MPI_Comm comm = xmap_intersection_new->comm;
925
926 switch ((int)type) {
927 case (XT_REORDER_NONE):
928 break;
929 case (XT_REORDER_SEND_UP):
930 reorder_transfer_pos(n_out, n_in, out_msg, in_msg, comm, config);
931 break;
932 case (XT_REORDER_RECV_UP):
933 reorder_transfer_pos(n_in, n_out, in_msg, out_msg, comm, config);
934 break;
935 default:
936 Xt_abort(comm, "ERROR(xmap_intersection_reorder):invalid reorder type",
937 filename, __LINE__);
938 }
939
940 return (Xt_xmap)xmap_intersection_new;
941}
942
943static int
944subst_positions(size_t num_pos,
945 int *restrict pos, const int *restrict orig_pos,
946 const void *new_pos_)
947{
948 const int *restrict new_pos = new_pos_;
949 int max_pos = 0;
950 for (size_t i = 0; i < num_pos; ++i) {
951 int np = new_pos[orig_pos[i]];
952 pos[i] = np;
953 if (np > max_pos)
954 max_pos = np;
955 }
956 return max_pos;
957}
958
959static Xt_xmap
961 const int *src_positions,
962 const int *dst_positions) {
963
964 return xmap_intersection_copy_(xmap, 1,
965 subst_positions, dst_positions,
966 subst_positions, src_positions);
967}
968
970{
972 const int *restrict displacements;
973};
974
975static int
976pos_copy_spread(size_t num_pos, int *restrict pos,
977 const int *restrict orig_pos, const void *state)
978{
979 const struct spread_state *sp = state;
981 const int *restrict displacements = sp->displacements;
982 num_pos = num_pos / (size_t)num_repetitions;
983 int max_pos = -1;
984 for (int i = 0, k = 0; i < num_repetitions; ++i) {
985 int curr_disp = displacements[i];
986 for (size_t j = 0; j < num_pos; ++j, ++k) {
987 int np = orig_pos[j] + curr_disp;
988 pos[k] = np;
989 if (np > max_pos)
990 max_pos = np;
991 }
992 }
993 return max_pos;
994}
995
996
997static Xt_xmap
999 const int src_displacements[num_repetitions],
1000 const int dst_displacements[num_repetitions])
1001{
1004 &(struct spread_state){
1005 .num_repetitions = num_repetitions,
1006 .displacements = src_displacements },
1008 &(struct spread_state){
1009 .num_repetitions = num_repetitions,
1010 .displacements = dst_displacements });
1011}
1012
1013/* how many pos values have monotonically either positively or
1014 * negatively consecutive values and copy to pos_copy */
1015static inline struct pos_run copy_get_pos_run_len(
1016 size_t num_pos, const int *restrict pos,
1017 int *restrict pos_copy)
1018{
1019 size_t i = 0, j = 1;
1020 int direction = 0;
1021 int start = pos_copy[0] = pos[0];
1022 if (j < num_pos) {
1023 direction = isign_mask(pos[1] - pos[0]);
1024 while (j < num_pos
1025 && (pos_copy[j] = pos[j]) == start + (~direction & (int)(j - i)) +
1026 (direction & -(int)(j - i))) {
1027 pos_copy[j] = pos[j];
1028 ++j;
1029 }
1030 direction = direction & ((j == 1) - 1);
1031 }
1032 return (struct pos_run){ .start = start, .len = j, .direction = direction };
1033}
1034
1035/* compute number of position extents that would be required
1036 to represent positions array and copy to pos_copy */
1037static struct pos_count_max
1038max_count_pos_ext_and_copy(int max_pos, size_t num_pos, const int *restrict pos,
1039 int *restrict pos_copy)
1040{
1041 size_t i = 0, num_pos_ext = 0;
1042 while (i < num_pos) {
1043 struct pos_run run = copy_get_pos_run_len(num_pos - i, pos + i, pos_copy + i);
1044 i += run.len;
1045 int max_of_run = (run.start & run.direction) | ((run.start + (int)run.len - 1) & ~run.direction);
1046 if (max_of_run > max_pos) max_pos = max_of_run;
1047 ++num_pos_ext;
1048 }
1049 return (struct pos_count_max){ .count = (int)num_pos_ext, .max_pos = max_pos };
1050}
1051
1053 int count, struct exchange_data *restrict msgs,
1054 const struct Xt_com_pos *restrict com, int *max_pos) {
1055
1056 int max_pos_ = -1;
1057 for (int i = 0; i < count; ++i) {
1058 int num_transfer_pos = com[i].num_transfer_pos;
1059 int *restrict transfer_pos =
1060 xmalloc((size_t)num_transfer_pos * sizeof(*transfer_pos));
1061 msgs[i].transfer_pos = transfer_pos;
1062 msgs[i].transfer_pos_ext_cache = NULL;
1063 msgs[i].num_transfer_pos = num_transfer_pos;
1064 msgs[i].rank = com[i].rank;
1065 struct pos_count_max max_count
1066 = max_count_pos_ext_and_copy(max_pos_, (size_t)num_transfer_pos,
1067 com[i].transfer_pos, transfer_pos);
1068 msgs[i].num_transfer_pos_ext = max_count.count;
1069 if (max_count.max_pos > max_pos_) max_pos_ = max_count.max_pos;
1070 }
1071 *max_pos = max_pos_;
1072}
1073
1074Xt_xmap
1076 int num_src_msg, const struct Xt_com_pos src_com[num_src_msg],
1077 int num_dst_msg, const struct Xt_com_pos dst_com[num_dst_msg],
1078 MPI_Comm comm) {
1079
1080 // ensure that yaxt is initialized
1081 assert(xt_initialized());
1082
1083 size_t num_msg = (size_t)num_src_msg + (size_t)num_dst_msg;
1085 = xmalloc(sizeof (*xmap) + num_msg * sizeof (struct exchange_data));
1086
1088 xmap->n_in = num_dst_msg;
1089 xmap->n_out = num_src_msg;
1090 xmap->comm = comm = xt_mpi_comm_smart_dup(comm, &xmap->tag_offset);
1092 num_dst_msg, xmap->msg, dst_com, &xmap->max_dst_pos);
1094 num_src_msg, xmap->msg + num_dst_msg, src_com, &xmap->max_src_pos);
1095
1096 return (Xt_xmap)xmap;
1097}
1098
1100
1101 Xt_xmap_iter_intersection iter_intersection = xmii(iter);
1102
1103 if (iter_intersection == NULL || iter_intersection->msgs_left == 0)
1104 return 0;
1105
1106 iter_intersection->msg++;
1107 iter_intersection->msgs_left--;
1108
1109 return 1;
1110}
1111
1113
1114 assert(iter != NULL);
1115 return xmii(iter)->msg->rank;
1116}
1117
1118static int const *
1120
1121 assert(iter != NULL);
1122 return xmii(iter)->msg->transfer_pos;
1123}
1124
1125static const struct Xt_pos_ext *
1127
1128 assert(iter != NULL);
1129 if (!xmii(iter)->msg->transfer_pos_ext_cache) {
1130 size_t num_transfer_pos_ext = (size_t)((size_t)xmii(iter)->msg->num_transfer_pos_ext);
1131 struct Xt_pos_ext * transfer_pos_ext =
1133 xmalloc(num_transfer_pos_ext * sizeof(*transfer_pos_ext)));
1134 generate_pos_ext((size_t)xmii(iter)->msg->num_transfer_pos,
1135 xmii(iter)->msg->transfer_pos,
1136 num_transfer_pos_ext, transfer_pos_ext);
1137 }
1138 return xmii(iter)->msg->transfer_pos_ext_cache;
1139}
1140
1141static int
1143 assert(iter != NULL);
1144 return xmii(iter)->msg->num_transfer_pos_ext;
1145}
1146
1147static int
1149
1150 assert(iter != NULL);
1151 return xmii(iter)->msg->num_transfer_pos;
1152}
1153
1155
1156 free(iter);
1157}
1158
1159/*
1160 * Local Variables:
1161 * c-basic-offset: 2
1162 * coding: utf-8
1163 * indent-tabs-mode: nil
1164 * show-trailing-whitespace: t
1165 * require-trailing-newline: t
1166 * End:
1167 */
int MPI_Comm
Definition core.h:64
#define XT_UNUSED(x)
Definition core.h:84
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
add versions of standard API functions not returning on error
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:71
#define xcalloc(nmemb, size)
Definition ppm_xfuncs.h:68
#define xmalloc(size)
Definition ppm_xfuncs.h:70
const struct Xt_sort_algo_funcptr * sort_funcs
void(* sort_int)(int *a, size_t n)
void(* sort_int_permutation)(int a[], size_t n, int permutation[])
const struct Xt_xmap_vtable * vtable
struct exchange_data msg[]
const struct Xt_xmap_iter_vtable * vtable
struct Xt_pos_ext * transfer_pos_ext_cache
const int *restrict displacements
Xt_int * indices_to_remove
static int isign_mask(int x)
static const char filename[]
Definition xt_config.c:76
struct Xt_config_ xt_default_config
Definition xt_config.c:204
struct Xt_config_ * Xt_config
Definition xt_config.h:58
implementation of configuration object
int xt_initialized(void)
#define Xt_int_dt
Definition xt_core.h:73
struct Xt_xmap_ * Xt_xmap
Definition xt_core.h:85
XT_INT Xt_int
Definition xt_core.h:72
struct Xt_idxlist_ * Xt_idxlist
Definition xt_core.h:84
index list declaration
int xt_idxlist_get_positions_of_indices(Xt_idxlist idxlist, const Xt_int *indices, int num_indices, int *positions, int single_match_only)
Definition xt_idxlist.c:221
const Xt_int * xt_idxlist_get_indices_const(Xt_idxlist idxlist)
Definition xt_idxlist.c:119
Provide non-public declarations common to all index lists.
#define xt_idxlist_get_num_indices(idxlist)
MPI_Comm xt_mpi_comm_smart_dup(MPI_Comm comm, int *tag_offset)
Definition xt_mpi.c:333
void xt_mpi_comm_smart_dedup(MPI_Comm *comm, int tag_offset)
Definition xt_mpi.c:386
utility routines for MPI
#define xt_mpi_call(call, comm)
Definition xt_mpi.h:68
@ xt_mpi_tag_xmap_intersection_data_exchange
@ xt_mpi_tag_xmap_intersection_header_exchange
exchange map declarations
struct Xt_xmap_iter_ * Xt_xmap_iter
Definition xt_xmap.h:73
xt_reorder_type
Definition xt_xmap.h:240
@ XT_REORDER_RECV_UP
optimise data access on receiver side
Definition xt_xmap.h:243
@ XT_REORDER_NONE
no reordering
Definition xt_xmap.h:241
@ XT_REORDER_SEND_UP
optimise data access on sender side
Definition xt_xmap.h:242
contains declaration for the exchange map data structure
static const struct Xt_xmap_vtable xmap_intersection_vtable
static struct pos_count_max max_count_pos_ext_and_copy(int max_pos, size_t num_pos, const int *restrict pos, int *restrict pos_copy)
static Xt_xmap xmap_intersection_update_positions(Xt_xmap xmap, const int *src_positions, const int *dst_positions)
static Xt_xmap xmap_intersection_copy_(Xt_xmap xmap, int num_repetitions, Xt_pos_copy pos_copy_in, const void *pci_state, Xt_pos_copy pos_copy_out, const void *pco_state)
static Xt_int * exchange_points_to_remove(int num_src_intersections, const struct Xt_com_list src_com[num_src_intersections], int num_dst_intersections, const struct Xt_com_list dst_com[num_dst_intersections], int *restrict num_src_indices_to_remove_per_intersection, Xt_int *dst_indices_to_remove, const int *restrict num_dst_indices_to_remove_per_intersection, int tag_offset, MPI_Comm comm)
static Xt_xmap_iter xmap_intersection_get_in_iterator(Xt_xmap xmap)
struct Xt_xmap_iter_intersection_ * Xt_xmap_iter_intersection
static Xt_xmap xmap_intersection_spread(Xt_xmap xmap, int num_repetitions, const int src_displacements[num_repetitions], const int dst_displacements[num_repetitions])
static const struct Xt_xmap_iter_vtable xmap_iterator_intersection_vtable
static int xmap_intersection_iterator_get_rank(Xt_xmap_iter iter)
static struct a2abuf setup_buffer(int comm_size, int n, const struct exchange_data *msgs)
static Xt_xmap_intersection xmi(void *xmap)
static void xmap_intersection_msg_delete(int nmsg, struct exchange_data *msg)
struct Xt_xmap_intersection_ * Xt_xmap_intersection
static int pos_copy_verbatim(size_t num_pos, int *pos, const int *orig_pos, const void *state)
static void xmap_intersection_get_source_ranks(Xt_xmap xmap, int *ranks)
static void init_exchange_data_from_com_pos(int count, struct exchange_data *restrict msgs, const struct Xt_com_pos *restrict com, int *max_pos)
static int xmap_intersection_get_max_dst_pos(Xt_xmap xmap)
static void xmap_intersection_get_destination_ranks(Xt_xmap xmap, int *ranks)
Xt_xmap xt_xmap_intersection_pos_new(int num_src_msg, const struct Xt_com_pos src_com[num_src_msg], int num_dst_msg, const struct Xt_com_pos dst_com[num_dst_msg], MPI_Comm comm)
static int xmap_intersection_get_num_sources(Xt_xmap xmap)
Xt_xmap xt_xmap_intersection_new(int num_src_intersections, const struct Xt_com_list src_com[num_src_intersections], int num_dst_intersections, const struct Xt_com_list dst_com[num_dst_intersections], Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist, MPI_Comm comm)
static Xt_xmap xmap_intersection_copy(Xt_xmap xmap)
static int pos_copy_spread(size_t num_pos, int *restrict pos, const int *restrict orig_pos, const void *state)
@ bitsPerCoverageElement
static void reorder_transfer_pos(int n_out, int n_in, struct exchange_data *out_msg, struct exchange_data *in_msg, MPI_Comm comm, Xt_config config)
static MPI_Comm xmap_intersection_get_communicator(Xt_xmap xmap)
static void xmap_intersection_delete(Xt_xmap xmap)
static void xmap_intersection_msg_copy(size_t nmsg, const struct exchange_data *restrict msg, int *nmsg_copy, struct exchange_data *restrict msg_copy, int *max_pos_, int num_repetitions, Xt_pos_copy pos_copy, const void *pos_copy_state)
static struct pos_count_max generate_dir_transfer_pos_src(int num_intersections, const struct Xt_com_list intersections[num_intersections], Xt_idxlist mypart_idxlist, struct exchange_data *restrict resSets, const Xt_int *indices_to_remove, const int *num_indices_to_remove_per_intersection)
static void xmap_intersection_iterator_delete(Xt_xmap_iter iter)
static Xt_xmap_iter_intersection xmii(void *iter)
static int subst_positions(size_t num_pos, int *restrict pos, const int *restrict orig_pos, const void *new_pos_)
static struct pos_run copy_get_pos_run_len(size_t num_pos, const int *restrict pos, int *restrict pos_copy)
static int xmap_intersection_iterator_next(Xt_xmap_iter iter)
static Xt_xmap_iter xmap_intersection_get_out_iterator(Xt_xmap xmap)
static int const * xmap_intersection_iterator_get_transfer_pos(Xt_xmap_iter iter)
static int xmap_intersection_iterator_get_num_transfer_pos_ext(Xt_xmap_iter iter)
static int xmap_intersection_get_num_destinations(Xt_xmap xmap)
static const struct Xt_pos_ext * xmap_intersection_iterator_get_transfer_pos_ext(Xt_xmap_iter iter)
static int xmap_intersection_iterator_get_num_transfer_pos(Xt_xmap_iter iter)
static int xmap_intersection_get_max_src_pos(Xt_xmap xmap)
static struct tpd_result generate_dir_transfer_pos_dst(int num_intersections, const struct Xt_com_list intersections[num_intersections], Xt_idxlist mypart_idxlist, struct exchange_data *restrict resSets, int *restrict num_indices_to_remove_per_intersection)
static Xt_xmap xmap_intersection_reorder(Xt_xmap xmap, enum xt_reorder_type type, Xt_config config)
Xt_xmap xt_xmap_intersection_custom_new(int num_src_intersections, const struct Xt_com_list src_com[num_src_intersections], int num_dst_intersections, const struct Xt_com_list dst_com[num_dst_intersections], Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist, MPI_Comm comm, Xt_config XT_UNUSED(config))
int(* Xt_pos_copy)(size_t num_pos, int *pos, const int *orig_pos, const void *state)
static int generate_transfer_pos(struct Xt_xmap_intersection_ *xmap, int num_src_intersections, const struct Xt_com_list src_com[num_src_intersections], int num_dst_intersections, const struct Xt_com_list dst_com[num_dst_intersections], Xt_idxlist src_idxlist_local, Xt_idxlist dst_idxlist_local, MPI_Comm comm)
Utility functions shared by xt_xmap_intersection and xt_xmap_intersection_ext.
static void print_miss_msg(Xt_idxlist dst_idxlist, int missing_pos, MPI_Comm comm, const char *source, int line) __attribute__((noreturn))
static size_t count_pos_ext(size_t num_pos, const int *restrict pos)
static void generate_pos_ext(size_t num_pos, const int *restrict pos, size_t num_pos_ext, struct Xt_pos_ext *restrict pos_ext)