Yet Another eXchange Tool  DO_NOT_EDIT_HERE
xt_xmap_dist_dir_intercomm.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 <stdbool.h>
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <assert.h>
55 #include <limits.h>
56 
57 #include <mpi.h>
58 
59 #include "xt/xt_idxlist.h"
61 #include "xt/xt_idxvec.h"
62 #include "xt/xt_idxstripes.h"
63 #include "xt/xt_idxempty.h"
64 #include "xt/xt_xmap.h"
65 #include "xt/xt_xmap_dist_dir.h"
67 #include "xt/xt_mpi.h"
68 #include "xt_arithmetic_util.h"
69 #include "xt_idxstripes_internal.h"
70 #include "xt_mpi_internal.h"
71 #include "core/core.h"
72 #include "core/ppm_xfuncs.h"
73 #include "ensure_array_size.h"
75 #include "xt_idxlist_internal.h"
77 #include "instr.h"
78 
79 static inline void
81  bool *stripify, Xt_int interval_size[2],
82  MPI_Comm intra_comm, MPI_Comm inter_comm,
83  int comm_size, int remote_size,
84  int comm_rank, int tag_offset_inter)
85 {
86  /* global_sums[0] and [1] refer to the local and remote group of
87  * intercommunicator inter_comm */
88  unsigned long long local_vals[2], global_sums[2][2];
89 
90  unsigned num_indices_src = (unsigned)xt_idxlist_get_num_indices(src);
91  local_vals[0] = num_indices_src;
92  local_vals[1] = (num_indices_src >= CHEAP_VECTOR_SIZE)
94 
95  xt_mpi_call(MPI_Allreduce(local_vals, global_sums[0], 2,
96  MPI_UNSIGNED_LONG_LONG, MPI_SUM, intra_comm),
97  intra_comm);
98  /* instead of sendrecv one might use hand-programmed multi-casts
99  * sending to each rank in a range from the remote group and
100  * receiving from the first rank in that group,
101  * the better choice probably depends on the asymmetry of the group
102  * sizes, i.e. use bcast from a very small to a very large group
103  * and few sends from a large to a small group */
104  if (comm_rank == 0) {
105  int tag = tag_offset_inter + xt_mpi_tag_xmap_dist_dir_src_send;
106  xt_mpi_call(MPI_Sendrecv(global_sums[0], 2, MPI_UNSIGNED_LONG_LONG, 0, tag,
107  global_sums[1], 2, MPI_UNSIGNED_LONG_LONG, 0, tag,
108  inter_comm, MPI_STATUS_IGNORE), inter_comm);
109  }
110  xt_mpi_call(MPI_Bcast(global_sums[1], 2, MPI_UNSIGNED_LONG_LONG,
111  0, intra_comm), intra_comm);
112  *stripify = (global_sums[0][1] > 0 || global_sums[1][1] > 0);
113  interval_size[0]
114  = (Xt_int)(((global_sums[0][0] + (unsigned)comm_size - 1)
115  / (unsigned)comm_size) * (unsigned)comm_size);
116  interval_size[1]
117  = (Xt_int)(((global_sums[1][0] + (unsigned)remote_size - 1)
118  / (unsigned)remote_size) * (unsigned)remote_size);
119 }
120 
121 enum {
123  SEND_NUM = 1,
125 };
126 
127 static inline void
128 rank_no_send(size_t rank, int (*restrict send_size)[SEND_SIZE_ASIZE])
129 {
130  send_size[rank][SEND_SIZE] = 0;
131  send_size[rank][SEND_NUM] = 0;
132 }
133 
134 static size_t
136  Xt_idxlist idxlist,
137  int (*send_size)[SEND_SIZE_ASIZE],
138  void **send_buffer_,
139  MPI_Comm comm, int comm_size)
140 {
141  size_t num_msg = 0;
142  Xt_int local_index_range_lbound = bucket_params->local_index_range_lbound;
143  Xt_int local_index_range_ubound = bucket_params->local_index_range_ubound;
144  if (local_index_range_lbound <= local_index_range_ubound) {
145  int send_buffer_size = 0;
146  Xt_idxlist *restrict send_list
147  = xmalloc((size_t)comm_size * sizeof(*send_list));
148  struct Xt_stripe *stripes = NULL;
149  size_t stripes_array_size = 0;
150  Xt_int global_interval = bucket_params->global_interval;
151  Xt_int local_interval = bucket_params->local_interval;
152  size_t first_overlapping_bucket = 0;
153  /* is it impossible for early buckets to overlap our lists? */
154  if (local_index_range_lbound >= 0
155  && (local_index_range_ubound < global_interval)) {
156  first_overlapping_bucket
157  = (size_t)(local_index_range_lbound / local_interval);
158  for (size_t i = 0; i < first_overlapping_bucket; ++i)
159  rank_no_send(i, send_size);
160  }
161  /* is it impossible for later ranks to overlap our lists? */
162  size_t start_of_non_overlapping_bucket_suffix
163  = (size_t)(((long long)local_index_range_ubound + local_interval - 1)
164  / local_interval) + 1;
165  if (local_index_range_lbound < 0
166  || start_of_non_overlapping_bucket_suffix > (size_t)comm_size)
167  start_of_non_overlapping_bucket_suffix = (size_t)comm_size;
168  size_t i = first_overlapping_bucket;
169  for (; i < (size_t)start_of_non_overlapping_bucket_suffix; ++i) {
170  Xt_idxlist bucket
171  = xt_xmap_dist_dir_get_bucket(bucket_params,
172  &stripes, &stripes_array_size, (int)i);
173  if (bucket) {
174  Xt_idxlist isect2send = xt_idxlist_get_intersection(idxlist, bucket);
175  xt_idxlist_delete(bucket);
176  if (xt_idxlist_get_num_indices(isect2send) > 0) {
177  send_list[num_msg] = isect2send;
178  send_size[i][SEND_SIZE]
179  = (int)xt_idxlist_get_pack_size(isect2send, comm);
180  send_size[i][SEND_NUM] = 1;
181  ++num_msg;
182  } else {
183  send_size[i][SEND_SIZE] = 0;
184  send_size[i][SEND_NUM] = 0;
185  xt_idxlist_delete(isect2send);
186  }
187  } else
188  rank_no_send(i, send_size);
189 
190  send_buffer_size += send_size[i][SEND_SIZE];
191  }
192  for (; i < (size_t)comm_size; ++i)
193  rank_no_send(i, send_size);
194 
195  void *send_buffer
196  = *send_buffer_ = xrealloc(stripes, (size_t)send_buffer_size);
197 
198  int position = 0;
199  for (i = 0; i < num_msg; ++i) {
200  xt_idxlist_pack(send_list[i], send_buffer, send_buffer_size,
201  &position, comm);
202  xt_idxlist_delete(send_list[i]);
203  }
204 
205  free(send_list);
206  } else
207  memset(send_size, 0, (size_t)comm_size * sizeof (*send_size));
208  return num_msg;
209 }
210 
211 static inline Xt_int
213 {
214  int num_idx = xt_idxlist_get_num_indices(l);
215  Xt_int min_index = num_idx ? xt_idxlist_get_min_index(l) : XT_INT_MAX;
216  return min_index;
217 }
218 
219 static inline Xt_int
221 {
222  int num_idx = xt_idxlist_get_num_indices(l);
223  Xt_int max_index = num_idx ? xt_idxlist_get_max_index(l) : XT_INT_MIN;
224  return max_index;
225 }
226 
227 static struct bucket_params
229  Xt_int global_interval, int comm_size)
230 {
231  /* guard vs. comm_size being larger than number of indices */
232  Xt_int local_interval = MAX((Xt_int)1, (Xt_int)(global_interval / comm_size));
235  return (struct bucket_params){
236  .global_interval = global_interval,
237  .local_interval = local_interval,
238  .local_index_range_lbound = local_index_range_lbound,
239  .local_index_range_ubound = local_index_range_ubound,
240  };
241 }
242 
243 static void
244 compress_sizes(int (*restrict sizes)[SEND_SIZE_ASIZE], int comm_size,
245  struct Xt_xmdd_txstat *tx_stat, int *counts)
246 {
247  size_t tx_num = 0, size_sum = 0;
248  for (size_t i = 0; i < (size_t)comm_size; ++i)
249  if (sizes[i][SEND_SIZE]) {
250  int tx_size = sizes[i][SEND_SIZE];
251  size_sum += (size_t)tx_size;
252  sizes[tx_num][SEND_SIZE] = tx_size;
253  if (counts) counts[tx_num] = sizes[i][SEND_NUM];
254  sizes[tx_num][SEND_NUM] = (int)i;
255  ++tx_num;
256  }
257  *tx_stat = (struct Xt_xmdd_txstat){ .bytes = size_sum, .num_msg = tx_num };
258 }
259 
260 static void
262  int recv_size[][SEND_SIZE_ASIZE],
263  void **send_buffer, int send_size[][SEND_SIZE_ASIZE],
264  Xt_idxlist idxlist, Xt_int interval_size,
265  MPI_Comm comm, int comm_size)
266 {
267  struct bucket_params bucket_params
268  = get_bucket_params(idxlist, interval_size, comm_size);
269  *send_buffer = NULL;
270  size_t num_msg = compute_and_pack_bucket_intersections(
271  &bucket_params, idxlist, send_size, send_buffer, comm, comm_size);
272  xt_mpi_call(MPI_Alltoall(send_size, SEND_SIZE_ASIZE, MPI_INT,
273  recv_size, SEND_SIZE_ASIZE, MPI_INT, comm), comm);
274  compress_sizes(recv_size, comm_size, tx_stat + 0, NULL);
275  compress_sizes(send_size, comm_size, tx_stat + 1, NULL);
276  assert(num_msg == tx_stat[1].num_msg);
277 }
278 
279 typedef int (*tx_fp)(void *, int, MPI_Datatype, int, int,
280  MPI_Comm, MPI_Request *);
281 static void
282 tx_intersections(size_t num_msg,
283  const int (*sizes)[SEND_SIZE_ASIZE],
284  unsigned char *buffer, MPI_Request *requests,
285  int tag, MPI_Comm comm, tx_fp tx_op)
286 {
287  size_t ofs = 0;
288  for (size_t i = 0; i < num_msg; ++i)
289  {
290  int rank = sizes[i][SEND_NUM], count = sizes[i][SEND_SIZE];
291  xt_mpi_call(tx_op((unsigned char *)buffer + ofs,
292  count, MPI_PACKED, rank, tag, comm, requests + i), comm);
293  ofs += (size_t)count;
294  }
295 }
296 
297 static void
298 irecv_intersections(size_t num_msg,
299  const int (*recv_size)[SEND_SIZE_ASIZE],
300  void *recv_buffer, MPI_Request *requests,
301  int tag, MPI_Comm comm)
302 {
303  tx_intersections(num_msg, recv_size, recv_buffer, requests, tag, comm,
304  (tx_fp)MPI_Irecv);
305 }
306 
307 static void
308 isend_intersections(size_t num_msg,
309  const int (*send_size)[SEND_SIZE_ASIZE],
310  void *send_buffer, MPI_Request *requests,
311  int tag, MPI_Comm comm)
312 {
313  tx_intersections(num_msg, send_size, send_buffer, requests, tag, comm,
314  (tx_fp)MPI_Isend);
315 }
316 
317 
318 static void
320  const int (*sizes)[SEND_SIZE_ASIZE],
321  const void *buffer,
322  struct dist_dir **dist_dir,
323  MPI_Comm comm)
324 {
325  size_t num_msg = tx_stat.num_msg, buf_size = tx_stat.bytes;
326  struct dist_dir *restrict dist_dir_
327  = *dist_dir = xmalloc(sizeof (*dist_dir_)
328  + sizeof (*dist_dir_->entries) * num_msg);
329  dist_dir_->num_entries = (int)num_msg;
330  int position = 0;
331  for (size_t i = 0; i < num_msg; ++i)
332  {
333  int rank = sizes[i][SEND_NUM];
334  dist_dir_->entries[i].rank = rank;
335  dist_dir_->entries[i].list
336  = xt_idxlist_unpack((void *)buffer, (int)buf_size, &position, comm);
337  }
338 }
339 
340 static void
342  struct dist_dir **dst_dist_dir,
343  bool *stripify,
344  Xt_idxlist src_idxlist,
345  Xt_idxlist dst_idxlist,
346  int tag_offset_inter, int tag_offset_intra,
347  MPI_Comm inter_comm, MPI_Comm intra_comm,
348  int remote_size, int comm_size,
349  int comm_rank) {
350 
351  /* interval_size[0] and interval_size[1] are the global interval
352  * size for the local and remote group */
353  Xt_int interval_size[2];
354  get_dist_dir_global_interval_size(src_idxlist, dst_idxlist,
355  stripify, interval_size,
356  intra_comm, inter_comm,
357  comm_size, remote_size,
358  comm_rank, tag_offset_inter);
359  void *send_buffer_local, *send_buffer_remote;
360  int (*send_size_local)[SEND_SIZE_ASIZE]
361  = xmalloc(((size_t)comm_size + (size_t)remote_size)
362  * 2 * sizeof(*send_size_local)),
363  (*send_size_remote)[SEND_SIZE_ASIZE] = send_size_local + comm_size,
364  (*recv_size_local)[SEND_SIZE_ASIZE] = send_size_remote + remote_size,
365  (*recv_size_remote)[SEND_SIZE_ASIZE] = recv_size_local + comm_size;
366  struct Xt_xmdd_txstat tx_stat_local[2], tx_stat_remote[2];
367  create_intersections(tx_stat_local, recv_size_local, &send_buffer_local,
368  send_size_local, src_idxlist, interval_size[0],
369  intra_comm, comm_size);
370  create_intersections(tx_stat_remote, recv_size_remote, &send_buffer_remote,
371  send_size_remote, dst_idxlist, interval_size[1],
372  inter_comm, remote_size);
373 
374  size_t num_req = tx_stat_local[0].num_msg + tx_stat_remote[0].num_msg
375  + tx_stat_local[1].num_msg + tx_stat_remote[1].num_msg;
376  MPI_Request *dir_init_requests
377  = xmalloc(num_req * sizeof(*dir_init_requests)
378  + tx_stat_local[0].bytes + tx_stat_remote[0].bytes);
379  void *recv_buffer_local = dir_init_requests + num_req,
380  *recv_buffer_remote = ((unsigned char *)recv_buffer_local
381  + tx_stat_local[0].bytes);
382  int tag_intra = tag_offset_intra + xt_mpi_tag_xmap_dist_dir_src_send;
383  size_t req_ofs = tx_stat_local[0].num_msg;
384  irecv_intersections(tx_stat_local[0].num_msg,
385  (const int (*)[SEND_SIZE_ASIZE])recv_size_local,
386  recv_buffer_local, dir_init_requests,
387  tag_intra, intra_comm);
388  int tag_inter = tag_offset_inter + xt_mpi_tag_xmap_dist_dir_src_send;
389  irecv_intersections(tx_stat_remote[0].num_msg,
390  (const int (*)[SEND_SIZE_ASIZE])recv_size_remote,
391  recv_buffer_remote, dir_init_requests + req_ofs,
392  tag_inter, inter_comm);
393  req_ofs += tx_stat_remote[0].num_msg;
394  isend_intersections(tx_stat_local[1].num_msg,
395  (const int (*)[SEND_SIZE_ASIZE])send_size_local,
396  send_buffer_local, dir_init_requests + req_ofs,
397  tag_intra, intra_comm);
398  req_ofs += tx_stat_local[1].num_msg;
399  isend_intersections(tx_stat_remote[1].num_msg,
400  (const int (*)[SEND_SIZE_ASIZE])send_size_remote,
401  send_buffer_remote, dir_init_requests + req_ofs,
402  tag_inter, inter_comm);
403  // wait for data transfers to complete
404  xt_mpi_call(MPI_Waitall((int)num_req, dir_init_requests,
405  MPI_STATUSES_IGNORE), inter_comm);
406  free(send_buffer_local);
407  free(send_buffer_remote);
408  unpack_dist_dir(tx_stat_local[0],
409  (const int (*)[SEND_SIZE_ASIZE])recv_size_local,
410  recv_buffer_local, src_dist_dir, intra_comm);
411  unpack_dist_dir(tx_stat_remote[0],
412  (const int (*)[SEND_SIZE_ASIZE])recv_size_remote,
413  recv_buffer_remote, dst_dist_dir, inter_comm);
414  free(send_size_local);
415  free(dir_init_requests);
416 }
417 
418 
419 static int
420 send_size_from_intersections(size_t num_intersections,
421  const struct isect *restrict src_dst_intersections,
422  enum xt_xmdd_direction target,
423  MPI_Comm comm, int comm_size,
424  int (*restrict send_size_target)[SEND_SIZE_ASIZE])
425 {
426  size_t total_send_size = 0;
427  for (int i = 0; i < comm_size; ++i)
428  send_size_target[i][SEND_SIZE] = 0, send_size_target[i][SEND_NUM] = 0;
429 
430  int rank_pack_size;
431  xt_mpi_call(MPI_Pack_size(1, MPI_INT, comm, &rank_pack_size), comm);
432 
433  for (size_t i = 0; i < num_intersections; ++i)
434  {
435  int msg_size = rank_pack_size
436  + (int)xt_idxlist_get_pack_size(src_dst_intersections[i].idxlist, comm);
437  size_t target_rank = (size_t)src_dst_intersections[i].rank[target];
438  send_size_target[target_rank][SEND_SIZE] += msg_size;
439  ++(send_size_target[target_rank][SEND_NUM]);
440  total_send_size += (size_t)msg_size;
441  }
442  assert(total_send_size <= INT_MAX);
443  return (int)total_send_size;
444 }
445 
446 
447 static int
448 pack_dist_dirs(size_t num_intersections,
449  struct isect *restrict src_dst_intersections,
450  int (*send_size)[SEND_SIZE_ASIZE],
451  void **send_buffer_, enum xt_xmdd_direction target,
452  bool isect_idxlist_delete, MPI_Comm comm, int comm_size) {
453 
454  int total_send_size
455  = send_size_from_intersections(num_intersections,
456  src_dst_intersections,
457  target,
458  comm, comm_size, send_size);
459 
460  void *send_buffer = (*send_buffer_) = xmalloc((size_t)total_send_size);
461  int position = 0;
462  qsort(src_dst_intersections, num_intersections,
463  sizeof (src_dst_intersections[0]),
464  target == xt_xmdd_direction_src
466  int num_requests
468  target, num_intersections, src_dst_intersections,
469  isect_idxlist_delete, send_buffer, total_send_size, &position, comm);
470  return num_requests;
471 }
472 
473 static void
475  struct dist_dir **dist_dir,
476  void *restrict recv_buffer,
477  int *restrict entry_counts,
478  MPI_Comm comm)
479 {
480  size_t num_msg = tx_stat.num_msg;
481  int buf_size = (int)tx_stat.bytes;
482  int position = 0;
483  size_t num_entries_sent = 0;
484  for (size_t i = 0; i < num_msg; ++i)
485  num_entries_sent += (size_t)entry_counts[i];
486  *dist_dir = xmalloc(sizeof (struct dist_dir)
487  + (sizeof (struct Xt_com_list) * num_entries_sent));
488  (*dist_dir)->num_entries = (int)num_entries_sent;
489  struct Xt_com_list *restrict entries = (*dist_dir)->entries;
490  size_t num_entries = 0;
491  for (size_t i = 0; i < num_msg; ++i) {
492  size_t num_entries_from_rank = (size_t)entry_counts[i];
493  for (size_t j = 0; j < num_entries_from_rank; ++j) {
494  xt_mpi_call(MPI_Unpack(recv_buffer, buf_size, &position,
495  &entries[num_entries].rank,
496  1, MPI_INT, comm), comm);
497  entries[num_entries].list =
498  xt_idxlist_unpack(recv_buffer, buf_size, &position, comm);
499  ++num_entries;
500  }
501  }
502  assert(num_entries == num_entries_sent);
503  qsort(entries, num_entries_sent, sizeof(*entries), xt_com_list_rank_cmp);
505 }
506 
507 
508 static void
509 exchange_idxlists(struct dist_dir **src_intersections,
510  struct dist_dir **dst_intersections,
511  bool *stripify,
512  Xt_idxlist src_idxlist,
513  Xt_idxlist dst_idxlist,
514  int tag_offset_inter, int tag_offset_intra,
515  MPI_Comm inter_comm, MPI_Comm intra_comm) {
516 
517  int comm_size, remote_size, comm_rank;
518  xt_mpi_call(MPI_Comm_size(inter_comm, &comm_size), inter_comm);
519  xt_mpi_call(MPI_Comm_rank(inter_comm, &comm_rank), inter_comm);
520  xt_mpi_call(MPI_Comm_remote_size(inter_comm, &remote_size), inter_comm);
521 
522  struct dist_dir *src_dist_dir, *dst_dist_dir;
523 
524  generate_distributed_directories(&src_dist_dir, &dst_dist_dir, stripify,
525  src_idxlist, dst_idxlist,
526  tag_offset_inter, tag_offset_intra,
527  inter_comm, intra_comm,
528  remote_size, comm_size,
529  comm_rank);
530 
531 
532  int (*send_size_local)[SEND_SIZE_ASIZE]
533  = xmalloc(((size_t)comm_size + (size_t)remote_size)
534  * 2U * sizeof(*send_size_local)),
535  (*recv_size_local)[SEND_SIZE_ASIZE] = send_size_local + comm_size,
536  (*send_size_remote)[SEND_SIZE_ASIZE] = recv_size_local + comm_size,
537  (*recv_size_remote)[SEND_SIZE_ASIZE] = send_size_remote + remote_size;
538 
539  /* match the source and destination entries in the local distributed
540  * directories... */
541  struct isect *src_dst_intersections;
542  size_t num_intersections
543  = xt_xmap_dist_dir_match_src_dst(src_dist_dir, dst_dist_dir,
544  &src_dst_intersections);
545  xt_xmdd_free_dist_dir(src_dist_dir);
546  xt_xmdd_free_dist_dir(dst_dist_dir);
547  /* ... and pack the results into a sendable format */
548  void *send_buffer_local, *send_buffer_remote;
549  int num_send_requests_local
550  = pack_dist_dirs(num_intersections, src_dst_intersections,
551  send_size_local, &send_buffer_local,
552  xt_xmdd_direction_src, false, intra_comm, comm_size),
553  num_send_requests_remote
554  = pack_dist_dirs(num_intersections, src_dst_intersections,
555  send_size_remote, &send_buffer_remote,
556  xt_xmdd_direction_dst, true, inter_comm, remote_size);
557  free(src_dst_intersections);
558 
559  // get the data size the local process will receive from other processes
560  xt_mpi_call(MPI_Alltoall(send_size_local, SEND_SIZE_ASIZE, MPI_INT,
561  recv_size_local, SEND_SIZE_ASIZE, MPI_INT,
562  intra_comm), intra_comm);
563  xt_mpi_call(MPI_Alltoall(send_size_remote, SEND_SIZE_ASIZE, MPI_INT,
564  recv_size_remote, SEND_SIZE_ASIZE, MPI_INT,
565  inter_comm), inter_comm);
566 
567  struct Xt_xmdd_txstat tx_stat_local[2], tx_stat_remote[2];
568  int *isect_counts_recv_local
569  = xmalloc(((size_t)comm_size + (size_t)remote_size) * sizeof (int)),
570  *isect_counts_recv_remote = isect_counts_recv_local + comm_size;
571  compress_sizes(send_size_local, comm_size, tx_stat_local+1, NULL);
572  compress_sizes(recv_size_local, comm_size, tx_stat_local+0,
573  isect_counts_recv_local);
574  compress_sizes(send_size_remote, remote_size, tx_stat_remote+1, NULL);
575  compress_sizes(recv_size_remote, remote_size, tx_stat_remote+0,
576  isect_counts_recv_remote);
577  assert(tx_stat_local[1].num_msg == (size_t)num_send_requests_local
578  && tx_stat_remote[1].num_msg == (size_t)num_send_requests_remote);
579  size_t num_requests
580  = (size_t)num_send_requests_local + (size_t)num_send_requests_remote
581  + tx_stat_local[0].num_msg + tx_stat_remote[0].num_msg;
582  MPI_Request *requests
583  = xmalloc(num_requests * sizeof(*requests)
584  + tx_stat_local[0].bytes + tx_stat_remote[0].bytes);
585  void *recv_buf_local = requests + num_requests,
586  *recv_buf_remote = (unsigned char *)recv_buf_local + tx_stat_local[0].bytes;
587  size_t req_ofs = tx_stat_local[0].num_msg;
588  int tag_intra = tag_offset_intra + xt_mpi_tag_xmap_dist_dir_src_send;
589  irecv_intersections(tx_stat_local[0].num_msg,
590  (const int (*)[SEND_SIZE_ASIZE])recv_size_local,
591  recv_buf_local, requests, tag_intra, intra_comm);
592  int tag_inter = tag_offset_inter + xt_mpi_tag_xmap_dist_dir_src_send;
593  irecv_intersections(tx_stat_remote[0].num_msg,
594  (const int (*)[SEND_SIZE_ASIZE])recv_size_remote,
595  recv_buf_remote, requests+req_ofs, tag_inter, inter_comm);
596  req_ofs += tx_stat_remote[0].num_msg;
597  isend_intersections(tx_stat_local[1].num_msg,
598  (const int (*)[SEND_SIZE_ASIZE])send_size_local,
599  send_buffer_local, requests+req_ofs, tag_intra,
600  intra_comm);
601  req_ofs += tx_stat_local[1].num_msg;
602  isend_intersections(tx_stat_remote[1].num_msg,
603  (const int (*)[SEND_SIZE_ASIZE])send_size_remote,
604  send_buffer_remote, requests+req_ofs, tag_inter,
605  inter_comm);
606  xt_mpi_call(MPI_Waitall((int)num_requests, requests, MPI_STATUSES_IGNORE),
607  inter_comm);
608  free(send_buffer_local);
609  free(send_buffer_remote);
610  free(send_size_local);
611 
612  unpack_dist_dir_results(tx_stat_local[0], src_intersections, recv_buf_local,
613  isect_counts_recv_local, intra_comm);
614  unpack_dist_dir_results(tx_stat_remote[0], dst_intersections, recv_buf_remote,
615  isect_counts_recv_remote, inter_comm);
616  free(requests);
617  free(isect_counts_recv_local);
618 }
619 
620 
621 
622 Xt_xmap
624  MPI_Comm inter_comm_, MPI_Comm intra_comm_)
625 {
626  INSTR_DEF(this_instr,"xt_xmap_dist_dir_intercomm_new")
627  INSTR_START(this_instr);
628  int tag_offset_inter, tag_offset_intra;
629  MPI_Comm inter_comm = xt_mpi_comm_smart_dup(inter_comm_, &tag_offset_inter),
630  intra_comm = xt_mpi_comm_smart_dup(intra_comm_, &tag_offset_intra);
631 
632  struct dist_dir *src_intersections, *dst_intersections;
633 
634  bool stripify;
635  exchange_idxlists(&src_intersections, &dst_intersections, &stripify,
636  src_idxlist, dst_idxlist,
637  tag_offset_inter, tag_offset_intra,
638  inter_comm, intra_comm);
639 
640  Xt_xmap (*xmap_new)(int num_src_intersections,
641  const struct Xt_com_list *src_com,
642  int num_dst_intersections,
643  const struct Xt_com_list *dst_com,
644  Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist,
645  MPI_Comm comm)
647 
648  Xt_xmap xmap
649  = xmap_new(src_intersections->num_entries, src_intersections->entries,
650  dst_intersections->num_entries, dst_intersections->entries,
651  src_idxlist, dst_idxlist, inter_comm);
652 
653  xt_mpi_comm_smart_dedup(&inter_comm, tag_offset_inter);
654  xt_mpi_comm_smart_dedup(&intra_comm, tag_offset_intra);
655 
656  xt_xmdd_free_dist_dir(src_intersections);
657  xt_xmdd_free_dist_dir(dst_intersections);
658  INSTR_STOP(this_instr);
659  return xmap;
660 }
661 
662 
663 
664 /*
665  * Local Variables:
666  * c-basic-offset: 2
667  * coding: utf-8
668  * indent-tabs-mode: nil
669  * show-trailing-whitespace: t
670  * require-trailing-newline: t
671  * End:
672  */
Xt_xmap xt_xmap_dist_dir_intercomm_new(Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist, MPI_Comm inter_comm_, MPI_Comm intra_comm_)
static void compress_sizes(int(*restrict sizes)[SEND_SIZE_ASIZE], int comm_size, struct Xt_xmdd_txstat *tx_stat, int *counts)
Xt_idxlist xt_idxlist_unpack(void *buffer, int buffer_size, int *position, MPI_Comm comm)
int xt_idxlist_get_num_indices(Xt_idxlist idxlist)
Definition: xt_idxlist.c:97
static void irecv_intersections(size_t num_msg, const int(*recv_size)[SEND_SIZE_ASIZE], void *recv_buffer, MPI_Request *requests, int tag, MPI_Comm comm)
#define XT_INT_MAX
Definition: xt_core.h:73
struct Xt_xmap_ * Xt_xmap
Definition: xt_core.h:81
Uitlity functions for creation of distributed directories.
#define INSTR_START(T)
Definition: instr.h:68
static int send_size_from_intersections(size_t num_intersections, const struct isect *restrict src_dst_intersections, enum xt_xmdd_direction target, MPI_Comm comm, int comm_size, int(*restrict send_size_target)[SEND_SIZE_ASIZE])
int xt_com_list_rank_cmp(const void *a_, const void *b_)
int xt_xmdd_cmp_isect_dst_rank(const void *a_, const void *b_)
size_t xt_xmap_dist_dir_match_src_dst(const struct dist_dir *src_dist_dir, const struct dist_dir *dst_dist_dir, struct isect **src_dst_intersections)
add versions of standard API functions not returning on error
static void isend_intersections(size_t num_msg, const int(*send_size)[SEND_SIZE_ASIZE], void *send_buffer, MPI_Request *requests, int tag, MPI_Comm comm)
void xt_idxlist_delete(Xt_idxlist idxlist)
Definition: xt_idxlist.c:73
Xt_idxlist xt_xmap_dist_dir_get_bucket(const struct bucket_params *bucket_params, struct Xt_stripe **stripes_, size_t *stripes_array_size, int dist_dir_rank)
generates the buckets of the distributed directory
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)
Xt_int xt_idxlist_get_min_index(Xt_idxlist idxlist)
Definition: xt_idxlist.c:296
#define xrealloc(ptr, size)
Definition: ppm_xfuncs.h:67
static void generate_distributed_directories(struct dist_dir **src_dist_dir, struct dist_dir **dst_dist_dir, bool *stripify, Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist, int tag_offset_inter, int tag_offset_intra, MPI_Comm inter_comm, MPI_Comm intra_comm, int remote_size, int comm_size, int comm_rank)
exchange map declarations
void xt_xmap_dist_dir_same_rank_merge(struct dist_dir **dist_dir_results)
static Xt_int get_min_idxlist_index(Xt_idxlist l)
XT_INT Xt_int
Definition: xt_core.h:68
Provide non-public declarations common to all index lists.
int xt_xmap_dist_dir_pack_intersections(enum xt_xmdd_direction target, size_t num_intersections, const struct isect *restrict src_dst_intersections, bool isect_idxlist_delete, void *buffer, int buf_size, int *position, MPI_Comm comm)
void xt_xmdd_free_dist_dir(struct dist_dir *dist_dir)
int xt_xmdd_cmp_isect_src_rank(const void *a_, const void *b_)
Xt_int xt_idxlist_get_max_index(Xt_idxlist idxlist)
Definition: xt_idxlist.c:301
static void exchange_idxlists(struct dist_dir **src_intersections, struct dist_dir **dst_intersections, bool *stripify, Xt_idxlist src_idxlist, Xt_idxlist dst_idxlist, int tag_offset_inter, int tag_offset_intra, MPI_Comm inter_comm, MPI_Comm intra_comm)
static void create_intersections(struct Xt_xmdd_txstat tx_stat[2], int recv_size[][SEND_SIZE_ASIZE], void **send_buffer, int send_size[][SEND_SIZE_ASIZE], Xt_idxlist idxlist, Xt_int interval_size, MPI_Comm comm, int comm_size)
static int pack_dist_dirs(size_t num_intersections, struct isect *restrict src_dst_intersections, int(*send_size)[SEND_SIZE_ASIZE], void **send_buffer_, enum xt_xmdd_direction target, bool isect_idxlist_delete, MPI_Comm comm, int comm_size)
static void unpack_dist_dir(struct Xt_xmdd_txstat tx_stat, const int(*sizes)[SEND_SIZE_ASIZE], const void *buffer, struct dist_dir **dist_dir, MPI_Comm comm)
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)
#define INSTR_DEF(T, S)
Definition: instr.h:66
struct Xt_com_list entries[]
static void get_dist_dir_global_interval_size(Xt_idxlist src, Xt_idxlist dst, bool *stripify, Xt_int interval_size[2], MPI_Comm intra_comm, MPI_Comm inter_comm, int comm_size, int remote_size, int comm_rank, int tag_offset_inter)
static Xt_int get_max_idxlist_index(Xt_idxlist l)
MPI_Comm xt_mpi_comm_smart_dup(MPI_Comm comm, int *tag_offset)
Definition: xt_mpi.c:850
static void tx_intersections(size_t num_msg, const int(*sizes)[SEND_SIZE_ASIZE], unsigned char *buffer, MPI_Request *requests, int tag, MPI_Comm comm, tx_fp tx_op)
void xt_mpi_comm_smart_dedup(MPI_Comm *comm, int tag_offset)
Definition: xt_mpi.c:901
static struct bucket_params get_bucket_params(Xt_idxlist idxlist, Xt_int global_interval, int comm_size)
size_t xt_idxlist_get_pack_size(Xt_idxlist idxlist, MPI_Comm comm)
Definition: xt_idxlist.c:78
#define xt_mpi_call(call, comm)
Definition: xt_mpi.h:68
#define INSTR_STOP(T)
Definition: instr.h:69
index list declaration
#define XT_INT_MIN
Definition: xt_core.h:74
static size_t compute_and_pack_bucket_intersections(struct bucket_params *bucket_params, Xt_idxlist idxlist, int(*send_size)[SEND_SIZE_ASIZE], void **send_buffer_, MPI_Comm comm, int comm_size)
int(* tx_fp)(void *, int, MPI_Datatype, int, int, MPI_Comm, MPI_Request *)
void xt_idxlist_pack(Xt_idxlist idxlist, void *buffer, int buffer_size, int *position, MPI_Comm comm)
Definition: xt_idxlist.c:84
#define xmalloc(size)
Definition: ppm_xfuncs.h:66
int MPI_Comm
Definition: core.h:64
static void rank_no_send(size_t rank, int(*restrict send_size)[SEND_SIZE_ASIZE])
utility routines for MPI
static void unpack_dist_dir_results(struct Xt_xmdd_txstat tx_stat, struct dist_dir **dist_dir, void *restrict recv_buffer, int *restrict entry_counts, MPI_Comm comm)
#define MAX(a, b)
Definition: xt_idxstripes.c:76
Xt_idxlist xt_idxlist_get_intersection(Xt_idxlist idxlist_src, Xt_idxlist idxlist_dst)