Example #1
0
int MPI_Finalize(void)
{
    int result, MPIT_result;
    uint64_t * exchange_count_matrix = NULL;
    uint64_t * exchange_size_matrix = NULL;
    uint64_t * exchange_avg_size_matrix = NULL;

    if (0 == comm_world_rank) {
        exchange_count_matrix = (uint64_t *) malloc(comm_world_size * comm_world_size * sizeof(uint64_t));
        exchange_size_matrix = (uint64_t *) malloc(comm_world_size * comm_world_size * sizeof(uint64_t));
        exchange_avg_size_matrix = (uint64_t *) malloc(comm_world_size * comm_world_size * sizeof(uint64_t));
    }

    stop_monitoring_result(&counts);
    stop_monitoring_result(&sizes);

    get_monitoring_result(&counts);
    get_monitoring_result(&sizes);

    PMPI_Gather(counts.vector, comm_world_size, MPI_UNSIGNED_LONG, exchange_count_matrix, comm_world_size, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);
    PMPI_Gather(sizes.vector,  comm_world_size, MPI_UNSIGNED_LONG, exchange_size_matrix,  comm_world_size, MPI_UNSIGNED_LONG, 0, MPI_COMM_WORLD);

    if (0 == comm_world_rank) {
        int i, j;

        //Get the same matrix than profile2mat.pl
        for (i = 0; i < comm_world_size; ++i) {
            for (j = i + 1; j < comm_world_size; ++j) {
                exchange_count_matrix[i * comm_world_size + j] = exchange_count_matrix[j * comm_world_size + i] = (exchange_count_matrix[i * comm_world_size + j] + exchange_count_matrix[j * comm_world_size + i]) / 2;
                exchange_size_matrix[i * comm_world_size + j] = exchange_size_matrix[j * comm_world_size + i] = (exchange_size_matrix[i * comm_world_size + j] + exchange_size_matrix[j * comm_world_size + i]) / 2;
                if (exchange_count_matrix[i * comm_world_size + j] != 0)
                    exchange_avg_size_matrix[i * comm_world_size + j] = exchange_avg_size_matrix[j * comm_world_size + i] = exchange_size_matrix[i * comm_world_size + j] / exchange_count_matrix[i * comm_world_size + j];
            }
        }

        write_mat("monitoring_msg.mat", exchange_count_matrix, comm_world_size);
        write_mat("monitoring_size.mat", exchange_size_matrix, comm_world_size);
        write_mat("monitoring_avg.mat", exchange_avg_size_matrix, comm_world_size);
    }

    free(exchange_count_matrix);
    free(exchange_size_matrix);
    free(exchange_avg_size_matrix);
    destroy_monitoring_result(&counts);
    destroy_monitoring_result(&sizes);

    MPIT_result = MPI_T_pvar_session_free(&session);
    if (MPIT_result != MPI_SUCCESS) {
        fprintf(stderr, "WARNING : failed to free MPI_T session, monitoring results may be impacted : check your OpenMPI installation\n");
    }

    MPIT_result = MPI_T_finalize();
    if (MPIT_result != MPI_SUCCESS) {
        fprintf(stderr, "WARNING : failed to finalize MPI_T interface, monitoring results may be impacted : check your OpenMPI installation\n");
    }

    result = PMPI_Finalize();

    return result;
}
Example #2
0
int main(int argc, char **argv)
{
    int i;
    int num;
    int rank, size;
/*#define STR_SZ (15)*/
#define STR_SZ (50)
    int name_len = STR_SZ;
    char name[STR_SZ] = "";
    int desc_len = STR_SZ;
    char desc[STR_SZ] = "";
    int verb;
    MPI_Datatype dtype;
    int count;
    int bind;
    int varclass;
    int readonly, continuous, atomic;
    int provided;
    MPI_T_enum enumtype;
    int pq_idx = -1, uq_idx = -1, pqm_idx = -1, uqm_idx = -1;
    int pqm_writable = -1, uqm_writable = -1;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    provided = 0xdeadbeef;
    MPI_T_init_thread(MPI_THREAD_SINGLE, &provided);
    assert(provided != 0xdeadbeef);

    num = 0xdeadbeef;
    MPI_T_pvar_get_num(&num);
    printf("get_num=%d\n", num);
    assert(num != 0xdeadbeef);
    for (i = 0; i < num; ++i) {
        name_len = desc_len = STR_SZ;
        MPI_T_pvar_get_info(i, name, &name_len, &verb, &varclass, &dtype, &enumtype, desc, &desc_len, &bind, &readonly, &continuous, &atomic);
        printf("index=%d\n", i);
        printf("--> name='%s' name_len=%d desc='%s' desc_len=%d\n", name, name_len, desc, desc_len);
        printf("--> verb=%d varclass=%d dtype=%#x bind=%d readonly=%d continuous=%d atomic=%d\n",
               verb, varclass, dtype, bind, readonly, continuous, atomic);

        if (0 == strcmp(name, "posted_recvq_length")) {
            pq_idx = i;
        }
        else if (0 == strcmp(name, "unexpected_recvq_length")) {
            uq_idx = i;
        }
        else if (0 == strcmp(name, "posted_recvq_match_attempts")) {
            pqm_idx = i;
            pqm_writable = !readonly;
        }
        else if (0 == strcmp(name, "unexpected_recvq_match_attempts")) {
            uqm_idx = i;
            uqm_writable = !readonly;
        }
    }

    printf("pq_idx=%d uq_idx=%d pqm_idx=%d uqm_idx=%d\n", pq_idx, uq_idx, pqm_idx, uqm_idx);

    /* setup a session and handles for the PQ and UQ length variables */
    session = MPI_T_PVAR_SESSION_NULL;
    MPI_T_pvar_session_create(&session);
    assert(session != MPI_T_PVAR_SESSION_NULL);

    pq_handle = MPI_T_PVAR_HANDLE_NULL;
    MPI_T_pvar_handle_alloc(session, pq_idx, NULL, &pq_handle, &count);
    assert(count = 1);
    assert(pq_handle != MPI_T_PVAR_HANDLE_NULL);

    uq_handle = MPI_T_PVAR_HANDLE_NULL;
    MPI_T_pvar_handle_alloc(session, uq_idx, NULL, &uq_handle, &count);
    assert(count = 1);
    assert(uq_handle != MPI_T_PVAR_HANDLE_NULL);

    pqm_handle = MPI_T_PVAR_HANDLE_NULL;
    MPI_T_pvar_handle_alloc(session, pqm_idx, NULL, &pqm_handle, &count);
    assert(count = 1);
    assert(pqm_handle != MPI_T_PVAR_HANDLE_NULL);

    uqm_handle = MPI_T_PVAR_HANDLE_NULL;
    MPI_T_pvar_handle_alloc(session, uqm_idx, NULL, &uqm_handle, &count);
    assert(count = 1);
    assert(uqm_handle != MPI_T_PVAR_HANDLE_NULL);

    /* now send/recv some messages and track the lengths of the queues */
    {
        int buf1, buf2, buf3, buf4;
        MPI_Request r1, r2, r3, r4;

        buf1 = buf2 = buf3 = buf4 = 0xfeedface;
        r1 = r2 = r3 = r4 = MPI_REQUEST_NULL;

        posted_qlen = 0x0123abcd;
        unexpected_qlen = 0x0123abcd;
        posted_queue_match_attempts = 0x0123abcd;
        unexpected_queue_match_attempts = 0x0123abcd;
        print_vars(1);

        MPI_Isend(&buf1, 1, MPI_INT, 0, /*tag=*/11, MPI_COMM_SELF, &r1);
        print_vars(2);
        printf("expected (posted_qlen,unexpected_qlen) = (0,1)\n");

        MPI_Isend(&buf1, 1, MPI_INT, 0, /*tag=*/22, MPI_COMM_SELF, &r2);
        print_vars(3);
        printf("expected (posted_qlen,unexpected_qlen) = (0,2)\n");

        MPI_Irecv(&buf2, 1, MPI_INT, 0, /*tag=*/33, MPI_COMM_SELF, &r3);
        print_vars(4);
        printf("expected (posted_qlen,unexpected_qlen) = (1,2)\n");

        MPI_Recv(&buf3, 1, MPI_INT, 0, /*tag=*/22, MPI_COMM_SELF, MPI_STATUS_IGNORE);
        MPI_Wait(&r2, MPI_STATUS_IGNORE);
        print_vars(5);
        printf("expected (posted_qlen,unexpected_qlen) = (1,1)\n");

        MPI_Recv(&buf3, 1, MPI_INT, 0, /*tag=*/11, MPI_COMM_SELF, MPI_STATUS_IGNORE);
        MPI_Wait(&r1, MPI_STATUS_IGNORE);
        print_vars(6);
        printf("expected (posted_qlen,unexpected_qlen) = (1,0)\n");

        MPI_Send(&buf3, 1, MPI_INT, 0, /*tag=*/33, MPI_COMM_SELF);
        MPI_Wait(&r3, MPI_STATUS_IGNORE);
        print_vars(7);
        printf("expected (posted_qlen,unexpected_qlen) = (0,0)\n");
    }

    if (pqm_writable) {
        posted_queue_match_attempts = 0;
        MPI_T_pvar_write(session, pqm_handle, &posted_queue_match_attempts);
    }
    if (uqm_writable) {
        unexpected_queue_match_attempts = 0;
        MPI_T_pvar_write(session, uqm_handle, &unexpected_queue_match_attempts);
    }
    print_vars(8);

    /* cleanup */
    MPI_T_pvar_handle_free(session, &uqm_handle);
    MPI_T_pvar_handle_free(session, &pqm_handle);
    MPI_T_pvar_handle_free(session, &uq_handle);
    MPI_T_pvar_handle_free(session, &pq_handle);
    MPI_T_pvar_session_free(&session);

    MPI_T_finalize();
    MPI_Finalize();

    return 0;
}
Example #3
0
int main(int argc, char **argv)
{
    int i;
    int num;
    int rank, size;
/*#define STR_SZ (15)*/
#define STR_SZ (50)
    int name_len = STR_SZ;
    char name[STR_SZ] = "";
    int desc_len = STR_SZ;
    char desc[STR_SZ] = "";
    int verb;
    MPI_Datatype dtype;
    int count;
    int bind;
    int scope;
    int provided;
    int initialize_mpi = 0;
    MPI_T_cvar_handle handle;
    MPI_T_enum enumtype;

    provided = 0xdeadbeef;
    MPI_T_init_thread(MPI_THREAD_SINGLE, &provided);
    assert(provided != 0xdeadbeef);

    if (initialize_mpi) {
        MPI_Init(&argc, &argv);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Comm_size(MPI_COMM_WORLD, &size);
    }

    num = 0xdeadbeef;
    MPI_T_cvar_get_num(&num);
    printf("get_num=%d\n", num);
    assert(num != 0xdeadbeef);
    for (i = 0; i < num; ++i) {
        name_len = desc_len = STR_SZ;
        MPI_T_cvar_get_info(i, name, &name_len, &verb, &dtype, &enumtype, desc, &desc_len, &bind, &scope);
        printf("index=%d\n", i);
        printf("--> name='%s' name_len=%d desc='%s' desc_len=%d\n", name, name_len, desc, desc_len);
        printf("--> verb=%d dtype=%#x bind=%d scope=%d\n", verb, dtype, bind, scope);

        MPI_T_cvar_handle_alloc(i, NULL, &handle, &count);
        printf("--> handle allocated: handle=%p count=%d\n", handle, count);
        if (dtype == MPI_INT) {
            int val = 0xdeadbeef;
            MPI_T_cvar_read(handle, &val);
            printf("--> val=%d\n", val);
            ++val;
            MPI_T_cvar_write(handle, &val);
            val = 0xdeadbeef;
            MPI_T_cvar_read(handle, &val);
            printf("--> incremented val=%d\n", val);
        }
        else if (dtype == MPI_DOUBLE) {
            double val = NAN;
            MPI_T_cvar_read(handle, &val);
            printf("--> val=%f\n", val);
            val *= 2.0;
            MPI_T_cvar_write(handle, &val);
            val = NAN;
            MPI_T_cvar_read(handle, &val);
            printf("--> doubled val=%f\n", val);
        }
        else if (dtype == MPI_CHAR) {
            char *str = malloc(count+1);
            MPI_T_cvar_read(handle, str);
            printf("--> str='%s'\n", str);
            /* just write the string back unmodified for now */
            MPI_T_cvar_write(handle, str);
            MPI_T_cvar_read(handle, str);
            printf("--> written-then-read str='%s'\n", str);
        }
        MPI_T_cvar_handle_free(&handle);
        printf("\n");
    }

    if (initialize_mpi) {
        MPI_Finalize();
    }

    MPI_T_finalize();

    return 0;
}
Example #4
0
int main(int argc, char *argv[])
{
	int err,errarg;
	int threadsupport,threadsupport_t;
	int rank;
	int opt,erropt;
	int reqthread=MPI_THREAD_MULTIPLE;

	/* Read options */

	verbosity=MPI_T_VERBOSITY_MPIDEV_ALL;
	list_pvar=1;
	list_cvar=1;
	longlist=0;
	runmpi=1;
	errarg=0;

	while ((opt=getopt(argc,argv, "hv:pclim")) != -1 ) {
		switch (opt) {
		case 'h':
			errarg=-1;
			break;
		case 'v':
			switch (atoi(optarg)) {
			case 1: verbosity=MPI_T_VERBOSITY_USER_BASIC; break;
			case 2: verbosity=MPI_T_VERBOSITY_USER_DETAIL; break;
			case 3: verbosity=MPI_T_VERBOSITY_USER_ALL; break;
			case 4: verbosity=MPI_T_VERBOSITY_TUNER_BASIC; break;
			case 5: verbosity=MPI_T_VERBOSITY_TUNER_DETAIL; break;
			case 6: verbosity=MPI_T_VERBOSITY_TUNER_ALL; break;
			case 7: verbosity=MPI_T_VERBOSITY_MPIDEV_BASIC; break;
			case 8: verbosity=MPI_T_VERBOSITY_MPIDEV_DETAIL; break;
			case 9: verbosity=MPI_T_VERBOSITY_MPIDEV_ALL; break;
			}
			break;
			case 'p':
				list_pvar=1;
				list_cvar=0;
				break;
			case 'c':
				list_cvar=1;
				list_pvar=0;
				break;
			case 'l':
				longlist=1;
				break;
			case 'm':
				runmpi=0;
				break;
			default:
				errarg=1;
				erropt=opt;
				break;
		}
	}

	/* Initialize */

	if (runmpi)
	{
		err=MPI_Init_thread(&argc,&argv,reqthread,&threadsupport);
		CHECKERR("Init",err);

		err=MPI_Comm_rank(MPI_COMM_WORLD,&rank);
		CHECKERR("Rank",err);
	}
	else
		rank=0;


	/* ONLY FOR RANK 0 */

	if (rank==0)
	{
		err=MPI_T_init_thread(reqthread, &threadsupport_t);
		CHECKERR("T_Init",err);

		if (errarg)
		{
			if (errarg>0)
				printf("Argument error: %c\n",erropt);
			usage(errarg!=-1);
		}


		/* Header */

		printf("MPI_T Variable List\n");

		if (runmpi)
		{
			/* Print thread support for MPI */

			printf("  MPI Thread support: ");
			switch (threadsupport) {
			case MPI_THREAD_SINGLE:
				printf("MPI_THREAD_SINGLE\n");
				break;
			case MPI_THREAD_FUNNELED:
				printf("MPI_THREAD_FUNNELED\n");
				break;
			case MPI_THREAD_SERIALIZED:
				printf("MPI_THREAD_SERIALIZED\n");
				break;
			case MPI_THREAD_MULTIPLE:
				printf("MPI_THREAD_MULTIPLE\n");
				break;
			default:
				printf("unknown (%i)\n",threadsupport);
			}
		}

		/* Print thread support for MPI_T */

		printf("  MPI_T Thread support: ");
		switch (threadsupport_t) {
		case MPI_THREAD_SINGLE:
			printf("MPI_THREAD_SINGLE\n");
			break;
		case MPI_THREAD_FUNNELED:
			printf("MPI_THREAD_FUNNELED\n");
			break;
		case MPI_THREAD_SERIALIZED:
			printf("MPI_THREAD_SERIALIZED\n");
			break;
		case MPI_THREAD_MULTIPLE:
			printf("MPI_THREAD_MULTIPLE\n");
			break;
		default:
			printf("unknown (%i)\n",threadsupport_t);
		}

		/* Start MPI_T */


		if (list_cvar)
		{
			printf("\n===============================\n");
			printf("Control Variables");
			printf("\n===============================\n\n");
			list_cvars();
			printf("\n");
		}

		if (list_pvar)
		{
			printf("\n===============================\n");
			printf("Performance Variables");
			printf("\n===============================\n\n");
			list_pvars();
			printf("\n");
		}
	}

	/* Clean up */

	if (runmpi)
	{
		err=MPI_Barrier(MPI_COMM_WORLD);
		CHECKERR("Barrier",err);
	}

	if (rank==0)
		MPI_T_finalize();

	if (runmpi)
		MPI_Finalize();

	if (rank==0)
		printf("Done.\n");

	return 0;
}
int main(int argc, char *argv[])
{
    int i, size, num, name_len, desc_len, verb, thread_support;
    int varclass, bind, readonly, continuous, atomic, uqsize_idx, count;
    char name[STR_LEN], desc[STR_LEN];
    MPI_Datatype dtype;
    MPI_T_enum enumtype;

    MPI_Init(NULL, NULL);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    if (rank == 0) {
        printf("MPIT pvar test: unexpected_recvq_buffer_size\n");
        fflush(stdout);
    }

    /* Ensure we're using exactly two ranks. */
    /* Future tests (using collectives) might need this because of the MPI_Barrier */
    assert(size == 2);

    /* Standard MPIT initialization. */
    TRY(MPI_T_init_thread(MPI_THREAD_SINGLE, &thread_support));
    TRY(MPI_T_pvar_get_num(&num));

    int found = 0;

    /* Locate desired MPIT variable. */
    for (i = 0; i < num; i++) {
        name_len = desc_len = STR_LEN;
        TRY(MPI_T_pvar_get_info(i, name, &name_len, &verb, &varclass, &dtype,
                                &enumtype, desc, &desc_len, &bind, &readonly,
                                &continuous, &atomic));

        if (strcmp(name, "unexpected_recvq_buffer_size") == 0) {
            uqsize_idx = i;
            found = 1;
        }
    }

    if (found) {
        /* Initialize MPIT session & variable handle. */
        MPI_T_pvar_session_create(&session);
        MPI_T_pvar_handle_alloc(session, uqsize_idx, NULL, &uqsize_handle, &count);

        /* Ensure the variable is of the correct size. */
        assert(count == 1);

        /* Run a batch of tests. */
        reversed_tags_test();
        rndv_test();

        /* Cleanup. */
        MPI_T_pvar_handle_free(session, &uqsize_handle);
        MPI_T_pvar_session_free(&session);
    }

    if (rank == 0) {
        printf("finished\n");
        fflush(stdout);
    }

    TRY(MPI_T_finalize());
    MPI_Finalize();

    return 0;
}
Example #6
0
int main(int argc, char **argv)
{
    int errs = 0;
    int i, j;
    int rank, size;
    int num_pvars, num_cvars, num_cat;
#define STR_SZ (50)
    int name_len;
    char name[STR_SZ + 1] = ""; /* +1 to check for overrun */
    int desc_len;
    char desc[STR_SZ + 1] = ""; /* +1 to check for overrun */
    int verb;
    MPI_Datatype dtype;
    int count;
    int bind;
    int scope;
    int provided;

    /* Init'ed to a garbage value, to trigger MPI_T bugs easily if there are. */
    MPI_T_enum enumtype = (MPI_T_enum) 0x31415926;

    MTest_Init(&argc, &argv);
    MPI_T_init_thread(MPI_THREAD_SINGLE, &provided);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    /* loop over all cvars and ask for string arguments with various valid
     * combinations of NULL and non-NULL to ensure that the library handles this
     * case correctly */
    MPI_T_cvar_get_num(&num_cvars);
    for (i = 0; i < num_cvars; ++i) {
        int full_name_len, full_desc_len;
        /* pass NULL string, non-zero lengths; should get full lengths */
        full_name_len = full_desc_len = 1;
        MPI_T_cvar_get_info(i, NULL, &full_name_len, &verb, &dtype,
                            &enumtype, NULL, &full_desc_len, &bind, &scope);
        check(full_name_len >= 0);
        check(full_desc_len >= 0);

        /* pass non-NULL string, zero lengths; should get full lengths also */
        name_len = desc_len = 0;
        MPI_T_cvar_get_info(i, name, &name_len, &verb, &dtype,
                            &enumtype, desc, &desc_len, &bind, &scope);
        check(full_name_len == name_len);
        check(full_desc_len == desc_len);

        /* regular call, no NULLs; should truncate (with termination) to STR_SZ
         * if necessary, otherwise returns strlen+1 in the corresponding "_len"
         * var */
        name_len = desc_len = STR_SZ;
        MPI_T_cvar_get_info(i, name, &name_len, &verb, &dtype,
                            &enumtype, desc, &desc_len, &bind, &scope);
        check((strlen(name) + 1) == min(name_len, STR_SZ));
        check((strlen(desc) + 1) == min(desc_len, STR_SZ));

        /* pass NULL lengths, string buffers should be left alone */
        for (j = 0; j < STR_SZ; ++j) {
            name[j] = j % CHAR_MAX;
            desc[j] = j % CHAR_MAX;
        }
        MPI_T_cvar_get_info(i, name, /*name_len= */ NULL, &verb, &dtype,
                            &enumtype, desc, /*desc_len= */ NULL, &bind, &scope);
        for (j = 0; j < STR_SZ; ++j) {
            check(name[j] == j % CHAR_MAX);
            check(desc[j] == j % CHAR_MAX);
        }

        /* not much of a string test, just need a quick spot to stick a test for
         * the existence of the correct MPI_T prototype (tt#1727) */
        /* Include test that enumtype is defined */
        if (dtype == MPI_INT && enumtype != MPI_T_ENUM_NULL) {
            int num_enumtype = -1;
            name_len = STR_SZ;
            MPI_T_enum_get_info(enumtype, &num_enumtype, name, &name_len);
            check(num_enumtype >= 0);
        }
    }

    /* check string handling for performance variables */
    MPI_T_pvar_get_num(&num_pvars);
    for (i = 0; i < num_pvars; ++i) {
        int varclass, bind, readonly, continuous, atomic;
        MPI_Datatype dtype;
        MPI_T_enum enumtype;

        int full_name_len, full_desc_len;
        /* pass NULL string, non-zero lengths; should get full lengths */
        full_name_len = full_desc_len = 1;
        MPI_T_pvar_get_info(i, NULL, &full_name_len, &verb, &varclass, &dtype,
                            &enumtype, NULL, &full_desc_len, &bind, &readonly,
                            &continuous, &atomic);
        check(full_name_len >= 0);
        check(full_desc_len >= 0);

        /* pass non-NULL string, zero lengths; should get full lengths also */
        name_len = desc_len = 0;
        MPI_T_pvar_get_info(i, name, &name_len, &verb, &varclass, &dtype,
                            &enumtype, desc, &desc_len, &bind, &readonly, &continuous, &atomic);
        check(full_name_len == name_len);
        check(full_desc_len == desc_len);

        /* regular call, no NULLs; should truncate (with termination) to STR_SZ
         * if necessary, otherwise returns strlen+1 in the corresponding "_len"
         * var */
        name[STR_SZ] = (char) 'Z';
        desc[STR_SZ] = (char) 'Z';
        name_len = desc_len = STR_SZ;
        MPI_T_pvar_get_info(i, name, &name_len, &verb, &varclass, &dtype,
                            &enumtype, desc, &desc_len, &bind, &readonly, &continuous, &atomic);
        check((strlen(name) + 1) == min(name_len, STR_SZ));
        check((strlen(desc) + 1) == min(desc_len, STR_SZ));
        check(name[STR_SZ] == (char) 'Z');
        check(desc[STR_SZ] == (char) 'Z');

        /* pass NULL lengths, string buffers should be left alone */
        for (j = 0; j < STR_SZ; ++j) {
            name[j] = j % CHAR_MAX;
            desc[j] = j % CHAR_MAX;
        }
        MPI_T_pvar_get_info(i, name, /*name_len= */ NULL, &verb, &varclass, &dtype,
                            &enumtype, desc, /*desc_len= */ NULL, &bind, &readonly,
                            &continuous, &atomic);
        for (j = 0; j < STR_SZ; ++j) {
            check(name[j] == j % CHAR_MAX);
            check(desc[j] == j % CHAR_MAX);
        }
    }

    /* check string handling for categories */
    MPI_T_category_get_num(&num_cat);
    for (i = 0; i < num_cat; ++i) {
        int full_name_len, full_desc_len;
        /* pass NULL string, non-zero lengths; should get full lengths */
        full_name_len = full_desc_len = 1;
        MPI_T_category_get_info(i, NULL, &full_name_len, NULL, &full_desc_len,
                                &num_cvars, &num_pvars, /*num_categories= */ &j);
        check(full_name_len >= 0);
        check(full_desc_len >= 0);

        /* pass non-NULL string, zero lengths; should get full lengths also */
        name_len = desc_len = 0;
        MPI_T_category_get_info(i, name, &name_len, desc, &desc_len,
                                &num_cvars, &num_pvars, /*num_categories= */ &j);
        check(full_name_len == name_len);
        check(full_desc_len == desc_len);

        /* regular call, no NULLs; should truncate (with termination) to STR_SZ
         * if necessary, otherwise returns strlen+1 in the corresponding "_len"
         * var */
        name[STR_SZ] = (char) 'Z';
        desc[STR_SZ] = (char) 'Z';
        name_len = desc_len = STR_SZ;
        MPI_T_category_get_info(i, name, &name_len, desc, &desc_len,
                                &num_cvars, &num_pvars, /*num_categories= */ &j);
        check((strlen(name) + 1) == min(name_len, STR_SZ));
        check((strlen(desc) + 1) == min(desc_len, STR_SZ));
        check(name[STR_SZ] == (char) 'Z');
        check(desc[STR_SZ] == (char) 'Z');

        /* pass NULL lengths, string buffers should be left alone */
        for (j = 0; j < STR_SZ; ++j) {
            name[j] = j % CHAR_MAX;
            desc[j] = j % CHAR_MAX;
        }
        MPI_T_category_get_info(i, name, /*name_len= */ NULL, desc,
                                /*desc_len= */ NULL, &num_cvars, &num_pvars,
                                /*num_categories= */ &j);
        for (j = 0; j < STR_SZ; ++j) {
            check(name[j] == j % CHAR_MAX);
            check(desc[j] == j % CHAR_MAX);
        }

        /* not really a string test, just need a quick spot to stick a test for the
         * existence of the correct MPI_T prototype (tt#1727) */
        {
            int indices[1];
            MPI_T_category_get_pvars(i, 1, indices);
        }
    }

    MPI_T_finalize();
    MTest_Finalize(errs);

    return MTestReturnValue(errs);
}