Yet Another eXchange Tool 0.11.1
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
142
143static inline Xt_xmap_iter_intersection
144xmii(void *iter)
145{
146 return (Xt_xmap_iter_intersection)iter;
147}
148
149
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
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
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 void *state);
684
685static int
686pos_copy_verbatim(size_t num_pos,
687 int *pos, const int *orig_pos, void *state)
688{
689 (void)state;
690 memcpy(pos, orig_pos, sizeof (*pos) * num_pos);
691 return -1;
692}
693
694typedef void (*Xt_pos_ncopy)(size_t num_pos, int *pos, const int *orig_pos,
695 void *state, int num_repetitions,
696 const int displacements[num_repetitions]);
697
698static void
700 const struct exchange_data *restrict msg,
701 int *nmsg_copy,
702 struct exchange_data *restrict msg_copy,
703 int *max_pos_, int num_repetitions,
704 Xt_pos_copy pos_copy, void *pos_copy_state) {
705 *nmsg_copy = (int)nmsg;
706 int max_pos = 0;
707 for (size_t i = 0; i < nmsg; ++i) {
708 size_t num_transfer_pos
709 = (size_t)(msg_copy[i].num_transfer_pos
710 = num_repetitions * msg[i].num_transfer_pos);
711 msg_copy[i].rank = msg[i].rank;
712 msg_copy[i].transfer_pos_ext_cache = NULL;
713 size_t size_transfer_pos
714 = num_transfer_pos * sizeof (*(msg[i].transfer_pos));
715 msg_copy[i].transfer_pos = xmalloc(size_transfer_pos);
716 int new_max_pos
717 = pos_copy(num_transfer_pos,
718 msg_copy[i].transfer_pos, msg[i].transfer_pos,
719 pos_copy_state);
720 if (new_max_pos > max_pos)
721 max_pos = new_max_pos;
722 if (pos_copy == pos_copy_verbatim)
723 msg_copy[i].num_transfer_pos_ext = msg[i].num_transfer_pos_ext;
724 else
725 msg_copy[i].num_transfer_pos_ext =
726 (int)(count_pos_ext(num_transfer_pos, msg_copy[i].transfer_pos));
727 }
728 if (pos_copy != pos_copy_verbatim)
729 *max_pos_ = max_pos;
730}
731
732static Xt_xmap
734 int num_repetitions,
735 Xt_pos_copy pos_copy_in, void *pci_state,
736 Xt_pos_copy pos_copy_out, void *pco_state)
737{
738 Xt_xmap_intersection xmap_intersection = xmi(xmap), xmap_intersection_new;
739 size_t n_in = (size_t)xmap_intersection->n_in,
740 n_out = (size_t)xmap_intersection->n_out,
741 num_isect = n_in + n_out;
742 xmap_intersection_new
743 = xmalloc(sizeof (*xmap_intersection_new)
744 + num_isect * sizeof (struct exchange_data));
745 xmap_intersection_new->vtable = xmap_intersection->vtable;
746 xmap_intersection_new->n_in = (int)n_in;
747 xmap_intersection_new->n_out = (int)n_out;
748 xmap_intersection_new->max_src_pos = xmap_intersection->max_src_pos;
749 xmap_intersection_new->max_dst_pos = xmap_intersection->max_dst_pos;
750 xmap_intersection_msg_copy(n_in, xmap_intersection->msg,
751 &xmap_intersection_new->n_in,
752 xmap_intersection_new->msg,
753 &xmap_intersection_new->max_dst_pos,
754 num_repetitions,
755 pos_copy_in, pci_state);
756 xmap_intersection_msg_copy(n_out, xmap_intersection->msg + n_in,
757 &xmap_intersection_new->n_out,
758 xmap_intersection_new->msg+n_in,
759 &xmap_intersection_new->max_src_pos,
760 num_repetitions,
761 pos_copy_out, pco_state);
762 xmap_intersection_new->comm
763 = xt_mpi_comm_smart_dup(xmap_intersection->comm,
764 &xmap_intersection_new->tag_offset);
765 return (Xt_xmap)xmap_intersection_new;
766}
767
768static Xt_xmap
770{
771 return xmap_intersection_copy_(xmap, 1,
772 pos_copy_verbatim, NULL,
773 pos_copy_verbatim, NULL);
774}
775
776static void
778 for (int i = 0; i < nmsg; ++i) {
779 free(msg[i].transfer_pos_ext_cache);
780 free(msg[i].transfer_pos);
781 }
782}
783
785
786 Xt_xmap_intersection xmap_intersection = xmi(xmap);
787
788 int num_isect = xmap_intersection->n_in + xmap_intersection->n_out;
789 xmap_intersection_msg_delete(num_isect, xmap_intersection->msg);
790 xt_mpi_comm_smart_dedup(&xmap_intersection->comm,
791 xmap_intersection->tag_offset);
792 free(xmap_intersection);
793}
794
796
797 Xt_xmap_intersection xmap_intersection = xmi(xmap);
798
799 if (xmap_intersection->n_in == 0)
800 return NULL;
801
802 Xt_xmap_iter_intersection iter = xmalloc(sizeof (*iter));
803
805 iter->msg = xmap_intersection->msg;
806 iter->msgs_left = xmap_intersection->n_in - 1;
807
808 return (Xt_xmap_iter)iter;
809}
810
812
813 Xt_xmap_intersection xmap_intersection = xmi(xmap);
814
815 if (xmap_intersection->n_out == 0)
816 return NULL;
817
818 Xt_xmap_iter_intersection iter = xmalloc(sizeof (*iter));
819
821 iter->msg = xmap_intersection->msg + xmap_intersection->n_in;
822 iter->msgs_left = xmap_intersection->n_out - 1;
823
824 return (Xt_xmap_iter)iter;
825}
826
827struct a2abuf
828{
830};
831
832static inline struct a2abuf
833setup_buffer(int comm_size, int n, const struct exchange_data *msgs)
834{
835 size_t buffer_size = 0;
836 for (int i = 0; i < n; ++i)
837 buffer_size += (size_t)msgs[i].num_transfer_pos;
838
839 int *restrict counts = xmalloc((2 * (size_t)comm_size + buffer_size)
840 * sizeof(*counts)),
841 *restrict displs = counts + comm_size,
842 *restrict buffer = counts + 2 * comm_size;
843 for (int i = 0; i < comm_size; ++i)
844 counts[i] = 0;
845
846 for (int i = 0; i < n; ++i)
847 counts[msgs[i].rank] = msgs[i].num_transfer_pos;
848
849 for (int i = 0, accu = 0; i < comm_size; ++i) {
850 displs[i] = accu;
851 accu += counts[i];
852 }
853 return (struct a2abuf){ .buffer=buffer, .counts=counts, .displs=displs };
854}
855
857 int n_out, int n_in, struct exchange_data * out_msg,
858 struct exchange_data * in_msg, MPI_Comm comm, Xt_config config) {
859
860 int comm_size;
861 xt_mpi_call(MPI_Comm_size(comm, &comm_size), comm);
862
863 struct a2abuf
864 out = setup_buffer(comm_size, n_out, out_msg),
865 in = setup_buffer(comm_size, n_in, in_msg);
866
867 void (*sort_int)(int a[], size_t n) = config->sort_funcs->sort_int;
868 for (int i = 0; i < n_out; ++i) {
869 const struct exchange_data * curr_msg = out_msg + i;
870 int count = curr_msg->num_transfer_pos;
871 if (count > 0) {
872 // pack local out transfer_pos into out buffer
873 memcpy(out.buffer + out.displs[curr_msg->rank],
874 curr_msg->transfer_pos, (size_t)count * sizeof(*out.buffer));
875 // sort local out transfer_pos
876 sort_int(curr_msg->transfer_pos, (size_t)count);
877 }
878 }
879
880 // exchange local out transfer_pos
881 xt_mpi_call(MPI_Alltoallv(out.buffer, out.counts, out.displs, MPI_INT,
882 in.buffer, in.counts, in.displs, MPI_INT,
883 comm), comm);
884
885 void (*sort_int_permutation)(int a[], size_t n, int permutation[])
887 for (int i = 0; i < n_in; ++i) {
888 const struct exchange_data * curr_msg = in_msg + i;
889 int count = curr_msg->num_transfer_pos;
890 if (count > 0)
891 // reorder local receive transfer_pos (curr_msg->transfer_pos) based
892 // on remote out transfer_pos (in_buffer + in_displs[curr_msg->rank])
893 sort_int_permutation(
894 in.buffer + in.displs[curr_msg->rank], (size_t)count,
895 curr_msg->transfer_pos);
896 }
897
898 free(out.counts);
899 free(in.counts);
900
901 for (int i = 0; i < n_out; ++i) {
902 free(out_msg[i].transfer_pos_ext_cache);
903 out_msg[i].transfer_pos_ext_cache = NULL;
904 out_msg[i].num_transfer_pos_ext =
905 (int)count_pos_ext(
906 (size_t)out_msg[i].num_transfer_pos, out_msg[i].transfer_pos);
907 }
908 for (int i = 0; i < n_in; ++i) {
909 free(in_msg[i].transfer_pos_ext_cache);
910 in_msg[i].transfer_pos_ext_cache = NULL;
911 in_msg[i].num_transfer_pos_ext =
912 (int)count_pos_ext(
913 (size_t)in_msg[i].num_transfer_pos, in_msg[i].transfer_pos);
914 }
915}
916
917static Xt_xmap
919 Xt_config config) {
920
921 Xt_xmap_intersection xmap_intersection_new =
923
924 int n_out = xmap_intersection_new->n_out,
925 n_in = xmap_intersection_new->n_in;
926 struct exchange_data *in_msg = xmap_intersection_new->msg,
927 *out_msg = in_msg+n_in;
928 MPI_Comm comm = xmap_intersection_new->comm;
929
930 switch ((int)type) {
931 case (XT_REORDER_NONE):
932 break;
933 case (XT_REORDER_SEND_UP):
934 reorder_transfer_pos(n_out, n_in, out_msg, in_msg, comm, config);
935 break;
936 case (XT_REORDER_RECV_UP):
937 reorder_transfer_pos(n_in, n_out, in_msg, out_msg, comm, config);
938 break;
939 default:
940 Xt_abort(comm, "ERROR(xmap_intersection_reorder):invalid reorder type",
941 filename, __LINE__);
942 }
943
944 return (Xt_xmap)xmap_intersection_new;
945}
946
947static int
948subst_positions(size_t num_pos,
949 int *restrict pos, const int *restrict orig_pos, void *new_pos_)
950{
951 const int *restrict new_pos = new_pos_;
952 int max_pos = 0;
953 for (size_t i = 0; i < num_pos; ++i) {
954 int np = new_pos[orig_pos[i]];
955 pos[i] = np;
956 if (np > max_pos)
957 max_pos = np;
958 }
959 return max_pos;
960}
961
962static Xt_xmap
964 const int *src_positions,
965 const int *dst_positions) {
966
967 return xmap_intersection_copy_(xmap, 1,
968 subst_positions, (void *)dst_positions,
969 subst_positions, (void *)src_positions);
970}
971
973{
975 const int *restrict displacements;
976};
977
978static int
979pos_copy_spread(size_t num_pos, int *restrict pos,
980 const int *restrict orig_pos, void *state)
981{
982 struct spread_state *sp = state;
984 const int *restrict displacements = sp->displacements;
985 num_pos = num_pos / (size_t)num_repetitions;
986 int max_pos = -1;
987 for (int i = 0, k = 0; i < num_repetitions; ++i) {
988 int curr_disp = displacements[i];
989 for (size_t j = 0; j < num_pos; ++j, ++k) {
990 int np = orig_pos[j] + curr_disp;
991 pos[k] = np;
992 if (np > max_pos)
993 max_pos = np;
994 }
995 }
996 return max_pos;
997}
998
999
1000static Xt_xmap
1002 const int src_displacements[num_repetitions],
1003 const int dst_displacements[num_repetitions])
1004{
1007 &(struct spread_state){
1008 .num_repetitions = num_repetitions,
1009 .displacements = src_displacements },
1011 &(struct spread_state){
1012 .num_repetitions = num_repetitions,
1013 .displacements = dst_displacements });
1014}
1015
1016/* how many pos values have monotonically either positively or
1017 * negatively consecutive values and copy to pos_copy */
1018static inline struct pos_run copy_get_pos_run_len(
1019 size_t num_pos, const int *restrict pos,
1020 int *restrict pos_copy)
1021{
1022 size_t i = 0, j = 1;
1023 int direction = 0;
1024 int start = pos_copy[0] = pos[0];
1025 if (j < num_pos) {
1026 direction = isign_mask(pos[1] - pos[0]);
1027 while (j < num_pos
1028 && (pos_copy[j] = pos[j]) == start + (~direction & (int)(j - i)) +
1029 (direction & -(int)(j - i))) {
1030 pos_copy[j] = pos[j];
1031 ++j;
1032 }
1033 direction = direction & ((j == 1) - 1);
1034 }
1035 return (struct pos_run){ .start = start, .len = j, .direction = direction };
1036}
1037
1038/* compute number of position extents that would be required
1039 to represent positions array and copy to pos_copy */
1040static struct pos_count_max
1041max_count_pos_ext_and_copy(int max_pos, size_t num_pos, const int *restrict pos,
1042 int *restrict pos_copy)
1043{
1044 size_t i = 0, num_pos_ext = 0;
1045 while (i < num_pos) {
1046 struct pos_run run = copy_get_pos_run_len(num_pos - i, pos + i, pos_copy + i);
1047 i += run.len;
1048 int max_of_run = (run.start & run.direction) | ((run.start + (int)run.len - 1) & ~run.direction);
1049 if (max_of_run > max_pos) max_pos = max_of_run;
1050 ++num_pos_ext;
1051 }
1052 return (struct pos_count_max){ .count = (int)num_pos_ext, .max_pos = max_pos };
1053}
1054
1056 int count, struct exchange_data *restrict msgs,
1057 const struct Xt_com_pos *restrict com, int *max_pos) {
1058
1059 int max_pos_ = -1;
1060 for (int i = 0; i < count; ++i) {
1061 int num_transfer_pos = com[i].num_transfer_pos;
1062 int *restrict transfer_pos =
1063 xmalloc((size_t)num_transfer_pos * sizeof(*transfer_pos));
1064 msgs[i].transfer_pos = transfer_pos;
1065 msgs[i].transfer_pos_ext_cache = NULL;
1066 msgs[i].num_transfer_pos = num_transfer_pos;
1067 msgs[i].rank = com[i].rank;
1068 struct pos_count_max max_count
1069 = max_count_pos_ext_and_copy(max_pos_, (size_t)num_transfer_pos,
1070 com[i].transfer_pos, transfer_pos);
1071 msgs[i].num_transfer_pos_ext = max_count.count;
1072 if (max_count.max_pos > max_pos_) max_pos_ = max_count.max_pos;
1073 }
1074 *max_pos = max_pos_;
1075}
1076
1077Xt_xmap
1079 int num_src_msg, const struct Xt_com_pos src_com[num_src_msg],
1080 int num_dst_msg, const struct Xt_com_pos dst_com[num_dst_msg],
1081 MPI_Comm comm) {
1082
1083 // ensure that yaxt is initialized
1084 assert(xt_initialized());
1085
1086 size_t num_msg = (size_t)num_src_msg + (size_t)num_dst_msg;
1088 = xmalloc(sizeof (*xmap) + num_msg * sizeof (struct exchange_data));
1089
1091 xmap->n_in = num_dst_msg;
1092 xmap->n_out = num_src_msg;
1093 xmap->comm = comm = xt_mpi_comm_smart_dup(comm, &xmap->tag_offset);
1095 num_dst_msg, xmap->msg, dst_com, &xmap->max_dst_pos);
1097 num_src_msg, xmap->msg + num_dst_msg, src_com, &xmap->max_src_pos);
1098
1099 return (Xt_xmap)xmap;
1100}
1101
1103
1104 Xt_xmap_iter_intersection iter_intersection = xmii(iter);
1105
1106 if (iter_intersection == NULL || iter_intersection->msgs_left == 0)
1107 return 0;
1108
1109 iter_intersection->msg++;
1110 iter_intersection->msgs_left--;
1111
1112 return 1;
1113}
1114
1116
1117 assert(iter != NULL);
1118 return xmii(iter)->msg->rank;
1119}
1120
1121static int const *
1123
1124 assert(iter != NULL);
1125 return xmii(iter)->msg->transfer_pos;
1126}
1127
1128static const struct Xt_pos_ext *
1130
1131 assert(iter != NULL);
1132 if (!xmii(iter)->msg->transfer_pos_ext_cache) {
1133 size_t num_transfer_pos_ext = (size_t)((size_t)xmii(iter)->msg->num_transfer_pos_ext);
1134 struct Xt_pos_ext * transfer_pos_ext =
1136 xmalloc(num_transfer_pos_ext * sizeof(*transfer_pos_ext)));
1137 generate_pos_ext((size_t)xmii(iter)->msg->num_transfer_pos,
1138 xmii(iter)->msg->transfer_pos,
1139 num_transfer_pos_ext, transfer_pos_ext);
1140 }
1141 return xmii(iter)->msg->transfer_pos_ext_cache;
1142}
1143
1144static int
1146 assert(iter != NULL);
1147 return xmii(iter)->msg->num_transfer_pos_ext;
1148}
1149
1150static int
1152
1153 assert(iter != NULL);
1154 return xmii(iter)->msg->num_transfer_pos;
1155}
1156
1158
1159 free(iter);
1160}
1161
1162/*
1163 * Local Variables:
1164 * c-basic-offset: 2
1165 * coding: utf-8
1166 * indent-tabs-mode: nil
1167 * show-trailing-whitespace: t
1168 * require-trailing-newline: t
1169 * End:
1170 */
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
int(* next)(Xt_xmap_iter iter)
MPI_Comm(* get_communicator)(Xt_xmap)
struct Xt_pos_ext * transfer_pos_ext_cache
const int *restrict displacements
Xt_int * indices_to_remove
static int isign_mask(int x)
struct Xt_config_ xt_default_config
Definition xt_config.c:203
implementation of configuration object
int xt_initialized(void)
#define Xt_int_dt
Definition xt_core.h:73
XT_INT Xt_int
Definition xt_core.h:72
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
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_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 const char filename[]
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
void(* Xt_pos_ncopy)(size_t num_pos, int *pos, const int *orig_pos, void *state, int num_repetitions, const int displacements[num_repetitions])
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)
int(* Xt_pos_copy)(size_t num_pos, int *pos, const int *orig_pos, void *state)
static void xmap_intersection_msg_delete(int nmsg, struct exchange_data *msg)
static Xt_xmap xmap_intersection_copy_(Xt_xmap xmap, int num_repetitions, Xt_pos_copy pos_copy_in, void *pci_state, Xt_pos_copy pos_copy_out, void *pco_state)
struct Xt_xmap_intersection_ * Xt_xmap_intersection
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 int subst_positions(size_t num_pos, int *restrict pos, const int *restrict orig_pos, void *new_pos_)
static void xmap_intersection_get_destination_ranks(Xt_xmap xmap, int *ranks)
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, void *pos_copy_state)
static int pos_copy_spread(size_t num_pos, int *restrict pos, const int *restrict orig_pos, void *state)
static int xmap_intersection_get_num_sources(Xt_xmap xmap)
static Xt_xmap xmap_intersection_copy(Xt_xmap xmap)
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 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 struct pos_run copy_get_pos_run_len(size_t num_pos, const int *restrict pos, int *restrict pos_copy)
@ bitsPerCoverageElement
static int xmap_intersection_iterator_next(Xt_xmap_iter iter)
static Xt_xmap_iter xmap_intersection_get_out_iterator(Xt_xmap xmap)
static int pos_copy_verbatim(size_t num_pos, int *pos, const int *orig_pos, void *state)
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))
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)
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)
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)
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)