X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/97439eeb5618c81c605bfa0a9fa03364ae2f2d8e..d144105ea9f597667575c74c2d8b7252ebddb84e:/teshsuite/smpi/mpich3-test/util/mtest_datatype_gen.c diff --git a/teshsuite/smpi/mpich3-test/util/mtest_datatype_gen.c b/teshsuite/smpi/mpich3-test/util/mtest_datatype_gen.c new file mode 100644 index 0000000000..11eb0de387 --- /dev/null +++ b/teshsuite/smpi/mpich3-test/util/mtest_datatype_gen.c @@ -0,0 +1,626 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */ +/* + * + * (C) 2014 by Argonne National Laboratory. + * See COPYRIGHT in top-level directory. + */ +#include "mtest_datatype.h" +#if defined(HAVE_STDIO_H) || defined(STDC_HEADERS) +#include +#endif +#if defined(HAVE_STDLIB_H) || defined(STDC_HEADERS) +#include +#endif +#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif +/* The following two includes permit the collection of resource usage + data in the tests + */ +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif +#include + +static int dbgflag = 0; /* Flag used for debugging */ +static int wrank = -1; /* World rank */ +static int verbose = 0; /* Message level (0 is none) */ + +/* + * Utility routines for writing MPI datatype communication tests. + * + * Both basic and derived datatype are included. + * For basic datatypes, every type has a test case that both the send and + * receive buffer use the same datatype and count. + * + * For derived datatypes: + * All the test cases are defined in this file, and the datatype definitions + * are in file mtest_datatype.c. Each test case will be automatically called + * by every datatype. + * + * Test case generation: + * Every datatype tests derived datatype send buffer and + * derived datatype receive buffer separately. Each test contains various sub + * tests for different structures (i.e., different value of count or block + * length). The following four structures are defined: + * L count & S block length & S stride + * S count & L block length & S stride + * L count & S block length & L stride + * S count & L block length & L stride + * S count & L block length & S stride & S lower-bound + * contiguous (stride = block length) + * contiguous (stride = block length) & S lower-bound + * + * How to add a new structure for each datatype: + * 1. Add structure definition in function MTestDdtStructDefine. + * 2. Increase MTEST_DDT_NUM_SUBTESTS + * + * Datatype definition: + * Every type is initialized by the creation function stored in + * mtestDdtCreators variable, all of their create/init/check functions are + * defined in file mtest_datatype.c. + * + * How to add a new derived datatype: + * 1. Add the new datatype in enum MTEST_DERIVED_DT. + * 2. Add its create/init/check functions in file mtest_datatype.c + * 3. Add its creator function to mtestDdtCreators variable + * + * Following three test levels of datatype are defined. + * 1. Basic + * All basic datatypes + * 2. Minimum + * All basic datatypes | Vector | Indexed + * 3. Full + * All basic datatypes | Vector | Hvector | Indexed | Hindexed | + * Indexed-block | Hindexed-block | Subarray with order-C | Subarray with order-Fortran + * + * There are two ways to specify the test level of datatype. The second way has + * higher priority (means the value specified by the first way will be overwritten + * by that in the second way). + * 1. Specify global test level by setting the MPITEST_DATATYPE_TEST_LEVEL + * environment variable before execution (basic,min,full|full by default). + * 2. Initialize a special level for a datatype loop by calling the corresponding + * initialization function before that loop, otherwise the default value specified + * in the first way is used. + * Basic : MTestInitBasicDatatypes + * Minimum : MTestInitMinDatatypes + * Full : MTestInitFullDatatypes + */ + +static int datatype_index = 0; + +/* ------------------------------------------------------------------------ */ +/* Routine and internal parameters to define the range of datatype tests */ +/* ------------------------------------------------------------------------ */ + +#define MTEST_DDT_NUM_SUBTESTS 7 /* 7 kinds of derived datatype structure */ +static MTestDdtCreator mtestDdtCreators[MTEST_DDT_MAX]; + +static int MTEST_BDT_START_IDX = -1; +static int MTEST_BDT_NUM_TESTS = 0; +static int MTEST_BDT_RANGE = 0; + +static int MTEST_DDT_NUM_TYPES = 0; +static int MTEST_SEND_DDT_START_IDX = 0; +static int MTEST_SEND_DDT_NUM_TESTS = 0; +static int MTEST_SEND_DDT_RANGE = 0; + +static int MTEST_RECV_DDT_START_IDX = 0; +static int MTEST_RECV_DDT_NUM_TESTS = 0; +static int MTEST_RECV_DDT_RANGE = 0; + +enum { + MTEST_DATATYPE_TEST_LEVEL_FULL, + MTEST_DATATYPE_TEST_LEVEL_MIN, + MTEST_DATATYPE_TEST_LEVEL_BASIC +}; + +/* current datatype test level */ +static int MTEST_DATATYPE_TEST_LEVEL = MTEST_DATATYPE_TEST_LEVEL_FULL; +/* default datatype test level specified by environment variable */ +static int MTEST_DATATYPE_TEST_LEVEL_ENV = -1; +/* default datatype initialization function */ +static void (*MTestInitDefaultTestFunc) (void) = NULL; + +static void MTestInitDatatypeGen(int basic_dt_num, int derived_dt_num) +{ + MTEST_BDT_START_IDX = 0; + MTEST_BDT_NUM_TESTS = basic_dt_num; + MTEST_BDT_RANGE = MTEST_BDT_START_IDX + MTEST_BDT_NUM_TESTS; + MTEST_DDT_NUM_TYPES = derived_dt_num; + MTEST_SEND_DDT_START_IDX = MTEST_BDT_NUM_TESTS; + MTEST_SEND_DDT_NUM_TESTS = MTEST_DDT_NUM_TYPES * MTEST_DDT_NUM_SUBTESTS; + MTEST_SEND_DDT_RANGE = MTEST_SEND_DDT_START_IDX + MTEST_SEND_DDT_NUM_TESTS; + MTEST_RECV_DDT_START_IDX = MTEST_SEND_DDT_START_IDX + MTEST_SEND_DDT_NUM_TESTS; + MTEST_RECV_DDT_NUM_TESTS = MTEST_DDT_NUM_TYPES * MTEST_DDT_NUM_SUBTESTS; + MTEST_RECV_DDT_RANGE = MTEST_RECV_DDT_START_IDX + MTEST_RECV_DDT_NUM_TESTS; +} + +static int MTestIsDatatypeGenInited() +{ + return (MTEST_BDT_START_IDX < 0) ? 0 : 1; +} + +static void MTestPrintDatatypeGen() +{ + MTestPrintfMsg(1, "MTest datatype test level : %s. %d basic datatype tests, " + "%d derived datatype tests will be generated\n", + (MTEST_DATATYPE_TEST_LEVEL == MTEST_DATATYPE_TEST_LEVEL_FULL) ? "FULL" : "MIN", + MTEST_BDT_NUM_TESTS, MTEST_SEND_DDT_NUM_TESTS + MTEST_RECV_DDT_NUM_TESTS); +} + +static void MTestResetDatatypeGen() +{ + MTEST_BDT_START_IDX = -1; +} + +void MTestInitFullDatatypes(void) +{ + /* Do not allow to change datatype test level during loop. + * Otherwise indexes will be wrong. + * Test must explicitly call reset or wait for current datatype loop being + * done before changing to another test level. */ + if (!MTestIsDatatypeGenInited()) { + MTEST_DATATYPE_TEST_LEVEL = MTEST_DATATYPE_TEST_LEVEL_FULL; + MTestTypeCreatorInit((MTestDdtCreator *) mtestDdtCreators); + MTestInitDatatypeGen(MTEST_BDT_MAX, MTEST_DDT_MAX); + } + else { + printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!"); + } +} + +void MTestInitMinDatatypes(void) +{ + /* Do not allow to change datatype test level during loop. + * Otherwise indexes will be wrong. + * Test must explicitly call reset or wait for current datatype loop being + * done before changing to another test level. */ + if (!MTestIsDatatypeGenInited()) { + MTEST_DATATYPE_TEST_LEVEL = MTEST_DATATYPE_TEST_LEVEL_MIN; + MTestTypeMinCreatorInit((MTestDdtCreator *) mtestDdtCreators); + MTestInitDatatypeGen(MTEST_BDT_MAX, MTEST_MIN_DDT_MAX); + } + else { + printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!"); + } +} + +void MTestInitBasicDatatypes(void) +{ + /* Do not allow to change datatype test level during loop. + * Otherwise indexes will be wrong. + * Test must explicitly call reset or wait for current datatype loop being + * done before changing to another test level. */ + if (!MTestIsDatatypeGenInited()) { + MTEST_DATATYPE_TEST_LEVEL = MTEST_DATATYPE_TEST_LEVEL_BASIC; + MTestInitDatatypeGen(MTEST_BDT_MAX, 0); + } + else { + printf("Warning: trying to reinitialize mtest datatype during " "datatype iteration!"); + } +} + +static inline void MTestInitDatatypeEnv() +{ + char *envval = 0; + + /* Read global test level specified by user environment variable. + * Only initialize once at the first time that test calls datatype routine. */ + if (MTEST_DATATYPE_TEST_LEVEL_ENV > -1) + return; + + /* default full */ + MTEST_DATATYPE_TEST_LEVEL_ENV = MTEST_DATATYPE_TEST_LEVEL_FULL; + MTestInitDefaultTestFunc = MTestInitFullDatatypes; + + envval = getenv("MPITEST_DATATYPE_TEST_LEVEL"); + if (envval && strlen(envval)) { + if (!strncmp(envval, "min", strlen("min"))) { + MTEST_DATATYPE_TEST_LEVEL_ENV = MTEST_DATATYPE_TEST_LEVEL_MIN; + MTestInitDefaultTestFunc = MTestInitMinDatatypes; + } + else if (!strncmp(envval, "basic", strlen("basic"))) { + MTEST_DATATYPE_TEST_LEVEL_ENV = MTEST_DATATYPE_TEST_LEVEL_BASIC; + MTestInitDefaultTestFunc = MTestInitBasicDatatypes; + } + else if (strncmp(envval, "full", strlen("full"))) { + fprintf(stderr, "Unknown MPITEST_DATATYPE_TEST_LEVEL %s\n", envval); + } + } +} + +/* -------------------------------------------------------------------------------*/ +/* Routine to define various sets of blocklen/count/stride for derived datatypes. */ +/* ------------------------------------------------------------------------------ */ + +static inline int MTestDdtStructDefine(int ddt_index, MPI_Aint tot_count, MPI_Aint * count, + MPI_Aint * blen, MPI_Aint * stride, + MPI_Aint * align_tot_count, MPI_Aint * lb) +{ + int merr = 0; + int ddt_c_st; + MPI_Aint _short = 0, _align_tot_count = 0, _count = 0, _blen = 0, _stride = 0; + MPI_Aint _lb = 0; + + ddt_c_st = ddt_index % MTEST_DDT_NUM_SUBTESTS; + + /* Get short value according to user specified tot_count. + * It is used as count for large-block-length structure, or block length + * for large-count structure. */ + if (tot_count < 2) { + _short = 1; + } + else if (tot_count < 64) { + _short = 2; + } + else { + _short = 64; + } + _align_tot_count = (tot_count + _short - 1) & ~(_short - 1); + + switch (ddt_c_st) { + case 0: + /* Large block length. */ + _count = _short; + _blen = _align_tot_count / _short; + _stride = _blen * 2; + break; + case 1: + /* Large count */ + _count = _align_tot_count / _short; + _blen = _short; + _stride = _blen * 2; + break; + case 2: + /* Large block length and large stride */ + _count = _short; + _blen = _align_tot_count / _short; + _stride = _blen * 10; + break; + case 3: + /* Large count and large stride */ + _count = _align_tot_count / _short; + _blen = _short; + _stride = _blen * 10; + break; + case 4: + /* Large block length with lb */ + _count = _short; + _blen = _align_tot_count / _short; + _stride = _blen * 2; + _lb = _short / 2; /* make sure lb < blen */ + break; + case 5: + /* Contig ddt (stride = block length) without lb */ + _count = _align_tot_count / _short; + _blen = _short; + _stride = _blen; + break; + case 6: + /* Contig ddt (stride = block length) with lb */ + _count = _short; + _blen = _align_tot_count / _short; + _stride = _blen; + _lb = _short / 2; /* make sure lb < blen */ + break; + default: + /* Undefined index */ + merr = 1; + break; + } + + *align_tot_count = _align_tot_count; + *count = _count; + *blen = _blen; + *stride = _stride; + *lb = _lb; + + return merr; +} + +/* ------------------------------------------------------------------------ */ +/* Routine to generate basic datatypes */ +/* ------------------------------------------------------------------------ */ + +static inline int MTestGetBasicDatatypes(MTestDatatype * sendtype, + MTestDatatype * recvtype, MPI_Aint tot_count) +{ + int merr = 0; + int bdt_index = datatype_index - MTEST_BDT_START_IDX; + if (bdt_index >= MTEST_BDT_MAX) { + printf("Wrong index: global %d, bst %d in %s\n", datatype_index, bdt_index, __FUNCTION__); + merr++; + return merr; + } + + switch (bdt_index) { + case MTEST_BDT_INT: + merr = MTestTypeBasicCreate(MPI_INT, sendtype); + merr = MTestTypeBasicCreate(MPI_INT, recvtype); + break; + case MTEST_BDT_DOUBLE: + merr = MTestTypeBasicCreate(MPI_DOUBLE, sendtype); + merr = MTestTypeBasicCreate(MPI_DOUBLE, recvtype); + break; + case MTEST_BDT_FLOAT_INT: + merr = MTestTypeBasicCreate(MPI_FLOAT_INT, sendtype); + merr = MTestTypeBasicCreate(MPI_FLOAT_INT, recvtype); + break; + case MTEST_BDT_SHORT: + merr = MTestTypeBasicCreate(MPI_SHORT, sendtype); + merr = MTestTypeBasicCreate(MPI_SHORT, recvtype); + break; + case MTEST_BDT_LONG: + merr = MTestTypeBasicCreate(MPI_LONG, sendtype); + merr = MTestTypeBasicCreate(MPI_LONG, recvtype); + break; + case MTEST_BDT_CHAR: + merr = MTestTypeBasicCreate(MPI_CHAR, sendtype); + merr = MTestTypeBasicCreate(MPI_CHAR, recvtype); + break; + case MTEST_BDT_UINT64_T: + merr = MTestTypeBasicCreate(MPI_UINT64_T, sendtype); + merr = MTestTypeBasicCreate(MPI_UINT64_T, recvtype); + break; + case MTEST_BDT_FLOAT: + merr = MTestTypeBasicCreate(MPI_FLOAT, sendtype); + merr = MTestTypeBasicCreate(MPI_FLOAT, recvtype); + break; + case MTEST_BDT_BYTE: + merr = MTestTypeBasicCreate(MPI_BYTE, sendtype); + merr = MTestTypeBasicCreate(MPI_BYTE, recvtype); + break; + } + sendtype->count = tot_count; + recvtype->count = tot_count; + + return merr; +} + +/* ------------------------------------------------------------------------ */ +/* Routine to generate send/receive derived datatypes */ +/* ------------------------------------------------------------------------ */ + +static inline int MTestGetSendDerivedDatatypes(MTestDatatype * sendtype, + MTestDatatype * recvtype, MPI_Aint tot_count) +{ + int merr = 0; + int ddt_datatype_index, ddt_c_dt; + MPI_Aint blen, stride, count, align_tot_count, lb; + MPI_Datatype old_type = MPI_DOUBLE; + + /* Check index */ + ddt_datatype_index = datatype_index - MTEST_SEND_DDT_START_IDX; + ddt_c_dt = ddt_datatype_index / MTEST_DDT_NUM_SUBTESTS; + if (ddt_c_dt >= MTEST_DDT_MAX || !mtestDdtCreators[ddt_c_dt]) { + printf("Wrong index: global %d, send %d send-ddt %d, or undefined creator in %s\n", + datatype_index, ddt_datatype_index, ddt_c_dt, __FUNCTION__); + merr++; + return merr; + } + + /* Set datatype structure */ + merr = MTestDdtStructDefine(ddt_datatype_index, tot_count, &count, &blen, + &stride, &align_tot_count, &lb); + if (merr) { + printf("Wrong index: global %d, send %d send-ddt %d, or undefined ddt structure in %s\n", + datatype_index, ddt_datatype_index, ddt_c_dt, __FUNCTION__); + merr++; + return merr; + } + + /* Create send datatype */ + merr = mtestDdtCreators[ddt_c_dt] (count, blen, stride, lb, old_type, "send", sendtype); + if (merr) + return merr; + + sendtype->count = 1; + + /* Create receive datatype */ + merr = MTestTypeBasicCreate(old_type, recvtype); + if (merr) + return merr; + + recvtype->count = sendtype->count * align_tot_count; + + return merr; +} + +static inline int MTestGetRecvDerivedDatatypes(MTestDatatype * sendtype, + MTestDatatype * recvtype, MPI_Aint tot_count) +{ + int merr = 0; + int ddt_datatype_index, ddt_c_dt; + MPI_Aint blen, stride, count, align_tot_count, lb; + MPI_Datatype old_type = MPI_DOUBLE; + + /* Check index */ + ddt_datatype_index = datatype_index - MTEST_RECV_DDT_START_IDX; + ddt_c_dt = ddt_datatype_index / MTEST_DDT_NUM_SUBTESTS; + if (ddt_c_dt >= MTEST_DDT_MAX || !mtestDdtCreators[ddt_c_dt]) { + printf("Wrong index: global %d, recv %d recv-ddt %d, or undefined creator in %s\n", + datatype_index, ddt_datatype_index, ddt_c_dt, __FUNCTION__); + merr++; + return merr; + } + + /* Set datatype structure */ + merr = MTestDdtStructDefine(ddt_datatype_index, tot_count, &count, &blen, + &stride, &align_tot_count, &lb); + if (merr) { + printf("Wrong index: global %d, recv %d recv-ddt %d, or undefined ddt structure in %s\n", + datatype_index, ddt_datatype_index, ddt_c_dt, __FUNCTION__); + return merr; + } + + /* Create receive datatype */ + merr = mtestDdtCreators[ddt_c_dt] (count, blen, stride, lb, old_type, "recv", recvtype); + if (merr) + return merr; + + recvtype->count = 1; + + /* Create send datatype */ + merr = MTestTypeBasicCreate(old_type, sendtype); + if (merr) + return merr; + + sendtype->count = recvtype->count * align_tot_count; + + return merr; +} + +/* ------------------------------------------------------------------------ */ +/* Exposed routine to external tests */ +/* ------------------------------------------------------------------------ */ +int MTestGetDatatypes(MTestDatatype * sendtype, MTestDatatype * recvtype, MPI_Aint tot_count) +{ + int merr = 0; + + MTestGetDbgInfo(&dbgflag, &verbose); + MTestInitDatatypeEnv(); + MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + + /* Initialize the default test level if test does not specify. */ + if (!MTestIsDatatypeGenInited()) { + MTestInitDefaultTestFunc(); + } + + if (datatype_index == 0) { + MTestPrintDatatypeGen(); + } + + /* Start generating tests */ + if (datatype_index < MTEST_BDT_RANGE) { + merr = MTestGetBasicDatatypes(sendtype, recvtype, tot_count); + + } + else if (datatype_index < MTEST_SEND_DDT_RANGE) { + merr = MTestGetSendDerivedDatatypes(sendtype, recvtype, tot_count); + + } + else if (datatype_index < MTEST_RECV_DDT_RANGE) { + merr = MTestGetRecvDerivedDatatypes(sendtype, recvtype, tot_count); + + } + else { + /* out of range */ + datatype_index = -1; + MTestResetDatatypeGen(); + } + + /* stop if error reported */ + if (merr) { + datatype_index = -1; + } + + if (datatype_index > 0) { + /* general initialization for receive buffer. */ + recvtype->InitBuf = MTestTypeInitRecv; + } + + datatype_index++; + + if (verbose >= 2 && datatype_index > 0) { + MPI_Count ssize, rsize; + MPI_Aint slb, rlb, sextent, rextent; + const char *sendtype_nm = MTestGetDatatypeName(sendtype); + const char *recvtype_nm = MTestGetDatatypeName(recvtype); + MPI_Type_size_x(sendtype->datatype, &ssize); + MPI_Type_size_x(recvtype->datatype, &rsize); + + MPI_Type_get_extent(sendtype->datatype, &slb, &sextent); + MPI_Type_get_extent(recvtype->datatype, &rlb, &rextent); + + MTestPrintfMsg(2, "Get datatypes: send = %s(size %d ext %ld lb %ld count %d basesize %d), " + "recv = %s(size %d ext %ld lb %ld count %d basesize %d), tot_count=%d\n", + sendtype_nm, ssize, sextent, slb, sendtype->count, sendtype->basesize, + recvtype_nm, rsize, rextent, rlb, recvtype->count, recvtype->basesize, + tot_count); + fflush(stdout); + } + + return datatype_index; +} + +/* Reset the datatype index (start from the initial data type. + Note: This routine is rarely needed; MTestGetDatatypes automatically + starts over after the last available datatype is used. +*/ +void MTestResetDatatypes(void) +{ + datatype_index = 0; + MTestResetDatatypeGen(); +} + +/* Return the index of the current datatype. This is rarely needed and + is provided mostly to enable debugging of the MTest package itself */ +int MTestGetDatatypeIndex(void) +{ + return datatype_index; +} + +/* Free the storage associated with a datatype */ +void MTestFreeDatatype(MTestDatatype * mtype) +{ + int merr; + /* Invoke a datatype-specific free function to handle + * both the datatype and the send/receive buffers */ + if (mtype->FreeBuf) { + (mtype->FreeBuf) (mtype); + } + /* Free the datatype itself if it was created */ + if (!mtype->isBasic) { + merr = MPI_Type_free(&mtype->datatype); + if (merr) + MTestPrintError(merr); + } +} + +/* Check that a message was received correctly. Returns the number of + errors detected. Status may be NULL or MPI_STATUS_IGNORE */ +int MTestCheckRecv(MPI_Status * status, MTestDatatype * recvtype) +{ + int count; + int errs = 0, merr; + + if (status && status != MPI_STATUS_IGNORE) { + merr = MPI_Get_count(status, recvtype->datatype, &count); + if (merr) + MTestPrintError(merr); + + /* Check count against expected count */ + if (count != recvtype->count) { + errs++; + } + } + + /* Check received data */ + if (!errs && recvtype->CheckBuf(recvtype)) { + errs++; + } + return errs; +} + +/* This next routine uses a circular buffer of static name arrays just to + simplify the use of the routine */ +const char *MTestGetDatatypeName(MTestDatatype * dtype) +{ + static char name[4][MPI_MAX_OBJECT_NAME]; + static int sp = 0; + int rlen, merr; + + if (sp >= 4) + sp = 0; + merr = MPI_Type_get_name(dtype->datatype, name[sp], &rlen); + if (merr) + MTestPrintError(merr); + return (const char *) name[sp++]; +}