1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
4 * (C) 2014 by Argonne National Laboratory.
5 * See COPYRIGHT in top-level directory.
7 #include "mtest_datatype.h"
8 #if defined(HAVE_STDIO_H) || defined(STDC_HEADERS)
11 #if defined(HAVE_STDLIB_H) || defined(STDC_HEADERS)
14 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
20 /* The following two includes permit the collection of resource usage
23 #ifdef HAVE_SYS_TIME_H
26 #ifdef HAVE_SYS_RESOURCE_H
27 #include <sys/resource.h>
31 static int dbgflag = 0; /* Flag used for debugging */
32 static int wrank = -1; /* World rank */
33 static int verbose = 0; /* Message level (0 is none) */
36 * Utility routines for writing MPI datatype communication tests.
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.
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
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
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
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.
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
74 * Following three test levels of datatype are defined.
78 * All basic datatypes | Vector | Indexed
80 * All basic datatypes | Vector | Hvector | Indexed | Hindexed |
81 * Indexed-block | Hindexed-block | Subarray with order-C | Subarray with order-Fortran
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
96 static int datatype_index = 0;
98 /* ------------------------------------------------------------------------ */
99 /* Routine and internal parameters to define the range of datatype tests */
100 /* ------------------------------------------------------------------------ */
102 #define MTEST_DDT_NUM_SUBTESTS 7 /* 7 kinds of derived datatype structure */
103 static MTestDdtCreator mtestDdtCreators[MTEST_DDT_MAX];
105 static int MTEST_BDT_START_IDX = -1;
106 static int MTEST_BDT_NUM_TESTS = 0;
107 static int MTEST_BDT_RANGE = 0;
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;
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;
119 MTEST_DATATYPE_TEST_LEVEL_FULL,
120 MTEST_DATATYPE_TEST_LEVEL_MIN,
121 MTEST_DATATYPE_TEST_LEVEL_BASIC
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;
131 static void MTestInitDatatypeGen(int basic_dt_num, int derived_dt_num)
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;
145 static int MTestIsDatatypeGenInited()
147 return (MTEST_BDT_START_IDX < 0) ? 0 : 1;
150 static void MTestPrintDatatypeGen()
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);
158 static void MTestResetDatatypeGen()
160 MTEST_BDT_START_IDX = -1;
163 void MTestInitFullDatatypes(void)
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);
175 printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!");
179 void MTestInitMinDatatypes(void)
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);
191 printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!");
195 void MTestInitBasicDatatypes(void)
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);
206 printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!");
210 static inline void MTestInitDatatypeEnv()
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)
220 MTEST_DATATYPE_TEST_LEVEL_ENV = MTEST_DATATYPE_TEST_LEVEL_FULL;
221 MTestInitDefaultTestFunc = MTestInitFullDatatypes;
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;
229 else if (!strncmp(envval, "basic", strlen("basic"))) {
230 MTEST_DATATYPE_TEST_LEVEL_ENV = MTEST_DATATYPE_TEST_LEVEL_BASIC;
231 MTestInitDefaultTestFunc = MTestInitBasicDatatypes;
233 else if (strncmp(envval, "full", strlen("full"))) {
234 fprintf(stderr, "Unknown MPITEST_DATATYPE_TEST_LEVEL %s\n", envval);
239 /* -------------------------------------------------------------------------------*/
240 /* Routine to define various sets of blocklen/count/stride for derived datatypes. */
241 /* ------------------------------------------------------------------------------ */
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)
249 MPI_Aint _short = 0, _align_tot_count = 0, _count = 0, _blen = 0, _stride = 0;
252 ddt_c_st = ddt_index % MTEST_DDT_NUM_SUBTESTS;
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. */
260 else if (tot_count < 64) {
266 _align_tot_count = (tot_count + _short - 1) & ~(_short - 1);
270 /* Large block length. */
272 _blen = _align_tot_count / _short;
277 _count = _align_tot_count / _short;
282 /* Large block length and large stride */
284 _blen = _align_tot_count / _short;
285 _stride = _blen * 10;
288 /* Large count and large stride */
289 _count = _align_tot_count / _short;
291 _stride = _blen * 10;
294 /* Large block length with lb */
296 _blen = _align_tot_count / _short;
298 _lb = _short / 2; /* make sure lb < blen */
301 /* Contig ddt (stride = block length) without lb */
302 _count = _align_tot_count / _short;
307 /* Contig ddt (stride = block length) with lb */
309 _blen = _align_tot_count / _short;
311 _lb = _short / 2; /* make sure lb < blen */
314 /* Undefined index */
319 *align_tot_count = _align_tot_count;
328 /* ------------------------------------------------------------------------ */
329 /* Routine to generate basic datatypes */
330 /* ------------------------------------------------------------------------ */
332 static inline int MTestGetBasicDatatypes(MTestDatatype * sendtype,
333 MTestDatatype * recvtype, MPI_Aint tot_count)
336 int bdt_index = datatype_index - MTEST_BDT_START_IDX;
337 if (bdt_index >= MTEST_BDT_MAX) {
338 printf("Wrong index: global %d, bst %d in %s\n", datatype_index, bdt_index, __func__);
345 merr = MTestTypeBasicCreate(MPI_INT, sendtype);
346 merr = MTestTypeBasicCreate(MPI_INT, recvtype);
348 case MTEST_BDT_DOUBLE:
349 merr = MTestTypeBasicCreate(MPI_DOUBLE, sendtype);
350 merr = MTestTypeBasicCreate(MPI_DOUBLE, recvtype);
352 case MTEST_BDT_FLOAT_INT:
353 merr = MTestTypeBasicCreate(MPI_FLOAT_INT, sendtype);
354 merr = MTestTypeBasicCreate(MPI_FLOAT_INT, recvtype);
356 case MTEST_BDT_SHORT:
357 merr = MTestTypeBasicCreate(MPI_SHORT, sendtype);
358 merr = MTestTypeBasicCreate(MPI_SHORT, recvtype);
361 merr = MTestTypeBasicCreate(MPI_LONG, sendtype);
362 merr = MTestTypeBasicCreate(MPI_LONG, recvtype);
365 merr = MTestTypeBasicCreate(MPI_CHAR, sendtype);
366 merr = MTestTypeBasicCreate(MPI_CHAR, recvtype);
368 case MTEST_BDT_UINT64_T:
369 merr = MTestTypeBasicCreate(MPI_UINT64_T, sendtype);
370 merr = MTestTypeBasicCreate(MPI_UINT64_T, recvtype);
372 case MTEST_BDT_FLOAT:
373 merr = MTestTypeBasicCreate(MPI_FLOAT, sendtype);
374 merr = MTestTypeBasicCreate(MPI_FLOAT, recvtype);
377 merr = MTestTypeBasicCreate(MPI_BYTE, sendtype);
378 merr = MTestTypeBasicCreate(MPI_BYTE, recvtype);
381 sendtype->count = tot_count;
382 recvtype->count = tot_count;
387 /* ------------------------------------------------------------------------ */
388 /* Routine to generate send/receive derived datatypes */
389 /* ------------------------------------------------------------------------ */
391 static inline int MTestGetSendDerivedDatatypes(MTestDatatype * sendtype,
392 MTestDatatype * recvtype, MPI_Aint tot_count)
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;
400 ddt_datatype_index = 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", datatype_index,
404 ddt_datatype_index, ddt_c_dt, __func__);
409 /* Set datatype structure */
410 merr = MTestDdtStructDefine(ddt_datatype_index, tot_count, &count, &blen,
411 &stride, &align_tot_count, &lb);
413 printf("Wrong index: global %d, send %d send-ddt %d, or undefined ddt structure in %s\n", datatype_index,
414 ddt_datatype_index, ddt_c_dt, __func__);
419 /* Create send datatype */
420 merr = mtestDdtCreators[ddt_c_dt] (count, blen, stride, lb, old_type, "send", sendtype);
426 /* Create receive datatype */
427 merr = MTestTypeBasicCreate(old_type, recvtype);
431 recvtype->count = sendtype->count * align_tot_count;
436 static inline int MTestGetRecvDerivedDatatypes(MTestDatatype * sendtype,
437 MTestDatatype * recvtype, MPI_Aint tot_count)
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;
445 ddt_datatype_index = 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", datatype_index,
449 ddt_datatype_index, ddt_c_dt, __func__);
454 /* Set datatype structure */
455 merr = MTestDdtStructDefine(ddt_datatype_index, tot_count, &count, &blen,
456 &stride, &align_tot_count, &lb);
458 printf("Wrong index: global %d, recv %d recv-ddt %d, or undefined ddt structure in %s\n", datatype_index,
459 ddt_datatype_index, ddt_c_dt, __func__);
463 /* Create receive datatype */
464 merr = mtestDdtCreators[ddt_c_dt] (count, blen, stride, lb, old_type, "recv", recvtype);
470 /* Create send datatype */
471 merr = MTestTypeBasicCreate(old_type, sendtype);
475 sendtype->count = recvtype->count * align_tot_count;
480 /* ------------------------------------------------------------------------ */
481 /* Exposed routine to external tests */
482 /* ------------------------------------------------------------------------ */
483 int MTestGetDatatypes(MTestDatatype * sendtype, MTestDatatype * recvtype, MPI_Aint tot_count)
487 MTestGetDbgInfo(&dbgflag, &verbose);
488 MTestInitDatatypeEnv();
489 MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
491 /* Initialize the default test level if test does not specify. */
492 if (!MTestIsDatatypeGenInited()) {
493 MTestInitDefaultTestFunc();
496 if (datatype_index == 0) {
497 MTestPrintDatatypeGen();
500 /* Start generating tests */
501 if (datatype_index < MTEST_BDT_RANGE) {
502 merr = MTestGetBasicDatatypes(sendtype, recvtype, tot_count);
505 else if (datatype_index < MTEST_SEND_DDT_RANGE) {
506 merr = MTestGetSendDerivedDatatypes(sendtype, recvtype, tot_count);
509 else if (datatype_index < MTEST_RECV_DDT_RANGE) {
510 merr = MTestGetRecvDerivedDatatypes(sendtype, recvtype, tot_count);
516 MTestResetDatatypeGen();
519 /* stop if error reported */
524 if (datatype_index > 0) {
525 /* general initialization for receive buffer. */
526 recvtype->InitBuf = MTestTypeInitRecv;
531 if (verbose >= 2 && 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);
539 MPI_Type_get_extent(sendtype->datatype, &slb, &sextent);
540 MPI_Type_get_extent(recvtype->datatype, &rlb, &rextent);
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,
550 return datatype_index;
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.
557 void MTestResetDatatypes(void)
560 MTestResetDatatypeGen();
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)
567 return datatype_index;
570 /* Free the storage associated with a datatype */
571 void MTestFreeDatatype(MTestDatatype * mtype)
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);
579 /* Free the datatype itself if it was created */
580 if (!mtype->isBasic) {
581 merr = MPI_Type_free(&mtype->datatype);
583 MTestPrintError(merr);
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)
594 if (status && status != MPI_STATUS_IGNORE) {
595 merr = MPI_Get_count(status, recvtype->datatype, &count);
597 MTestPrintError(merr);
599 /* Check count against expected count */
600 if (count != recvtype->count) {
605 /* Check received data */
606 if (!errs && recvtype->CheckBuf(recvtype)) {
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)
616 static char name[4][MPI_MAX_OBJECT_NAME];
622 merr = MPI_Type_get_name(dtype->datatype, name[sp], &rlen);
624 MTestPrintError(merr);
625 return (const char *) name[sp++];