/*-----------------------------------------------------------*/
int haloExchange(int benchmarkType){
	int dataSizeIter;

	/* find the ranks of the left and right neighbour */
	findNeighbours();

	/* initialise repsToDo to defaultReps */
	repsToDo = defaultReps;

	/* Start loop over data sizes */
	dataSizeIter = minDataSize; /* Initialise dataSizeIter */

    MPI_Barrier(comm);
	while (dataSizeIter <= maxDataSize){
		/* set sizeofBuffer */
		sizeofBuffer = dataSizeIter * numThreads;

		/*Allocate space for the main data arrays */
		allocateHaloexchangeData(sizeofBuffer);

		/* perform benchmark warm-up */
		if (benchmarkType == MASTERONLY){
			masteronlyHaloexchange(warmUpIters, dataSizeIter);
		}
		else if (benchmarkType == FUNNELLED){
			funnelledHaloexchange(warmUpIters, dataSizeIter);
		}
		else if (benchmarkType == MULTIPLE){
			multipleHaloexchange(warmUpIters, dataSizeIter);
		}

        GASPI(barrier(GASPI_GROUP_ALL, GASPI_BLOCK));
        /* Each process performs a verification test */
		testHaloexchange(sizeofBuffer, dataSizeIter);
        MPI_Barrier(comm);

		/*Initialise the benchmark */
		benchComplete = FALSE;

		/*Execute benchmark until target time is reached */
		while (benchComplete != TRUE){
			/*Start timer */
			GASPI(barrier(GASPI_GROUP_ALL, GASPI_BLOCK));
			startTime = MPI_Wtime();

			/*Execute benchmarkType for repsToDo repetitions*/
			if (benchmarkType == MASTERONLY){
				masteronlyHaloexchange(repsToDo, dataSizeIter);
			}
			else if (benchmarkType == FUNNELLED){
				funnelledHaloexchange(repsToDo, dataSizeIter);
			}
			else if (benchmarkType == MULTIPLE){
				multipleHaloexchange(repsToDo, dataSizeIter);
			}

			/*Stop timer */
			GASPI(barrier(GASPI_GROUP_ALL, GASPI_BLOCK));
			finishTime = MPI_Wtime();
			totalTime = finishTime - startTime;

            MPI_Barrier(comm);
            /* Test if target time is reached with the number of reps */
			if (myMPIRank==0){
			  benchComplete = repTimeCheck(totalTime, repsToDo);
			}
			/* Ensure all procs have the same value of benchComplete */
			/* and repsToDo */
			MPI_Bcast(&benchComplete, 1, MPI_INT, 0, comm);
			MPI_Bcast(&repsToDo, 1, MPI_INT, 0, comm);
		}

		/* Master process sets benchmark results */
		if (myMPIRank == 0 ){
			setReportParams(dataSizeIter, repsToDo, totalTime);
			printReport();
		}

		/* Free allocated data */
		freeHaloexchangeData();

		/* Double dataSize and loop again */
		dataSizeIter = dataSizeIter * 2;
	}

	return 0;
}
/*-----------------------------------------------------------*/
int reduction(int benchmarkType){
	int dataSizeIter, sizeofBuf;

	/* Initialise repsToDo to defaultReps */
	repsToDo = defaultReps;

	/* Start loop over data sizes */
	dataSizeIter = minDataSize; /* initialise dataSizeIter */
	while (dataSizeIter <= maxDataSize){
		/* allocate space for the main data arrays.. */
		allocateReduceData(dataSizeIter);

		/* Perform benchmark warm-up */
		if (benchmarkType == REDUCE){
			reduceKernel(warmUpIters, dataSizeIter);
			/* Master process tests if reduce was a success */
			if (myMPIRank == 0){
				testReduce(dataSizeIter, benchmarkType);
			}
		}
		else if (benchmarkType == ALLREDUCE){
			/* calculate sizeofBuf for test */
			sizeofBuf = dataSizeIter * numThreads;
			allReduceKernel(warmUpIters, dataSizeIter);
			/* all processes need to perform unit test */
			testReduce(sizeofBuf, benchmarkType);
		}

		/* Initialise the benchmark */
		benchComplete = FALSE;
		/* Execute benchmark until target time is reached */
		while (benchComplete != TRUE){
			/* Start timer */
			MPI_Barrier(comm);
			startTime = MPI_Wtime();

			/* Execute reduce for repsToDo repetitions */
			if (benchmarkType == REDUCE){
				reduceKernel(repsToDo, dataSizeIter);
			}
			else if (benchmarkType == ALLREDUCE){
				allReduceKernel(repsToDo, dataSizeIter);
			}

			/* Stop timer */
			MPI_Barrier(comm);
			finishTime = MPI_Wtime();
			totalTime = finishTime - startTime;

			/* Test if target time was reached with the number of reps */
			if (myMPIRank==0){
			  benchComplete = repTimeCheck(totalTime, repsToDo);
			}
			/* Ensure all procs have the same value of benchComplete */
			/* and repsToDo */
			MPI_Bcast(&benchComplete, 1, MPI_INT, 0, comm);
			MPI_Bcast(&repsToDo, 1, MPI_INT, 0, comm);
		}

		/* Master process sets benchmark result for reporting */
		if (myMPIRank == 0){
			setReportParams(dataSizeIter, repsToDo, totalTime);
			printReport();
		}

		/* Free allocated data */
		freeReduceData();

		/* Double dataSize and loop again */
		dataSizeIter = dataSizeIter * 2;

	}

	return 0;
}
/*-----------------------------------------------------------*/
int pingPing(int benchmarkType){
	int dataSizeIter;
	int sameNode;

	pingRankA = PPRanks[0];
	pingRankB = PPRanks[1];

	/* Check if pingRankA and pingRankB are on the same node */
	sameNode = compareProcNames(pingRankA, pingRankB);


	if (myMPIRank == 0){
		/* print message saying if benchmark is inter or intra node */
		printNodeReport(sameNode,pingRankA,pingRankB);
		/* then print report column headings. */
		printBenchHeader();
	}

	/* initialise repsToDo to defaultReps at start of benchmark */
	repsToDo = defaultReps;

	/* Loop over data sizes */
	dataSizeIter = minDataSize; /* initialise dataSizeIter to minDataSize */
	while (dataSizeIter <= maxDataSize){
		/* set sizeofBuffer */
		sizeofBuffer = dataSizeIter * numThreads;

		/* Allocate space for main data arrays */
		allocatePingpingData(sizeofBuffer);

		/* warm-up for benchmarkType */
		if (benchmarkType == MASTERONLY){
			/* Masteronly warmp sweep */
			masteronlyPingping(warmUpIters, dataSizeIter);
		}
		else if (benchmarkType == FUNNELLED){
			/* perform funnelled warm-up sweep */
			funnelledPingping(warmUpIters, dataSizeIter);
		}
		else if (benchmarkType == MULTIPLE){
			multiplePingping(warmUpIters, dataSizeIter);
		}

		/* perform verification test for the pingping */
		testPingping(sizeofBuffer, dataSizeIter);

		/* Initialise benchmark */
		benchComplete = FALSE;

		/* keep executing benchmark until target time is reached */
		while (benchComplete != TRUE){
			/* Start the timer...MPI_Barrier to synchronise */
			MPI_Barrier(comm);
			startTime = MPI_Wtime();

			if (benchmarkType == MASTERONLY){
				/* execute for repsToDo repetitions */
				masteronlyPingping(repsToDo, dataSizeIter);
			}
			else if (benchmarkType == FUNNELLED){
				funnelledPingping(repsToDo, dataSizeIter);
			}
			else if (benchmarkType == MULTIPLE){
				multiplePingping(repsToDo, dataSizeIter);
			}

			/* Stop the timer...MPI_Barrier to synchronise processes */
			MPI_Barrier(comm);
			finishTime = MPI_Wtime();
			totalTime = finishTime - startTime;

			/* Call repTimeCheck function to test if target time is reached */
			if (myMPIRank==0){
			  benchComplete = repTimeCheck(totalTime, repsToDo);
			}
			/* Ensure all procs have the same value of benchComplete */
			/* and repsToDo */
			MPI_Bcast(&benchComplete, 1, MPI_INT, 0, comm);
			MPI_Bcast(&repsToDo, 1, MPI_INT, 0, comm);
		}

		/* Master process sets benchmark results */
		if (myMPIRank == 0){
			setReportParams(dataSizeIter, repsToDo, totalTime);
			printReport();
		}

		/* Free the allocated space for the main data arrays */
		freePingpingData();

		/* Update dataSize before the next iteration */
		dataSizeIter = dataSizeIter * 2; /* double data size */
	}

	return 0;
}