Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot/simgrid/simgrid
[simgrid.git] / teshsuite / smpi / mpich3-test / datatype / contents.c
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  *  (C) 2001 by Argonne National Laboratory.
4  *      See COPYRIGHT in top-level directory.
5  */
6 #include "mpi.h"
7 #include "mpitestconf.h"
8 #if HAVE_UNISTD_H
9 #include <unistd.h>
10 #endif
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 static int verbose = 0;
15
16 /* tests */
17 int builtin_float_test(void);
18 int vector_of_vectors_test(void);
19 int optimizable_vector_of_basics_test(void);
20 int indexed_of_basics_test(void);
21 int indexed_of_vectors_test(void);
22 int struct_of_basics_test(void);
23
24 /* helper functions */
25 char *combiner_to_string(int combiner);
26 int parse_args(int argc, char **argv);
27
28 int main(int argc, char **argv)
29 {
30     int err, errs = 0;
31
32     MPI_Init(&argc, &argv); /* MPI-1.2 doesn't allow for MPI_Init(0,0) */
33     parse_args(argc, argv);
34
35     /* To improve reporting of problems about operations, we
36        change the error handler to errors return */
37     MPI_Comm_set_errhandler( MPI_COMM_WORLD, MPI_ERRORS_RETURN );
38
39     /* perform some tests */
40     err = builtin_float_test();
41     errs += err;
42     if (err) {
43         fprintf(stderr, "Found %d errors in builtin float test.\n", err);
44     }
45
46     err = vector_of_vectors_test();
47     errs += err;
48     if (err) {
49         fprintf(stderr, "Found %d errors in vector of vectors test.\n", err);
50     }
51
52     err = optimizable_vector_of_basics_test();
53     errs += err;
54     if (err) {
55         fprintf(stderr, "Found %d errors in vector of basics test.\n", err);
56     }
57
58     err = indexed_of_basics_test();
59     errs += err;
60     if (err) {
61         fprintf(stderr, "Found %d errors in indexed of basics test.\n", err);
62     }
63
64     err = indexed_of_vectors_test();
65     errs += err;
66     if (err) {
67         fprintf(stderr, "Found %d errors in indexed of vectors test.\n", err);
68     }
69
70 #ifdef HAVE_MPI_TYPE_CREATE_STRUCT
71     err = struct_of_basics_test();
72     errs += err;
73 #endif
74
75     /* print message and exit */
76     if (errs) {
77         fprintf(stderr, "Found %d errors\n", errs);
78     }
79     else {
80         printf(" No Errors\n");
81     }
82     MPI_Finalize();
83     return 0;
84 }
85
86 /* builtin_float_test()
87  *
88  * Tests functionality of get_envelope() and get_contents() on a MPI_FLOAT.
89  *
90  * Returns the number of errors encountered.
91  */
92 int builtin_float_test(void)
93 {
94     int nints, nadds, ntypes, combiner;
95
96     int /* err, */ errs = 0;
97
98     /* err = */ MPI_Type_get_envelope(MPI_FLOAT,
99                                 &nints,
100                                 &nadds,
101                                 &ntypes,
102                                 &combiner);
103     
104     if (combiner != MPI_COMBINER_NAMED) errs++;
105     if (verbose && combiner != MPI_COMBINER_NAMED)
106         fprintf(stderr, "combiner = %s; should be named\n", 
107                 combiner_to_string(combiner));
108
109     /* Note: it is erroneous to call MPI_Type_get_contents() on a basic. */
110     return errs;
111 }
112
113 /* vector_of_vectors_test()
114  *
115  * Builds a vector of a vector of ints.  Assuming an int array of size 9 
116  * integers, and treating the array as a 3x3 2D array, this will grab the 
117  * corners.
118  *
119  * Returns the number of errors encountered.
120  */
121 int vector_of_vectors_test(void)
122 {
123     MPI_Datatype inner_vector, inner_vector_copy;
124     MPI_Datatype outer_vector;
125
126     int nints, nadds, ntypes, combiner, *ints;
127     MPI_Aint *adds = NULL;
128     MPI_Datatype *types;
129
130     int err, errs = 0;
131
132     /* set up type */
133     err = MPI_Type_vector(2,
134                           1,
135                           2,
136                           MPI_INT,
137                           &inner_vector);
138     if (err != MPI_SUCCESS) {
139         if (verbose) fprintf(stderr, 
140                              "error in MPI call; aborting after %d errors\n",
141                              errs+1);
142         return errs+1;
143     }
144
145     err = MPI_Type_vector(2,
146                           1,
147                           2,
148                           inner_vector,
149                           &outer_vector);
150     if (err != MPI_SUCCESS) {
151         if (verbose) fprintf(stderr, 
152                              "error in MPI call; aborting after %d errors\n",
153                              errs+1);
154         return errs+1;
155     }
156
157     /* decode outer vector (get envelope, then contents) */
158     err = MPI_Type_get_envelope(outer_vector,
159                                 &nints,
160                                 &nadds,
161                                 &ntypes,
162                                 &combiner);
163     if (err != MPI_SUCCESS) {
164         if (verbose) fprintf(stderr, 
165                              "error in MPI call; aborting after %d errors\n",
166                              errs+1);
167         return errs+1;
168     }
169
170     if (nints != 3) errs++;
171     if (nadds != 0) errs++;
172     if (ntypes != 1) errs++;
173     if (combiner != MPI_COMBINER_VECTOR) errs++;
174
175     if (verbose) {
176         if (nints != 3) fprintf(stderr, 
177                                 "outer vector nints = %d; should be 3\n",
178                                 nints);
179         if (nadds != 0) fprintf(stderr, 
180                                 "outer vector nadds = %d; should be 0\n",
181                                 nadds);
182         if (ntypes != 1) fprintf(stderr, 
183                                  "outer vector ntypes = %d; should be 1\n",
184                                  ntypes);
185         if (combiner != MPI_COMBINER_VECTOR)
186             fprintf(stderr, "outer vector combiner = %s; should be vector\n",
187                     combiner_to_string(combiner));
188     }
189     if (errs) {
190         if (verbose) fprintf(stderr, "aborting after %d errors\n", errs);
191         return errs;
192     }
193
194     ints = malloc(nints * sizeof(*ints));
195     if (nadds) adds = malloc(nadds * sizeof(*adds));
196     types = malloc(ntypes * sizeof(*types));
197
198     /* get contents of outer vector */
199     err = MPI_Type_get_contents(outer_vector,
200                                 nints,
201                                 nadds,
202                                 ntypes,
203                                 ints,
204                                 adds,
205                                 types);
206
207     if (ints[0] != 2) errs++;
208     if (ints[1] != 1) errs++;
209     if (ints[2] != 2) errs++;
210
211     if (verbose) {
212         if (ints[0] != 2) fprintf(stderr, 
213                                   "outer vector count = %d; should be 2\n",
214                                   ints[0]);
215         if (ints[1] != 1) fprintf(stderr,
216                                   "outer vector blocklength = %d; should be 1\n",
217                                   ints[1]);
218         if (ints[2] != 2) fprintf(stderr, "outer vector stride = %d; should be 2\n",
219                                   ints[2]);
220     }
221     if (errs) {
222         if (verbose) fprintf(stderr, "aborting after %d errors\n", errs);
223         return errs;
224     }
225
226     inner_vector_copy = types[0];
227     free(ints);
228     if (nadds) free(adds);
229     free(types);
230
231     /* decode inner vector */
232     err = MPI_Type_get_envelope(inner_vector_copy,
233                                 &nints,
234                                 &nadds,
235                                 &ntypes,
236                                 &combiner);
237     if (err != MPI_SUCCESS) {
238         if (verbose) fprintf(stderr, 
239                              "error in MPI call; aborting after %d errors\n",
240                              errs+1);
241         return errs+1;
242     }
243
244     if (nints != 3) errs++;
245     if (nadds != 0) errs++;
246     if (ntypes != 1) errs++;
247     if (combiner != MPI_COMBINER_VECTOR) errs++;
248
249     if (verbose) {
250         if (nints != 3) fprintf(stderr, 
251                                 "inner vector nints = %d; should be 3\n",
252                                 nints);
253         if (nadds != 0) fprintf(stderr, 
254                                 "inner vector nadds = %d; should be 0\n",
255                                 nadds);
256         if (ntypes != 1) fprintf(stderr, 
257                                  "inner vector ntypes = %d; should be 1\n",
258                                  ntypes);
259         if (combiner != MPI_COMBINER_VECTOR)
260             fprintf(stderr, "inner vector combiner = %s; should be vector\n",
261                     combiner_to_string(combiner));
262     }
263     if (errs) {
264         if (verbose) fprintf(stderr, "aborting after %d errors\n", errs);
265         return errs;
266     }
267
268     ints = malloc(nints * sizeof(*ints));
269     if (nadds) adds = malloc(nadds * sizeof(*adds));
270     types = malloc(ntypes * sizeof(*types));
271
272     err = MPI_Type_get_contents(inner_vector_copy,
273                                 nints,
274                                 nadds,
275                                 ntypes,
276                                 ints,
277                                 adds,
278                                 types);
279
280     if (ints[0] != 2) errs++;
281     if (ints[1] != 1) errs++;
282     if (ints[2] != 2) errs++;
283
284     if (verbose) {
285         if (ints[0] != 2) fprintf(stderr, 
286                                   "inner vector count = %d; should be 2\n",
287                                   ints[0]);
288         if (ints[1] != 1) fprintf(stderr,
289                                   "inner vector blocklength = %d; should be 1\n",
290                                   ints[1]);
291         if (ints[2] != 2) fprintf(stderr, 
292                                   "inner vector stride = %d; should be 2\n",
293                                   ints[2]);
294     }
295     if (errs) {
296         if (verbose) fprintf(stderr, "aborting after %d errors\n", errs);
297         return errs;
298     }
299
300     free(ints);
301     if (nadds) free(adds);
302     free(types);
303
304     MPI_Type_free( &inner_vector_copy );
305     MPI_Type_free( &inner_vector );
306     MPI_Type_free( &outer_vector );
307
308     return 0;
309 }
310
311 /* optimizable_vector_of_basics_test()
312  *
313  * Builds a vector of ints.  Count is 10, blocksize is 2, stride is 2, so this
314  * is equivalent to a contig of 20.  But remember...we should get back our
315  * suboptimal values under MPI-2.
316  *
317  * Returns the number of errors encountered.
318  */
319 int optimizable_vector_of_basics_test(void)
320 {
321     MPI_Datatype parent_type;
322
323     int nints, nadds, ntypes, combiner, *ints;
324     MPI_Aint *adds = NULL;
325     MPI_Datatype *types;
326
327     int /* err, */ errs = 0;
328
329     /* set up type */
330     /* err = */ MPI_Type_vector(10,
331                           2,
332                           2,
333                           MPI_INT,
334                           &parent_type);
335
336     /* decode */
337     /* err = */ MPI_Type_get_envelope(parent_type,
338                                 &nints,
339                                 &nadds,
340                                 &ntypes,
341                                 &combiner);
342
343     if (nints != 3) errs++;
344     if (nadds != 0) errs++;
345     if (ntypes != 1) errs++;
346     if (combiner != MPI_COMBINER_VECTOR) errs++;
347
348     if (verbose) {
349         if (nints != 3) fprintf(stderr, "nints = %d; should be 3\n", nints);
350         if (nadds != 0) fprintf(stderr, "nadds = %d; should be 0\n", nadds);
351         if (ntypes != 1) fprintf(stderr, "ntypes = %d; should be 1\n", ntypes);
352         if (combiner != MPI_COMBINER_VECTOR)
353             fprintf(stderr, "combiner = %s; should be vector\n",
354                     combiner_to_string(combiner));
355     }
356
357     ints = malloc(nints * sizeof(*ints));
358     if (nadds) adds = malloc(nadds * sizeof(*adds));
359     types = malloc(ntypes *sizeof(*types));
360
361     /* err = */ MPI_Type_get_contents(parent_type,
362                                 nints,
363                                 nadds,
364                                 ntypes,
365                                 ints,
366                                 adds,
367                                 types);
368
369     if (ints[0] != 10) errs++;
370     if (ints[1] != 2) errs++;
371     if (ints[2] != 2) errs++;
372     if (types[0] != MPI_INT) errs++;
373
374     if (verbose) {
375         if (ints[0] != 10) fprintf(stderr, "count = %d; should be 10\n",
376                                    ints[0]);
377         if (ints[1] != 2) fprintf(stderr, "blocklength = %d; should be 2\n",
378                                   ints[1]);
379         if (ints[2] != 2) fprintf(stderr, "stride = %d; should be 2\n",
380                                   ints[2]);
381         if (types[0] != MPI_INT) fprintf(stderr, "type is not MPI_INT\n");
382     }
383
384     free(ints);
385     if (nadds) free(adds);
386     free(types);
387
388     MPI_Type_free( &parent_type );
389
390     return errs;
391 }
392
393
394 /* indexed_of_basics_test(void)
395  *
396  * Simple indexed type.
397  *
398  * Returns number of errors encountered.
399  */
400 int indexed_of_basics_test(void)
401 {
402     MPI_Datatype parent_type;
403     int s_count = 3, s_blocklengths[3] = { 3, 2, 1 };
404     int s_displacements[3] = { 10, 20, 30 };
405
406     int nints, nadds, ntypes, combiner, *ints;
407     MPI_Aint *adds = NULL;
408     MPI_Datatype *types;
409
410     int /* err, */ errs = 0;
411
412     /* set up type */
413     /* err = */ MPI_Type_indexed(s_count,
414                            s_blocklengths,
415                            s_displacements,
416                            MPI_INT,
417                            &parent_type);
418
419     /* decode */
420     /* err = */ MPI_Type_get_envelope(parent_type,
421                                 &nints,
422                                 &nadds,
423                                 &ntypes,
424                                 &combiner);
425
426     if (nints != 7) errs++;
427     if (nadds != 0) errs++;
428     if (ntypes != 1) errs++;
429     if (combiner != MPI_COMBINER_INDEXED) errs++;
430
431     if (verbose) {
432         if (nints != 7) fprintf(stderr, "nints = %d; should be 7\n", nints);
433         if (nadds != 0) fprintf(stderr, "nadds = %d; should be 0\n", nadds);
434         if (ntypes != 1) fprintf(stderr, "ntypes = %d; should be 1\n", ntypes);
435         if (combiner != MPI_COMBINER_INDEXED)
436             fprintf(stderr, "combiner = %s; should be indexed\n",
437                     combiner_to_string(combiner));
438     }
439
440     ints = malloc(nints * sizeof(*ints));
441     if (nadds) adds = malloc(nadds * sizeof(*adds));
442     types = malloc(ntypes *sizeof(*types));
443
444     /* err = */ MPI_Type_get_contents(parent_type,
445                                 nints,
446                                 nadds,
447                                 ntypes,
448                                 ints,
449                                 adds,
450                                 types);
451
452     if (ints[0] != s_count) errs++;
453     if (ints[1] != s_blocklengths[0]) errs++;
454     if (ints[2] != s_blocklengths[1]) errs++;
455     if (ints[3] != s_blocklengths[2]) errs++;
456     if (ints[4] != s_displacements[0]) errs++;
457     if (ints[5] != s_displacements[1]) errs++;
458     if (ints[6] != s_displacements[2]) errs++;
459     if (types[0] != MPI_INT) errs++;
460
461     if (verbose) {
462         if (ints[0] != s_count) 
463             fprintf(stderr, "count = %d; should be %d\n", ints[0], s_count);
464         if (ints[1] != s_blocklengths[0]) 
465             fprintf(stderr, "blocklength[0] = %d; should be %d\n", ints[1], s_blocklengths[0]);
466         if (ints[2] != s_blocklengths[1]) 
467             fprintf(stderr, "blocklength[1] = %d; should be %d\n", ints[2], s_blocklengths[1]);
468         if (ints[3] != s_blocklengths[2]) 
469             fprintf(stderr, "blocklength[2] = %d; should be %d\n", ints[3], s_blocklengths[2]);
470         if (ints[4] != s_displacements[0]) 
471             fprintf(stderr, "displacement[0] = %d; should be %d\n", ints[4], s_displacements[0]);
472         if (ints[5] != s_displacements[1]) 
473             fprintf(stderr, "displacement[1] = %d; should be %d\n", ints[5], s_displacements[1]);
474         if (ints[6] != s_displacements[2]) 
475             fprintf(stderr, "displacement[2] = %d; should be %d\n", ints[6], s_displacements[2]);
476         if (types[0] != MPI_INT) fprintf(stderr, "type[0] does not match\n");
477     }
478
479     free(ints);
480     if (nadds) free(adds);
481     free(types);
482
483     MPI_Type_free( &parent_type );
484     return errs;
485 }
486
487 /* indexed_of_vectors_test()
488  *
489  * Builds an indexed type of vectors of ints.
490  *
491  * Returns the number of errors encountered.
492  */
493 int indexed_of_vectors_test(void)
494 {
495     MPI_Datatype inner_vector, inner_vector_copy;
496     MPI_Datatype outer_indexed;
497     
498     int i_count = 3, i_blocklengths[3] = { 3, 2, 1 };
499     int i_displacements[3] = { 10, 20, 30 };
500
501     int nints, nadds, ntypes, combiner, *ints;
502     MPI_Aint *adds = NULL;
503     MPI_Datatype *types;
504
505     int err, errs = 0;
506
507     /* set up type */
508     err = MPI_Type_vector(2,
509                           1,
510                           2,
511                           MPI_INT,
512                           &inner_vector);
513     if (err != MPI_SUCCESS) {
514         if (verbose) fprintf(stderr, 
515                              "error in MPI call; aborting after %d errors\n",
516                              errs+1);
517         return errs+1;
518     }
519
520     err = MPI_Type_indexed(i_count,
521                            i_blocklengths,
522                            i_displacements,
523                            inner_vector,
524                            &outer_indexed);
525     if (err != MPI_SUCCESS) {
526         if (verbose) fprintf(stderr, 
527                              "error in MPI call; aborting after %d errors\n",
528                              errs+1);
529         return errs+1;
530     }
531
532     /* decode outer vector (get envelope, then contents) */
533     err = MPI_Type_get_envelope(outer_indexed,
534                                 &nints,
535                                 &nadds,
536                                 &ntypes,
537                                 &combiner);
538     if (err != MPI_SUCCESS) {
539         if (verbose) fprintf(stderr, 
540                              "error in MPI call; aborting after %d errors\n",
541                              errs+1);
542         return errs+1;
543     }
544
545     if (nints != 7) errs++;
546     if (nadds != 0) errs++;
547     if (ntypes != 1) errs++;
548     if (combiner != MPI_COMBINER_INDEXED) errs++;
549
550     if (verbose) {
551         if (nints != 7) fprintf(stderr, "nints = %d; should be 7\n", nints);
552         if (nadds != 0) fprintf(stderr, "nadds = %d; should be 0\n", nadds);
553         if (ntypes != 1) fprintf(stderr, "ntypes = %d; should be 1\n", ntypes);
554         if (combiner != MPI_COMBINER_INDEXED)
555             fprintf(stderr, "combiner = %s; should be indexed\n",
556                     combiner_to_string(combiner));
557     }
558
559     if (errs) {
560         if (verbose) fprintf(stderr, "aborting after %d errors\n", errs);
561         return errs;
562     }
563
564     ints = malloc(nints * sizeof(*ints));
565     if (nadds) adds = malloc(nadds * sizeof(*adds));
566     types = malloc(ntypes * sizeof(*types));
567
568     /* get contents of outer vector */
569     err = MPI_Type_get_contents(outer_indexed,
570                                 nints,
571                                 nadds,
572                                 ntypes,
573                                 ints,
574                                 adds,
575                                 types);
576
577     if (ints[0] != i_count) errs++;
578     if (ints[1] != i_blocklengths[0]) errs++;
579     if (ints[2] != i_blocklengths[1]) errs++;
580     if (ints[3] != i_blocklengths[2]) errs++;
581     if (ints[4] != i_displacements[0]) errs++;
582     if (ints[5] != i_displacements[1]) errs++;
583     if (ints[6] != i_displacements[2]) errs++;
584
585     if (verbose) {
586         if (ints[0] != i_count) 
587             fprintf(stderr, "count = %d; should be %d\n", ints[0], i_count);
588         if (ints[1] != i_blocklengths[0]) 
589             fprintf(stderr, "blocklength[0] = %d; should be %d\n", ints[1], i_blocklengths[0]);
590         if (ints[2] != i_blocklengths[1]) 
591             fprintf(stderr, "blocklength[1] = %d; should be %d\n", ints[2], i_blocklengths[1]);
592         if (ints[3] != i_blocklengths[2]) 
593             fprintf(stderr, "blocklength[2] = %d; should be %d\n", ints[3], i_blocklengths[2]);
594         if (ints[4] != i_displacements[0]) 
595             fprintf(stderr, "displacement[0] = %d; should be %d\n", ints[4], i_displacements[0]);
596         if (ints[5] != i_displacements[1]) 
597             fprintf(stderr, "displacement[1] = %d; should be %d\n", ints[5], i_displacements[1]);
598         if (ints[6] != i_displacements[2]) 
599             fprintf(stderr, "displacement[2] = %d; should be %d\n", ints[6], i_displacements[2]);
600     }
601
602     if (errs) {
603         if (verbose) fprintf(stderr, "aborting after %d errors\n", errs);
604         return errs;
605     }
606
607     inner_vector_copy = types[0];
608     free(ints);
609     if (nadds) free(adds);
610     free(types);
611
612     /* decode inner vector */
613     err = MPI_Type_get_envelope(inner_vector_copy,
614                                 &nints,
615                                 &nadds,
616                                 &ntypes,
617                                 &combiner);
618     if (err != MPI_SUCCESS) {
619         if (verbose) fprintf(stderr, 
620                              "error in MPI call; aborting after %d errors\n",
621                              errs+1);
622         return errs+1;
623     }
624
625     if (nints != 3) errs++;
626     if (nadds != 0) errs++;
627     if (ntypes != 1) errs++;
628     if (combiner != MPI_COMBINER_VECTOR) errs++;
629
630     if (verbose) {
631         if (nints != 3) fprintf(stderr, 
632                                 "inner vector nints = %d; should be 3\n",
633                                 nints);
634         if (nadds != 0) fprintf(stderr, 
635                                 "inner vector nadds = %d; should be 0\n",
636                                 nadds);
637         if (ntypes != 1) fprintf(stderr, 
638                                  "inner vector ntypes = %d; should be 1\n",
639                                  ntypes);
640         if (combiner != MPI_COMBINER_VECTOR)
641             fprintf(stderr, "inner vector combiner = %s; should be vector\n",
642                     combiner_to_string(combiner));
643     }
644     if (errs) {
645         if (verbose) fprintf(stderr, "aborting after %d errors\n", errs);
646         return errs;
647     }
648
649     ints = malloc(nints * sizeof(*ints));
650     if (nadds) adds = malloc(nadds * sizeof(*adds));
651     types = malloc(ntypes * sizeof(*types));
652
653     err = MPI_Type_get_contents(inner_vector_copy,
654                                 nints,
655                                 nadds,
656                                 ntypes,
657                                 ints,
658                                 adds,
659                                 types);
660
661     if (ints[0] != 2) errs++;
662     if (ints[1] != 1) errs++;
663     if (ints[2] != 2) errs++;
664
665     if (verbose) {
666         if (ints[0] != 2) fprintf(stderr, 
667                                   "inner vector count = %d; should be 2\n",
668                                   ints[0]);
669         if (ints[1] != 1) fprintf(stderr,
670                                   "inner vector blocklength = %d; should be 1\n",
671                                   ints[1]);
672         if (ints[2] != 2) fprintf(stderr, 
673                                   "inner vector stride = %d; should be 2\n",
674                                   ints[2]);
675     }
676     if (errs) {
677         if (verbose) fprintf(stderr, "aborting after %d errors\n", errs);
678         return errs;
679     }
680
681     free(ints);
682     if (nadds) free(adds);
683     free(types);
684
685     MPI_Type_free( &inner_vector_copy );
686     MPI_Type_free( &inner_vector );
687     MPI_Type_free( &outer_indexed );
688
689     return 0;
690 }
691
692
693 #ifdef HAVE_MPI_TYPE_CREATE_STRUCT
694 /* struct_of_basics_test(void)
695  *
696  * There's nothing simple about structs :).  Although this is an easy one.
697  *
698  * Returns number of errors encountered.
699  *
700  * NOT TESTED.
701  */
702 int struct_of_basics_test(void)
703 {
704     MPI_Datatype parent_type;
705     int s_count = 3, s_blocklengths[3] = { 3, 2, 1 };
706     MPI_Aint s_displacements[3] = { 10, 20, 30 };
707     MPI_Datatype s_types[3] = { MPI_CHAR, MPI_INT, MPI_FLOAT };
708
709     int nints, nadds, ntypes, combiner, *ints;
710     MPI_Aint *adds = NULL;
711     MPI_Datatype *types;
712
713     int err, errs = 0;
714
715     /* set up type */
716     err = MPI_Type_create_struct(s_count,
717                                  s_blocklengths,
718                                  s_displacements,
719                                  s_types,
720                                  &parent_type);
721
722     /* decode */
723     err = MPI_Type_get_envelope(parent_type,
724                                 &nints,
725                                 &nadds,
726                                 &ntypes,
727                                 &combiner);
728
729     if (nints != 4) errs++;
730     if (nadds != 3) errs++;
731     if (ntypes != 3) errs++;
732     if (combiner != MPI_COMBINER_STRUCT) errs++;
733
734     if (verbose) {
735         if (nints != 4) fprintf(stderr, "nints = %d; should be 3\n", nints);
736         if (nadds != 3) fprintf(stderr, "nadds = %d; should be 0\n", nadds);
737         if (ntypes != 3) fprintf(stderr, "ntypes = %d; should be 3\n", ntypes);
738         if (combiner != MPI_COMBINER_STRUCT)
739             fprintf(stderr, "combiner = %s; should be struct\n",
740                     combiner_to_string(combiner));
741     }
742
743     ints = malloc(nints * sizeof(*ints));
744     adds = malloc(nadds * sizeof(*adds));
745     types = malloc(ntypes *sizeof(*types));
746
747     err = MPI_Type_get_contents(parent_type,
748                                 nints,
749                                 nadds,
750                                 ntypes,
751                                 ints,
752                                 adds,
753                                 types);
754
755     if (ints[0] != s_count) errs++;
756     if (ints[1] != s_blocklengths[0]) errs++;
757     if (ints[2] != s_blocklengths[1]) errs++;
758     if (ints[3] != s_blocklengths[2]) errs++;
759     if (adds[0] != s_displacements[0]) errs++;
760     if (adds[1] != s_displacements[1]) errs++;
761     if (adds[2] != s_displacements[2]) errs++;
762     if (types[0] != s_types[0]) errs++;
763     if (types[1] != s_types[1]) errs++;
764     if (types[2] != s_types[2]) errs++;
765
766     if (verbose) {
767         if (ints[0] != s_count) 
768             fprintf(stderr, "count = %d; should be %d\n", ints[0], s_count);
769         if (ints[1] != s_blocklengths[0])
770             fprintf(stderr, "blocklength[0] = %d; should be %d\n", ints[1], s_blocklengths[0]);
771         if (ints[2] != s_blocklengths[1]) 
772             fprintf(stderr, "blocklength[1] = %d; should be %d\n", ints[2], s_blocklengths[1]);
773         if (ints[3] != s_blocklengths[2]) 
774             fprintf(stderr, "blocklength[2] = %d; should be %d\n", ints[3], s_blocklengths[2]);
775         if (adds[0] != s_displacements[0]) 
776             fprintf(stderr, "displacement[0] = %d; should be %d\n", adds[0], s_displacements[0]);
777         if (adds[1] != s_displacements[1]) 
778             fprintf(stderr, "displacement[1] = %d; should be %d\n", adds[1], s_displacements[1]);
779         if (adds[2] != s_displacements[2]) 
780             fprintf(stderr, "displacement[2] = %d; should be %d\n", adds[2], s_displacements[2]);
781         if (types[0] != s_types[0]) 
782             fprintf(stderr, "type[0] does not match\n");
783         if (types[1] != s_types[1]) 
784             fprintf(stderr, "type[1] does not match\n");
785         if (types[2] != s_types[2]) 
786             fprintf(stderr, "type[2] does not match\n");
787     }
788
789     free(ints);
790     free(adds);
791     free(types);
792
793     MPI_Type_free( &parent_type );
794
795     return errs;
796 }
797 #endif
798
799 /* combiner_to_string(combiner)
800  *
801  * Converts a numeric combiner into a pointer to a string used for printing.
802  */
803 char *combiner_to_string(int combiner)
804 {
805     static char c_named[]    = "named";
806     static char c_contig[]   = "contig";
807     static char c_vector[]   = "vector";
808     static char c_hvector[]  = "hvector";
809     static char c_indexed[]  = "indexed";
810     static char c_hindexed[] = "hindexed";
811     static char c_struct[]   = "struct";
812 #ifdef HAVE_MPI2_COMBINERS
813     static char c_dup[]              = "dup";
814     static char c_hvector_integer[]  = "hvector_integer";
815     static char c_hindexed_integer[] = "hindexed_integer";
816     static char c_indexed_block[]    = "indexed_block";
817     static char c_struct_integer[]   = "struct_integer";
818     static char c_subarray[]         = "subarray";
819     static char c_darray[]           = "darray";
820     static char c_f90_real[]         = "f90_real";
821     static char c_f90_complex[]      = "f90_complex";
822     static char c_f90_integer[]      = "f90_integer";
823     static char c_resized[]          = "resized";
824 #endif
825
826     if (combiner == MPI_COMBINER_NAMED)      return c_named;
827     if (combiner == MPI_COMBINER_CONTIGUOUS) return c_contig;
828     if (combiner == MPI_COMBINER_VECTOR)     return c_vector;
829     if (combiner == MPI_COMBINER_HVECTOR)    return c_hvector;
830     if (combiner == MPI_COMBINER_INDEXED)    return c_indexed;
831     if (combiner == MPI_COMBINER_HINDEXED)   return c_hindexed;
832     if (combiner == MPI_COMBINER_STRUCT)     return c_struct;
833 #ifdef HAVE_MPI2_COMBINERS
834     if (combiner == MPI_COMBINER_DUP)              return c_dup;
835     if (combiner == MPI_COMBINER_HVECTOR_INTEGER)  return c_hvector_integer;
836     if (combiner == MPI_COMBINER_HINDEXED_INTEGER) return c_hindexed_integer;
837     if (combiner == MPI_COMBINER_INDEXED_BLOCK)    return c_indexed_block;
838     if (combiner == MPI_COMBINER_STRUCT_INTEGER)   return c_struct_integer;
839     if (combiner == MPI_COMBINER_SUBARRAY)         return c_subarray;
840     if (combiner == MPI_COMBINER_DARRAY)           return c_darray;
841     if (combiner == MPI_COMBINER_F90_REAL)         return c_f90_real;
842     if (combiner == MPI_COMBINER_F90_COMPLEX)      return c_f90_complex;
843     if (combiner == MPI_COMBINER_F90_INTEGER)      return c_f90_integer;
844     if (combiner == MPI_COMBINER_RESIZED)          return c_resized;
845 #endif
846     
847     return NULL;
848 }
849
850 int parse_args(int argc, char **argv)
851 {
852 #ifdef HAVE_GET_OPT
853     int ret;
854
855     while ((ret = getopt(argc, argv, "v")) >= 0)
856     {
857         switch (ret) {
858             case 'v':
859                 verbose = 1;
860                 break;
861         }
862     }
863 #else
864 #endif
865     return 0;
866 }
867