Tuesday, November 30, 2010

MPI and Cartesian communicators

/* ----------------------------------------------------------------------- */
/*
 * file:        mpi-cart.c
 * compilation: mpicc -Wall -Wextra mpi-cart.c -o mpi-cart
 * invocation:  mpirun -n 8 mpi-cart
 */
/* ----------------------------------------------------------------------- */
/* Studying MPI functions related to the Cartesian topologies */
/* ----------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
/* ----------------------------------------------------------------------- */
#include <mpi.h>
/* ----------------------------------------------------------------------- */
typedef struct MPI_Data_s
{
    MPI_Comm comm;
    int size;
    int rank;
    int root;
} MPI_Data;
/* ----------------------------------------------------------------------- */
#define CART2D_NDIMS 2
typedef struct MPI_Cart2D_Data_s
{
    MPI_Data mpi_data;
    int ndims;
    int dims[CART2D_NDIMS];
    int periods[CART2D_NDIMS];
    int coords[CART2D_NDIMS];
} MPI_Cart2D_Data;
/* ----------------------------------------------------------------------- */
#define CART4D_NDIMS 4
typedef struct MPI_Cart4D_Data_s
{
    MPI_Data mpi_data;
    int ndims;
    int dims[CART4D_NDIMS];
    int periods[CART4D_NDIMS];
    int coords[CART4D_NDIMS];
} MPI_Cart4D_Data;
/* ----------------------------------------------------------------------- */
void Create_2D_Subcomms(MPI_Cart4D_Data *cart4d, int *remain_dims,
        MPI_Cart2D_Data *cart2d)
{
    MPI_Cart_sub(cart4d->mpi_data.comm, remain_dims,
            &(cart2d->mpi_data.comm)
    );

    MPI_Comm_size(cart2d->mpi_data.comm, &(cart2d->mpi_data.size));
    MPI_Comm_rank(cart2d->mpi_data.comm, &(cart2d->mpi_data.rank));
    cart2d->mpi_data.root = 0;
    cart2d->ndims = CART2D_NDIMS;
    MPI_Cart_get(cart2d->mpi_data.comm, cart2d->ndims,
            cart2d->dims, cart2d->periods, cart2d->coords);
}
/* ----------------------------------------------------------------------- */
int main(int argc, char **argv)
{
    /* Some variables */
    MPI_Data world;
    MPI_Cart4D_Data cart4d;
    int remain_dims[CART4D_NDIMS];
    MPI_Cart2D_Data cart2d_01, cart2d_12;

    /* Beginning of the program */
    MPI_Init(&argc, &argv);

    /* Fill-in MPI_COMM_WORLD data */
    world.comm = MPI_COMM_WORLD;
    MPI_Comm_size(world.comm, &(world.size));
    MPI_Comm_rank(world.comm, &(world.rank));
    world.root = 0;

    /* Create a division of processors in a 4D Cartesian grid */
    cart4d.ndims = CART4D_NDIMS;
    cart4d.dims[0] = 0;
    cart4d.dims[1] = 0;
    cart4d.dims[2] = 0;
    cart4d.dims[3] = 1;
    MPI_Dims_create(world.size, cart4d.ndims, cart4d.dims);
    if (world.rank == world.root)
        printf("cart4d dims: <%d, %d, %d, %d>\n",
                cart4d.dims[0],
                cart4d.dims[1],
                cart4d.dims[2],
                cart4d.dims[3]
        );

    /* Create a new communicator with 4D Cartesian topology attached */
    cart4d.periods[0] = 0;
    cart4d.periods[1] = 0;
    cart4d.periods[2] = 0;
    cart4d.periods[3] = 0;
    MPI_Cart_create(world.comm, cart4d.ndims, cart4d.dims, cart4d.periods,
            1, &(cart4d.mpi_data.comm)
    );

    /* Fill-in 4D Cartesian communicator data */
    MPI_Comm_size(cart4d.mpi_data.comm, &(cart4d.mpi_data.size));
    MPI_Comm_rank(cart4d.mpi_data.comm, &(cart4d.mpi_data.rank));
    cart4d.mpi_data.root = 0;
    MPI_Cart_coords(cart4d.mpi_data.comm, cart4d.mpi_data.rank,
            cart4d.ndims, cart4d.coords
    );

    /* Create 2D subcommunicators and fill-in associated data */
    remain_dims[0] = 1;
    remain_dims[1] = 1;
    remain_dims[2] = 0;
    remain_dims[3] = 0;
    Create_2D_Subcomms(&cart4d, remain_dims, &cart2d_01);

    remain_dims[0] = 0;
    remain_dims[1] = 1;
    remain_dims[2] = 1;
    remain_dims[3] = 0;
    Create_2D_Subcomms(&cart4d, remain_dims, &cart2d_12);

    /* Print info on communicators */
    printf("world: %d; cart4d: %d, (%d, %d, %d, %d); "
            "cart2d_01: %d, (%d, %d); cart2d_12: %d, (%d, %d)\n",
            world.rank,
            cart4d.mpi_data.rank,
            cart4d.coords[0],
            cart4d.coords[1],
            cart4d.coords[2],
            cart4d.coords[3],
            cart2d_01.mpi_data.rank,
            cart2d_01.coords[0],
            cart2d_01.coords[1],
            cart2d_12.mpi_data.rank,
            cart2d_12.coords[0],
            cart2d_12.coords[1]
    );

    /* End of the program */
    MPI_Finalize();

    return EXIT_SUCCESS;
}
/* ----------------------------------------------------------------------- */

Thursday, November 25, 2010

libiniparser sample

Ini-file:

# File: hpc-poisson.ini
#
# The file was created to examine what is libiniparser.
#
# The need to parse ini-files comes from the problem of testing
# Poisson's equation solver for various grids and number of processors.
#
# Note, that keywords and names of sections are lowercased.

# Some comments here look stupid - their purpose is demonstrate
# what is comment in ini-file.

[Test1]     ; Test #1
N1 = 64     ; Number of grid intervals in each direction
N2 = 128
N3 = 256

L1 = 1.0    ; The length of the domain in each direction
L2 = 2.0
L3 = 4.0

[TEST2]     ; Test #2
n1 = 640
n2 = 1280
n3 = 2560

l1 = 1.5
l2 = 2.5
l3 = 4.5

Source code:

/* File: main.c */

/* gcc -Wall -Wextra main.c -liniparser */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <iniparser.h>

int main()
{
    const char *ini_fname;
    dictionary *dict;
    int num_secs;   /* Number of sections in ini file */
    int curr_sec;   /* Index of current section */

    ini_fname = "hpc-poisson.ini";
    dict = iniparser_load(ini_fname);
    assert(dict);

    num_secs = iniparser_getnsec(dict);
    printf("{number of sections: %d}\n", num_secs);

    for (curr_sec = 0; curr_sec < num_secs; ++curr_sec)
    {
        char *section;
        const char *keyword;
        char *key;  /* The value of this var is constructed as "section:keyword" */
        int val;

        /* Get name of the current section */
        section = iniparser_getsecname(dict, curr_sec);
        assert(section);
        printf("[%s]\n", section);

        /* Construct key[] */
        keyword = "n2";
        key = malloc(
                (strlen(section) + strlen(":") + strlen(keyword) + strlen("\0")) *
                sizeof(key[0])
        );
        sprintf(key, "%s:%s", section, keyword);

        /* Get value associated with the key */
        val = iniparser_getint(dict, key, -1);
        printf("%s=%d\n", keyword, val);
        free(key);
    }

    iniparser_freedict(dict);

    return EXIT_SUCCESS;
}