#include <stdio.h>
#include "mpi.h"
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define TEST_SIZE 250*1024*1024

int main(int argc, char **argv)
{
	double *buf1, *buf2;
	int fd, i;
	struct timeval start, start1, end, end1;
	unsigned long time_diff;
	int rank = 0;
	char filename[256];
	unsigned long offset;

	int iter, jobsize;
	MPI_Comm    comm=MPI_COMM_WORLD;
	MPI_Init (&argc, &argv);
	MPI_Comm_rank (MPI_COMM_WORLD, &rank);
	MPI_Comm_size (comm, &jobsize);


for (iter = 1 ; iter < 2 ; iter++) {

	if (rank == 0)
		printf("Iteration %d, size = %d\n", iter, jobsize);

	gettimeofday(&start, NULL);
	MPI_Barrier (comm);
	gettimeofday(&end, NULL);

	time_diff = (unsigned long)(end.tv_sec - start.tv_sec)*1000000 +
		    (end.tv_usec-start.tv_usec);

	if (rank == 0)
		printf("%d: barrier time: %lf sec\n", rank, (double)time_diff/1000000 );

	if (iter == 1 || rank == 0) {
	
	buf1=malloc(TEST_SIZE);
	buf2=malloc(TEST_SIZE);

	if (!buf1 || !buf2)
		return -1;

	gettimeofday(&start, NULL);

	memset(buf1, 'A', TEST_SIZE);
	
	gettimeofday(&end, NULL);

	time_diff = (unsigned long)(end.tv_sec - start.tv_sec)*1000000 +
		    (end.tv_usec-start.tv_usec);

	printf("%d: memset speed: %lf MB/sec\n", rank, (double)TEST_SIZE/time_diff * 1.048576);

	gettimeofday(&start, NULL);
#if 1
	memset(buf2, buf1, TEST_SIZE);
#else
	for (i = 0; i < TEST_SIZE/sizeof(double) ; i++) {
		buf2[i] = buf1[i];
	}
#endif

	gettimeofday(&end, NULL);

        time_diff = (unsigned long)(end.tv_sec - start.tv_sec)*1000000 +
                    (end.tv_usec-start.tv_usec);

        printf("%d: memcopy speed: %lf MB/sec\n", rank, (double)TEST_SIZE/time_diff * 1.048576);

	sprintf(filename, "output.%d", rank);
	fd = open(filename, O_RDWR|O_TRUNC, 0666);
	if (fd < 0)
		return -2;

	if (iter) {
		gettimeofday(&start, NULL);
		MPI_Barrier (comm);
		gettimeofday(&end, NULL);

		time_diff = (unsigned long)(end.tv_sec - start.tv_sec)*1000000 +
			    (end.tv_usec-start.tv_usec);

		if (rank == 0)
			printf("%d: barrier time: %lf sec\n", rank, (double)time_diff/1000000 );
	}


	gettimeofday(&start, NULL);
	offset = write(fd, buf1, TEST_SIZE);
	gettimeofday(&end, NULL);

	if (rank == 0)
		gettimeofday(&start1, NULL);
	if (iter)
		MPI_Barrier (comm);
	if (rank == 0) {
		gettimeofday(&end1, NULL);

		time_diff = (unsigned long)(end1.tv_sec-start.tv_sec)*1000000 +
			    (end1.tv_usec-start.tv_usec);

		printf("%d: total fwrite speed: %lf MB/sec total time %lf sec\n", rank, (double)TEST_SIZE/time_diff * 1.048576 * jobsize, (double)time_diff/1000000);

		time_diff = (unsigned long)(end1.tv_sec-start1.tv_sec)*1000000 +
			    (end1.tv_usec-start1.tv_usec);
		printf("%d: barrier after write time: %lf sec\n", rank, (double)time_diff/1000000 );
		
	}
	if (rank == 0)
		gettimeofday(&start1, NULL);
	if (iter)
		MPI_Barrier (comm);
	if (rank == 0) {
		gettimeofday(&end1, NULL);

		time_diff = (unsigned long)(end1.tv_sec-start1.tv_sec)*1000000 +
			    (end1.tv_usec-start1.tv_usec);
		printf("%d: barrier after write 2 time: %lf sec\n", rank, (double)time_diff/1000000 );
	}

	if (iter)
		MPI_Barrier (comm);
        time_diff = (unsigned long)(end.tv_sec - start.tv_sec)*1000000 +
                    (end.tv_usec-start.tv_usec);
	printf("%d: fwrite speed: %lf MB/sec time %lf sec\n", rank, (double)TEST_SIZE/time_diff * 1.048576, (double)time_diff/1000000);

	close(fd);
	free(buf1);
	free(buf2);
}
	gettimeofday(&start, NULL);
	MPI_Barrier (comm);
	gettimeofday(&end, NULL);

	time_diff = (unsigned long)(end.tv_sec - start.tv_sec)*1000000 +
		    (end.tv_usec-start.tv_usec);

	if (rank == 0)
		printf("%d: barrier time: %lf sec\n", rank, (double)time_diff/1000000 );


}
	MPI_Finalize ();

	return 0;
}
