/* $Id: accu.c 1401 2006-12-15 16:04:57Z olau $
 *
 * Copyright (c) 2006 Oliver Lau <ola@ctmagazin.de>
 * Copyright (c) 2006 Heise Zeitschriften Verlag
 * Alle Rechte vorbehalten. All rights reserved.
 *
 */

#include <stdlib.h>
#include <mpi.h>

#include "globaldefs.h"

#define BUFSIZE              (10)
#define MPI_NO_ASSERTION      (0)

#define FENCE                  0x1
#define START_WAIT             0x2
#define SYNC                   FENCE

int main(int argc, char *argv[]) {
    int myrank, size;
    int *buf;
    int size_of_int;
    int i;
    MPI_Win win;
#if SYNC == START_WAIT
    MPI_Group group;
#endif

    MPI_Init(&argc, &argv);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    if (size != 2)
        MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);

    MPI_Comm_rank(MPI_COMM_WORLD, &myrank);

#if SYNC == START_WAIT
    MPI_Comm_group(MPI_COMM_WORLD, &group);
#endif

    MPI_Type_extent(MPI_INT, &size_of_int);

    MPI_Alloc_mem(BUFSIZE * size_of_int, MPI_INFO_NULL, &buf);
    MPI_Win_create(buf, BUFSIZE * size_of_int, size_of_int, MPI_INFO_NULL, MPI_COMM_WORLD, &win);

    switch(myrank) {

        ////////////////////////////////////////////////////////////
        /// Target
        ////////////////////////////////////////////////////////////
        case 0:
            for (i = 0; i < BUFSIZE; ++i)
                buf[i] = 2;
            INFO("Beginn der Exposition\n");
#if SYNC == FENCE
            MPI_Win_fence(MPI_NO_ASSERTION, win); 
#elif SYNC == START_WAIT
            MPI_Win_post(group, MPI_NO_ASSERTION, win);
#else 
#error Ungültige Synchronisierungsmethode
#endif

            // warten, dass Prozess 1 RMA vollzieht ...

            INFO("Ende der Exposition\n");
#if SYNC == FENCE
            MPI_Win_fence(MPI_NO_ASSERTION, win); 
#elif SYNC == START_WAIT
            MPI_Win_wait(win);
#else 
#error Ungültige Synchronisierungsmethode
#endif

            for (i = 0; i < BUFSIZE; ++i)
                printf("%d ", buf[i]);
            printf("\n");
            break;


        ////////////////////////////////////////////////////////////
        /// Origin
        ////////////////////////////////////////////////////////////
        case 1:
            for (i = 0; i < BUFSIZE; ++i)
                buf[i] = i;

            INFO("Beginn des Zugriffszeitraums\n");
#if SYNC == FENCE
            MPI_Win_fence(MPI_NO_ASSERTION, win); 
#elif SYNC == START_WAIT
            MPI_Win_start(group, MPI_NO_ASSERTION, win);
#else
#error Ungültige Synchronisierungsmethode
#endif

            MPI_Accumulate(buf, BUFSIZE, MPI_INT, 0, 0, BUFSIZE, MPI_INT, MPI_PROD, win);

            INFO("Ende des Zugriffszeitraums\n");
#if SYNC == FENCE
            MPI_Win_fence(MPI_NO_ASSERTION, win); 
#elif SYNC == START_WAIT
            MPI_Win_complete(win);
#else
#error Ungültige Synchronisierungsmethode
#endif
            break;
    }
    INFO("Fertig.\n");

    MPI_Win_free(&win);
#if SYNC == START_WAIT
    MPI_Group_free(&group);
#endif
    MPI_Free_mem(buf);
    MPI_Finalize();

    return EXIT_SUCCESS;
}
