diff --git a/HeterogeneousCore/MPICore/test/BuildFile.xml b/HeterogeneousCore/MPICore/test/BuildFile.xml
new file mode 100644
index 0000000000000..1cde1a4f390bc
--- /dev/null
+++ b/HeterogeneousCore/MPICore/test/BuildFile.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/HeterogeneousCore/MPICore/test/testMPI.cc b/HeterogeneousCore/MPICore/test/testMPI.cc
new file mode 100644
index 0000000000000..0ceedec9dc0a0
--- /dev/null
+++ b/HeterogeneousCore/MPICore/test/testMPI.cc
@@ -0,0 +1,806 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// std::cout << "\n\t++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
+// std::cout << "\n\t+ (1) Non Blocking Scatter. +";
+// std::cout << "\n\t+ (2) Blocking Scatter. +";
+// std::cout << "\n\t+ (3) Non Blocking Send and Receive. +";
+// std::cout << "\n\t+ (4) Blocking Send and Receive. +";
+// std::cout << "\n\t+ (5) Non Blocking Send and Receive with Multiple Tasks +";
+// std::cout << "\n\t++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
+
+struct MPIData {
+ int num_procs{0};
+ int rank{0};
+
+ std::pair workSplit;
+ std::vector input1; //declare vector 1.
+ std::vector input2; //declare vector 2.
+ std::vector output; //declare vector fulled only by root to get result from workers.
+ std::vector reference; //declare vector to verify the ruslt form each process.
+ std::vector vectorWorkers1; //declare vector 1 for workers only.
+ std::vector vectorWorkers2; //declare vector 2 for workers only.
+ std::vector displacement; //declare vector for selecting location of each element to be sent.
+ std::vector numberToSend;
+};
+
+int choices = 5; //number of functions of MPI.
+int size = 21; //default size of vectors.
+unsigned int runNumber = 5; //default number of time to run each function in order to take the average.
+int precision = 4; //default digits after decimal point.
+int function = 5; //Total number of functions in the program.
+int root = 0;
+int choice = 0; //user Choice to select function to run.
+
+std::vector userChoices(1, 1); //save convertion integer to vector.
+
+const std::vector chooseFunction(int toInteger); //Convert integers to a vector.
+std::vector> timing(
+ choices, std::make_pair(0, 0)); //to save time of scatter/send and gather/receive for each function.
+
+void randomGenerator(std::vector& vect); //generate uniform random numbers.
+std::pair splitProcess(int works, int numberOfProcess); //calcualte for each process number of works.
+const std::vector numberDataSend(
+ int numberOfProcess, std::pair splitWorks); //findout number of data to be sent for each process.
+const std::vector displacmentData(
+ int numberOfProcess,
+ std::pair splitWorks,
+ const std::vector& numberDataSend); //findout the index of data to be sent for each process
+void checkingResultsPrintout(std::vector& reference,
+ std::vector& output,
+ std::pair workSplit,
+ const std::vector& displacement,
+ const std::vector& numberDataSend);
+
+const std::pair nonBlockScatter(MPIData& mpiInput);
+const std::pair blockScatter(MPIData& mpiInput);
+const std::pair nonBlockSend(MPIData& mpiInput);
+const std::pair blockSend(MPIData& mpiInput);
+const std::pair multiNonBlockSend(MPIData& mpiInput);
+
+void compare(const std::vector>& timing,
+ int choices,
+ const std::vector& digits,
+ int runNumber); //to printout the time for each function that user chose.
+
+const std::pair returnAverage(const std::pair (*mpiFunctions)(MPIData&),
+ MPIData& mpiInput,
+ unsigned int runNumber); //to get the average of time for each function.
+
+int main(int argc, char* argv[]) {
+ int c;
+
+ while ((c = getopt(argc, argv, "s:r:n:")) != -1) {
+ switch (c) {
+ case 's':
+ try {
+ size = std::stoll(optarg, nullptr, 0);
+ } catch (std::exception& err) {
+ std::cout << "\n\tError Must be integer Argument!";
+ std::cout << "\n\t" << err.what() << std::endl;
+ return 0;
+ }
+ break;
+ case 'r':
+ try {
+ //size = std::stoll(optarg, nullptr, 0);
+ choice = std::stoll(optarg, nullptr, 0);
+ userChoices = chooseFunction(choice);
+ //runNumber = std::stoll(argv[3], nullptr, 0);
+ } catch (std::exception& err) {
+ std::cout << "\n\tError Must be integer Argument!";
+ std::cout << "\n\t" << err.what() << std::endl;
+ return 0;
+ }
+ break;
+ case 'n':
+ try {
+ //size = std::stoll(argv[1], nullptr, 0);
+ //choice = std::stoll(argv[2], nullptr, 0);
+ //userChoices = chooseFunction(choice);
+ runNumber = std::stoll(optarg, nullptr, 0);
+ } catch (std::exception& err) {
+ std::cout << "\n\tError Must be integer Argument!";
+ std::cout << "\n\t" << err.what() << std::endl;
+ return 0;
+ }
+ break;
+ default:
+ abort();
+ }
+ }
+
+ // if (argc == 2) {
+ // try {
+ // size = std::stoll(argv[1], nullptr, 0);
+ // } catch (std::exception& err) {
+ // std::cout << "\n\tError Must be integer Argument!";
+ // std::cout << "\n\t" << err.what() << std::endl;
+ // return 0;
+ // }
+ // } else if (argc == 3) {
+ // try {
+ // size = std::stoll(argv[1], nullptr, 0);
+ // choice = std::stoll(argv[2], nullptr, 0);
+ // userChoices = chooseFunction(choice);
+ // } catch (std::exception& err) {
+ // std::cout << "\n\tError Must be integer Argument!";
+ // std::cout << "\n\t" << err.what() << std::endl;
+ // return 0;
+ // }
+ // }else if (argc > 3) {
+ // try {
+ // size = std::stoll(argv[1], nullptr, 0);
+ // choice = std::stoll(argv[2], nullptr, 0);
+ // userChoices = chooseFunction(choice);
+ // runNumber = std::stoll(argv[3], nullptr, 0);
+ // } catch (std::exception& err) {
+ // std::cout << "\n\tError Must be integer Argument!";
+ // std::cout << "\n\t" << err.what() << std::endl;
+ // return 0;
+ // }
+ // }
+
+ MPIData mpiInputs; //greate object from structur to pass into MPI functios.
+
+ MPI_Init(&argc, &argv); //initialize communicator environment.
+ mpiInputs.num_procs = MPI::COMM_WORLD.Get_size(); //get total size of processes.
+ mpiInputs.rank = MPI::COMM_WORLD.Get_rank(); //get each process number.
+
+ mpiInputs.input1.resize(size); //initialize size.
+ mpiInputs.input2.resize(size);
+ mpiInputs.output.resize(size);
+ mpiInputs.reference.resize(size);
+
+ mpiInputs.workSplit = splitProcess(size, mpiInputs.num_procs);
+
+ if (!mpiInputs.workSplit.first) {
+ MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
+ return 0;
+ }
+
+ mpiInputs.numberToSend = numberDataSend(mpiInputs.num_procs, mpiInputs.workSplit);
+ mpiInputs.displacement = displacmentData(mpiInputs.num_procs, mpiInputs.workSplit, mpiInputs.numberToSend);
+
+ mpiInputs.vectorWorkers1.resize(
+ mpiInputs.numberToSend[mpiInputs.rank]); //Resizing each process with appropriate Receiving Data.
+ mpiInputs.vectorWorkers2.resize(mpiInputs.numberToSend[mpiInputs.rank]);
+
+ if (!mpiInputs.rank) //Only for root
+ {
+ randomGenerator(mpiInputs.input1); //generate random floating numbers from(0,1) Only in the root.
+ randomGenerator(mpiInputs.input2);
+ std::cout << "\n\tNumber of Processes " << mpiInputs.num_procs << std::endl;
+ std::cout << "\tNumber of workSplit First " << mpiInputs.workSplit.first << std::endl;
+ std::cout << "\tNumber of workSplit Second " << mpiInputs.workSplit.second << std::endl;
+ for (int j = 0; j < size; j++) {
+ mpiInputs.reference[j] = mpiInputs.input1[j] + mpiInputs.input2[j]; //Summing for verification.
+ }
+ }
+
+ for (long unsigned int i = 0; i < userChoices.size(); ++i) {
+ if (userChoices[i] == 1) {
+ timing[0] = returnAverage(nonBlockScatter, mpiInputs, runNumber);
+
+ } else if (userChoices[i] == 2) {
+ timing[1] = returnAverage(blockScatter, mpiInputs, runNumber);
+
+ } else if (userChoices[i] == 3) {
+ timing[2] = returnAverage(nonBlockSend, mpiInputs, runNumber);
+
+ } else if (userChoices[i] == 4) {
+ timing[3] = returnAverage(blockSend, mpiInputs, runNumber);
+
+ } else if (userChoices[i] == 5) {
+ timing[4] = returnAverage(multiNonBlockSend, mpiInputs, runNumber);
+
+ } else {
+ std::cout << "\n\n\tError the User has not chose any number of Function!\n";
+ break;
+ }
+ }
+
+ if (!mpiInputs.rank) {
+ compare(timing, choices, userChoices, runNumber);
+ }
+
+ MPI::Finalize();
+
+ return 0;
+}
+
+void randomGenerator(std::vector& vect) {
+ std::random_device rand;
+ std::default_random_engine gener(rand());
+ std::uniform_real_distribution<> dis(0., 1.);
+ int size = vect.size();
+ for (int i = 0; i < size; i++) {
+ vect.at(i) = dis(gener);
+ }
+}
+
+std::pair splitProcess(int works, int numberOfProcess) {
+ std::pair Return{0, 0};
+ if (numberOfProcess > 1 && numberOfProcess <= works) {
+ Return.first = works / (numberOfProcess - 1); //number of cycle for each process.
+ Return.second = works % (numberOfProcess - 1); //extra cycle for process.
+ } else {
+ std::cout << "\tError Either No worker are found OR Number Processes Larger than Length!!!\n";
+ }
+
+ return Return;
+}
+const std::vector numberDataSend(int numberOfProcess, std::pair splitWorks) {
+ std::vector dataSend(numberOfProcess, splitWorks.first);
+ dataSend[0] = 0;
+ for (int i = 1; i < splitWorks.second + 1; i++) //neglect root
+ {
+ dataSend[i] += 1; //extra work for each first processes.
+ }
+ return dataSend;
+}
+const std::vector displacmentData(int numberOfProcess,
+ std::pair splitWorks,
+ const std::vector& numberDataSend) {
+ std::vector displacment(numberOfProcess, splitWorks.first);
+
+ displacment[0] = 0;
+ displacment[1] = 0; //start Here.
+
+ for (int i = 2; i < numberOfProcess; i++) //neglect root
+ {
+ displacment[i] = numberDataSend[i - 1] + displacment[i - 1]; //extra work for each first processes.
+ }
+ return displacment;
+}
+
+void checkingResultsPrintout(std::vector& reference,
+ std::vector& output,
+ std::pair workSplit,
+ const std::vector& displacement,
+ const std::vector& numberDataSend) {
+ float percent{0.0};
+ float totalError{0.0};
+ int p{1};
+ for (int j = 0; j < size; j++) {
+ percent = ((reference[j] - output[j]) / reference[j]) * 100;
+ totalError += percent;
+ }
+ if (totalError) {
+ std::cout << "\n-------------------------------------------------------\n";
+ std::cout << "| RootSum | WorksSum | Error | Error % | Process # |";
+ std::cout << "\n-------------------------------------------------------\n";
+ std::cout.precision(precision);
+ for (int j = 0; j < size; j++) {
+ std::cout << "| " << reference[j] << " | " << output[j] << " |" << std::setw(9) << reference[j] - output[j]
+ << " |" << std::setw(9) << percent << " |" << std::setw(9) << p << " |\n";
+
+ if (j + 1 == displacement[p + 1]) {
+ ++p;
+ }
+ }
+ std::cout << "-------------------------------------------------------\n";
+ std::cout << "-Total Error is " << totalError << std::endl;
+ for (long unsigned int j = 1; j < displacement.size(); j++) {
+ std::cout << "Process [" << j << "]"
+ << " Worked On " << numberDataSend[j] << " Data\n";
+ }
+ }
+}
+
+const std::pair nonBlockScatter(MPIData& mpiInput) {
+ std::pair returnValue;
+ std::cout.setf(std::ios::fixed, std::ios::floatfield);
+ double startTimeScatter = 0;
+ double endTimeScatter = 0;
+ double startTimeGather = 0;
+ double endTimeGather = 0;
+
+ MPI_Request requestRootScatter[2];
+ MPI_Request requestRootGather;
+
+ startTimeScatter = MPI_Wtime(); //get time before scattering.
+
+ //Non-Blocking Scatter.
+ MPI_Iscatterv(&mpiInput.input1[0],
+ &mpiInput.numberToSend[0],
+ &mpiInput.displacement[0],
+ MPI_FLOAT,
+ &mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootScatter[0]);
+ MPI_Iscatterv(&mpiInput.input2[0],
+ &mpiInput.numberToSend[0],
+ &mpiInput.displacement[0],
+ MPI_FLOAT,
+ &mpiInput.vectorWorkers2[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootScatter[1]);
+ MPI_Waitall(2, requestRootScatter, MPI_STATUS_IGNORE);
+
+ endTimeScatter = MPI_Wtime(); //get time after scattering.
+
+ if (mpiInput.rank) //Only for Workers
+ {
+ for (long unsigned int i = 0; i < mpiInput.vectorWorkers1.size(); i++) {
+ mpiInput.vectorWorkers1[i] += mpiInput.vectorWorkers2[i];
+ }
+ }
+
+ startTimeGather = MPI_Wtime(); //get time before Gathering.
+
+ //Non Blocking Gathering.
+ MPI_Igatherv(&mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ &mpiInput.output[0],
+ &mpiInput.numberToSend[0],
+ &mpiInput.displacement[0],
+ MPI_FLOAT,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootGather);
+
+ MPI_Wait(&requestRootGather, MPI_STATUS_IGNORE);
+ endTimeGather = MPI_Wtime(); //get time after Gathering.
+
+ if (!mpiInput.rank) //Only root print out the results.
+ {
+ checkingResultsPrintout(
+ mpiInput.reference, mpiInput.output, mpiInput.workSplit, mpiInput.displacement, mpiInput.numberToSend);
+ returnValue.first = (endTimeScatter - startTimeScatter) * 1000;
+ returnValue.second = (endTimeGather - startTimeGather) * 1000;
+ }
+ return returnValue;
+}
+const std::pair blockScatter(MPIData& mpiInput) {
+ std::pair returnValue;
+ std::cout.setf(std::ios::fixed, std::ios::floatfield);
+
+ double startTimeScatter = 0;
+ double endTimeScatter = 0;
+ double startTimeGather = 0;
+ double endTimeGather = 0;
+
+ //Blocking Scattering.
+ mpiInput.vectorWorkers1.resize(
+ mpiInput.numberToSend[mpiInput.rank]); //Resizing each process with appropriate Receiving Data.
+ mpiInput.vectorWorkers2.resize(mpiInput.numberToSend[mpiInput.rank]);
+
+ startTimeScatter = MPI_Wtime();
+ MPI_Scatterv(&mpiInput.input1[0],
+ &mpiInput.numberToSend[0],
+ &mpiInput.displacement[0],
+ MPI_FLOAT,
+ &mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ 0,
+ MPI_COMM_WORLD);
+ MPI_Scatterv(&mpiInput.input2[0],
+ &mpiInput.numberToSend[0],
+ &mpiInput.displacement[0],
+ MPI_FLOAT,
+ &mpiInput.vectorWorkers2[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ 0,
+ MPI_COMM_WORLD);
+ endTimeScatter = MPI_Wtime();
+
+ if (mpiInput.rank) //Only for Workers
+ {
+ for (long unsigned int i = 0; i < mpiInput.vectorWorkers1.size(); i++) {
+ mpiInput.vectorWorkers1[i] += mpiInput.vectorWorkers2[i];
+ }
+ }
+
+ startTimeGather = MPI_Wtime();
+ //Blocking Gathering.
+ MPI_Gatherv(&mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ &mpiInput.output[0],
+ &mpiInput.numberToSend[0],
+ &mpiInput.displacement[0],
+ MPI_FLOAT,
+ 0,
+ MPI_COMM_WORLD);
+
+ endTimeGather = MPI_Wtime();
+
+ if (!mpiInput.rank) //Only root print out the results.
+ {
+ checkingResultsPrintout(
+ mpiInput.reference, mpiInput.output, mpiInput.workSplit, mpiInput.displacement, mpiInput.numberToSend);
+ returnValue.first = (endTimeScatter - startTimeScatter) * 1000;
+ returnValue.second = (endTimeGather - startTimeGather) * 1000;
+ }
+ return returnValue;
+}
+const std::pair nonBlockSend(MPIData& mpiInput) {
+ std::pair returnValue;
+ double startTimeRootSend = 0;
+ double endTimeRootSend = 0;
+ double startTimeRootRecv = 0;
+ double endTimeRootRecv = 0;
+
+ MPI_Request requestRootSend[2];
+ MPI_Request requestRootRecv;
+ MPI_Request requestWorkerSend;
+ MPI_Request requestWorkerRecv[1];
+
+ std::cout.setf(std::ios::fixed, std::ios::floatfield);
+
+ if (!mpiInput.rank) //Only for root
+ {
+ // std::cout << "\n\t\tNon-Blocking Send and Receive " << std::endl;
+ startTimeRootSend = MPI_Wtime();
+ for (int i = 1; i < mpiInput.num_procs; i++) {
+ MPI_Issend(&mpiInput.input1[mpiInput.displacement[i]],
+ mpiInput.numberToSend[i],
+ MPI_FLOAT,
+ i,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootSend[0]); //Tag is 0
+ MPI_Issend(&mpiInput.input2[mpiInput.displacement[i]],
+ mpiInput.numberToSend[i],
+ MPI_FLOAT,
+ i,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootSend[1]);
+ MPI_Waitall(2, requestRootSend, MPI_STATUS_IGNORE);
+ }
+ endTimeRootSend = MPI_Wtime();
+ }
+
+ if (mpiInput.rank) //Only for Workers
+ {
+ MPI_Irecv(&mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD,
+ &requestWorkerRecv[0]);
+ MPI_Irecv(&mpiInput.vectorWorkers2[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD,
+ &requestWorkerRecv[1]);
+
+ MPI_Waitall(2, requestWorkerRecv, MPI_STATUS_IGNORE);
+ for (long unsigned int i = 0; i < mpiInput.vectorWorkers1.size(); i++) {
+ mpiInput.vectorWorkers1[i] += mpiInput.vectorWorkers2[i];
+ }
+ MPI_Issend(&mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD,
+ &requestWorkerSend); //Tag is 0
+ MPI_Wait(&requestWorkerSend, MPI_STATUS_IGNORE);
+ }
+
+ if (!mpiInput.rank) //Only for root
+ {
+ startTimeRootRecv = MPI_Wtime();
+ for (int i = 1; i < mpiInput.num_procs; i++) {
+ MPI_Irecv(&mpiInput.output[mpiInput.displacement[i]],
+ mpiInput.numberToSend[i],
+ MPI_FLOAT,
+ i,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootRecv);
+ MPI_Wait(&requestRootRecv, MPI_STATUS_IGNORE);
+ }
+ endTimeRootRecv = MPI_Wtime();
+
+ checkingResultsPrintout(mpiInput.reference,
+ mpiInput.output,
+ mpiInput.workSplit,
+ mpiInput.displacement,
+ mpiInput.numberToSend); //Only root print out the results.
+ returnValue.first = (endTimeRootSend - startTimeRootSend) * 1000;
+ returnValue.second = (endTimeRootRecv - startTimeRootRecv) * 1000;
+ }
+ return returnValue;
+}
+const std::pair blockSend(MPIData& mpiInput) {
+ std::pair returnValue;
+ double startTimeRootSend = 0;
+ double endTimeRootSend = 0;
+ double startTimeRootRecv = 0;
+ double endTimeRootRecv = 0;
+
+ std::cout.setf(std::ios::fixed, std::ios::floatfield);
+
+ if (!mpiInput.rank) //Only for root
+ {
+ // std::cout << "\n\t\tBlocking Send and Receive " << std::endl;
+ startTimeRootSend = MPI_Wtime();
+ for (int i = 1; i < mpiInput.num_procs; i++) {
+ MPI_Send(&mpiInput.input1[mpiInput.displacement[i]],
+ mpiInput.numberToSend[i],
+ MPI_FLOAT,
+ i,
+ 0,
+ MPI_COMM_WORLD); //Tag is 0
+ MPI_Send(&mpiInput.input2[mpiInput.displacement[i]], mpiInput.numberToSend[i], MPI_FLOAT, i, 0, MPI_COMM_WORLD);
+ }
+ endTimeRootSend = MPI_Wtime();
+ }
+
+ if (mpiInput.rank) //Only for Workers
+ {
+ MPI_Recv(&mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD,
+ MPI_STATUS_IGNORE);
+ MPI_Recv(&mpiInput.vectorWorkers2[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD,
+ MPI_STATUS_IGNORE);
+
+ for (long unsigned int i = 0; i < mpiInput.vectorWorkers1.size(); i++) {
+ mpiInput.vectorWorkers1[i] += mpiInput.vectorWorkers2[i];
+ }
+ MPI_Send(&mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD); //Tag is 0
+ }
+
+ if (!mpiInput.rank) //Only for root
+ {
+ startTimeRootRecv = MPI_Wtime();
+ for (int i = 1; i < mpiInput.num_procs; i++) {
+ MPI_Recv(&mpiInput.output[mpiInput.displacement[i]],
+ mpiInput.numberToSend[i],
+ MPI_FLOAT,
+ i,
+ 0,
+ MPI_COMM_WORLD,
+ MPI_STATUS_IGNORE);
+ }
+ endTimeRootRecv = MPI_Wtime();
+
+ checkingResultsPrintout(mpiInput.reference,
+ mpiInput.output,
+ mpiInput.workSplit,
+ mpiInput.displacement,
+ mpiInput.numberToSend); //Only root print out the results.
+ returnValue.first = (endTimeRootSend - startTimeRootSend) * 1000;
+ returnValue.second = (endTimeRootRecv - startTimeRootRecv) * 1000;
+ }
+ return returnValue;
+}
+const std::pair multiNonBlockSend(MPIData& mpiInput) {
+ std::pair returnValue;
+ int lastPointCount = 0;
+ double startTimeRootSend = 0;
+ double endTimeRootSend = 0;
+ double startTimeRootRecv = 0;
+ double endTimeRootRecv = 0;
+
+ MPI_Request requestRootSend[2];
+ MPI_Request requestRootRecv;
+ MPI_Request requestWorkerSend;
+ MPI_Request requestWorkerRecv[2];
+
+ std::cout.setf(std::ios::fixed, std::ios::floatfield);
+
+ if (!mpiInput.rank) //Only for root
+ {
+ // std::cout << "\n\t\tNon-Blocking Send and Receive with Multiple Tasks" << std::endl;
+ int flage = 0; //set operation to processed.
+ startTimeRootSend = MPI_Wtime();
+ for (int i = 1; i < mpiInput.num_procs; i++) {
+ MPI_Issend(&mpiInput.input1[mpiInput.displacement[i]],
+ mpiInput.numberToSend[i],
+ MPI_FLOAT,
+ i,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootSend[0]); //Tag is 0
+ MPI_Issend(&mpiInput.input2[mpiInput.displacement[i]],
+ mpiInput.numberToSend[i],
+ MPI_FLOAT,
+ i,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootSend[1]);
+ do {
+ MPI_Testall(2, requestRootSend, &flage, MPI_STATUS_IGNORE); //2 for two requests above. Check on flage.
+ for (; lastPointCount < size && !flage;
+ lastPointCount++) //do the summing while waiting for the sending request is done.
+ {
+ mpiInput.reference[lastPointCount] = mpiInput.input1[lastPointCount] + mpiInput.input2[lastPointCount];
+
+ MPI_Testall(2, requestRootSend, &flage, MPI_STATUS_IGNORE); //2 for two requests above. Check on flage.
+ }
+ } while (!flage);
+ }
+ endTimeRootSend = MPI_Wtime();
+ }
+
+ if (mpiInput.rank) //Only for Workers
+ {
+ MPI_Irecv(&mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD,
+ &requestWorkerRecv[0]);
+ MPI_Irecv(&mpiInput.vectorWorkers2[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD,
+ &requestWorkerRecv[1]);
+ MPI_Waitall(2, requestWorkerRecv, MPI_STATUS_IGNORE); //2 for two requests above.
+
+ for (long unsigned int i = 0; i < mpiInput.vectorWorkers1.size(); i++) {
+ mpiInput.vectorWorkers1[i] += mpiInput.vectorWorkers2[i];
+ }
+ MPI_Issend(&mpiInput.vectorWorkers1[0],
+ mpiInput.numberToSend[mpiInput.rank],
+ MPI_FLOAT,
+ root,
+ 0,
+ MPI_COMM_WORLD,
+ &requestWorkerSend); //Tag is 0
+ MPI_Wait(&requestWorkerSend, MPI_STATUS_IGNORE);
+ }
+
+ if (!mpiInput.rank) //Only for root
+ {
+ int flage2 = 0; //set operation to processed.
+ startTimeRootRecv = MPI_Wtime();
+ for (int i = 1; i < mpiInput.num_procs; i++) {
+ MPI_Irecv(&mpiInput.output[mpiInput.displacement[i]],
+ mpiInput.numberToSend[i],
+ MPI_FLOAT,
+ i,
+ 0,
+ MPI_COMM_WORLD,
+ &requestRootRecv);
+ do {
+ MPI_Test(&requestRootRecv, &flage2, MPI_STATUS_IGNORE); //Check on flage2.
+ for (; lastPointCount < size && !flage2;
+ lastPointCount++) //do the summing while waiting for the sending request is done.
+ {
+ mpiInput.reference[lastPointCount] = mpiInput.input1[lastPointCount] + mpiInput.input2[lastPointCount];
+
+ MPI_Test(&requestRootRecv, &flage2, MPI_STATUS_IGNORE); //Check on flage.
+ }
+ } while (!flage2);
+ }
+ endTimeRootRecv = MPI_Wtime();
+ for (; lastPointCount < size; lastPointCount++) {
+ mpiInput.reference[lastPointCount] = mpiInput.input1[lastPointCount] + mpiInput.input2[lastPointCount];
+ }
+ checkingResultsPrintout(mpiInput.reference,
+ mpiInput.output,
+ mpiInput.workSplit,
+ mpiInput.displacement,
+ mpiInput.numberToSend); //Only root print out the results.
+ returnValue.first = (endTimeRootSend - startTimeRootSend) * 1000;
+ returnValue.second = (endTimeRootRecv - startTimeRootRecv) * 1000;
+ }
+ return returnValue;
+}
+
+const std::vector chooseFunction(int toInteger) {
+ std::vector digits(0, 0);
+ std::vector ERROR(0, 0);
+
+ int digit{1};
+
+ while (toInteger > 0) {
+ digit = toInteger % 10;
+ if (digit > choices) {
+ std::cout << "\n\tError Must be integer Argument <= " << choices << std::endl;
+ return ERROR;
+ }
+ digits.push_back(digit);
+ toInteger /= 10;
+ }
+ std::reverse(digits.begin(), digits.end());
+ return digits;
+}
+
+void compare(const std::vector>& timing,
+ int choices,
+ const std::vector& digits,
+ int runNumber) {
+ std::cout.setf(std::ios::fixed, std::ios::floatfield);
+
+ int j{0};
+ int k{0};
+ for (long unsigned int i = 0; i < timing.size(); ++i) {
+ if (timing[i].first) {
+ switch (i) {
+ case 0:
+ std::cout << "\n\t\t(1) Non-Blocking Scatter " << std::endl;
+ break;
+ case 1:
+ std::cout << "\n\t\t(2) Blocking Scatter " << std::endl;
+ break;
+ case 2:
+ std::cout << "\n\t\t(3) Non-Blocking Send and Receive " << std::endl;
+ break;
+ case 3:
+ std::cout << "\n\t\t(4) Blocking Send and Receive " << std::endl;
+ break;
+ case 4:
+ std::cout << "\n\t\t(5) Non-Blocking Send and Receive with Multiple Tasks" << std::endl;
+ break;
+ default:
+ std::cout << "\nSomething went wrong!\n";
+ }
+ }
+ }
+ std::cout << "\n\n\t=============================================================";
+ std::cout << "\n\t|| Func || Scatter/Send || Gather/Receive || Number Run||";
+ std::cout << "\n\t=============================================================";
+ for (long unsigned int i = 0; i < timing.size(); ++i) {
+ if (timing[i].first) {
+ if (k < j) {
+ std::cout << "\n\t------------------------------------------------------------";
+ }
+ std::cout.flags(std::ios::fixed | std::ios::showpoint);
+ std::cout.precision(precision);
+ std::cout << "\n\t|| " << std::setw(1) << digits[k] << " || " << std::setw(5) << timing[i].first
+ << " || " << std::setw(5) << timing[i].second << " || " << std::setw(3) << runNumber
+ << " ||";
+ j += 2;
+ ++k;
+ }
+ }
+ std::cout << "\n\t=============================================================\n\n";
+}
+
+const std::pair returnAverage(const std::pair (*mpiFunctions)(MPIData&),
+ MPIData& mpiInput,
+ unsigned int runNumber) {
+ std::pair output;
+ for (long unsigned int i = 0; i < runNumber; ++i) {
+ auto accum = mpiFunctions(mpiInput);
+ output.first += accum.first;
+ output.second += accum.second;
+ }
+ output.first /= runNumber;
+ output.second /= runNumber;
+ return output;
+}
\ No newline at end of file