Yet Another eXchange Tool  DO_NOT_EDIT_HERE
xt_mpi.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 <inttypes.h>
52 #include <limits.h>
53 #include <stdbool.h>
54 #include <stdlib.h>
55 #include <stdio.h>
56 
57 #include <mpi.h>
58 #include "core/core.h"
59 #include "core/ppm_xfuncs.h"
60 #include "xt/xt_core.h"
61 #include "xt/xt_mpi.h"
62 #include "xt_mpi_internal.h"
63 
69 #define COMPACT_DT
70 
71 #define zero_stripe ((struct Xt_offset_ext){ .start=0, .stride=0, .size=0 })
72 
73 static MPI_Datatype
74 xt_mpi_generate_compact_datatype_block(const int *disp, const int *blocklengths,
75  int count, MPI_Datatype old_type);
76 static MPI_Datatype
77 xt_mpi_generate_compact_datatype(int const *disp, int disp_len,
78  MPI_Datatype old_type);
79 
80 
81 //taken from http://beige.ucs.indiana.edu/I590/node85.html
82 void xt_mpi_error(int error_code, MPI_Comm comm) {
83  int rank;
84  MPI_Comm_rank(comm, &rank);
85 
86  char error_string[MPI_MAX_ERROR_STRING];
87  int length_of_error_string, error_class;
88 
89  MPI_Error_class(error_code, &error_class);
90  MPI_Error_string(error_class, error_string, &length_of_error_string);
91  fprintf(stderr, "%3d: %s\n", rank, error_string);
92  MPI_Error_string(error_code, error_string, &length_of_error_string);
93  fprintf(stderr, "%3d: %s\n", rank, error_string);
94  MPI_Abort(comm, error_code);
95 }
96 
97 #ifndef COMPACT_DT
98 static MPI_Datatype copy_mpi_datatype(MPI_Datatype old_type, MPI_Comm comm) {
99 
100  MPI_Datatype datatype;
101 
102  xt_mpi_call(MPI_Type_dup(old_type, &datatype), comm);
103 
104  return datatype;
105 }
106 
107 static MPI_Datatype
108 gen_mpi_datatype_simple(int displacement, MPI_Datatype old_type, MPI_Comm comm)
109 {
110  MPI_Datatype datatype;
111 
112  xt_mpi_call(MPI_Type_create_indexed_block(1, 1, &displacement, old_type,
113  &datatype), comm);
114  xt_mpi_call(MPI_Type_commit(&datatype), comm);
115 
116  return datatype;
117 }
118 
119 static MPI_Datatype
120 gen_mpi_datatype_contiguous(int displacement, int blocklength,
121  MPI_Datatype old_type, MPI_Comm comm) {
122 
123  MPI_Datatype datatype;
124 
125  if (displacement == 0)
126  xt_mpi_call(MPI_Type_contiguous(blocklength, old_type, &datatype),
127  comm);
128  else
129  xt_mpi_call(MPI_Type_create_indexed_block(1, blocklength,
130  &displacement, old_type,
131  &datatype), comm);
132 
133  xt_mpi_call(MPI_Type_commit(&datatype), comm);
134 
135  return datatype;
136 
137 }
138 
139 static MPI_Datatype
140 gen_mpi_datatype_vector(int count, int blocklength, int stride,
141  int offset, MPI_Datatype old_type, MPI_Comm comm) {
142 
143  MPI_Datatype datatype;
144 
145  xt_mpi_call(MPI_Type_vector(count, blocklength, stride, old_type,
146  &datatype), comm);
147  if (offset != 0) {
148 
149  MPI_Datatype datatype_;
150  int hindexed_blocklength = 1;
151  MPI_Aint old_type_size, old_type_lb;
152 
153  xt_mpi_call(MPI_Type_get_extent(old_type, &old_type_lb,
154  &old_type_size), comm);
155 
156  MPI_Aint displacement = offset * old_type_size;
157 
158  xt_mpi_call(MPI_Type_create_hindexed(1, &hindexed_blocklength,
159  &displacement, datatype, &datatype_),
160  comm);
161  xt_mpi_call(MPI_Type_free(&datatype), comm);
162  datatype = datatype_;
163  }
164  xt_mpi_call(MPI_Type_commit(&datatype), comm);
165 
166  return datatype;
167 }
168 
169 static MPI_Datatype
170 gen_mpi_datatype_indexed_block(int const * displacements, int blocklength,
171  int count, MPI_Datatype old_type, MPI_Comm comm)
172 {
173  MPI_Datatype datatype;
174 
175  xt_mpi_call(MPI_Type_create_indexed_block(count, blocklength,
176  (void *)displacements,
177  old_type, &datatype), comm);
178  xt_mpi_call(MPI_Type_commit(&datatype), comm);
179 
180  return datatype;
181 }
182 
183 static MPI_Datatype
184 gen_mpi_datatype_indexed(const int *displacements, const int *blocklengths,
185  int count, MPI_Datatype old_type, MPI_Comm comm) {
186 
187  MPI_Datatype datatype;
188 
189  xt_mpi_call(MPI_Type_indexed(count, (int*)blocklengths, (void*)displacements,
190  old_type, &datatype), comm);
191  xt_mpi_call(MPI_Type_commit(&datatype), comm);
192 
193  return datatype;
194 }
195 
196 static inline int
197 check_for_vector_type(const int *displacements, const int *blocklengths,
198  int count) {
199 
200  int blocklength = blocklengths[0];
201 
202  for (int i = 1; i < count; ++i)
203  if (blocklengths[i] != blocklength)
204  return 0;
205 
206  int stride = displacements[1] - displacements[0];
207 
208  for (int i = 1; i + 1 < count; ++i)
209  if (displacements[i+1] - displacements[i] != stride)
210  return 0;
211 
212  return 1;
213 }
214 
215 static inline int check_for_indexed_block_type(const int *blocklengths,
216  int count) {
217 
218  int blocklength = blocklengths[0];
219 
220  for (int i = 1; i < count; ++i)
221  if (blocklengths[i] != blocklength)
222  return 0;
223 
224  return 1;
225 }
226 #endif
227 
228 MPI_Datatype
229 xt_mpi_generate_datatype_block(const int *displacements,
230  const int *blocklengths,
231  int count, MPI_Datatype old_type,
232  MPI_Comm comm) {
233 #ifdef COMPACT_DT
234  (void)comm;
235  return xt_mpi_generate_compact_datatype_block(displacements, blocklengths, count, old_type);
236 #else
237  MPI_Datatype datatype;
238 
239  if (count == 0)
240  datatype = MPI_DATATYPE_NULL;
241  else if (count == 1 && blocklengths[0] == 1 && displacements[0] == 0)
242  datatype = copy_mpi_datatype(old_type, comm);
243  else if (count == 1 && blocklengths[0] == 1)
244  datatype = gen_mpi_datatype_simple(displacements[0], old_type, comm);
245  else if (count == 1)
246  datatype = gen_mpi_datatype_contiguous(displacements[0], blocklengths[0],
247  old_type, comm);
248  else if (check_for_vector_type(displacements, blocklengths, count))
249  datatype = gen_mpi_datatype_vector(count, blocklengths[0],
250  displacements[1] - displacements[0],
251  displacements[0], old_type, comm);
252  else if (check_for_indexed_block_type(blocklengths, count))
253  datatype = gen_mpi_datatype_indexed_block(displacements, blocklengths[0],
254  count, old_type, comm);
255  else
256  datatype = gen_mpi_datatype_indexed(displacements, blocklengths, count,
257  old_type, comm);
258 
259  return datatype;
260 #endif
261 }
262 
263 MPI_Datatype xt_mpi_generate_datatype(int const * displacements, int count,
264  MPI_Datatype old_type, MPI_Comm comm) {
265 
266  if (count <= 0)
267  return MPI_DATATYPE_NULL;
268 
269 #ifdef COMPACT_DT
270  return xt_mpi_generate_compact_datatype(displacements, count, old_type);
271 #endif
272 
273  int * blocklengths = xmalloc((size_t)count * sizeof(*blocklengths));
274  int new_count = 0;
275  {
276  int i = 0;
277  do {
278  int j = 1;
279  while (i + j < count && displacements[i] + j == displacements[i + j])
280  ++j;
281  blocklengths[new_count++] = j;
282  i += j;
283  } while (i < count);
284  }
285 
286  int * tmp_displ = NULL;
287  const int *displ;
288 
289  if (new_count != count) {
290 
291  tmp_displ = xmalloc((size_t)new_count * sizeof(*tmp_displ));
292 
293  int offset = 0;
294 
295  for (int i = 0; i < new_count; ++i) {
296 
297  tmp_displ[i] = displacements[offset];
298  offset += blocklengths[i];
299  }
300 
301  displ = tmp_displ;
302  } else
303  displ = displacements;
304 
305  MPI_Datatype datatype;
306 
307  datatype = xt_mpi_generate_datatype_block(displ, blocklengths, new_count,
308  old_type, comm);
309 
310  free(blocklengths);
311 
312  free(tmp_displ);
313 
314  return datatype;
315 }
316 
317 
318 static size_t
319 scan_stripe(const int *disp, size_t disp_len, struct Xt_offset_ext *restrict v,
320  size_t vsize) {
321 
322  if (disp_len<1) return 0;
323 
324  struct Xt_offset_ext x = zero_stripe;
325  size_t i = 0, p = 0;
326  while (p < disp_len) {
327 
328  if (!x.size) {
329  x.start = disp[p];
330  x.stride = 1;
331  x.size = 1;
332  p++; continue;
333  }
334 
335  if (x.size == 1) {
336  x.stride = disp[p] - disp[p-1];
337  x.size = 2;
338  p++; continue;
339  }
340 
341  // x.size >= 2:
342  if (disp[p] - disp[p-1] == x.stride) {
343  x.size++;
344  p++; continue;
345  }
346 
347  if (x.size > 2 || (x.size == 2 && x.stride == 1) ) {
348  // we accept small contiguous vectors (nstrides==2, stride==1)
349  if (i >= vsize) die("scan_stripe: vsize too small\n");
350  v[i]= x;
351  i++;
352  x = zero_stripe;
353  continue;
354  }
355 
356  if (x.size == 2) {
357  // break up trivial vec:
358  if (i >= vsize) die("scan_stripe: vsize too small\n");
359  v[i] = x;
360  v[i].size = 1;
361  v[i].stride = 1;
362  i++;
363  x.start += x.stride;
364  x.size = 1;
365  x.stride = 1;
366  continue;
367  }
368 
369  }
370 
371  // tail cases:
372  if (x.size > 2 || (x.size == 2 && x.stride == 1) ) {
373  if (i >= vsize) die("scan_stripe: vsize too small\n");
374  v[i]= x;
375  i++;
376  } else if (x.size == 2) {
377  if (i+1 >= vsize) die("scan_stripe: vsize too small\n");
378  v[i] = x;
379  v[i].size = 1;
380  v[i].stride = 1;
381  i++;
382  v[i] = x;
383  v[i].start += x.stride;
384  v[i].size = 1;
385  v[i].stride = 1;
386  i++;
387  } else if (x.size == 1) {
388  if (i >= vsize) die("scan_stripe: vsize too small\n");
389  v[i] = x;
390  v[i].size = 1;
391  v[i].stride = 1;
392  i++;
393  }
394 
395  size_t vn = i;
396 
397  // check:
398  p = 0;
399  for (size_t j = 0; j < vn; j++) {
400  for (int k = 0; k < v[j].size; ++k, ++p) {
401  int d = v[j].start + k*v[j].stride;
402  static const char die_msg[2][32] = { "scan_stripe: internal error (1)",
403  "scan_stripe: internal error (2)" };
404  int err_code = p > disp_len || (disp[p] != d) * 2;
405  if (err_code) die(die_msg[err_code - 1]);
406  }
407  }
408  if (p != disp_len) die("scan_stripe: internal error (3)");
409 
410  return vn;
411 }
412 
413 static int
414 match_simple_vec(size_t *pstart_, const struct Xt_offset_ext *v, size_t vlen,
415  MPI_Datatype old_type, int *disp, MPI_Datatype *dt) {
416  // we only accept non-trivial matches (nsteps>2) with stride /= 1
417  // using only one vector from v
418  size_t p = *pstart_;
419  if (p >= vlen) return 0;
420  int nstrides = v[p].size;
421  int stride = v[p].stride;
422  if (nstrides < 2 || stride == 1 ) return 0;
423 
424  *pstart_ = p + 1;
425 
426  *disp = vlen > 1 ? v[p].start : 0;
427 
428  MPI_Datatype dt1;
429  xt_mpi_call(MPI_Type_vector(nstrides, 1, stride, old_type, &dt1),
430  Xt_default_comm);
431 
432  int start = v[p].start - *disp;
433  if (!start) {
434  *dt = dt1;
435  } else {
436  // (start != 0) => add offset:
437  MPI_Aint old_type_size, old_type_lb;
438  xt_mpi_call(MPI_Type_get_extent(old_type, &old_type_lb,
439  &old_type_size), Xt_default_comm);
440 
441  MPI_Aint displacement = start * old_type_size;
442  int bl2 = 1;
443  MPI_Datatype dt2;
444  xt_mpi_call(MPI_Type_create_hindexed(1, &bl2, &displacement, dt1, &dt2),
445  Xt_default_comm);
446 
447  xt_mpi_call(MPI_Type_free(&dt1), Xt_default_comm);
448 
449  *dt = dt2;
450  }
451  return nstrides;
452 }
453 
457 static bool
458 match_block_vec(size_t *pstart_, const struct Xt_offset_ext *v, size_t vlen,
459  MPI_Datatype old_type, int *disp, MPI_Datatype *dt) {
460  // using at least 3 vectors
461  size_t p = *pstart_, pstart = p;
462  if (p+2 >= vlen || v[p].stride != 1 || v[p+1].stride != 1 ) return 0;
463  int bl = v[p].size;
464  if (bl < 1 || v[p+1].size != bl) return 0;
465 
466  int vstride = v[p+1].start - v[p].start;
467 
468  p += 2;
469  while( p < vlen && v[p].stride == 1 && v[p].size == bl &&
470  v[p].start - v[p-1].start == vstride ) {
471  p++;
472  }
473  size_t n = p - pstart;
474  if (n<3) return false;
475 
476  *disp = n == vlen ? 0 : v[pstart].start;
477 
478  MPI_Datatype dt1;
479  xt_mpi_call(MPI_Type_vector((int)n, bl, vstride, old_type, &dt1),
480  Xt_default_comm);
481 
482  int start = v[pstart].start - *disp;
483 
484  *pstart_ = p;
485  if (!start) {
486  *dt = dt1;
487  } else {
488  // (start != 0) => add offset:
489  MPI_Aint old_type_size, old_type_lb;
490  xt_mpi_call(MPI_Type_get_extent(old_type, &old_type_lb,
491  &old_type_size), Xt_default_comm);
492 
493  MPI_Aint displacement = start * old_type_size;
494  int bl2 = 1;
495  MPI_Datatype dt2;
496  xt_mpi_call(MPI_Type_create_hindexed(1, &bl2, &displacement, dt1, &dt2),
497  Xt_default_comm);
498  xt_mpi_call(MPI_Type_free(&dt1), Xt_default_comm);
499  *dt = dt2;
500  }
501  return n != 0;
502 }
503 
504 static bool
505 match_contiguous(size_t *pstart_, const struct Xt_offset_ext *v, size_t vlen,
506  MPI_Datatype old_type, int *restrict disp, MPI_Datatype *dt) {
507  size_t p = *pstart_;
508  if (p >= vlen || v[p].stride != 1 || v[p].size < 2) return 0;
509 
510  int d = v[p].start - (*disp = vlen > 1 ? v[p].start : 0);
511 
512  if (!d)
513  xt_mpi_call(MPI_Type_contiguous(v[p].size, old_type, dt), Xt_default_comm) ;
514  else
515  xt_mpi_call(MPI_Type_create_indexed_block(1, v[p].size, &d, old_type, dt),
516  Xt_default_comm);
517 
518  *pstart_ = p+1;
519  return v[p].size != 0;
520 }
521 
522 static bool
523 match_indexed(size_t *pstart_, const struct Xt_offset_ext *v, size_t vlen,
524  MPI_Datatype old_type, int *disp, MPI_Datatype *dt) {
525  // we only accept non-trivial matches
526  size_t p = *pstart_, pstart = p;
527  if (p >= vlen || v[p].stride != 1 || v[p].size < 2) return 0;
528 
529  do
530  ++p;
531  while (p < vlen && v[p].stride == 1);
532 
533  size_t n = p - pstart;
534 
535  if (n < 2) return false;
536 
537  int start = (*disp = n == vlen ? 0 : v[pstart].start);
538 
539  int *restrict bl = xmalloc(2 * n * sizeof (*bl)),
540  *restrict d = bl + n;
541  bool hom_bl = true;
542  d[0] = v[pstart].start - start;
543  int bl0 = bl[0] = v[pstart].size;
544  for (size_t i = 1; i < n; i++) {
545  size_t iv = pstart + i;
546  d[i] = v[iv].start - start;
547  bl[i] = v[iv].size;
548  hom_bl &= (bl[i] == bl0);
549  }
550 
551  if (hom_bl) {
552  xt_mpi_call(MPI_Type_create_indexed_block((int)n, bl0, d, old_type, dt),
553  Xt_default_comm);
554  } else {
555  xt_mpi_call(MPI_Type_indexed((int)n, bl, d, old_type, dt), Xt_default_comm);
556  }
557 
558  *pstart_ = p;
559 
560  free(bl);
561  return n != 0;
562 }
563 
564 static int
565 gen_fallback_type(size_t set_start, size_t set_end,
566  const struct Xt_offset_ext *v,
567  size_t vlen, MPI_Datatype old_type, int *offset,
568  MPI_Datatype *dt) {
569  size_t ia = set_start;
570  size_t ib = set_end;
571  if (ib <= ia || ib > vlen) return 0;
572 
573  int n = 0;
574  for (size_t i=ia; i < ib; i++)
575  n += v[i].size;
576 
577  if (n<1) return 0;
578 
579  int start;
580  if (ia == 0 && ib == vlen) {
581  // generate absolute datatype
582  start = 0;
583  } else {
584  // generate relative datatype that gets embedded by the caller
585  start = v[ia].start;
586  }
587 
588  *offset = start;
589 
590  int *restrict d = xmalloc(sizeof (*d) * (size_t)n);
591  size_t p=0;
592 
593  for (size_t i=ia; i < ib; i++) {
594  size_t v_i_size = (size_t)(v[i].size > 0 ? v[i].size : 0);
595  for (size_t k=0; k < v_i_size; k++) {
596  d[p] = v[i].start + (int)k * v[i].stride - start;
597  p++;
598  }
599  }
600 
601  if (n==1 && d[0] == 0) {
602  // At the moment we disable the embed aspect that was used to avoid MPI_Type_dup.
603  // It turned out this creates more complexity when freeing the intermediate datatypes in the callin function.
604  // maybe we just forget the whole idea - then we can also remove the embed logic here.
605  //if (embed)
606  // *dt = old_type;
607  //else
608  xt_mpi_call(MPI_Type_dup(old_type, dt), Xt_default_comm);
609  } else {
610  xt_mpi_call(MPI_Type_create_indexed_block(n, 1, d, old_type, dt), Xt_default_comm);
611  }
612  free(d);
613 
614  return n;
615 }
616 
617 static MPI_Datatype
618 parse_stripe(const struct Xt_offset_ext *v, size_t vlen, MPI_Datatype old_type) {
619  /* [set_start,set_end) describes the prefix of non-matching
620  * elements in v that then need to be handled with gen_fallback_type */
621  size_t set_start = 0, set_end = 0;
622  MPI_Datatype *restrict wdt = xmalloc(sizeof(*wdt) * (size_t)vlen);
623  int *restrict wdisp = xmalloc(sizeof (*wdisp) * (size_t)vlen);
624  /* [p,vlen) is the part of v that still needs matching performed */
625  /* m is the index of the next datatype and displacements to write
626  * to wdt and wdisp respectively */
627  size_t p = 0, m = 0;
628  while (p<vlen) {
629  /* depending on wether there is a non-empty prefix, the datatype
630  * and displacement corresponding to a match need to be written
631  * to wdt[m+1] and wdisp[m+1] or wdt[m] and wdisp[m] respectively */
632  size_t mm = m + (set_start < set_end);
633  if ( match_block_vec(&p, v, vlen, old_type, wdisp+mm, wdt+mm) ||
634  match_indexed(&p, v, vlen, old_type, wdisp+mm, wdt+mm) ||
635  match_simple_vec(&p, v, vlen, old_type, wdisp+mm, wdt+mm) ||
636  match_contiguous(&p, v, vlen, old_type, wdisp+mm, wdt+mm) ) {
637  /* in case a match is found generate fallback datatype for
638  * non-matching, preceding extents */
639  if (set_start < set_end) {
640  gen_fallback_type(set_start, set_end, v, vlen, old_type, wdisp+m, wdt+m);
641  m++;
642  }
643  m++;
644  set_start = p;
645  } else {
646  /* assign ext investigated last to prefix */
647  set_end = ++p;
648  }
649  }
650  if (set_start < set_end) {
651  gen_fallback_type(set_start, set_end, v, vlen, old_type, wdisp+m, wdt+m);
652  m++;
653  }
654  size_t wlen = m;
655  MPI_Datatype result_dt;
656  if (wlen == 1 ) {
657  if (wdisp[0] == 0)
658  result_dt = wdt[0];
659  else
660  die("parse_stripe: internal error; wlen == 1 && match_disp != 0\n");
661  } else {
662  MPI_Aint old_type_lb, old_type_extent;
663  MPI_Aint *restrict wbdisp = xmalloc((size_t)wlen * sizeof (*wbdisp));
664  int *restrict wblocklength
665  = xmalloc((size_t)wlen * sizeof (*wblocklength));;
666  xt_mpi_call(MPI_Type_get_extent(old_type, &old_type_lb,
667  &old_type_extent), Xt_default_comm);
668  for(size_t i=0; i<wlen; i++) {
669  wbdisp[i] = wdisp[i] * old_type_extent;
670  wblocklength[i] = 1;
671  }
672  xt_mpi_call(MPI_Type_create_struct((int)wlen, wblocklength, wbdisp,
673  wdt, &result_dt), Xt_default_comm);
674  free(wblocklength);
675  free(wbdisp);
676  for (size_t i = 0; i < wlen; i++)
677  xt_mpi_call(MPI_Type_free(wdt+i), Xt_default_comm);
678  }
679  xt_mpi_call(MPI_Type_commit(&result_dt), Xt_default_comm);
680  free(wdt);
681  free(wdisp);
682  return result_dt;
683 }
684 
685 MPI_Datatype
687  int count, MPI_Datatype old_type,
688  MPI_Comm XT_UNUSED(comm))
689 {
690  if (count < 1) return MPI_DATATYPE_NULL;
691  return parse_stripe(v, (size_t)count, old_type);
692 }
693 
694 
695 static MPI_Datatype
696 xt_mpi_generate_compact_datatype_block(const int *disp, const int *blocklengths,
697  int count, MPI_Datatype old_type) {
698 
699  if (count < 1) return MPI_DATATYPE_NULL;
700  struct Xt_offset_ext *restrict v = xmalloc(sizeof(*v) * (size_t)count);
701  for (size_t i=0; i<(size_t)count; ++i) {
702  v[i].start = disp[i];
703  v[i].stride = 1;
704  v[i].size = blocklengths[i];
705  }
706  MPI_Datatype dt = parse_stripe(v, (size_t)count, old_type);
707  free(v);
708  return dt;
709 }
710 
711 static MPI_Datatype
712 xt_mpi_generate_compact_datatype(const int *disp, int disp_len,
713  MPI_Datatype old_type) {
714 
715  if (disp_len < 1) return MPI_DATATYPE_NULL;
716 
717  struct Xt_offset_ext *v = xmalloc(sizeof(*v) * (size_t)disp_len);
718  size_t vlen = scan_stripe(disp, (size_t)disp_len, v, (size_t)disp_len);
719  MPI_Datatype dt = parse_stripe(v, vlen, old_type);
720  free(v);
721  return dt;
722 }
723 
724 /* functions to handle optimizations on communicators */
726 
727 typedef unsigned long used_map_elem;
728 
729 enum {
730  used_map_elem_bits = sizeof (used_map_elem) * CHAR_BIT,
731 };
732 
734  int refcount;
735  unsigned used_map_size;
736  used_map_elem used_map[];
737 };
738 
739 static int
741  MPI_Comm XT_UNUSED(oldcomm), int XT_UNUSED(keyval),
742  void *XT_UNUSED(extra_state), void *XT_UNUSED(attribute_val_in),
743  void *attribute_val_out, int *flag)
744 {
745  struct xt_mpi_comm_internal_attr *new_comm_attr
746  = malloc(sizeof (struct xt_mpi_comm_internal_attr)
747  + sizeof (used_map_elem));
748  int retval;
749  if (new_comm_attr)
750  {
751  new_comm_attr->refcount = 1;
752  new_comm_attr->used_map_size = 1;
753  new_comm_attr->used_map[0] = 1U;
754  *(void **)attribute_val_out = new_comm_attr;
755  *flag = 1;
756  retval = MPI_SUCCESS;
757  } else {
758  *flag = 0;
759  retval = MPI_ERR_NO_MEM;
760  }
761  return retval;
762 }
763 
764 static int
766  MPI_Comm XT_UNUSED(comm), int XT_UNUSED(comm_keyval),
767  void *attribute_val, void *XT_UNUSED(extra_state))
768 {
769  free(attribute_val);
770  return MPI_SUCCESS;
771 }
772 
773 static int xt_mpi_tag_ub_val;
774 
775 void
776 xt_mpi_init(void) {
777  xt_mpi_call(MPI_Comm_create_keyval(xt_mpi_comm_internal_keyval_copy,
779  &xt_mpi_comm_internal_keyval, NULL),
780  Xt_default_comm);
781  void *attr;
782  int flag;
783  xt_mpi_call(MPI_Comm_get_attr(MPI_COMM_WORLD, MPI_TAG_UB, &attr, &flag),
785  assert(flag);
786  xt_mpi_tag_ub_val = *(int *)attr;
787 }
788 
789 void
791  xt_mpi_call(MPI_Comm_free_keyval(&xt_mpi_comm_internal_keyval),
792  Xt_default_comm);
793 }
794 
795 static struct xt_mpi_comm_internal_attr *
797 {
798  int attr_found;
799  void *attr_val;
800  xt_mpi_call(MPI_Comm_get_attr(comm, xt_mpi_comm_internal_keyval,
801  &attr_val, &attr_found),
802  comm);
803  return attr_found ? attr_val : NULL;
804 }
805 
806 #if HAVE_DECL___BUILTIN_CTZL
807 #define ctzl(v) (__builtin_ctzl(v))
808 #elif HAVE_DECL___BUILTIN_CLZL
809 static inline int
810 ctzl(unsigned long v) {
811  enum {
812  ulong_bits = sizeof (unsigned long) * CHAR_BIT,
813  };
814  /* clear all but lowest 1 bit */
815  v = v & ~(v - 1);
816  int c = ulong_bits - __builtin_clzl(v) - 1;
817  return c;
818 }
819 #else
820 static inline int
821 ctzl(unsigned long v) {
822  enum {
823  ulong_bits = sizeof (unsigned long) * CHAR_BIT,
824  };
825  // c will be the number of zero bits on the right
826  unsigned int c = ulong_bits;
827  v &= (unsigned long)-(long)v;
828  if (v) c--;
829 #if SIZEOF_UNSIGNED_LONG * CHAR_BIT == 64
830  if (v & UINT64_C(0x00000000ffffffff)) c -= 32;
831  if (v & UINT64_C(0x0000ffff0000ffff)) c -= 16;
832  if (v & UINT64_C(0x00ff00ff00ff00ff)) c -= 8;
833  if (v & UINT64_C(0x0f0f0f0f0f0f0f0f)) c -= 4;
834  if (v & UINT64_C(0x3333333333333333)) c -= 2;
835  if (v & UINT64_C(0x5555555555555555)) c -= 1;
836 #elif SIZEOF_UNSIGNED_LONG * CHAR_BIT == 32
837  if (v & 0x0000FFFFUL) c -= 16;
838  if (v & 0x00FF00FFUL) c -= 8;
839  if (v & 0x0F0F0F0FUL) c -= 4;
840  if (v & 0x33333333UL) c -= 2;
841  if (v & 0x55555555UL) c -= 1;
842 #else
843  error "Unexpected size of long.\n"
844 #endif
845  return (int)c;
846 }
847 #endif
848 
849 MPI_Comm
850 xt_mpi_comm_smart_dup(MPI_Comm comm, int *tag_offset)
851 {
852  MPI_Comm comm_dest;
853  struct xt_mpi_comm_internal_attr *comm_xt_attr_val
855  size_t position = 0;
856  int refcount = comm_xt_attr_val ? comm_xt_attr_val->refcount : 0;
857  if (comm_xt_attr_val
858  && (refcount + 1) < xt_mpi_tag_ub_val / xt_mpi_num_tags) {
859  comm_dest = comm;
860  comm_xt_attr_val->refcount = ++refcount;
861  size_t used_map_size = comm_xt_attr_val->used_map_size;
862  while (position < used_map_size
863  && comm_xt_attr_val->used_map[position] == ~(used_map_elem)0)
864  ++position;
865  if (position >= used_map_size) {
866  /* sadly, we need to recreate the value to enlarge it */
867  struct xt_mpi_comm_internal_attr *new_comm_xt_attr_val
868  = xmalloc(sizeof (*new_comm_xt_attr_val)
869  + (used_map_size + 1) * sizeof (used_map_elem));
870  new_comm_xt_attr_val->refcount = refcount;
871  new_comm_xt_attr_val->used_map_size = (unsigned)(used_map_size + 1);
872  for (size_t i = 0; i < used_map_size; ++i)
873  new_comm_xt_attr_val->used_map[i] = comm_xt_attr_val->used_map[i];
874  new_comm_xt_attr_val->used_map[used_map_size] = 1U;
875  position *= used_map_elem_bits;
876  xt_mpi_call(MPI_Comm_set_attr(comm_dest, xt_mpi_comm_internal_keyval,
877  new_comm_xt_attr_val), comm_dest);
878  } else {
879  /* not all bits are set, find first unset position and insert */
880  used_map_elem used_map_entry = comm_xt_attr_val->used_map[position],
881  unset_lsb = ~used_map_entry & (used_map_entry + 1),
882  bit_pos = (used_map_elem)ctzl(unset_lsb);
883  comm_xt_attr_val->used_map[position] = used_map_entry | unset_lsb;
884  position = position * used_map_elem_bits + (size_t)bit_pos;
885  }
886  } else {
887  struct xt_mpi_comm_internal_attr *comm_attr
888  = xmalloc(sizeof (*comm_attr) + sizeof (used_map_elem));
889  comm_attr->refcount = 1;
890  comm_attr->used_map_size = 1;
891  comm_attr->used_map[0] = 1U;
892  xt_mpi_call(MPI_Comm_dup(comm, &comm_dest), comm);
893  xt_mpi_call(MPI_Comm_set_attr(comm_dest, xt_mpi_comm_internal_keyval,
894  comm_attr), comm_dest);
895  }
896  *tag_offset = (int)(position * xt_mpi_num_tags);
897  return comm_dest;
898 }
899 
900 void
901 xt_mpi_comm_smart_dedup(MPI_Comm *comm, int tag_offset)
902 {
903  struct xt_mpi_comm_internal_attr *comm_xt_attr_val
905  int refcount = comm_xt_attr_val ? --(comm_xt_attr_val->refcount) : 0;
906  if (refcount < 1) {
907  xt_mpi_call(MPI_Comm_free(comm), MPI_COMM_WORLD);
908  *comm = MPI_COMM_NULL;
909  } else {
910  size_t position = (size_t)tag_offset / xt_mpi_num_tags,
911  map_elem = position / used_map_elem_bits,
912  in_elem_bit = position % used_map_elem_bits;
913  comm_xt_attr_val->used_map[map_elem] &= ~((used_map_elem)1 << in_elem_bit);
914  }
915 }
916 
917 void
919  struct xt_mpi_comm_internal_attr *comm_attr
920  = xmalloc(sizeof (*comm_attr) + sizeof (used_map_elem));
921  comm_attr->refcount = 1;
922  comm_attr->used_map_size = 1;
923  comm_attr->used_map[0] = 1U;
924  xt_mpi_call(MPI_Comm_set_attr(comm, xt_mpi_comm_internal_keyval,
925  comm_attr), comm);
926 }
927 
928 bool
929 xt_mpi_test_some(int *restrict num_req,
930  MPI_Request *restrict req,
931  int *restrict ops_completed, MPI_Comm comm)
932 {
933  int done_count;
934  size_t num_req_ = (size_t)*num_req;
935  xt_mpi_call(MPI_Testsome(*num_req, req, &done_count, ops_completed,
936  MPI_STATUSES_IGNORE), comm);
937  if (done_count != MPI_UNDEFINED) {
938  if (num_req_ > (size_t)done_count) {
939  size_t j = num_req_;
940  for (size_t i = 0;
941  i < (size_t)done_count && j >= num_req_ - (size_t)done_count;
942  ++i)
943  if (ops_completed[i] < (int)num_req_ - done_count) {
944  while (req[--j] == MPI_REQUEST_NULL);
945  req[ops_completed[i]] = req[j];
946  }
947  num_req_ -= (size_t)done_count;
948  }
949  else
950  num_req_ = 0;
951  }
952  *num_req = (int)num_req_;
953  return num_req_ == 0;
954 }
955 
956 
957 /*
958  * Local Variables:
959  * c-basic-offset: 2
960  * coding: utf-8
961  * indent-tabs-mode: nil
962  * show-trailing-whitespace: t
963  * require-trailing-newline: t
964  * End:
965  */
MPI_Datatype xt_mpi_generate_datatype(int const *displacements, int count, MPI_Datatype old_type, MPI_Comm comm)
Definition: xt_mpi.c:263
void xt_mpi_comm_mark_exclusive(MPI_Comm comm)
Definition: xt_mpi.c:918
static int gen_fallback_type(size_t set_start, size_t set_end, const struct Xt_offset_ext *v, size_t vlen, MPI_Datatype old_type, int *offset, MPI_Datatype *dt)
Definition: xt_mpi.c:565
static bool match_block_vec(size_t *pstart_, const struct Xt_offset_ext *v, size_t vlen, MPI_Datatype old_type, int *disp, MPI_Datatype *dt)
Definition: xt_mpi.c:458
base definitions header file
used_map_elem used_map[]
Definition: xt_mpi.c:736
int xt_mpi_comm_internal_keyval
Definition: xt_mpi.c:725
#define die(msg)
Definition: core.h:131
static bool match_indexed(size_t *pstart_, const struct Xt_offset_ext *v, size_t vlen, MPI_Datatype old_type, int *disp, MPI_Datatype *dt)
Definition: xt_mpi.c:523
static int xt_mpi_comm_internal_keyval_delete(MPI_Comm XT_UNUSED(comm), int XT_UNUSED(comm_keyval), void *attribute_val, void *XT_UNUSED(extra_state))
Definition: xt_mpi.c:765
static int xt_mpi_tag_ub_val
Definition: xt_mpi.c:773
add versions of standard API functions not returning on error
#define zero_stripe
Definition: xt_mpi.c:71
bool xt_mpi_test_some(int *restrict num_req, MPI_Request *restrict req, int *restrict ops_completed, MPI_Comm comm)
Definition: xt_mpi.c:929
unsigned long used_map_elem
Definition: xt_mpi.c:727
void xt_mpi_error(int error_code, MPI_Comm comm)
Definition: xt_mpi.c:82
void xt_mpi_init(void)
Definition: xt_mpi.c:776
MPI_Datatype xt_mpi_generate_datatype_block(const int *displacements, const int *blocklengths, int count, MPI_Datatype old_type, MPI_Comm comm)
Definition: xt_mpi.c:229
static size_t scan_stripe(const int *disp, size_t disp_len, struct Xt_offset_ext *restrict v, size_t vsize)
Definition: xt_mpi.c:319
#define XT_UNUSED(x)
Definition: core.h:84
MPI_Datatype xt_mpi_generate_datatype_stripe(const struct Xt_offset_ext *v, int count, MPI_Datatype old_type, MPI_Comm XT_UNUSED(comm))
Definition: xt_mpi.c:686
static MPI_Datatype xt_mpi_generate_compact_datatype(int const *disp, int disp_len, MPI_Datatype old_type)
Definition: xt_mpi.c:712
static int xt_mpi_comm_internal_keyval_copy(MPI_Comm XT_UNUSED(oldcomm), int XT_UNUSED(keyval), void *XT_UNUSED(extra_state), void *XT_UNUSED(attribute_val_in), void *attribute_val_out, int *flag)
Definition: xt_mpi.c:740
static MPI_Datatype parse_stripe(const struct Xt_offset_ext *v, size_t vlen, MPI_Datatype old_type)
Definition: xt_mpi.c:618
static int ctzl(unsigned long v)
Definition: xt_mpi.c:821
void xt_mpi_finalize(void)
Definition: xt_mpi.c:790
MPI_Comm xt_mpi_comm_smart_dup(MPI_Comm comm, int *tag_offset)
Definition: xt_mpi.c:850
static MPI_Datatype xt_mpi_generate_compact_datatype_block(const int *disp, const int *blocklengths, int count, MPI_Datatype old_type)
Definition: xt_mpi.c:696
void xt_mpi_comm_smart_dedup(MPI_Comm *comm, int tag_offset)
Definition: xt_mpi.c:901
static int match_simple_vec(size_t *pstart_, const struct Xt_offset_ext *v, size_t vlen, MPI_Datatype old_type, int *disp, MPI_Datatype *dt)
Definition: xt_mpi.c:414
#define xt_mpi_call(call, comm)
Definition: xt_mpi.h:68
#define xmalloc(size)
Definition: ppm_xfuncs.h:66
static bool match_contiguous(size_t *pstart_, const struct Xt_offset_ext *v, size_t vlen, MPI_Datatype old_type, int *restrict disp, MPI_Datatype *dt)
Definition: xt_mpi.c:505
int MPI_Comm
Definition: core.h:64
utility routines for MPI
static struct xt_mpi_comm_internal_attr * xt_mpi_comm_get_internal_attr(MPI_Comm comm)
Definition: xt_mpi.c:796