Yet Another eXchange Tool 0.11.3
Loading...
Searching...
No Matches
xt_ddt_create.c
Go to the documentation of this file.
1
12/*
13 * Keywords:
14 * Maintainer: Jörg Behrens <behrens@dkrz.de>
15 * Moritz Hanke <hanke@dkrz.de>
16 * Thomas Jahns <jahns@dkrz.de>
17 * URL: https://dkrz-sw.gitlab-pages.dkrz.de/yaxt/
18 *
19 * Redistribution and use in source and binary forms, with or without
20 * modification, are permitted provided that the following conditions are
21 * met:
22 *
23 * Redistributions of source code must retain the above copyright notice,
24 * this list of conditions and the following disclaimer.
25 *
26 * Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 *
30 * Neither the name of the DKRZ GmbH nor the names of its contributors
31 * may be used to endorse or promote products derived from this software
32 * without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
35 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
37 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
38 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
40 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
41 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
42 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
43 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
44 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 */
46#ifdef HAVE_CONFIG_H
47#include "config.h"
48#endif
49
50#include <assert.h>
51#include <stdbool.h>
52#include <string.h>
53#include <mpi.h>
54
55#include "core/core.h"
56#include "core/ppm_xfuncs.h"
57#include "xt/xt_mpi.h"
58
59#include "xt_ddt_internal.h"
60
61static const char filename[] = "xt_ddt_create.c";
62
64 MPI_Aint extent; // not necessarly the true extent
65 enum {
66 DTYPE, // element is a basic MPI datatype
67 SINGLE_SUB, // element contains a single sub element
68 MULTI_SUB, // element contains a dedicated sub element
69 // for each displacement
70 } type; // type of this element
71 size_t displ_count; // number of displacement
72 MPI_Aint displs[];
73 // following these is one of
74 // MPI_Datatype dtype; when type == DTYPE
75 // struct xt_ddt_tree_elem *sub_elems[]; when type == SINGLE_SUB or MULTI_SUB
76};
77
78#define MAX(a,b) ((a) >= (b) ? (a) : (b))
79
80static inline void *after_displs(struct xt_ddt_tree_elem *elem)
81{
82 return elem->displs + elem->displ_count;
83}
84
85static struct xt_ddt_tree_elem *
86 mpi_ddt_2_xt_ddt_tree(MPI_Datatype mpi_ddt, int free_mpi_ddt);
87
88static struct xt_ddt_tree_elem *
89xt_ddt_tree_elem_named_new(MPI_Aint extent, MPI_Datatype mpi_ddt)
90{
91 struct xt_ddt_tree_elem *elem
92 = xmalloc(sizeof(*elem) + sizeof (MPI_Aint) + sizeof (MPI_Datatype));
93 elem->extent = extent;
94 elem->type = DTYPE;
95 elem->displ_count = 1;
96 elem->displs[0] = 0;
97 *(MPI_Datatype *)after_displs(elem) = mpi_ddt;
98 return elem;
99}
100
101static void free_unnamed_mpi_ddt(MPI_Datatype mpi_ddt) {
102
103 // get parameters for decoding of MPI datatype
104 int num_ints, num_adds, num_dtypes, combiner;
106 MPI_Type_get_envelope(
107 mpi_ddt, &num_ints, &num_adds, &num_dtypes, &combiner), Xt_default_comm);
108
109 if (combiner != MPI_COMBINER_NAMED)
110 xt_mpi_call(MPI_Type_free(&mpi_ddt), Xt_default_comm);
111}
112
113// generates a ddt tree element with count contiguous entries of mpi_ddt
114static struct xt_ddt_tree_elem *
115xt_ddt_tree_elem_cont_new(int count, MPI_Datatype mpi_ddt)
116{
117
118 // if the sub element count is zero
119 if (count == 0) {
120 free_unnamed_mpi_ddt(mpi_ddt);
121 return NULL;
122 }
123
124 struct xt_ddt_tree_elem * sub_elem = mpi_ddt_2_xt_ddt_tree(mpi_ddt, 1);
125
126 // if the sub element is empty
127 if (sub_elem == NULL) return NULL;
128
129 // if there is only a single sub element
130 if (count == 1) return sub_elem;
131
132 struct xt_ddt_tree_elem * elem;
133 MPI_Aint sub_elem_extent = sub_elem->extent;
134
135 // if the sub element is a basic MPI_Datatype
136 if ((sub_elem->type == DTYPE) &&
137 (sub_elem->displ_count == 1) &&
138 (sub_elem->displs[0] == 0)) {
139
140 elem = xrealloc(sub_elem,
141 sizeof (*elem) + (size_t)count * sizeof (MPI_Aint)
142 + sizeof (MPI_Datatype));
143 MPI_Datatype dt = *(MPI_Datatype *)after_displs(elem);
144 elem->displ_count = (size_t)count;
145 *(MPI_Datatype *)after_displs(elem) = dt;
146 } else {
147
148 elem = xmalloc(sizeof(*elem) + (size_t)count * sizeof (MPI_Aint)
149 + sizeof (struct xt_ddt_tree_elem *));
150 elem->type = SINGLE_SUB;
151 elem->displ_count = (size_t)count;
152 *(struct xt_ddt_tree_elem **)after_displs(elem) = sub_elem;
153 }
154
155 elem->extent = (MPI_Aint)count * sub_elem_extent;
156 MPI_Aint *displs = elem->displs;
157 for (int i = 0; i < count; ++i) displs[i] = (MPI_Aint)i * sub_elem_extent;
158
159 return elem;
160}
161
162// generates a ddt tree element based on a hvector style memory layout
163static struct xt_ddt_tree_elem *
165 MPI_Aint extent, int count, int blocklength, MPI_Aint stride,
166 MPI_Datatype mpi_ddt) {
167
168 // if the sub element count is zero
169 if (count == 0) {
170 free_unnamed_mpi_ddt(mpi_ddt);
171 return NULL;
172 }
173
174 struct xt_ddt_tree_elem *sub_elem =
175 xt_ddt_tree_elem_cont_new(blocklength, mpi_ddt);
176
177 // if the sub element is empty
178 if (sub_elem == NULL) return NULL;
179
180 // if there is only a single sub element
181 if (count == 1) return sub_elem;
182
183 struct xt_ddt_tree_elem *elem
184 = xmalloc(sizeof(*elem) + (size_t)count * sizeof (MPI_Aint)
185 + sizeof (struct xt_ddt_tree_elem *));
186
187 elem->displ_count = (size_t)count;
188 elem->extent = extent;
189 elem->type = SINGLE_SUB;
190 *(struct xt_ddt_tree_elem **)after_displs(elem) = sub_elem;
191
192 MPI_Aint *displs = elem->displs;
193 for (int i = 0; i < count; ++i) displs[i] = (MPI_Aint)i * stride;
194
195 return elem;
196}
197
198// generates a ddt tree element based on a vector style memory layout
200 MPI_Aint extent, int count, int blocklength, int stride,
201 MPI_Datatype mpi_ddt) {
202
203 MPI_Aint lb, base_extent;
205 MPI_Type_get_extent(mpi_ddt, &lb, &base_extent), Xt_default_comm);
206
207 MPI_Aint hstride = base_extent * (MPI_Aint)stride;
208
209 return
211 extent, count, blocklength, hstride, mpi_ddt);
212}
213
214// generates a ddt tree element based on a hindexed style memory layout
216 MPI_Aint extent, int count, int *blocklengths,
217 MPI_Aint *displacements, MPI_Datatype mpi_ddt) {
218
219 size_t displ_count = 0;
220 for (int i = 0; i < count; ++i)
221 displ_count += (size_t)blocklengths[i];
222
223 // if there are no entries
224 if (displ_count == 0) {
225 free_unnamed_mpi_ddt(mpi_ddt);
226 return NULL;
227 }
228
229 MPI_Aint lb, base_extent;
230 MPI_Type_get_extent(mpi_ddt, &lb, &base_extent);
231 struct xt_ddt_tree_elem *sub_elem = mpi_ddt_2_xt_ddt_tree(mpi_ddt, 1);
232
233 // if the sub element is empty
234 if (sub_elem == NULL) return NULL;
235
236 struct xt_ddt_tree_elem *elem
237 = xmalloc(sizeof(*elem) + displ_count * sizeof (MPI_Aint)
238 + sizeof (struct xt_ddt_tree_elem *));
239
240 elem->displ_count = displ_count;
241 elem->extent = extent;
242 elem->type = SINGLE_SUB;
243 MPI_Aint *displs = elem->displs;
244 *(struct xt_ddt_tree_elem **)(displs + displ_count) = sub_elem;
245
246 size_t idx = 0;
247 for (int i = 0; i < count; ++i) {
248 MPI_Aint block_displacement = displacements[i];
249 for (int j = 0; j < blocklengths[i]; ++j, ++idx) {
250 displs[idx] = block_displacement + (MPI_Aint)j * base_extent;
251 }
252 }
253
254 return elem;
255}
256
257// generates a ddt tree element based on an indexed style memory layout
259 MPI_Aint extent, int count, int *blocklengths,
260 int *displacements, MPI_Datatype mpi_ddt) {
261
262 MPI_Aint lb, base_extent;
263 MPI_Type_get_extent(mpi_ddt, &lb, &base_extent);
264
265 MPI_Aint *hdisplacements = xmalloc((size_t)count * sizeof(*hdisplacements));
266 for (int i = 0; i < count; ++i)
267 hdisplacements[i] = (MPI_Aint)displacements[i] * base_extent;
268
269 struct xt_ddt_tree_elem *elem =
271 extent, count, blocklengths, hdisplacements, mpi_ddt);
272
273 free(hdisplacements);
274
275 return elem;
276}
277
278// generates a ddt tree element based on an hindexed block style memory layout
280 MPI_Aint extent, int count, int blocklength, MPI_Aint *displacements,
281 MPI_Datatype mpi_ddt) {
282
283 // if there are no blocks or if the blocks are empty
284 if ((count == 0) || (blocklength == 0)) {
285 free_unnamed_mpi_ddt(mpi_ddt);
286 return NULL;
287 }
288
289 struct xt_ddt_tree_elem *sub_elem =
290 xt_ddt_tree_elem_cont_new(blocklength, mpi_ddt);
291
292 // if the sub element is empty
293 if (sub_elem == NULL) return NULL;
294
295 struct xt_ddt_tree_elem *elem
296 = xmalloc(sizeof(*elem) + (size_t)count * sizeof (MPI_Aint)
297 + sizeof (struct xt_ddt_tree_elem *));
298
299 elem->displ_count = (size_t)count;
300 elem->extent = extent;
301 elem->type = SINGLE_SUB;
302 MPI_Aint *displs = elem->displs;
303 *(struct xt_ddt_tree_elem **)(displs + count) = sub_elem;
304
305 for (int i = 0; i < count; ++i) displs[i] = displacements[i];
306
307 return elem;
308}
309
310// generates a ddt tree element based on an indexed block style memory layout
312 MPI_Aint extent, int count, int blocklength, int *displacements,
313 MPI_Datatype mpi_ddt) {
314
315 MPI_Aint lb, base_extent;
317 MPI_Type_get_extent(mpi_ddt, &lb, &base_extent), Xt_default_comm);
318
319 MPI_Aint *hdisplacements = xmalloc((size_t)count * sizeof(*hdisplacements));
320 for (int i = 0; i < count; ++i)
321 hdisplacements[i] = (MPI_Aint)displacements[i] * base_extent;
322
323 struct xt_ddt_tree_elem *elem =
325 extent, count, blocklength, hdisplacements, mpi_ddt);
326
327 free(hdisplacements);
328
329 return elem;
330}
331
332// generates a ddt tree element based on a struct style memory layout
334 MPI_Aint extent, int count, int *blocklengths, MPI_Aint *displacements,
335 MPI_Datatype *mpi_ddts) {
336
337 size_t count_ = count > 0 ? (size_t)count : (size_t)0;
338 // remove empty blocks
339 size_t new_count = 0;
340 for (size_t i = 0; i < count_; ++i) {
341
342 MPI_Aint true_lb, true_extent;
344 MPI_Type_get_true_extent(mpi_ddts[i], &true_lb, &true_extent),
345 Xt_default_comm);
346
347 if ((blocklengths[i] != 0) && (true_extent != 0)) {
348
349 if (new_count != count_) {
350
351 blocklengths[new_count] = blocklengths[i];
352 displacements[new_count] = displacements[i];
353 mpi_ddts[new_count] = mpi_ddts[i];
354 }
355
356 ++new_count;
357 } else {
358 free_unnamed_mpi_ddt(mpi_ddts[i]);
359 }
360 }
361 if (new_count != count_) count_ = new_count;
362
363 // if there are no blocks
364 if (count_ == 0) return NULL;
365
366 // if there is only a single block
367 if (count_ == 1)
368 return
370 extent, 1, blocklengths[0], displacements, *mpi_ddts);
371
372 struct xt_ddt_tree_elem *elem
373 = xmalloc(sizeof(*elem) + count_ * sizeof (MPI_Aint)
374 + count_ * sizeof(struct xt_ddt_tree_elem *));
375 elem->displ_count = count_;
376 elem->extent = extent;
377 elem->type = MULTI_SUB;
378 MPI_Aint *displs = elem->displs;
379 struct xt_ddt_tree_elem **sub_elems
380 = (struct xt_ddt_tree_elem **)(displs + count_);
381
382 for (size_t i = 0; i < count_; ++i) {
383 sub_elems[i] = xt_ddt_tree_elem_cont_new(blocklengths[i], mpi_ddts[i]);
384 displs[i] = displacements[i];
385 }
386
387 return elem;
388}
389
390// generate the displacements for a subarray
391// (this routine is recursive)
393 MPI_Aint *displs, MPI_Aint dim_displ,
394 size_t ndim, int *sizes, int *sub_sizes, int *starts, int order,
395 MPI_Aint base_extent) {
396
397 // if the base element is reached
398 if (ndim == 0) {
399 *displs = dim_displ;
400 return;
401 }
402
403 // number of entries in the current dimension and index of the first entry
404 int dim_sub_size, dim_start;
405
406 if (order == MPI_ORDER_FORTRAN) {
407 dim_sub_size = sub_sizes[ndim - 1];
408 dim_start = starts[ndim - 1];
409 } else {
410 dim_sub_size = sub_sizes[0];
411 dim_start = starts[0];
412 sizes += 1;
413 sub_sizes += 1;
414 starts += 1;
415 }
416
417 size_t sub_array_size = 1;
418 MPI_Aint sub_array_extent = base_extent;
419 for (size_t i = 0; i < ndim-1; ++i) {
420 sub_array_size *= (size_t)(sub_sizes[i]);
421 sub_array_extent *= sizes[i];
422 }
423
424 // set current offset to the first entry in the current dimension
425 dim_displ += (MPI_Aint)dim_start * sub_array_extent;
426
427 // for the number of entries in the current dimension
428 for (int i = 0; i < dim_sub_size; ++i) {
429
430 // recursive call for sub dimensions
432 displs, dim_displ, ndim - 1,
433 sizes, sub_sizes, starts, order, base_extent);
434
435 // set to next entry in current dimension
436 displs += sub_array_size;
437 dim_displ += sub_array_extent;
438 }
439}
440
442 MPI_Aint extent, int ndim, int *sizes, int *sub_sizes,
443 int *starts, int order, MPI_Datatype mpi_ddt) {
444
445 struct xt_ddt_tree_elem *sub_elem = mpi_ddt_2_xt_ddt_tree(mpi_ddt, 1);
446
447 // if the sub element is empty
448 if (sub_elem == NULL) return NULL;
449
450 MPI_Aint base_extent = sub_elem->extent;
451
452 size_t displ_count = 1;
453 for (int i = 0; i < ndim; ++i)
454 displ_count *= (size_t)sub_sizes[i];
455
456 struct xt_ddt_tree_elem *elem
457 = xmalloc(sizeof(*elem) + displ_count * sizeof (MPI_Aint)
458 + sizeof (struct xt_ddt_tree_elem *));
459 elem->displ_count = displ_count;
460 elem->extent = extent;
461 elem->type = SINGLE_SUB;
462 MPI_Aint *displs = elem->displs;
463 *(struct xt_ddt_tree_elem **)(displs + displ_count) = sub_elem;
464
466 displs, 0, (size_t)ndim, sizes, sub_sizes, starts, order, base_extent);
467
468 return elem;
469}
470
472 MPI_Aint extent, MPI_Datatype mpi_ddt) {
473
474 struct xt_ddt_tree_elem *elem = mpi_ddt_2_xt_ddt_tree(mpi_ddt, 1);
475 elem->extent = extent;
476
477 return elem;
478}
479
480// generates a ddt tree element from a MPI datatype
481static struct xt_ddt_tree_elem *
482 mpi_ddt_2_xt_ddt_tree(MPI_Datatype mpi_ddt, int free_mpi_ddt) {
483
484 // get parameters for decoding of MPI datatype
485 int num_ints, num_adds, num_dtypes, combiner;
487 MPI_Type_get_envelope(
488 mpi_ddt, &num_ints, &num_adds, &num_dtypes, &combiner), Xt_default_comm);
489 MPI_Datatype oldtype[1];
490
491 // get the extent of the MPI datatype
492 MPI_Aint lb, extent;
493 xt_mpi_call(MPI_Type_get_extent(mpi_ddt, &lb, &extent), Xt_default_comm);
494
495 struct xt_ddt_tree_elem *elem;
496
497 // decode MPI datatype
498 switch (combiner) {
499
500 default: {
501 Xt_abort(
502 Xt_default_comm,
503 "ERROR(mpi_ddt_2_xt_ddt_tree): unsupported combiner type",
504 filename, __LINE__);
505 return NULL;
506 }
507
508 case MPI_COMBINER_NAMED:
509
510 elem = xt_ddt_tree_elem_named_new(extent, mpi_ddt);
511 break;
512
513 case MPI_COMBINER_DUP: {
514
516 MPI_Type_get_contents(
517 mpi_ddt, num_ints, num_adds, num_dtypes,
518 NULL, NULL, oldtype), Xt_default_comm);
519
520 elem = mpi_ddt_2_xt_ddt_tree(oldtype[0], 1);
521 break;
522 }
523
524 case MPI_COMBINER_CONTIGUOUS: {
525
526 int array_of_ints[1];
527
529 MPI_Type_get_contents(
530 mpi_ddt, num_ints, num_adds, num_dtypes,
531 array_of_ints, NULL, oldtype), Xt_default_comm);
532
533 elem =
535 array_of_ints[0], oldtype[0]);
536 break;
537 }
538
539 case MPI_COMBINER_VECTOR: {
540
541 int array_of_ints[3];
542
544 MPI_Type_get_contents(
545 mpi_ddt, num_ints, num_adds, num_dtypes,
546 array_of_ints, NULL, oldtype), Xt_default_comm);
547
548 elem =
550 extent, array_of_ints[0], array_of_ints[1], array_of_ints[2],
551 oldtype[0]);
552 break;
553 }
554
555 case MPI_COMBINER_HVECTOR: {
556
557 int array_of_ints[2];
558 MPI_Aint array_of_adds[1];
559
561 MPI_Type_get_contents(
562 mpi_ddt, num_ints, num_adds, num_dtypes,
563 array_of_ints, array_of_adds, oldtype), Xt_default_comm);
564
565 elem =
567 extent, array_of_ints[0], array_of_ints[1], array_of_adds[0],
568 oldtype[0]);
569 break;
570 }
571 case MPI_COMBINER_INDEXED:{
572
573 int *array_of_ints = xmalloc((size_t)num_ints * sizeof(*array_of_ints));
574
576 MPI_Type_get_contents(
577 mpi_ddt, num_ints, num_adds, num_dtypes,
578 array_of_ints, NULL, oldtype), Xt_default_comm);
579
580 elem =
582 extent, array_of_ints[0],
583 array_of_ints + 1, array_of_ints + 1 + 1 * array_of_ints[0],
584 oldtype[0]);
585
586 free(array_of_ints);
587
588 break;
589 }
590 case MPI_COMBINER_HINDEXED:{
591
592 MPI_Aint *array_of_adds =
593 xmalloc((size_t)num_adds * sizeof(*array_of_adds)
594 + (size_t)num_ints * sizeof(int));
595 int *array_of_ints = (void *)(array_of_adds + num_adds);
596
598 MPI_Type_get_contents(
599 mpi_ddt, num_ints, num_adds, num_dtypes,
600 array_of_ints, array_of_adds, oldtype), Xt_default_comm);
601
602 elem =
604 extent, array_of_ints[0], array_of_ints + 1,
605 array_of_adds, oldtype[0]);
606
607 free(array_of_adds);
608
609 break;
610 }
611 case MPI_COMBINER_INDEXED_BLOCK:{
612
613 int *array_of_ints = xmalloc((size_t)num_ints * sizeof(*array_of_ints));
614
616 MPI_Type_get_contents(
617 mpi_ddt, num_ints, num_adds, num_dtypes,
618 array_of_ints, NULL, oldtype), Xt_default_comm);
619
620 elem =
622 extent, array_of_ints[0], array_of_ints[1], array_of_ints + 2,
623 oldtype[0]);
624
625 free(array_of_ints);
626
627 break;
628 }
629#if MPI_VERSION >= 3
631
632 int array_of_ints[2];
633 MPI_Aint *array_of_adds =
634 xmalloc((size_t)num_adds * sizeof(*array_of_adds));
635
637 MPI_Type_get_contents(
638 mpi_ddt, num_ints, num_adds, num_dtypes,
639 array_of_ints, array_of_adds, oldtype), Xt_default_comm);
640
641 elem =
643 extent, array_of_ints[0], array_of_ints[1], array_of_adds,
644 oldtype[0]);
645
646 free(array_of_adds);
647
648 break;
649 }
650#endif
651 case MPI_COMBINER_STRUCT:{
652
653 MPI_Aint *array_of_adds =
654 xmalloc((size_t)num_adds * sizeof(*array_of_adds)
655 + (size_t)num_dtypes * sizeof(MPI_Datatype)
656 + (size_t)num_ints * sizeof(int));
657 MPI_Datatype *array_of_dtypes = (void *)(array_of_adds + num_adds);
658 int *array_of_ints = (void *)(array_of_dtypes + num_dtypes);
659
661 MPI_Type_get_contents(
662 mpi_ddt, num_ints, num_adds, num_dtypes,
663 array_of_ints, array_of_adds, array_of_dtypes), Xt_default_comm);
664
665 elem =
667 extent, array_of_ints[0], array_of_ints + 1,
668 array_of_adds, array_of_dtypes);
669
670 free(array_of_adds);
671
672 break;
673 }
674 case MPI_COMBINER_SUBARRAY:{
675
676 int *array_of_ints =
677 xmalloc((size_t)num_ints * sizeof(*array_of_ints));
678
680 MPI_Type_get_contents(
681 mpi_ddt, num_ints, num_adds, num_dtypes,
682 array_of_ints, NULL, oldtype), Xt_default_comm);
683
684 elem =
686 extent, array_of_ints[0],
687 array_of_ints + 1 + 0 * array_of_ints[0],
688 array_of_ints + 1 + 1 * array_of_ints[0],
689 array_of_ints + 1 + 2 * array_of_ints[0],
690 array_of_ints[1 + 3 * array_of_ints[0]],
691 oldtype[0]);
692
693 free(array_of_ints);
694
695 break;
696 }
697 case MPI_COMBINER_RESIZED:{
698
699 MPI_Aint array_of_adds[2];
700
702 MPI_Type_get_contents(
703 mpi_ddt, num_ints, num_adds, num_dtypes,
704 NULL, array_of_adds, oldtype), Xt_default_comm);
705
706 elem = xt_ddt_tree_elem_resized_new(extent, oldtype[0]);
707 break;
708 }
709 }
710
711 if ((combiner != MPI_COMBINER_NAMED) && (free_mpi_ddt))
712 xt_mpi_call(MPI_Type_free(&mpi_ddt), Xt_default_comm);
713
714 return elem;
715}
716
717static void xt_ddt_tree_elem_delete(struct xt_ddt_tree_elem *elem) {
718
719 if (elem == NULL) return;
720
721 size_t num_sub_elem = 0;
722 switch (elem->type) {
723 case DTYPE:
724 num_sub_elem = 0;
725 break;
726 case SINGLE_SUB:
727 num_sub_elem = 1;
728 break;
729 case MULTI_SUB:
730 num_sub_elem = elem->displ_count;
731 break;
732# if HAVE_DECL___BUILTIN_UNREACHABLE && !__clang__
733 default:
734 __builtin_unreachable();
735# endif
736 }
737 struct xt_ddt_tree_elem **sub_elems
738 = (struct xt_ddt_tree_elem **)(elem->displs + elem->displ_count);
739 for (size_t i = 0; i < num_sub_elem; ++i)
740 xt_ddt_tree_elem_delete(sub_elems[i]);
741 free(elem);
742}
743
744static void xt_ddt_tree_delete(struct xt_ddt_tree_elem *tree) {
745
746 if (tree != NULL) xt_ddt_tree_elem_delete(tree);
747}
748
749static inline size_t mpi_ddt_to_data_idx(MPI_Datatype mpi_ddt) {
750
751 MPI_Aint true_lb, true_extent;
753 MPI_Type_get_true_extent(mpi_ddt, &true_lb, &true_extent),
754 Xt_default_comm);
755
756 size_t base_pack_size;
757 if (mpi_ddt == MPI_FLOAT_INT)
758 base_pack_size = MAX(sizeof(float), sizeof(int));
759 else
760 base_pack_size = (size_t)true_extent;
761 for (size_t i = 0; i < NUM_VALID_KERNELS; ++i)
762 if (xt_ddt_valid_kernels[i].element_size == (size_t)true_extent
763 && xt_ddt_valid_kernels[i].base_pack_size == base_pack_size)
764 return i;
765 for (size_t i = 0; i < NUM_VALID_KERNELS; ++i)
766 if (xt_ddt_valid_kernels[i].element_size == (size_t)true_extent)
767 return i;
768
769 char err_msg[128];
770 snprintf(
771 err_msg, sizeof(err_msg),
772 "ERROR(mpi_ddt_to_data_idx): unsupported datatype size (%d Byte)",
773 (int)true_extent);
774 Xt_abort(Xt_default_comm, err_msg, filename, __LINE__);
775 return SIZE_MAX;
776}
777
779 struct xt_ddt_tree_elem *elem, MPI_Datatype *prev_dtype,
780 size_t *prev_data_idx, struct xt_ddt_data *data) {
781
782 void *dtype_data = after_displs(elem);
783 size_t displ_count = elem->displ_count;
784 switch (elem->type) {
785
786 case(DTYPE): {
787
788 MPI_Datatype dt = *(MPI_Datatype *)dtype_data;
789 if (dt != *prev_dtype) {
790
791 *prev_dtype = dt;
792 *prev_data_idx = mpi_ddt_to_data_idx(dt);
793 }
794
795 data[*prev_data_idx].displ_count += displ_count;
796 break;
797 }
798 case (SINGLE_SUB): {
799
800 struct xt_ddt_tree_elem *sub_elem
801 = *(struct xt_ddt_tree_elem **)dtype_data;
802
803 if (sub_elem)
804 for (size_t i = 0; i < displ_count; ++i)
806 sub_elem, prev_dtype, prev_data_idx, data);
807 break;
808 }
809 case (MULTI_SUB): {
810
811 struct xt_ddt_tree_elem **sub_elems
812 = (struct xt_ddt_tree_elem **)dtype_data;
813
814 for (size_t i = 0; i < displ_count; ++i)
815 if (sub_elems[i])
817 sub_elems[i], prev_dtype, prev_data_idx, data);
818 break;
819 }
820# if HAVE_DECL___BUILTIN_UNREACHABLE && !__clang__
821 default:
822 __builtin_unreachable();
823# endif
824 }
825}
826
828 struct xt_ddt_tree_elem *tree, struct xt_ddt_data *data) {
829
830 MPI_Datatype prev_dtype = MPI_DATATYPE_NULL;
831 size_t prev_data_idx = SIZE_MAX;
832
833 if (tree != NULL)
835 tree, &prev_dtype, &prev_data_idx, data);
836}
837
839 struct xt_ddt_tree_elem *elem, struct xt_ddt_data *data, MPI_Aint displ,
840 MPI_Datatype *prev_dtype, size_t *prev_data_idx) {
841
842 size_t elem_displ_count = elem->displ_count;
843 MPI_Aint *elem_displs = elem->displs;
844 void *dtype_data = after_displs(elem);
845
846 switch (elem->type) {
847
848 case(DTYPE): {
849
850 MPI_Datatype dt = *(MPI_Datatype *)dtype_data;
851 if (dt != *prev_dtype) {
852
853 *prev_dtype = dt;
854 *prev_data_idx = mpi_ddt_to_data_idx(dt);
855 }
856
857 size_t displ_count = data[*prev_data_idx].displ_count;
858 ssize_t *displs = data[*prev_data_idx].displs[XT_MEMTYPE_HOST];
859 for (size_t i = 0; i < elem_displ_count; ++i, ++displ_count)
860 displs[displ_count] = (ssize_t)displ + (ssize_t)elem_displs[i];
861 data[*prev_data_idx].displ_count = displ_count;
862
863 break;
864 }
865 case (SINGLE_SUB): {
866
867 struct xt_ddt_tree_elem *sub_elem
868 = *(struct xt_ddt_tree_elem **)dtype_data;
869
870 if (sub_elem)
871 for (size_t i = 0; i < elem_displ_count; ++i)
873 sub_elem, data, displ + elem_displs[i],
874 prev_dtype, prev_data_idx);
875 break;
876 }
877 case (MULTI_SUB): {
878
879 struct xt_ddt_tree_elem **sub_elems
880 = (struct xt_ddt_tree_elem **)dtype_data;
881
882 for (size_t i = 0; i < elem_displ_count; ++i)
883 if (sub_elems[i])
885 sub_elems[i], data, displ + elem_displs[i],
886 prev_dtype, prev_data_idx);
887 break;
888 }
889# if HAVE_DECL___BUILTIN_UNREACHABLE && !__clang__
890 default:
891 __builtin_unreachable();
892# endif
893 }
894}
895
897 struct xt_ddt_tree_elem *tree, struct xt_ddt_data *data) {
898
899 MPI_Aint displ = 0;
900 MPI_Datatype prev_dtype = MPI_DATATYPE_NULL;
901 size_t prev_data_idx = SIZE_MAX;
902
903 if (tree != NULL)
905 tree, data, displ, &prev_dtype, &prev_data_idx);
906}
907
908static int compare_kernels(const void * a, const void * b) {
909 struct xt_ddt_kernels const * k_a = (struct xt_ddt_kernels const *)a;
910 struct xt_ddt_kernels const * k_b = (struct xt_ddt_kernels const *)b;
911
912 int kcmp = (k_a->base_pack_size < k_b->base_pack_size)
913 - (k_a->base_pack_size > k_b->base_pack_size);
914 if (!kcmp)
915 kcmp = (k_a->element_size < k_b->element_size)
916 - (k_a->element_size > k_b->element_size);
917 return kcmp;
918}
919
920static Xt_ddt xt_ddt_new(MPI_Datatype mpi_ddt) {
921
922 static bool sort_kernels = true;
923 if (sort_kernels) {
924 assert(NUM_VALID_KERNELS
925 == sizeof(xt_ddt_valid_kernels)/sizeof(xt_ddt_valid_kernels[0]));
926
927 // sort the supported kernels by their base_pack_size (this
928 // avoids alignment issues when packing)
931 sort_kernels = false;
932 }
933
934
935 // parse the MPI datatype
936 struct xt_ddt_tree_elem *tree = mpi_ddt_2_xt_ddt_tree(mpi_ddt, 0);
937
938 struct xt_ddt_data data[NUM_VALID_KERNELS];
939 for (size_t i = 0; i < NUM_VALID_KERNELS; ++i) {
940 data[i].kernel_idx = i;
941 data[i].displ_count = 0;
942 for (int j = 0; j < XT_MEMTYPE_COUNT; ++j) data[i].displs[j] = NULL;
943 }
944
945 // determine the number of displacements for each elemental data size
946 xt_ddt_tree_get_data_sizes(tree, data);
947
948 // compute the total number of elemental data
949 size_t total_displs_size = 0;
950 size_t data_count = 0;
951 size_t pack_size = 0;
952 for (size_t i = 0; i < NUM_VALID_KERNELS; ++i) {
953 total_displs_size += data[i].displ_count;
954 if (data[i].displ_count > 0) {
955 pack_size +=
957 ++data_count;
958 }
959 }
960
961 Xt_ddt ddt = xmalloc(1 * sizeof(*ddt) + data_count * sizeof(ddt->data[0]));
962 ddt->ref_count = 1;
963 ddt->count = data_count;
964 ddt->pack_size = pack_size;
965 for (int i = 0; i < XT_MEMTYPE_COUNT; ++i) ddt->displs_available[i] = 0;
967
968 if (total_displs_size > 0) {
969
970 // allocate memory for all displacements
971 ssize_t *displs =
972 xt_gpu_malloc(total_displs_size * sizeof(*displs), XT_MEMTYPE_HOST);
973
974 for (size_t i = 0, offset = 0; i < NUM_VALID_KERNELS; ++i) {
975 data[i].displs[XT_MEMTYPE_HOST] = displs + offset;
976 offset += data[i].displ_count;
977 data[i].displ_count = 0;
978 }
979
980 // determine all displacements
981 xt_ddt_tree_to_data(tree, data);
982
983 for (int i = 0, j = 0; i < NUM_VALID_KERNELS; ++i)
984 if (data[i].displ_count > 0)
985 ddt->data[j++] = data[i];
986 }
987
988 // free internal representation of MPI datatype
989 xt_ddt_tree_delete(tree);
990
991 return ddt;
992}
993
995
996 ddt->ref_count++;
997}
998
1000
1001 if (ddt == NULL) return;
1002
1003 ddt->ref_count--;
1004
1005 if (ddt->ref_count) return;
1006
1007 // only the displacements of the first entry needs to be freed, all other
1008 // are part of the same allocation
1009 if (ddt->count > 0) {
1010 for (int i = 0; i < XT_MEMTYPE_COUNT; ++i) {
1011 if (ddt->displs_available[i]) {
1012 xt_gpu_free(ddt->data[0].displs[i], (enum xt_memtype)i);
1013 }
1014 }
1015 }
1016 free(ddt);
1017}
1018
1019/* attribute handle for attaching xt_ddt objects to MPI datatypes */
1020static int xt_ddt_internal_keyval = MPI_KEYVAL_INVALID;
1021
1022/* attribute attached MPI_COMM_SELF which cleans up
1023 * xt_mpi_datatype_ddt_internal_keyval when finalize is called */
1024static int xt_ddt_cleanup_internal_keyval = MPI_KEYVAL_INVALID;
1025
1027 MPI_Datatype XT_UNUSED(dtype), int XT_UNUSED(dtype_keyval),
1028 void *XT_UNUSED(extra_state), void *attribute_val_in,
1029 void *attribute_val_out, int *flag) {
1030
1031 xt_ddt_inc_ref_count((Xt_ddt)attribute_val_in);
1032 *(Xt_ddt*)attribute_val_out = (Xt_ddt)attribute_val_in;
1033 *flag = 1;
1034 return MPI_SUCCESS;
1035}
1036
1038 MPI_Datatype XT_UNUSED(dtype), int XT_UNUSED(dtype_keyval),
1039 void *attribute_val, void *XT_UNUSED(extra_state)) {
1040
1041 xt_ddt_delete((Xt_ddt)attribute_val);
1042 return MPI_SUCCESS;
1043}
1044
1046 MPI_Comm comm, int XT_UNUSED(dtype_keyval),
1047 void *XT_UNUSED(attribute_val), void *XT_UNUSED(extra_state))
1048{
1049
1050 if (xt_ddt_internal_keyval != MPI_KEYVAL_INVALID) {
1052 MPI_Type_free_keyval(&xt_ddt_internal_keyval), comm);
1053 xt_ddt_internal_keyval = MPI_KEYVAL_INVALID;
1054 }
1055
1057 MPI_Comm_free_keyval(&xt_ddt_cleanup_internal_keyval), comm);
1058 xt_ddt_cleanup_internal_keyval = MPI_KEYVAL_INVALID;
1059
1060 return MPI_SUCCESS;
1061}
1062
1063Xt_ddt xt_ddt_from_mpi_ddt(MPI_Datatype mpi_ddt) {
1064
1066
1067 // if xt_ddt_internal_keyval has not yet been created
1068 if (xt_ddt_internal_keyval == MPI_KEYVAL_INVALID) {
1069
1070 // create keyval that will store xt_ddt's in MPI_Datatype's
1072 MPI_Type_create_keyval(
1073 // MPI_TYPE_NULL_COPY_FN,
1076 &xt_ddt_internal_keyval, NULL),
1077 Xt_default_comm);
1078
1079 // register a callback in MPI_Finalize (via an attribute to MPI_COMM_SELF)
1080 // to clean up xt_ddt_internal_keyval
1082 MPI_Comm_create_keyval(
1083 MPI_COMM_NULL_COPY_FN,
1086 Xt_default_comm);
1088 MPI_Comm_set_attr(
1089 MPI_COMM_SELF, xt_ddt_cleanup_internal_keyval, NULL),
1090 Xt_default_comm);
1091 }
1092
1093 Xt_ddt ddt;
1094 // get xt_ddt from MPI datatype, if available
1095 void *attr;
1096 int flag;
1098 MPI_Type_get_attr(
1099 mpi_ddt, xt_ddt_internal_keyval, &attr, &flag), Xt_default_comm);
1100
1101 // if the MPI datatype had already a xt_ddt attached to itself
1102 if (flag) {
1103 ddt = attr;
1104 } else {
1105 // generate a xt_ddt from the MPI datatype
1106 ddt = xt_ddt_new(mpi_ddt);
1107
1108 // attach this xt_ddt to the MPI datatype for later use
1110 MPI_Type_set_attr(
1111 mpi_ddt, xt_ddt_internal_keyval, ddt), Xt_default_comm);
1112 }
1114 return ddt;
1115}
1116
1117/*
1118 * Local Variables:
1119 * c-basic-offset: 2
1120 * coding: utf-8
1121 * indent-tabs-mode: nil
1122 * show-trailing-whitespace: t
1123 * require-trailing-newline: t
1124 * End:
1125 */
int MPI_Comm
Definition core.h:64
#define XT_UNUSED(x)
Definition core.h:84
add versions of standard API functions not returning on error
#define xrealloc(ptr, size)
Definition ppm_xfuncs.h:71
#define xmalloc(size)
Definition ppm_xfuncs.h:70
size_t count
size_t pack_size
int displs_available[XT_MEMTYPE_COUNT]
struct xt_ddt_data data[]
ssize_t * displs[XT_MEMTYPE_COUNT]
enum xt_ddt_tree_elem::@8 type
MPI_Aint displs[]
int MPI_Type_free(MPI_Datatype *datatype)
struct xt_ddt_kernels xt_ddt_valid_kernels[]
Definition xt_ddt.c:127
static void xt_ddt_tree_to_data(struct xt_ddt_tree_elem *tree, struct xt_ddt_data *data)
static void xt_ddt_tree_elem_get_data_sizes(struct xt_ddt_tree_elem *elem, MPI_Datatype *prev_dtype, size_t *prev_data_idx, struct xt_ddt_data *data)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_indexed_block_new(MPI_Aint extent, int count, int blocklength, int *displacements, MPI_Datatype mpi_ddt)
static const char filename[]
static void xt_ddt_tree_elem_subarray_get_displs(MPI_Aint *displs, MPI_Aint dim_displ, size_t ndim, int *sizes, int *sub_sizes, int *starts, int order, MPI_Aint base_extent)
void xt_ddt_delete(Xt_ddt ddt)
static int xt_ddt_cleanup_internal_keyval
void xt_ddt_inc_ref_count(Xt_ddt ddt)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_indexed_new(MPI_Aint extent, int count, int *blocklengths, int *displacements, MPI_Datatype mpi_ddt)
static void * after_displs(struct xt_ddt_tree_elem *elem)
static struct xt_ddt_tree_elem * mpi_ddt_2_xt_ddt_tree(MPI_Datatype mpi_ddt, int free_mpi_ddt)
static void xt_ddt_tree_elem_to_data(struct xt_ddt_tree_elem *elem, struct xt_ddt_data *data, MPI_Aint displ, MPI_Datatype *prev_dtype, size_t *prev_data_idx)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_hvector_new(MPI_Aint extent, int count, int blocklength, MPI_Aint stride, MPI_Datatype mpi_ddt)
static void xt_ddt_tree_elem_delete(struct xt_ddt_tree_elem *elem)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_hindexed_new(MPI_Aint extent, int count, int *blocklengths, MPI_Aint *displacements, MPI_Datatype mpi_ddt)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_vector_new(MPI_Aint extent, int count, int blocklength, int stride, MPI_Datatype mpi_ddt)
Xt_ddt xt_ddt_from_mpi_ddt(MPI_Datatype mpi_ddt)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_resized_new(MPI_Aint extent, MPI_Datatype mpi_ddt)
static int xt_ddt_internal_keyval
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_hindexed_block_new(MPI_Aint extent, int count, int blocklength, MPI_Aint *displacements, MPI_Datatype mpi_ddt)
static int xt_ddt_cleanup_internal_keyval_delete(MPI_Comm comm, int XT_UNUSED(dtype_keyval), void *XT_UNUSED(attribute_val), void *XT_UNUSED(extra_state))
static size_t mpi_ddt_to_data_idx(MPI_Datatype mpi_ddt)
static Xt_ddt xt_ddt_new(MPI_Datatype mpi_ddt)
static int xt_ddt_internal_keyval_copy(MPI_Datatype XT_UNUSED(dtype), int XT_UNUSED(dtype_keyval), void *XT_UNUSED(extra_state), void *attribute_val_in, void *attribute_val_out, int *flag)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_cont_new(int count, MPI_Datatype mpi_ddt)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_named_new(MPI_Aint extent, MPI_Datatype mpi_ddt)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_subarray_new(MPI_Aint extent, int ndim, int *sizes, int *sub_sizes, int *starts, int order, MPI_Datatype mpi_ddt)
static struct xt_ddt_tree_elem * xt_ddt_tree_elem_struct_new(MPI_Aint extent, int count, int *blocklengths, MPI_Aint *displacements, MPI_Datatype *mpi_ddts)
static int xt_ddt_internal_keyval_delete(MPI_Datatype XT_UNUSED(dtype), int XT_UNUSED(dtype_keyval), void *attribute_val, void *XT_UNUSED(extra_state))
static int compare_kernels(const void *a, const void *b)
static void xt_ddt_tree_delete(struct xt_ddt_tree_elem *tree)
static void free_unnamed_mpi_ddt(MPI_Datatype mpi_ddt)
#define MAX(a, b)
static void xt_ddt_tree_get_data_sizes(struct xt_ddt_tree_elem *tree, struct xt_ddt_data *data)
internal utility routines for manual handling of MPI DDT's
@ NUM_VALID_KERNELS
void * xt_gpu_malloc(size_t alloc_size, enum xt_memtype memtype)
Definition xt_gpu.c:183
void xt_gpu_free(void *ptr, enum xt_memtype memtype)
Definition xt_gpu.c:187
#define XT_GPU_INSTR_POP
Definition xt_gpu.h:60
xt_memtype
Definition xt_gpu.h:68
@ XT_MEMTYPE_HOST
Definition xt_gpu.h:69
@ XT_MEMTYPE_COUNT
Definition xt_gpu.h:71
#define XT_GPU_INSTR_PUSH(arg)
Definition xt_gpu.h:59
utility routines for MPI
#define xt_mpi_call(call, comm)
Definition xt_mpi.h:68
@ MPI_COMBINER_HINDEXED_BLOCK