Blame test/mpi/comm/cmsplit2.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2011 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
/* This test ensures that MPI_Comm_split breaks ties in key values by using the
Packit Service c5cf8c
 * original rank in the input communicator.  This typically corresponds to
Packit Service c5cf8c
 * the difference between using a stable sort or using an unstable sort.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * It checks all sizes from 1..comm_size(world)-1, so this test does not need to
Packit Service c5cf8c
 * be run multiple times at process counts from a higher-level test driver. */
Packit Service c5cf8c
Packit Service c5cf8c
#include <stdio.h>
Packit Service c5cf8c
#include <stdlib.h>
Packit Service c5cf8c
#include "mpi.h"
Packit Service c5cf8c
#include "mpitest.h"
Packit Service c5cf8c
Packit Service c5cf8c
#define ERRLIMIT (10)
Packit Service c5cf8c
Packit Service c5cf8c
#define my_assert(cond_)                                     \
Packit Service c5cf8c
    do {                                                     \
Packit Service c5cf8c
        if (!(cond_)) {                                      \
Packit Service c5cf8c
            if (errs < ERRLIMIT)                             \
Packit Service c5cf8c
                printf("assertion \"%s\" failed\n", #cond_); \
Packit Service c5cf8c
            ++errs;                                          \
Packit Service c5cf8c
        }                                                    \
Packit Service c5cf8c
    } while (0)
Packit Service c5cf8c
Packit Service c5cf8c
int main(int argc, char **argv)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, j, pos, modulus, cs, rank, size;
Packit Service c5cf8c
    int wrank, wsize;
Packit Service c5cf8c
    int newrank, newsize;
Packit Service c5cf8c
    int errs = 0;
Packit Service c5cf8c
    int key;
Packit Service c5cf8c
    int *oldranks = NULL;
Packit Service c5cf8c
    int *identity = NULL;
Packit Service c5cf8c
    int verbose = 0;
Packit Service c5cf8c
    MPI_Comm comm, splitcomm;
Packit Service c5cf8c
    MPI_Group wgroup, newgroup;
Packit Service c5cf8c
Packit Service c5cf8c
    MTest_Init(&argc, &argv);
Packit Service c5cf8c
Packit Service c5cf8c
    if (getenv("MPITEST_VERBOSE"))
Packit Service c5cf8c
        verbose = 1;
Packit Service c5cf8c
Packit Service c5cf8c
    MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
Packit Service c5cf8c
    MPI_Comm_size(MPI_COMM_WORLD, &wsize);
Packit Service c5cf8c
Packit Service c5cf8c
    oldranks = malloc(wsize * sizeof(int));
Packit Service c5cf8c
    identity = malloc(wsize * sizeof(int));
Packit Service c5cf8c
    for (i = 0; i < wsize; ++i) {
Packit Service c5cf8c
        identity[i] = i;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    for (cs = 1; cs <= wsize; ++cs) {
Packit Service c5cf8c
        /* yes, we are using comm_split to test comm_split, but this test is
Packit Service c5cf8c
         * mainly about ensuring that the stable sort behavior is correct, not
Packit Service c5cf8c
         * about whether the partitioning by color behavior is correct */
Packit Service c5cf8c
        MPI_Comm_split(MPI_COMM_WORLD, (wrank < cs ? 0 : MPI_UNDEFINED), wrank, &comm);
Packit Service c5cf8c
        if (comm != MPI_COMM_NULL) {
Packit Service c5cf8c
            MPI_Comm_rank(comm, &rank;;
Packit Service c5cf8c
            MPI_Comm_size(comm, &size);
Packit Service c5cf8c
Packit Service c5cf8c
            for (modulus = 1; modulus <= size; ++modulus) {
Packit Service c5cf8c
                /* Divide all ranks into one of "modulus" equivalence classes.  Ranks in
Packit Service c5cf8c
                 * output comm will be ordered first by class, then within the class by
Packit Service c5cf8c
                 * rank in comm world. */
Packit Service c5cf8c
                key = rank % modulus;
Packit Service c5cf8c
Packit Service c5cf8c
                /* all pass same color, variable keys */
Packit Service c5cf8c
                MPI_Comm_split(comm, 5, key, &splitcomm);
Packit Service c5cf8c
                MPI_Comm_rank(splitcomm, &newrank);
Packit Service c5cf8c
                MPI_Comm_size(splitcomm, &newsize);
Packit Service c5cf8c
                my_assert(newsize == size);
Packit Service c5cf8c
Packit Service c5cf8c
                MPI_Comm_group(MPI_COMM_WORLD, &wgroup);
Packit Service c5cf8c
                MPI_Comm_group(splitcomm, &newgroup);
Packit Service c5cf8c
                int gsize;
Packit Service c5cf8c
                MPI_Group_size(newgroup, &gsize);
Packit Service c5cf8c
                MPI_Group_translate_ranks(newgroup, size, identity, wgroup, oldranks);
Packit Service c5cf8c
                MPI_Group_free(&wgroup);
Packit Service c5cf8c
                MPI_Group_free(&newgroup);
Packit Service c5cf8c
Packit Service c5cf8c
                if (splitcomm != MPI_COMM_NULL)
Packit Service c5cf8c
                    MPI_Comm_free(&splitcomm);
Packit Service c5cf8c
Packit Service c5cf8c
                /* now check that comm_split broke any ties correctly */
Packit Service c5cf8c
                if (rank == 0) {
Packit Service c5cf8c
                    if (verbose) {
Packit Service c5cf8c
                        /* debugging code that is useful when the test fails */
Packit Service c5cf8c
                        printf("modulus=%d oldranks={", modulus);
Packit Service c5cf8c
                        for (i = 0; i < size - 1; ++i) {
Packit Service c5cf8c
                            printf("%d,", oldranks[i]);
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        printf("%d} keys={", oldranks[i]);
Packit Service c5cf8c
                        for (i = 0; i < size - 1; ++i) {
Packit Service c5cf8c
                            printf("%d,", i % modulus);
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                        printf("%d}\n", i % modulus);
Packit Service c5cf8c
                    }
Packit Service c5cf8c
Packit Service c5cf8c
                    pos = 0;
Packit Service c5cf8c
                    for (i = 0; i < modulus; ++i) {
Packit Service c5cf8c
                        /* there's probably a better way to write these loop bounds and
Packit Service c5cf8c
                         * indices, but this is the first (correct) way that occurred to me */
Packit Service c5cf8c
                        for (j = 0; j < (size / modulus + (i < size % modulus ? 1 : 0)); ++j) {
Packit Service c5cf8c
                            if (errs < ERRLIMIT && oldranks[pos] != i + modulus * j) {
Packit Service c5cf8c
                                printf
Packit Service c5cf8c
                                    ("size=%d i=%d j=%d modulus=%d pos=%d i+modulus*j=%d oldranks[pos]=%d\n",
Packit Service c5cf8c
                                     size, i, j, modulus, pos, i + modulus * j, oldranks[pos]);
Packit Service c5cf8c
                            }
Packit Service c5cf8c
                            my_assert(oldranks[pos] == i + modulus * j);
Packit Service c5cf8c
                            ++pos;
Packit Service c5cf8c
                        }
Packit Service c5cf8c
                    }
Packit Service c5cf8c
                }
Packit Service c5cf8c
            }
Packit Service c5cf8c
            MPI_Comm_free(&comm);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (oldranks != NULL)
Packit Service c5cf8c
        free(oldranks);
Packit Service c5cf8c
    if (identity != NULL)
Packit Service c5cf8c
        free(identity);
Packit Service c5cf8c
Packit Service c5cf8c
    MTest_Finalize(errs);
Packit Service c5cf8c
    return MTestReturnValue(errs);
Packit Service c5cf8c
}