Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Hopefully the last vars to manually privatize here
[simgrid.git] / teshsuite / smpi / mpich3-test / util / mtest_datatype_gen_manual.c
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  *
4  *  (C) 2014 by Argonne National Laboratory.
5  *      See COPYRIGHT in top-level directory.
6  */
7 #include "mtest_datatype.h"
8 #if defined(HAVE_STDIO_H) || defined(STDC_HEADERS)
9 #include <stdio.h>
10 #endif
11 #if defined(HAVE_STDLIB_H) || defined(STDC_HEADERS)
12 #include <stdlib.h>
13 #endif
14 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
15 #include <string.h>
16 #endif
17 #ifdef HAVE_STDARG_H
18 #include <stdarg.h>
19 #endif
20 /* The following two includes permit the collection of resource usage
21    data in the tests
22  */
23 #ifdef HAVE_SYS_TIME_H
24 #include <sys/time.h>
25 #endif
26 #ifdef HAVE_SYS_RESOURCE_H
27 #include <sys/resource.h>
28 #endif
29 #include <errno.h>
30
31 static int dbgflag = 0;         /* Flag used for debugging */
32 SMPI_VARINIT_GLOBAL_AND_SET(wrank2, int, -1);  /* World rank */
33 static int verbose = 0;         /* Message level (0 is none) */
34
35 /*
36  * Utility routines for writing MPI datatype communication tests.
37  *
38  * Both basic and derived datatype are included.
39  * For basic datatypes, every type has a test case that both the send and
40  * receive buffer use the same datatype and count.
41  *
42  *  For derived datatypes:
43  *    All the test cases are defined in this file, and the datatype definitions
44  *    are in file mtest_datatype.c. Each test case will be automatically called
45  *    by every datatype.
46  *
47  *  Test case generation:
48  *    Every datatype tests derived datatype send buffer and
49  *    derived datatype receive buffer separately. Each test contains various sub
50  *    tests for different structures (i.e., different value of count or block
51  *    length). The following four structures are defined:
52  *      L count & S block length & S stride
53  *      S count & L block length & S stride
54  *      L count & S block length & L stride
55  *      S count & L block length & L stride
56  *      S count & L block length & S stride & S lower-bound
57  *      contiguous (stride = block length)
58  *      contiguous (stride = block length) & S lower-bound
59  *
60  *  How to add a new structure for each datatype:
61  *    1. Add structure definition in function MTestDdtStructDefine.
62  *    2. Increase MTEST_DDT_NUM_SUBTESTS
63  *
64  *  Datatype definition:
65  *    Every type is initialized by the creation function stored in
66  *    mtestDdtCreators variable, all of their create/init/check functions are
67  *    defined in file mtest_datatype.c.
68  *
69  *  How to add a new derived datatype:
70  *    1. Add the new datatype in enum MTEST_DERIVED_DT.
71  *    2. Add its create/init/check functions in file mtest_datatype.c
72  *    3. Add its creator function to mtestDdtCreators variable
73  *
74  *  Following three test levels of datatype are defined.
75  *    1. Basic
76  *      All basic datatypes
77  *    2. Minimum
78  *      All basic datatypes | Vector | Indexed
79  *    3. Full
80  *      All basic datatypes | Vector | Hvector | Indexed | Hindexed |
81  *      Indexed-block | Hindexed-block | Subarray with order-C | Subarray with order-Fortran
82  *
83  *  There are two ways to specify the test level of datatype. The second way has
84  *  higher priority (means the value specified by the first way will be overwritten
85  *  by that in the second way).
86  *  1. Specify global test level by setting the MPITEST_DATATYPE_TEST_LEVEL
87  *     environment variable before execution (basic,min,full|full by default).
88  *  2. Initialize a special level for a datatype loop by calling the corresponding
89  *     initialization function before that loop, otherwise the default value specified
90  *     in the first way is used.
91  *    Basic     : MTestInitBasicDatatypes
92  *    Minimum   : MTestInitMinDatatypes
93  *    Full      : MTestInitFullDatatypes
94  */
95
96 SMPI_VARINIT_GLOBAL_AND_SET(datatype_index,int,0);
97
98 /* ------------------------------------------------------------------------ */
99 /* Routine and internal parameters to define the range of datatype tests */
100 /* ------------------------------------------------------------------------ */
101
102 #define MTEST_DDT_NUM_SUBTESTS 7        /* 7 kinds of derived datatype structure */
103 static MTestDdtCreator mtestDdtCreators[MTEST_DDT_MAX];
104
105 static int MTEST_BDT_START_IDX = -1;
106 static int MTEST_BDT_NUM_TESTS = 0;
107 static int MTEST_BDT_RANGE = 0;
108
109 static int MTEST_DDT_NUM_TYPES = 0;
110 static int MTEST_SEND_DDT_START_IDX = 0;
111 static int MTEST_SEND_DDT_NUM_TESTS = 0;
112 static int MTEST_SEND_DDT_RANGE = 0;
113
114 static int MTEST_RECV_DDT_START_IDX = 0;
115 static int MTEST_RECV_DDT_NUM_TESTS = 0;
116 static int MTEST_RECV_DDT_RANGE = 0;
117
118 enum {
119     MTEST_DATATYPE_TEST_LEVEL_FULL,
120     MTEST_DATATYPE_TEST_LEVEL_MIN,
121     MTEST_DATATYPE_TEST_LEVEL_BASIC
122 };
123
124 /* current datatype test level */
125 static int MTEST_DATATYPE_TEST_LEVEL = MTEST_DATATYPE_TEST_LEVEL_FULL;
126 /* default datatype test level specified by environment variable */
127 static int MTEST_DATATYPE_TEST_LEVEL_ENV = -1;
128 /* default datatype initialization function */
129 static void (*MTestInitDefaultTestFunc) (void) = NULL;
130
131 static void MTestInitDatatypeGen(int basic_dt_num, int derived_dt_num)
132 {
133     MTEST_BDT_START_IDX = 0;
134     MTEST_BDT_NUM_TESTS = basic_dt_num;
135     MTEST_BDT_RANGE = MTEST_BDT_START_IDX + MTEST_BDT_NUM_TESTS;
136     MTEST_DDT_NUM_TYPES = derived_dt_num;
137     MTEST_SEND_DDT_START_IDX = MTEST_BDT_NUM_TESTS;
138     MTEST_SEND_DDT_NUM_TESTS = MTEST_DDT_NUM_TYPES * MTEST_DDT_NUM_SUBTESTS;
139     MTEST_SEND_DDT_RANGE = MTEST_SEND_DDT_START_IDX + MTEST_SEND_DDT_NUM_TESTS;
140     MTEST_RECV_DDT_START_IDX = MTEST_SEND_DDT_START_IDX + MTEST_SEND_DDT_NUM_TESTS;
141     MTEST_RECV_DDT_NUM_TESTS = MTEST_DDT_NUM_TYPES * MTEST_DDT_NUM_SUBTESTS;
142     MTEST_RECV_DDT_RANGE = MTEST_RECV_DDT_START_IDX + MTEST_RECV_DDT_NUM_TESTS;
143 }
144
145 static int MTestIsDatatypeGenInited()
146 {
147     return (MTEST_BDT_START_IDX < 0) ? 0 : 1;
148 }
149
150 static void MTestPrintDatatypeGen()
151 {
152     MTestPrintfMsg(1, "MTest datatype test level : %s. %d basic datatype tests, "
153                    "%d derived datatype tests will be generated\n",
154                    (MTEST_DATATYPE_TEST_LEVEL == MTEST_DATATYPE_TEST_LEVEL_FULL) ? "FULL" : "MIN",
155                    MTEST_BDT_NUM_TESTS, MTEST_SEND_DDT_NUM_TESTS + MTEST_RECV_DDT_NUM_TESTS);
156 }
157
158 static void MTestResetDatatypeGen()
159 {
160     MTEST_BDT_START_IDX = -1;
161 }
162
163 void MTestInitFullDatatypes(void)
164 {
165     /* Do not allow to change datatype test level during loop.
166      * Otherwise indexes will be wrong.
167      * Test must explicitly call reset or wait for current datatype loop being
168      * done before changing to another test level. */
169     if (!MTestIsDatatypeGenInited()) {
170         MTEST_DATATYPE_TEST_LEVEL = MTEST_DATATYPE_TEST_LEVEL_FULL;
171         MTestTypeCreatorInit((MTestDdtCreator *) mtestDdtCreators);
172         MTestInitDatatypeGen(MTEST_BDT_MAX, MTEST_DDT_MAX);
173     }
174     else {
175         printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!");
176     }
177 }
178
179 void MTestInitMinDatatypes(void)
180 {
181     /* Do not allow to change datatype test level during loop.
182      * Otherwise indexes will be wrong.
183      * Test must explicitly call reset or wait for current datatype loop being
184      * done before changing to another test level. */
185     if (!MTestIsDatatypeGenInited()) {
186         MTEST_DATATYPE_TEST_LEVEL = MTEST_DATATYPE_TEST_LEVEL_MIN;
187         MTestTypeMinCreatorInit((MTestDdtCreator *) mtestDdtCreators);
188         MTestInitDatatypeGen(MTEST_BDT_MAX, MTEST_MIN_DDT_MAX);
189     }
190     else {
191         printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!");
192     }
193 }
194
195 void MTestInitBasicDatatypes(void)
196 {
197     /* Do not allow to change datatype test level during loop.
198      * Otherwise indexes will be wrong.
199      * Test must explicitly call reset or wait for current datatype loop being
200      * done before changing to another test level. */
201     if (!MTestIsDatatypeGenInited()) {
202         MTEST_DATATYPE_TEST_LEVEL = MTEST_DATATYPE_TEST_LEVEL_BASIC;
203         MTestInitDatatypeGen(MTEST_BDT_MAX, 0);
204     }
205     else {
206         printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!");
207     }
208 }
209
210 static inline void MTestInitDatatypeEnv()
211 {
212     char *envval = 0;
213
214     /* Read global test level specified by user environment variable.
215      * Only initialize once at the first time that test calls datatype routine. */
216     if (MTEST_DATATYPE_TEST_LEVEL_ENV > -1)
217         return;
218
219     /* default full */
220     MTEST_DATATYPE_TEST_LEVEL_ENV = MTEST_DATATYPE_TEST_LEVEL_FULL;
221     MTestInitDefaultTestFunc = MTestInitFullDatatypes;
222
223     envval = getenv("MPITEST_DATATYPE_TEST_LEVEL");
224     if (envval && strlen(envval)) {
225         if (!strncmp(envval, "min", strlen("min"))) {
226             MTEST_DATATYPE_TEST_LEVEL_ENV = MTEST_DATATYPE_TEST_LEVEL_MIN;
227             MTestInitDefaultTestFunc = MTestInitMinDatatypes;
228         }
229         else if (!strncmp(envval, "basic", strlen("basic"))) {
230             MTEST_DATATYPE_TEST_LEVEL_ENV = MTEST_DATATYPE_TEST_LEVEL_BASIC;
231             MTestInitDefaultTestFunc = MTestInitBasicDatatypes;
232         }
233         else if (strncmp(envval, "full", strlen("full"))) {
234             fprintf(stderr, "Unknown MPITEST_DATATYPE_TEST_LEVEL %s\n", envval);
235         }
236     }
237 }
238
239 /* -------------------------------------------------------------------------------*/
240 /* Routine to define various sets of blocklen/count/stride for derived datatypes. */
241 /* ------------------------------------------------------------------------------ */
242
243 static inline int MTestDdtStructDefine(int ddt_index, MPI_Aint tot_count, MPI_Aint * count,
244                                        MPI_Aint * blen, MPI_Aint * stride,
245                                        MPI_Aint * align_tot_count, MPI_Aint * lb)
246 {
247     int merr = 0;
248     int ddt_c_st;
249     MPI_Aint _short = 0, _align_tot_count = 0, _count = 0, _blen = 0, _stride = 0;
250     MPI_Aint _lb = 0;
251
252     ddt_c_st = ddt_index % MTEST_DDT_NUM_SUBTESTS;
253
254     /* Get short value according to user specified tot_count.
255      * It is used as count for large-block-length structure, or block length
256      * for large-count structure. */
257     if (tot_count < 2) {
258         _short = 1;
259     }
260     else if (tot_count < 64) {
261         _short = 2;
262     }
263     else {
264         _short = 64;
265     }
266     _align_tot_count = (tot_count + _short - 1) & ~(_short - 1);
267
268     switch (ddt_c_st) {
269     case 0:
270         /* Large block length. */
271         _count = _short;
272         _blen = _align_tot_count / _short;
273         _stride = _blen * 2;
274         break;
275     case 1:
276         /* Large count */
277         _count = _align_tot_count / _short;
278         _blen = _short;
279         _stride = _blen * 2;
280         break;
281     case 2:
282         /* Large block length and large stride */
283         _count = _short;
284         _blen = _align_tot_count / _short;
285         _stride = _blen * 10;
286         break;
287     case 3:
288         /* Large count and large stride */
289         _count = _align_tot_count / _short;
290         _blen = _short;
291         _stride = _blen * 10;
292         break;
293     case 4:
294         /* Large block length with lb */
295         _count = _short;
296         _blen = _align_tot_count / _short;
297         _stride = _blen * 2;
298         _lb = _short / 2;       /* make sure lb < blen */
299         break;
300     case 5:
301         /* Contig ddt (stride = block length) without lb */
302         _count = _align_tot_count / _short;
303         _blen = _short;
304         _stride = _blen;
305         break;
306     case 6:
307         /* Contig ddt (stride = block length) with lb */
308         _count = _short;
309         _blen = _align_tot_count / _short;
310         _stride = _blen;
311         _lb = _short / 2;       /* make sure lb < blen */
312         break;
313     default:
314         /* Undefined index */
315         merr = 1;
316         break;
317     }
318
319     *align_tot_count = _align_tot_count;
320     *count = _count;
321     *blen = _blen;
322     *stride = _stride;
323     *lb = _lb;
324
325     return merr;
326 }
327
328 /* ------------------------------------------------------------------------ */
329 /* Routine to generate basic datatypes                                       */
330 /* ------------------------------------------------------------------------ */
331
332 static inline int MTestGetBasicDatatypes(MTestDatatype * sendtype,
333                                          MTestDatatype * recvtype, MPI_Aint tot_count)
334 {
335     int merr = 0;
336     int bdt_index = SMPI_VARGET_GLOBAL(datatype_index) - MTEST_BDT_START_IDX;
337     if (bdt_index >= MTEST_BDT_MAX) {
338         printf("Wrong index:  global %d, bst %d in %s\n", SMPI_VARGET_GLOBAL(datatype_index), bdt_index, __FUNCTION__);
339         merr++;
340         return merr;
341     }
342
343     switch (bdt_index) {
344     case MTEST_BDT_INT:
345         merr = MTestTypeBasicCreate(MPI_INT, sendtype);
346         merr = MTestTypeBasicCreate(MPI_INT, recvtype);
347         break;
348     case MTEST_BDT_DOUBLE:
349         merr = MTestTypeBasicCreate(MPI_DOUBLE, sendtype);
350         merr = MTestTypeBasicCreate(MPI_DOUBLE, recvtype);
351         break;
352     case MTEST_BDT_FLOAT_INT:
353         merr = MTestTypeBasicCreate(MPI_FLOAT_INT, sendtype);
354         merr = MTestTypeBasicCreate(MPI_FLOAT_INT, recvtype);
355         break;
356     case MTEST_BDT_SHORT:
357         merr = MTestTypeBasicCreate(MPI_SHORT, sendtype);
358         merr = MTestTypeBasicCreate(MPI_SHORT, recvtype);
359         break;
360     case MTEST_BDT_LONG:
361         merr = MTestTypeBasicCreate(MPI_LONG, sendtype);
362         merr = MTestTypeBasicCreate(MPI_LONG, recvtype);
363         break;
364     case MTEST_BDT_CHAR:
365         merr = MTestTypeBasicCreate(MPI_CHAR, sendtype);
366         merr = MTestTypeBasicCreate(MPI_CHAR, recvtype);
367         break;
368     case MTEST_BDT_UINT64_T:
369         merr = MTestTypeBasicCreate(MPI_UINT64_T, sendtype);
370         merr = MTestTypeBasicCreate(MPI_UINT64_T, recvtype);
371         break;
372     case MTEST_BDT_FLOAT:
373         merr = MTestTypeBasicCreate(MPI_FLOAT, sendtype);
374         merr = MTestTypeBasicCreate(MPI_FLOAT, recvtype);
375         break;
376     case MTEST_BDT_BYTE:
377         merr = MTestTypeBasicCreate(MPI_BYTE, sendtype);
378         merr = MTestTypeBasicCreate(MPI_BYTE, recvtype);
379         break;
380     }
381     sendtype->count = tot_count;
382     recvtype->count = tot_count;
383
384     return merr;
385 }
386
387 /* ------------------------------------------------------------------------ */
388 /* Routine to generate send/receive derived datatypes                     */
389 /* ------------------------------------------------------------------------ */
390
391 static inline int MTestGetSendDerivedDatatypes(MTestDatatype * sendtype,
392                                                MTestDatatype * recvtype, MPI_Aint tot_count)
393 {
394     int merr = 0;
395     int ddt_datatype_index, ddt_c_dt;
396     MPI_Aint blen, stride, count, align_tot_count, lb;
397     MPI_Datatype old_type = MPI_DOUBLE;
398
399     /* Check index */
400     ddt_datatype_index = SMPI_VARGET_GLOBAL(datatype_index) - MTEST_SEND_DDT_START_IDX;
401     ddt_c_dt = ddt_datatype_index / MTEST_DDT_NUM_SUBTESTS;
402     if (ddt_c_dt >= MTEST_DDT_MAX || !mtestDdtCreators[ddt_c_dt]) {
403         printf("Wrong index:  global %d, send %d send-ddt %d, or undefined creator in %s\n",
404                SMPI_VARGET_GLOBAL(datatype_index), ddt_datatype_index, ddt_c_dt, __FUNCTION__);
405         merr++;
406         return merr;
407     }
408
409     /* Set datatype structure */
410     merr = MTestDdtStructDefine(ddt_datatype_index, tot_count, &count, &blen,
411                                 &stride, &align_tot_count, &lb);
412     if (merr) {
413         printf("Wrong index:  global %d, send %d send-ddt %d, or undefined ddt structure in %s\n",
414                SMPI_VARGET_GLOBAL(datatype_index), ddt_datatype_index, ddt_c_dt, __FUNCTION__);
415         merr++;
416         return merr;
417     }
418
419     /* Create send datatype */
420     merr = mtestDdtCreators[ddt_c_dt] (count, blen, stride, lb, old_type, "send", sendtype);
421     if (merr)
422         return merr;
423
424     sendtype->count = 1;
425
426     /* Create receive datatype */
427     merr = MTestTypeBasicCreate(old_type, recvtype);
428     if (merr)
429         return merr;
430
431     recvtype->count = sendtype->count * align_tot_count;
432
433     return merr;
434 }
435
436 static inline int MTestGetRecvDerivedDatatypes(MTestDatatype * sendtype,
437                                                MTestDatatype * recvtype, MPI_Aint tot_count)
438 {
439     int merr = 0;
440     int ddt_datatype_index, ddt_c_dt;
441     MPI_Aint blen, stride, count, align_tot_count, lb;
442     MPI_Datatype old_type = MPI_DOUBLE;
443
444     /* Check index */
445     ddt_datatype_index = SMPI_VARGET_GLOBAL(datatype_index) - MTEST_RECV_DDT_START_IDX;
446     ddt_c_dt = ddt_datatype_index / MTEST_DDT_NUM_SUBTESTS;
447     if (ddt_c_dt >= MTEST_DDT_MAX || !mtestDdtCreators[ddt_c_dt]) {
448         printf("Wrong index:  global %d, recv %d recv-ddt %d, or undefined creator in %s\n",
449                SMPI_VARGET_GLOBAL(datatype_index), ddt_datatype_index, ddt_c_dt, __FUNCTION__);
450         merr++;
451         return merr;
452     }
453
454     /* Set datatype structure */
455     merr = MTestDdtStructDefine(ddt_datatype_index, tot_count, &count, &blen,
456                                 &stride, &align_tot_count, &lb);
457     if (merr) {
458         printf("Wrong index:  global %d, recv %d recv-ddt %d, or undefined ddt structure in %s\n",
459                SMPI_VARGET_GLOBAL(datatype_index), ddt_datatype_index, ddt_c_dt, __FUNCTION__);
460         return merr;
461     }
462
463     /* Create receive datatype */
464     merr = mtestDdtCreators[ddt_c_dt] (count, blen, stride, lb, old_type, "recv", recvtype);
465     if (merr)
466         return merr;
467
468     recvtype->count = 1;
469
470     /* Create send datatype */
471     merr = MTestTypeBasicCreate(old_type, sendtype);
472     if (merr)
473         return merr;
474
475     sendtype->count = recvtype->count * align_tot_count;
476
477     return merr;
478 }
479
480 /* ------------------------------------------------------------------------ */
481 /* Exposed routine to external tests                                         */
482 /* ------------------------------------------------------------------------ */
483 int MTestGetDatatypes(MTestDatatype * sendtype, MTestDatatype * recvtype, MPI_Aint tot_count)
484 {
485     int merr = 0;
486
487     MTestGetDbgInfo(&dbgflag, &verbose);
488     MTestInitDatatypeEnv();
489     MPI_Comm_rank(MPI_COMM_WORLD, &SMPI_VARGET_GLOBAL(wrank2));
490
491     /* Initialize the default test level if test does not specify. */
492     if (!MTestIsDatatypeGenInited()) {
493         MTestInitDefaultTestFunc();
494     }
495
496     if (SMPI_VARGET_GLOBAL(datatype_index) == 0) {
497         MTestPrintDatatypeGen();
498     }
499
500     /* Start generating tests */
501     if (SMPI_VARGET_GLOBAL(datatype_index) < MTEST_BDT_RANGE) {
502         merr = MTestGetBasicDatatypes(sendtype, recvtype, tot_count);
503
504     }
505     else if (SMPI_VARGET_GLOBAL(datatype_index) < MTEST_SEND_DDT_RANGE) {
506         merr = MTestGetSendDerivedDatatypes(sendtype, recvtype, tot_count);
507
508     }
509     else if (SMPI_VARGET_GLOBAL(datatype_index) < MTEST_RECV_DDT_RANGE) {
510         merr = MTestGetRecvDerivedDatatypes(sendtype, recvtype, tot_count);
511
512     }
513     else {
514         /* out of range */
515         SMPI_VARGET_GLOBAL(datatype_index) = -1;
516         MTestResetDatatypeGen();
517     }
518
519     /* stop if error reported */
520     if (merr) {
521         SMPI_VARGET_GLOBAL(datatype_index) = -1;
522     }
523
524     if (SMPI_VARGET_GLOBAL(datatype_index) > 0) {
525         /* general initialization for receive buffer. */
526         recvtype->InitBuf = MTestTypeInitRecv;
527     }
528
529     SMPI_VARGET_GLOBAL(datatype_index)++;
530
531     if (verbose >= 2 && SMPI_VARGET_GLOBAL(datatype_index) > 0) {
532         MPI_Count ssize, rsize;
533         MPI_Aint slb, rlb, sextent, rextent;
534         const char *sendtype_nm = MTestGetDatatypeName(sendtype);
535         const char *recvtype_nm = MTestGetDatatypeName(recvtype);
536         MPI_Type_size_x(sendtype->datatype, &ssize);
537         MPI_Type_size_x(recvtype->datatype, &rsize);
538
539         MPI_Type_get_extent(sendtype->datatype, &slb, &sextent);
540         MPI_Type_get_extent(recvtype->datatype, &rlb, &rextent);
541
542         MTestPrintfMsg(2, "Get datatypes: send = %s(size %d ext %ld lb %ld count %d basesize %d), "
543                        "recv = %s(size %d ext %ld lb %ld count %d basesize %d), tot_count=%d\n",
544                        sendtype_nm, ssize, sextent, slb, sendtype->count, sendtype->basesize,
545                        recvtype_nm, rsize, rextent, rlb, recvtype->count, recvtype->basesize,
546                        tot_count);
547         fflush(stdout);
548     }
549
550     return SMPI_VARGET_GLOBAL(datatype_index);
551 }
552
553 /* Reset the datatype index (start from the initial data type.
554    Note: This routine is rarely needed; MTestGetDatatypes automatically
555    starts over after the last available datatype is used.
556 */
557 void MTestResetDatatypes(void)
558 {
559     SMPI_VARGET_GLOBAL(datatype_index) = 0;
560     MTestResetDatatypeGen();
561 }
562
563 /* Return the index of the current datatype.  This is rarely needed and
564    is provided mostly to enable debugging of the MTest package itself */
565 int MTestGetDatatypeIndex(void)
566 {
567     return SMPI_VARGET_GLOBAL(datatype_index);
568 }
569
570 /* Free the storage associated with a datatype */
571 void MTestFreeDatatype(MTestDatatype * mtype)
572 {
573     int merr;
574     /* Invoke a datatype-specific free function to handle
575      * both the datatype and the send/receive buffers */
576     if (mtype->FreeBuf) {
577         (mtype->FreeBuf) (mtype);
578     }
579     /* Free the datatype itself if it was created */
580     if (!mtype->isBasic) {
581         merr = MPI_Type_free(&mtype->datatype);
582         if (merr)
583             MTestPrintError(merr);
584     }
585 }
586
587 /* Check that a message was received correctly.  Returns the number of
588    errors detected.  Status may be NULL or MPI_STATUS_IGNORE */
589 int MTestCheckRecv(MPI_Status * status, MTestDatatype * recvtype)
590 {
591     int count;
592     int errs = 0, merr;
593
594     if (status && status != MPI_STATUS_IGNORE) {
595         merr = MPI_Get_count(status, recvtype->datatype, &count);
596         if (merr)
597             MTestPrintError(merr);
598
599         /* Check count against expected count */
600         if (count != recvtype->count) {
601             errs++;
602         }
603     }
604
605     /* Check received data */
606     if (!errs && recvtype->CheckBuf(recvtype)) {
607         errs++;
608     }
609     return errs;
610 }
611
612 /* This next routine uses a circular buffer of static name arrays just to
613    simplify the use of the routine */
614 const char *MTestGetDatatypeName(MTestDatatype * dtype)
615 {
616     static char name[4][MPI_MAX_OBJECT_NAME];
617     static int sp = 0;
618     int rlen, merr;
619
620     if (sp >= 4)
621         sp = 0;
622     merr = MPI_Type_get_name(dtype->datatype, name[sp], &rlen);
623     if (merr)
624         MTestPrintError(merr);
625     return (const char *) name[sp++];
626 }