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

#define LENGTH 30000000

int main(int argc, char** argv) {
    float *a, *b, *r, *a_loc, *b_loc, *r_loc;
    long i, i_loc, proc, n_loc;
    double start, end;
    int my_rank, p;
    MPI_Status status;

    MPI_Init(&argc,(char***) &argv);

    MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
    MPI_Comm_size(MPI_COMM_WORLD, &p);

    n_loc = LENGTH / p;

    if (my_rank == 0) {
	a = (float*) malloc(LENGTH * sizeof(float));
	b = (float*) malloc(LENGTH * sizeof(float));
	r = (float*) malloc(LENGTH * sizeof(float));

	a_loc = a;
	b_loc = b;
	r_loc = r;

	for (i=0; i<LENGTH; i++) {
	    a[i] = rand();
	    b[i] = rand();
	}
	for (proc=1; proc<p; proc++) {
	    MPI_Send(&(a[n_loc*proc]), n_loc, MPI_FLOAT, proc, 1, MPI_COMM_WORLD);
	    MPI_Send(&(b[n_loc*proc]), n_loc, MPI_FLOAT, proc, 2, MPI_COMM_WORLD);
	}
    } else {
	a_loc = (float*) malloc(n_loc * sizeof(float));
	b_loc = (float*) malloc(n_loc * sizeof(float));
	r_loc = (float*) malloc(n_loc * sizeof(float));

	MPI_Recv(a_loc, n_loc, MPI_FLOAT, 0, 1, MPI_COMM_WORLD, &status);
	MPI_Recv(b_loc, n_loc, MPI_FLOAT, 0, 2, MPI_COMM_WORLD, &status);
    }

    start = MPI_Wtime();

    for (i=0; i<n_loc; i++) {
	r_loc[i] = a_loc[i] + b_loc[i];
    }

    end = MPI_Wtime();

    if (my_rank !=0) {
	MPI_Send(r_loc, n_loc, MPI_FLOAT, 0, 1, MPI_COMM_WORLD);
    } else {
	for (proc=1; proc < p; proc++) {
	    MPI_Recv( &(r[n_loc*proc]), n_loc, MPI_FLOAT, proc, 1, MPI_COMM_WORLD, &status);
	}
    }

    printf("Process %d: elapsed time %f\n", my_rank, end-start);
    
    fflush(stdout);
    fflush(stderr);
    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Finalize();

    return 0;
}

