Yet Another eXchange Tool  DO_NOT_EDIT_HERE
xt_xmap_intersection_ext.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://doc.redmine.dkrz.de/yaxt/html/
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 <limits.h>
52 #include <stdbool.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <string.h>
56 
57 #include <mpi.h>
58 
59 #include "xt/xt_idxlist.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"
68 #include "xt_arithmetic_util.h"
69 #include "ensure_array_size.h"
70 #include "xt_cover.h"
71 
75 static void
77 static void
82 static void xmap_intersection_ext_delete(Xt_xmap xmap);
85 
86 
89  .get_num_destinations = xmap_intersection_ext_get_num_destinations,
90  .get_num_sources = xmap_intersection_ext_get_num_sources,
91  .get_destination_ranks = xmap_intersection_ext_get_destination_ranks,
92  .get_source_ranks = xmap_intersection_ext_get_source_ranks,
93  .get_out_iterator = xmap_intersection_ext_get_out_iterator,
94  .get_in_iterator = xmap_intersection_ext_get_in_iterator,
97  .get_max_src_pos = xmap_intersection_ext_get_max_src_pos,
98  .get_max_dst_pos = xmap_intersection_ext_get_max_dst_pos};
99 
100 struct exchange_ext {
101  // list of relative position extents in index list to send or receive
103  /* generated on-demand */
106  int rank;
107 };
108 
110 
111  const struct Xt_xmap_vtable * vtable;
112 
113  struct exchange_ext *in_msg, *out_msg;
114  int n_in, n_out;
115 
116  // we need the max position in order to enable quick range-checks
117  // for xmap-users like redist
118  int max_src_pos; // max possible pos over all src transfer_pos (always >= 0)
119  int max_dst_pos; // same for dst
120  int tag_offset; /* offset to add to message tags for uniqueness */
122 };
123 
125 
126 static inline Xt_xmap_intersection_ext xmie(void *xmap)
127 {
128  return (Xt_xmap_intersection_ext)xmap;
129 }
130 
132 {
133  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap);
134  return xmap_intersection_ext->comm;
135 }
136 
138 {
139  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap);
140  // the number of destination equals the number of source messages
141  return xmap_intersection_ext->n_out;
142 }
143 
145 {
146  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap);
147  // the number of sources equals the number of destination messages
148  return xmap_intersection_ext->n_in;
149 }
150 
151 static void
153 {
154  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap);
155  size_t n_out = (size_t)xmap_intersection_ext->n_out;
156  struct exchange_ext *restrict out_msg = xmap_intersection_ext->out_msg;
157  for (size_t i = 0; i < n_out; ++i)
158  ranks[i] = out_msg[i].rank;
159 }
160 
161 static void
163 {
164  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap);
165  size_t n_in = (size_t)xmap_intersection_ext->n_in;
166  struct exchange_ext *restrict in_msg = xmap_intersection_ext->in_msg;
167  for (size_t i = 0; i < n_in; ++i)
168  ranks[i] = in_msg[i].rank;
169 }
170 
172  return xmie(xmap)->max_src_pos;
173 }
174 
176  return xmie(xmap)->max_dst_pos;
177 }
178 
179 static void
180 xmap_intersection_ext_msg_copy(size_t nmsg, struct exchange_ext *restrict msg,
181  int *nmsg_copy, struct exchange_ext **msg_copy)
182 {
183  *nmsg_copy = (int)nmsg;
184  struct exchange_ext *restrict msg_copy_
185  = *msg_copy = xmalloc(sizeof (*msg_copy_) * nmsg);
186  for (size_t i = 0; i < nmsg; ++i) {
187  size_t num_transfer_pos_ext
188  = (size_t)(msg_copy_[i].num_transfer_pos_ext
189  = msg[i].num_transfer_pos_ext);
190  msg_copy_[i].num_transfer_pos = msg[i].num_transfer_pos;
191  msg_copy_[i].rank = msg[i].rank;
192  msg_copy_[i].transfer_pos = NULL;
193  size_t size_transfer_pos_ext
194  = num_transfer_pos_ext * sizeof (*(msg[i].transfer_pos_ext));
195  msg_copy_[i].transfer_pos_ext = xmalloc(size_transfer_pos_ext);
196  memcpy(msg_copy_[i].transfer_pos_ext, msg[i].transfer_pos_ext,
197  size_transfer_pos_ext);
198  }
199 }
200 
201 static Xt_xmap
203 {
204  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap),
205  xmap_intersection_ext_new = xmalloc(sizeof (*xmap_intersection_ext_new));
206  xmap_intersection_ext_new->vtable = xmap_intersection_ext->vtable;
207  size_t n_in = (size_t)(xmap_intersection_ext_new->n_in = xmap_intersection_ext->n_in),
208  n_out = (size_t)(xmap_intersection_ext_new->n_out = xmap_intersection_ext->n_out);
209  xmap_intersection_ext_new->max_src_pos = xmap_intersection_ext->max_src_pos;
210  xmap_intersection_ext_new->max_dst_pos = xmap_intersection_ext->max_dst_pos;
211  xmap_intersection_ext_msg_copy(n_in, xmap_intersection_ext->in_msg,
212  &xmap_intersection_ext_new->n_in,
213  &xmap_intersection_ext_new->in_msg);
214  xmap_intersection_ext_msg_copy(n_out, xmap_intersection_ext->out_msg,
215  &xmap_intersection_ext_new->n_out,
216  &xmap_intersection_ext_new->out_msg);
217  xmap_intersection_ext_new->comm
218  = xt_mpi_comm_smart_dup(xmap_intersection_ext->comm,
219  &xmap_intersection_ext_new->tag_offset);
220  return (Xt_xmap)xmap_intersection_ext_new;
221 }
222 
223 
224 static void
225 xt_free_exchange_ext(size_t num_msg, struct exchange_ext *restrict msg)
226 {
227  for (size_t i = 0; i < num_msg; ++i) {
228  free(msg[i].transfer_pos);
229  free(msg[i].transfer_pos_ext);
230  }
231  free(msg);
232 }
233 
235 
236  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap);
237 
238  xt_free_exchange_ext((size_t)xmap_intersection_ext->n_in,
239  xmap_intersection_ext->in_msg);
240 
241  xt_free_exchange_ext((size_t)xmap_intersection_ext->n_out,
242  xmap_intersection_ext->out_msg);
243 
244  xt_mpi_comm_smart_dedup(&xmap_intersection_ext->comm,
245  xmap_intersection_ext->tag_offset);
246  free(xmap_intersection_ext);
247 }
248 
249 static void
251  int num_src_intersections,
252  const struct Xt_com_list src_com[num_src_intersections],
253  int num_dst_intersections,
254  const struct Xt_com_list dst_com[num_dst_intersections],
255  Xt_idxlist src_idxlist_local,
256  Xt_idxlist dst_idxlist_local,
257  MPI_Comm comm);
258 
259 Xt_xmap
260 xt_xmap_intersection_ext_new(int num_src_intersections,
261  const struct Xt_com_list
262  src_com[num_src_intersections],
263  int num_dst_intersections,
264  const struct Xt_com_list
265  dst_com[num_dst_intersections],
266  Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist,
267  MPI_Comm comm) {
268 
269  Xt_xmap_intersection_ext xmap = xmalloc(sizeof (*xmap));
270 
272 
273  xmap->comm = comm = xt_mpi_comm_smart_dup(comm, &xmap->tag_offset);
274 
275  // generate exchange lists
277  num_src_intersections, src_com,
278  num_dst_intersections, dst_com,
279  src_idxlist, dst_idxlist, comm);
280 
281  // we could also calculate the (more precise) max pos using only xmap data
282  // but using this simple estimate we are still okay for usage checks
283  xmap->max_src_pos = xt_idxlist_get_num_indices(src_idxlist);
284  xmap->max_dst_pos = xt_idxlist_get_num_indices(dst_idxlist);
285 
286  return (Xt_xmap)xmap;
287 }
288 
289 static struct Xt_pos_ext_vec
290 generate_dir_transfer_ext_dst(
291  int num_intersections,
292  const struct Xt_com_list intersections[num_intersections],
293  Xt_idxlist mypart_idxlist,
294  int *resCount,
295  struct exchange_ext **resSets,
296  int (*restrict dst_removals_per_intersection)[2]);
297 
298 
299 static struct Xt_pos_ext *
301  int num_src_intersections,
302  const struct Xt_com_list src_com[num_src_intersections],
303  int num_dst_intersections,
304  const struct Xt_com_list dst_com[num_dst_intersections],
305  struct exchange_ext dst_ext[num_dst_intersections],
306  int (*restrict src_removals_per_intersection)[2],
307  int (*restrict dst_removals_per_intersection)[2],
308  int tag_offset,
309  MPI_Comm comm);
310 
311 static void
312 remap_dst_intersections(int num_dst_intersections,
313  const struct Xt_com_list dst_com[num_dst_intersections],
314  Xt_idxlist mypart_idxlist,
315  int resCount,
316  struct exchange_ext resSets[resCount],
317  int (*removals_per_intersection)[2]);
318 
319 static void
321  int num_intersections,
322  const struct Xt_com_list intersections[num_intersections],
323  Xt_idxlist mypart_idxlist,
324  int *resCount,
325  struct exchange_ext **resSets,
326  int (*restrict removals_per_intersection)[2],
327  struct Xt_pos_ext *pos_updates);
328 
329 static void
331  int num_src_intersections,
332  const struct Xt_com_list src_com[num_src_intersections],
333  int num_dst_intersections,
334  const struct Xt_com_list dst_com[num_dst_intersections],
335  Xt_idxlist src_idxlist_local,
336  Xt_idxlist dst_idxlist_local,
337  MPI_Comm comm) {
338 
339  /* {dst|src}_removals_per_intersection[i][0] denotes the number of
340  * indices to be removed from the intersection with {src|dst}_com[i].rank.
341  * {dst|src}_removals_per_intersection[rank][1] denotes the number of
342  * pos_ext needed to represent this change (0 if either none or all
343  * indices got removed).
344  */
345  int (*src_removals_per_intersection)[2] =
346  xmalloc(((size_t)num_dst_intersections + (size_t)num_src_intersections)
347  * sizeof(*src_removals_per_intersection)),
348  (*dst_removals_per_intersection)[2]
349  = src_removals_per_intersection + num_src_intersections;
350 
351  {
352  struct Xt_pos_ext_vec cover
354  num_dst_intersections, dst_com, dst_idxlist_local,
355  &(xmap->n_in), &(xmap->in_msg), dst_removals_per_intersection);
356 
357  if (!xt_idxlist_pos_ext_is_full_cover(dst_idxlist_local, cover)) {
358  if (xt_idxlist_get_num_indices(dst_idxlist_local) == 0)
359  Xt_abort(comm, "ERROR: ups...this should not have happend...", __FILE__,
360  __LINE__);
361  int first_missing_pos = 0;
362  Xt_int missing_index;
363  if ((cover.num_pos_ext > 0) && (cover.pos_ext[0].start == 0))
364  first_missing_pos = cover.pos_ext[0].start + cover.pos_ext[0].size - 1;
365  xt_idxlist_get_index_at_position(dst_idxlist_local, first_missing_pos,
366  &missing_index);
367  char error_message[1024];
368  sprintf(error_message, "ERROR: destination intersections do not match "
369  "with destination index list (first missing index %lld "
370  "at position %d)", (long long)missing_index, first_missing_pos);
371  Xt_abort(comm, error_message, __FILE__, __LINE__);
372  }
373  xt_cover_finish(&cover);
374  }
375 
376  // exchange pos_ext of lists where additional indices need to be removed
377  struct Xt_pos_ext *pos_updates
379  num_src_intersections, src_com, num_dst_intersections, dst_com,
380  xmap->in_msg,
381  src_removals_per_intersection,
382  dst_removals_per_intersection, xmap->tag_offset, comm);
383 
384  remap_dst_intersections(num_dst_intersections, dst_com, dst_idxlist_local,
385  xmap->n_in, xmap->in_msg,
386  dst_removals_per_intersection);
387 
388  src_removals_per_intersection =
389  xrealloc(src_removals_per_intersection, (size_t)num_src_intersections
390  * sizeof(*src_removals_per_intersection));
391 
393  num_src_intersections, src_com, src_idxlist_local,
394  &(xmap->n_out), &(xmap->out_msg),
395  src_removals_per_intersection, pos_updates);
396 
397  free(src_removals_per_intersection);
398  free(pos_updates);
399 }
400 
402  int skip, overlap, tail;
403 };
404 
405 static struct Xt_pos_ext_overlap
407 {
408  /* == 0 if a.size >= 0 ; == ~0 if a.size < 0 */
409  int aSizeMaskNeg = isign_mask(a.size),
410  /* compute start and end indices of ranges */
411  a_s = a.start + (aSizeMaskNeg & (a.size + 1)),
412  a_e = a.start + (~aSizeMaskNeg & (a.size - 1)),
413  bSizeMaskNeg = isign_mask(b.size),
414  b_s = b.start + (bSizeMaskNeg & (b.size + 1)),
415  b_e = b.start + (~bSizeMaskNeg & (b.size - 1));
416  /* does overlap exist? */
417  if ((b_s > a_e) | (a_s > b_e))
418  return (struct Xt_pos_ext_overlap){ a.size, 0, 0};
419  else {
420  /* determine length of overlap parts */
421  int lowSkipA = b_s - a_s;
422  int lowSkipB = -lowSkipA;
423  lowSkipA = (int)((unsigned)(lowSkipA + abs(lowSkipA))/2U);
424  lowSkipB = (int)((unsigned)(lowSkipB + abs(lowSkipB))/2U);
425  int overlapLen = imin(b_e - b_s - lowSkipB + 1,
426  abs(a.size) - lowSkipA);
427  int highSkipA = abs(a.size) - lowSkipA - overlapLen;
428  /* then adjust lengths to direction of overlap (from
429  * perspective of a */
430  int aSkipLen = (~aSizeMaskNeg & lowSkipA)
431  | (aSizeMaskNeg & -highSkipA),
432  aTailLen = (aSizeMaskNeg & -lowSkipA)
433  | (~aSizeMaskNeg & highSkipA);
434  return (struct Xt_pos_ext_overlap){ aSkipLen, overlapLen, aTailLen };
435  }
436 }
437 
438 
439 
440 static void
442  size_t *num_pos_exts,
443  size_t *size_pos_exts,
444  struct Xt_pos_ext **pos_exts);
445 
446 static struct Xt_pos_ext_vec
447 generate_dir_transfer_ext_dst(
448  int num_intersections,
449  const struct Xt_com_list intersections[num_intersections],
450  Xt_idxlist mypart_idxlist,
451  int *resCount, struct exchange_ext **resSets,
452  int (*restrict dst_removals_per_intersection)[2])
453 {
454  struct exchange_ext *restrict resSets_
455  = *resSets = xmalloc((size_t)num_intersections * sizeof(**resSets));
456 
457  int new_num_intersections = 0;
458 
459  // we have to enforce single_match_only not only within a single
460  // intersection, but also between all intersections
461  /* ranges already covered from previous intersections, i.e. which
462  * must not be transmitted twice */
463  struct Xt_pos_ext_vec cover;
464  xt_cover_start(&cover, 8);
465 
466  struct Xt_pos_ext *restrict isect_transfer_pos_ext = NULL;
467 
468  for (int i = 0; i < num_intersections; ++i) {
469 
470  int num_stripes, num_indices_to_remove = 0;
471  struct Xt_stripe *restrict intersection_idxstripes;
472  xt_idxlist_get_index_stripes(intersections[i].list,
473  (struct Xt_stripe **)&intersection_idxstripes,
474  &num_stripes);
475  struct Xt_pos_ext *restrict isect_pos_exts = NULL;
476  int num_isect_pos_exts;
478  mypart_idxlist, num_stripes, intersection_idxstripes,
479  &num_isect_pos_exts, (struct Xt_pos_ext **)&isect_pos_exts, 1);
480  assert(retval == 0);
481  int isect_pos_exts_size_psum = 0;
482  int intersection_size = xt_idxlist_get_num_indices(intersections[i].list);
483  /* start with all indices from intersection as used,
484  later split ranges, if overlaps are found */
485  size_t num_isect_transfer_pos_ext = 1, size_isect_transfer_pos_ext = 8;
486  isect_transfer_pos_ext
487  = xrealloc(intersection_idxstripes, sizeof (*isect_transfer_pos_ext)
488  * size_isect_transfer_pos_ext);
489  intersection_idxstripes = NULL;
490  isect_transfer_pos_ext[0]
491  = (struct Xt_pos_ext){ .start = 0, .size = intersection_size };
492  /* find overlap(s) with previously found ranges for all
493  * stripes mapped to position extents */
494  for (size_t j = 0; j < (size_t)num_isect_pos_exts; ++j) {
495  struct Xt_pos_ext isect_pos_ext = isect_pos_exts[j];
496  /* ensure isect_pos_ext is oriented with ascending positions */
497  int isign_mask_isect_pos_ext_size = isign_mask(isect_pos_ext.size);
498  isect_pos_ext.start
499  += isign_mask_isect_pos_ext_size & (isect_pos_ext.size + 1);
500  int isect_pos_ext_orig_size = isect_pos_ext.size;
501  isect_pos_ext.size = abs(isect_pos_ext.size);
502  isect_pos_exts_size_psum += isect_pos_ext.size;
503  /* keep progress as inverse of change to psum to compensate for
504  * eventual correction later */
505  int progress = -isect_pos_ext.size;
506  size_t search_start_pos = 0, insert_pos;
507  do {
508  struct Xt_pos_range query = (struct Xt_pos_range){
509  .start = isect_pos_ext.start,
510  .end = isect_pos_ext.start + isect_pos_ext.size - 1 };
511  insert_pos
512  = xt_cover_insert_or_overlap(&cover, query, true, search_start_pos);
513  if (insert_pos == SIZE_MAX)
514  goto next_isect_pos_ext;
515  struct Xt_pos_ext_overlap overlap_desc
516  = Xt_get_pos_ext_overlap(isect_pos_ext, cover.pos_ext[insert_pos]);
517  /* insert overlap into updates
518  * by ...*/
519  /* ...first inserting the skipped part into
520  * cover.pos_ext, since that is sorted
521  * and obviously precedes cover.pos_ext[insert_pos],
522  * cover.pos_ext[insert_pos] can be seemlessly extended...
523  */
524  cover.pos_ext[insert_pos].start -= overlap_desc.skip;
525  cover.pos_ext[insert_pos].size += overlap_desc.skip;
526  /* ...and optionally merged with its predecessor, if the
527  * intervening range becomes zero, ... */
528  if (insert_pos > 0
529  && (cover.pos_ext[insert_pos].start
530  == (cover.pos_ext[insert_pos - 1].start
531  + cover.pos_ext[insert_pos - 1].size)))
532  {
533  cover.pos_ext[insert_pos - 1].size
534  += cover.pos_ext[insert_pos].size;
535  memmove(cover.pos_ext + insert_pos, cover.pos_ext + insert_pos + 1,
536  (--cover.num_pos_ext - insert_pos)
537  * sizeof (*cover.pos_ext));
538  --insert_pos;
539  }
540  progress = (~isign_mask_isect_pos_ext_size
541  & (progress + overlap_desc.skip))
542  | (isign_mask_isect_pos_ext_size
543  & (isect_pos_ext_orig_size + overlap_desc.tail));
544  /* ... then splitting isect_transfer_pos accordingly, ... */
545  num_indices_to_remove += overlap_desc.overlap;
547  .start = isect_pos_exts_size_psum + progress,
548  .size = overlap_desc.overlap },
549  &num_isect_transfer_pos_ext, &size_isect_transfer_pos_ext,
550  (struct Xt_pos_ext **)&isect_transfer_pos_ext);
551  progress += overlap_desc.overlap;
552  /* ... lastly the search can continue with the tail ... */
553  isect_pos_ext.start += overlap_desc.skip + overlap_desc.overlap;
554  /* ... if there is any */
555  isect_pos_ext.size = overlap_desc.tail;
556  search_start_pos = ++insert_pos;
557  } while ((isect_pos_ext.size != 0)
558  & (search_start_pos != cover.num_pos_ext));
559  if (isect_pos_ext.size)
560  /* already at end of list -> append ... */
561  xt_cover_range_append(&cover, isect_pos_ext);
562  /* ... and start the next intersection range */
563  next_isect_pos_ext:
564  ;
565  }
566 
567  if (intersection_size > num_indices_to_remove) {
568  resSets_[new_num_intersections].transfer_pos_ext
569  = xrealloc(isect_transfer_pos_ext, sizeof (*isect_transfer_pos_ext)
570  * num_isect_transfer_pos_ext);
571  /* start with empty cache of positions to transfer */
572  resSets_[new_num_intersections].transfer_pos = NULL;
573  resSets_[new_num_intersections].num_transfer_pos
574  = intersection_size - num_indices_to_remove;
575  resSets_[new_num_intersections].num_transfer_pos_ext
576  = (int)num_isect_transfer_pos_ext;
577  resSets_[new_num_intersections].rank = intersections[i].rank;
578  ++new_num_intersections;
579  isect_transfer_pos_ext = NULL;
580  }
581  dst_removals_per_intersection[i][0] = num_indices_to_remove;
582  dst_removals_per_intersection[i][1]
583  = ((num_indices_to_remove == intersection_size)
584  | (num_indices_to_remove == 0))?0:(int)num_isect_transfer_pos_ext;
585  free(isect_transfer_pos_ext);
586  free(isect_pos_exts);
587  }
588  *resCount = new_num_intersections;
589  if (num_intersections != new_num_intersections)
590  *resSets = xrealloc(resSets_,
591  (size_t)new_num_intersections * sizeof(**resSets));
592  return cover;
593 }
594 
595 static void
597  size_t *num_pos_exts,
598  size_t *size_pos_exts,
599  struct Xt_pos_ext **pos_exts)
600 {
601  struct Xt_pos_ext *restrict pos_exts_ = *pos_exts;
602  size_t num_pos_exts_ = *num_pos_exts;
603  size_t i = num_pos_exts_;
604  while (pos_exts_[--i].start > pos_ext.start)
605  ;
606  int db_skip = pos_ext.start - pos_exts_[i].start;
607  if ((!db_skip) & (pos_ext.size == pos_exts_[i].size))
608  {
609  /* delete fully overlapped transfer part */
610  memmove(pos_exts_ + i, pos_exts_ + i + 1,
611  sizeof (*pos_exts_) * (num_pos_exts_ - i - 1));
612  *num_pos_exts = --num_pos_exts_;
613  }
614  else if (db_skip + pos_ext.size == pos_exts_[i].size)
615  {
616  /* pos_ext overlaps end of pos_exts_[i] */
617  pos_exts_[i].size -= pos_ext.size;
618  }
619  else if (db_skip == 0)
620  {
621  /* pos_ext overlaps start of pos_exts_[i] */
622  pos_exts_[i].start = pos_ext.start + pos_ext.size;
623  pos_exts_[i].size -= pos_ext.size;
624  }
625  else
626  {
627  struct Xt_pos_ext orig = pos_exts_[i];
628  ENSURE_ARRAY_SIZE(*pos_exts, *size_pos_exts, num_pos_exts_ + 1);
629  pos_exts_ = *pos_exts;
630  memmove(pos_exts_ + i + 1, pos_exts_ + i,
631  (num_pos_exts_ - i) * sizeof (*pos_exts_));
632  pos_exts_[i] = (struct Xt_pos_ext){.start = orig.start,
633  .size = db_skip };
634  pos_exts_[i + 1] = (struct Xt_pos_ext){
635  .start = pos_ext.start + pos_ext.size,
636  .size = orig.size - db_skip - pos_ext.size };
637  *num_pos_exts = ++num_pos_exts_;
638  }
639 }
640 
641 static struct Xt_pos_ext *
643  int num_src_intersections,
644  const struct Xt_com_list src_com[num_src_intersections],
645  int num_dst_intersections,
646  const struct Xt_com_list dst_com[num_dst_intersections],
647  struct exchange_ext dst_ext[num_dst_intersections],
648  int (*restrict src_removals_per_intersection)[2],
649  int (*restrict dst_removals_per_intersection)[2],
650  int tag_offset,
651  MPI_Comm comm)
652 {
653  MPI_Request * requests
654  = xmalloc((size_t)(num_src_intersections + 2 * num_dst_intersections) *
655  sizeof(*requests));
656  MPI_Request *restrict recv_requests = requests,
657  *restrict send_header_requests = requests + num_src_intersections,
658  *restrict send_data_requests = send_header_requests + num_dst_intersections;
659 
660  // set up receives for indices that need to be removed from the send messages
661  for (int i = 0; i < num_src_intersections; ++i)
662  xt_mpi_call(MPI_Irecv(
663  src_removals_per_intersection[i], 2, MPI_INT, src_com[i].rank,
665  comm, recv_requests + i), comm);
666 
667  /* send rebuilt pos_ext vectors that needed to be modified on the
668  * target side due to duplicated receives
669  */
670  unsigned num_active_dst = 0, num_dst_changes = 0;
671  for (int i = 0; i < num_dst_intersections; ++i) {
672  xt_mpi_call(MPI_Isend(
673  dst_removals_per_intersection[i], 2, MPI_INT, dst_com[i].rank,
675  comm, send_header_requests + i), comm);
676 
677  if (dst_removals_per_intersection[i][1] > 0) {
678 
679  assert(dst_removals_per_intersection[i][1]
680  == dst_ext[num_active_dst].num_transfer_pos_ext);
681  assert(dst_com[i].rank
682  == dst_ext[num_active_dst].rank);
683  xt_mpi_call(MPI_Isend(
684  dst_ext[num_active_dst].transfer_pos_ext,
685  dst_removals_per_intersection[i][1],
686  MPI_2INT, dst_com[i].rank,
688  comm, send_data_requests + num_dst_changes),
689  comm);
690  ++num_dst_changes;
691  }
692  num_active_dst += (unsigned)((dst_removals_per_intersection[i][0] == 0)
693  | (dst_removals_per_intersection[i][1] != 0));
694  }
695 
696  // wait for the receiving of headers to complete
697  xt_mpi_call(MPI_Waitall(num_src_intersections + num_dst_intersections,
698  recv_requests, MPI_STATUSES_IGNORE), comm);
699 
700  size_t total_num_pos_ext_to_recv = 0;
701 
702  for (size_t i = 0; i < (size_t)num_src_intersections; ++i)
703  total_num_pos_ext_to_recv += (size_t)src_removals_per_intersection[i][1];
704 
705  struct Xt_pos_ext *src_updated_pos_ext;
706  unsigned num_src_changes = 0;
707  if (total_num_pos_ext_to_recv > 0) {
708 
709  src_updated_pos_ext
710  = xmalloc(total_num_pos_ext_to_recv * sizeof(*src_updated_pos_ext));
711 
712  /* set up receive for pos_ext that need to be modified because
713  * indices needed to be removed from the intersection */
714  size_t offset = 0;
715  for (int i = 0; i < num_src_intersections; ++i)
716  if (src_removals_per_intersection[i][1] > 0) {
717  xt_mpi_call(MPI_Irecv(
718  src_updated_pos_ext + offset,
719  src_removals_per_intersection[i][1], MPI_2INT,
720  src_com[i].rank,
722  comm, recv_requests + num_src_changes), comm);
723 
724  offset += (size_t)src_removals_per_intersection[i][1];
725  ++num_src_changes;
726  }
727  } else
728  src_updated_pos_ext = NULL;
729 
730  /* move data request handles for compact wait */
731  memcpy(recv_requests + num_src_changes, send_data_requests,
732  num_dst_changes * sizeof (recv_requests[0]));
733 
734  // wait until all communication is completed
735  xt_mpi_call(MPI_Waitall((int)num_src_changes + (int)num_dst_changes,
736  recv_requests, MPI_STATUSES_IGNORE), comm);
737 
738  free(requests);
739  return src_updated_pos_ext;
740 }
741 
742 static void
743 remap_intersection(Xt_idxlist mypart_idxlist,
744  Xt_idxlist intersection,
745  size_t num_pos_updates,
746  struct Xt_pos_ext pos_updates[num_pos_updates],
747  struct exchange_ext *resSet,
748  int single_match_only);
749 
750 static void
752  int num_dst_intersections,
753  const struct Xt_com_list intersections[num_dst_intersections],
754  Xt_idxlist mypart_idxlist,
755  int resCount,
756  struct exchange_ext resSets[resCount],
757  int (*removals_per_intersection)[2])
758 {
759  size_t resIdx = 0;
760  for (size_t i = 0; i < (size_t)num_dst_intersections; ++i)
761  {
762  int intersection_size
763  = xt_idxlist_get_num_indices(intersections[i].list);
764 
765  int num_indices_to_remove = removals_per_intersection[i][0];
766 
767  if (num_indices_to_remove != intersection_size) {} else
768  /* intersection is made redundant */
769  continue;
770 
771  struct Xt_pos_ext *pos_updates = resSets[resIdx].transfer_pos_ext;
772  remap_intersection(mypart_idxlist, intersections[i].list,
773  (size_t)removals_per_intersection[i][1],
774  pos_updates, resSets + resIdx, 1);
775  free(pos_updates);
776  ++resIdx;
777  }
778  assert(resIdx == (size_t)resCount);
779 }
780 
781 
782 /* compute updated positions for send direction */
783 static void
785  int num_intersections,
786  const struct Xt_com_list intersections[num_intersections],
787  Xt_idxlist mypart_idxlist,
788  int *resCount,
789  struct exchange_ext **resSets,
790  int (*restrict removals_per_intersection)[2],
791  struct Xt_pos_ext *pos_updates)
792 {
793  struct exchange_ext *restrict resSets_ = *resSets
794  = xmalloc((size_t)num_intersections * sizeof(**resSets));
795 
796  /* count total number of intersections that results */
797  int new_num_intersections = 0;
798  /* indexes into pos_updates */
799  size_t intersection_pos_ext = 0;
800 
801  for (int i = 0; i < num_intersections; ++i) {
802 
803  int intersection_size
804  = xt_idxlist_get_num_indices(intersections[i].list);
805 
806  int num_indices_to_remove = removals_per_intersection[i][0];
807 
808  if (num_indices_to_remove != intersection_size) {} else
809  /* intersection is made redundant */
810  continue;
811 
812  remap_intersection(mypart_idxlist, intersections[i].list,
813  (size_t)removals_per_intersection[i][1],
814  pos_updates + intersection_pos_ext,
815  resSets_ + new_num_intersections, 0);
816 
817  /* evaluate cache lazily */
818  resSets_[new_num_intersections].transfer_pos = NULL;
819  resSets_[new_num_intersections].num_transfer_pos
820  = intersection_size - num_indices_to_remove;
821  resSets_[new_num_intersections].rank = intersections[i].rank;
822  new_num_intersections++;
823  intersection_pos_ext += (size_t)removals_per_intersection[i][1];
824  }
825 
826  *resCount = new_num_intersections;
827  if (num_intersections != new_num_intersections)
828  *resSets = xrealloc(resSets_,
829  (size_t)new_num_intersections * sizeof(**resSets));
830 }
831 
832 static struct Xt_stripe *
833 refine_stripes(int *num_stripes_,
834  struct Xt_stripe *restrict intersection_idxstripes,
835  size_t num_pos_updates,
836  struct Xt_pos_ext *restrict pos_updates)
837 {
838  /* trim intersection_idxstripes to those actually used */
839  size_t num_refined_intersection_idxstripes = 0,
840  size_refined_intersection_idxstripes = num_pos_updates;
841  struct Xt_stripe *restrict refined_intersection_idxstripes
842  = xmalloc(size_refined_intersection_idxstripes
843  * sizeof (*refined_intersection_idxstripes));
844  size_t i_stripe = 0;
845  int nstrides_psum = 0;
846  for (size_t i_pos_ext = 0; i_pos_ext < num_pos_updates; ++i_pos_ext)
847  {
848  int pos = pos_updates[i_pos_ext].start;
849  int size = pos_updates[i_pos_ext].size;
850  while (nstrides_psum + intersection_idxstripes[i_stripe].nstrides <= pos)
851  {
852  nstrides_psum += intersection_idxstripes[i_stripe].nstrides;
853  ++i_stripe;
854  }
855  do {
856  int instripe_pos = pos - nstrides_psum;
857  ENSURE_ARRAY_SIZE(refined_intersection_idxstripes,
858  size_refined_intersection_idxstripes,
859  num_refined_intersection_idxstripes + 1);
860  struct Xt_stripe cur_stripe = intersection_idxstripes[i_stripe];
861  int cur_stripe_nstrides = cur_stripe.nstrides;
862  int overlap = imin(cur_stripe_nstrides - instripe_pos, size);
863  cur_stripe.start
864  = (Xt_int)(cur_stripe.start
865  + (Xt_int)instripe_pos * cur_stripe.stride);
866  cur_stripe.nstrides = overlap;
867  refined_intersection_idxstripes[num_refined_intersection_idxstripes]
868  = cur_stripe;
869  ++num_refined_intersection_idxstripes;
870  i_stripe += (instripe_pos + overlap == cur_stripe_nstrides);
871  nstrides_psum += (instripe_pos + overlap == cur_stripe_nstrides)
872  ? cur_stripe_nstrides : 0;
873  pos += overlap;
874  size -= overlap;
875  } while (size);
876  }
877  free(intersection_idxstripes);
878  *num_stripes_ = (int)num_refined_intersection_idxstripes;
879  return refined_intersection_idxstripes;
880 }
881 
882 
883 /* match index stripes of intersection to corresponding positions in
884  * partition list, optionally updating the stripes
885  * @param num_pos_updates number of position extents describing the
886  * subset of positions from intersections to use
887  * @param pos_updates list of position extents to use from \a intersection
888  */
889 static void
890 remap_intersection(Xt_idxlist mypart_idxlist,
891  Xt_idxlist intersection,
892  size_t num_pos_updates,
893  struct Xt_pos_ext pos_updates[num_pos_updates],
894  struct exchange_ext *resSet,
895  int single_match_only)
896 {
897  struct Xt_stripe *intersection_idxstripes;
898  int num_stripes;
899  xt_idxlist_get_index_stripes(intersection,
900  &intersection_idxstripes,
901  &num_stripes);
902  if (num_pos_updates)
903  intersection_idxstripes
904  = refine_stripes(&num_stripes, intersection_idxstripes,
905  num_pos_updates, pos_updates);
906 
907  /* match back intersection_idxstripes to positions in mypart */
908  resSet->transfer_pos_ext = NULL;
910  mypart_idxlist, num_stripes, intersection_idxstripes,
911  &resSet->num_transfer_pos_ext,
912  &resSet->transfer_pos_ext, single_match_only);
913  assert(retval == 0);
914  free(intersection_idxstripes);
915 }
916 
917 
918 /* iterator operations */
919 
922 static int const *
924 static int
926 static const struct Xt_pos_ext *
928 static int
931 
932 static const struct Xt_xmap_iter_vtable
939  .get_num_transfer_pos_ext
941  .delete = xmap_intersection_ext_iterator_delete};
942 
944 
946 
948 
949  struct exchange_ext *msg;
951 };
952 
954 
955  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap);
956 
957  if (xmap_intersection_ext->n_in == 0)
958  return NULL;
959 
960  Xt_xmap_iter_intersection_ext iter = xmalloc(sizeof (*iter));
961 
963  iter->msg = xmap_intersection_ext->in_msg;
964  iter->msgs_left = xmap_intersection_ext->n_in - 1;
965 
966  return (Xt_xmap_iter)iter;
967 }
968 
970 
971  Xt_xmap_intersection_ext xmap_intersection_ext = xmie(xmap);
972 
973  if (xmap_intersection_ext->n_out == 0)
974  return NULL;
975 
976  Xt_xmap_iter_intersection_ext iter = xmalloc(sizeof (*iter));
977 
979  iter->msg = xmap_intersection_ext->out_msg;
980  iter->msgs_left = xmap_intersection_ext->n_out - 1;
981 
982  return (Xt_xmap_iter)iter;
983 }
984 
985 static inline Xt_xmap_iter_intersection_ext
986 xmiei(void *iter)
987 {
988  return (Xt_xmap_iter_intersection_ext)iter;
989 }
990 
992 
993  Xt_xmap_iter_intersection_ext iter_intersection = xmiei(iter);
994 
995  if (iter_intersection == NULL || iter_intersection->msgs_left == 0)
996  return 0;
997 
998  iter_intersection->msg++;
999  iter_intersection->msgs_left--;
1000 
1001  return 1;
1002 }
1003 
1005 
1006  assert(iter != NULL);
1007  return xmiei(iter)->msg->rank;
1008 }
1009 
1010 static int const *
1012 
1013  assert(iter != NULL);
1014  struct exchange_ext *restrict msg = xmiei(iter)->msg;
1015  if ((!msg->num_transfer_pos) | (msg->transfer_pos != NULL)) { } else {
1016  size_t num_transfer_pos = (size_t)msg->num_transfer_pos;
1017  int *restrict transfer_pos = msg->transfer_pos
1018  = xmalloc(num_transfer_pos * sizeof (*msg->transfer_pos));
1019  size_t num_transfer_pos_ext = (size_t)msg->num_transfer_pos_ext;
1020  struct Xt_pos_ext *restrict transfer_pos_ext = msg->transfer_pos_ext;
1021  size_t ofs = 0;
1022  for (size_t i = 0; i < num_transfer_pos_ext; ++i) {
1023  int abssize = abs(transfer_pos_ext[i].size);
1024  int step = isign(transfer_pos_ext[i].size);
1025  for (int j = 0; j < abssize; ++j)
1026  transfer_pos[ofs + (size_t)j] = transfer_pos_ext[i].start + j * step;
1027  ofs += (size_t)abssize;
1028  }
1029  assert(ofs == num_transfer_pos);
1030  }
1031  return msg->transfer_pos;
1032 }
1033 
1034 static int
1036  assert(iter != NULL);
1037  return xmiei(iter)->msg->num_transfer_pos;
1038 }
1039 
1040 static const struct Xt_pos_ext *
1042  assert(iter != NULL);
1043  return xmiei(iter)->msg->transfer_pos_ext;
1044 }
1045 
1046 static int
1048  assert(iter != NULL);
1049  return xmiei(iter)->msg->num_transfer_pos_ext;
1050 }
1051 
1053 
1054  free(iter);
1055 }
1056 
1057 /*
1058  * Local Variables:
1059  * c-basic-offset: 2
1060  * coding: utf-8
1061  * indent-tabs-mode: nil
1062  * show-trailing-whitespace: t
1063  * require-trailing-newline: t
1064  * End:
1065  */
const struct Xt_xmap_vtable * vtable
static const struct Xt_xmap_iter_vtable xmap_iterator_intersection_ext_vtable
int xt_idxlist_get_num_indices(Xt_idxlist idxlist)
Definition: xt_idxlist.c:97
static int xmap_intersection_ext_iterator_get_num_transfer_pos_ext(Xt_xmap_iter iter)
static int xmap_intersection_ext_iterator_get_rank(Xt_xmap_iter iter)
int size
Definition: xt_core.h:93
static struct Xt_pos_ext * exchange_pos_ext_modifications(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], struct exchange_ext dst_ext[num_dst_intersections], int(*restrict src_removals_per_intersection)[2], int(*restrict dst_removals_per_intersection)[2], int tag_offset, MPI_Comm comm)
static void generate_transfer_ext(struct Xt_xmap_intersection_ext_ *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)
static void remap_intersection(Xt_idxlist mypart_idxlist, Xt_idxlist intersection, size_t num_pos_updates, struct Xt_pos_ext pos_updates[num_pos_updates], struct exchange_ext *resSet, int single_match_only)
void xt_cover_range_append(struct Xt_pos_ext_vec *restrict cover, struct Xt_pos_ext range)
Definition: xt_cover.c:128
static int xmap_intersection_ext_get_max_src_pos(Xt_xmap xmap)
int(* next)(Xt_xmap_iter iter)
static int imin(int a, int b)
add versions of standard API functions not returning on error
static int xmap_intersection_ext_iterator_get_num_transfer_pos(Xt_xmap_iter iter)
static Xt_xmap_iter xmap_intersection_ext_get_in_iterator(Xt_xmap xmap)
contains declaration for the exchange map data structure
static void cut_pos_ext_from_pos_exts(struct Xt_pos_ext pos_ext, size_t *num_pos_exts, size_t *size_pos_exts, struct Xt_pos_ext **pos_exts)
static int isign(int x)
struct Xt_pos_ext * transfer_pos_ext
struct Xt_pos_ext * pos_ext
Definition: xt_cover.h:60
void xt_idxlist_get_index_stripes(Xt_idxlist idxlist, struct Xt_stripe **stripes, int *num_stripes)
Definition: xt_idxlist.c:117
static Xt_xmap_intersection_ext xmie(void *xmap)
#define xrealloc(ptr, size)
Definition: ppm_xfuncs.h:67
static int xmap_intersection_ext_get_max_dst_pos(Xt_xmap xmap)
static struct Xt_pos_ext_overlap Xt_get_pos_ext_overlap(struct Xt_pos_ext a, struct Xt_pos_ext b)
static struct Xt_pos_ext_vec generate_dir_transfer_ext_dst(int num_intersections, const struct Xt_com_list intersections[num_intersections], Xt_idxlist mypart_idxlist, int *resCount, struct exchange_ext **resSets, int(*restrict dst_removals_per_intersection)[2])
bool xt_idxlist_pos_ext_is_full_cover(Xt_idxlist idxlist, struct Xt_pos_ext_vec cover)
Definition: xt_cover.c:75
int xt_idxlist_get_pos_exts_of_index_stripes(Xt_idxlist idxlist, int num_stripes, const struct Xt_stripe stripes[num_stripes], int *num_ext, struct Xt_pos_ext **pos_ext, int single_match_only)
Definition: xt_idxlist.c:226
exchange map declarations
int xt_idxlist_get_index_at_position(Xt_idxlist idxlist, int position, Xt_int *index)
Definition: xt_idxlist.c:147
int nstrides
Definition: xt_stripe.h:57
MPI_Comm(* get_communicator)(Xt_xmap)
static Xt_xmap_iter xmap_intersection_ext_get_out_iterator(Xt_xmap xmap)
XT_INT Xt_int
Definition: xt_core.h:68
static void xt_free_exchange_ext(size_t num_msg, struct exchange_ext *restrict msg)
static Xt_xmap xmap_intersection_ext_copy(Xt_xmap xmap)
static const struct Xt_xmap_vtable xmap_intersection_vtable
static int isign_mask(int x)
Xt_xmap xt_xmap_intersection_ext_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)
size_t num_pos_ext
Definition: xt_cover.h:59
struct Xt_xmap_intersection_ext_ * Xt_xmap_intersection_ext
#define ENSURE_ARRAY_SIZE(arrayp, curr_array_size, req_size)
Xt_int stride
Definition: xt_stripe.h:56
static void xmap_intersection_ext_delete(Xt_xmap xmap)
static MPI_Comm xmap_intersection_ext_get_communicator(Xt_xmap xmap)
static void generate_dir_transfer_pos_ext_src(int num_intersections, const struct Xt_com_list intersections[num_intersections], Xt_idxlist mypart_idxlist, int *resCount, struct exchange_ext **resSets, int(*restrict removals_per_intersection)[2], struct Xt_pos_ext *pos_updates)
static Xt_xmap_iter_intersection_ext xmiei(void *iter)
const struct Xt_xmap_iter_vtable * vtable
Xt_int start
Definition: xt_stripe.h:55
static void xmap_intersection_ext_get_destination_ranks(Xt_xmap xmap, int *ranks)
MPI_Comm xt_mpi_comm_smart_dup(MPI_Comm comm, int *tag_offset)
Definition: xt_mpi.c:850
void xt_mpi_comm_smart_dedup(MPI_Comm *comm, int tag_offset)
Definition: xt_mpi.c:901
static void xmap_intersection_ext_iterator_delete(Xt_xmap_iter iter)
static void xmap_intersection_ext_get_source_ranks(Xt_xmap xmap, int *ranks)
static void xmap_intersection_ext_msg_copy(size_t nmsg, struct exchange_ext *restrict msg, int *nmsg_copy, struct exchange_ext **msg_copy)
#define xt_mpi_call(call, comm)
Definition: xt_mpi.h:68
static int xmap_intersection_ext_iterator_next(Xt_xmap_iter iter)
index list declaration
static const struct Xt_pos_ext * xmap_intersection_ext_iterator_get_transfer_pos_ext(Xt_xmap_iter iter)
static struct Xt_stripe * refine_stripes(int *num_stripes_, struct Xt_stripe *restrict intersection_idxstripes, size_t num_pos_updates, struct Xt_pos_ext *restrict pos_updates)
struct Xt_xmap_iter_intersection_ext_ * Xt_xmap_iter_intersection_ext
void xt_cover_start(struct Xt_pos_ext_vec *restrict cover, size_t initial_size)
Definition: xt_cover.c:60
int start
Definition: xt_core.h:93
void xt_cover_finish(struct Xt_pos_ext_vec *restrict cover)
Definition: xt_cover.c:69
#define xmalloc(size)
Definition: ppm_xfuncs.h:66
static int const * xmap_intersection_ext_iterator_get_transfer_pos(Xt_xmap_iter iter)
int MPI_Comm
Definition: core.h:64
static int xmap_intersection_ext_get_num_sources(Xt_xmap xmap)
utility routines for MPI
size_t xt_cover_insert_or_overlap(struct Xt_pos_ext_vec *restrict cover, struct Xt_pos_range range, bool forward, size_t search_start_pos)
Definition: xt_cover.c:148
static int xmap_intersection_ext_get_num_destinations(Xt_xmap xmap)
static void remap_dst_intersections(int num_dst_intersections, const struct Xt_com_list dst_com[num_dst_intersections], Xt_idxlist mypart_idxlist, int resCount, struct exchange_ext resSets[resCount], int(*removals_per_intersection)[2])