Commit 0010cbde authored by Martin Khannouz's avatar Martin Khannouz Committed by Berenger Bramas

Modify tests to compare performance

parent e9668d99
......@@ -317,14 +317,8 @@ public:
~FGroupTaskStarPUMpiAlgorithm(){
starpu_resume();
std::cout << "Loutre " << comm.processId() << std::endl;
comm.barrier();
cleanHandle();
std::cout << "Canard " << comm.processId() << std::endl;
comm.barrier();
cleanHandleMpi();
std::cout << "Suricate " << comm.processId() << std::endl;
comm.barrier();
delete[] cellHandles;
starpu_pthread_mutex_t releaseMutex;
......@@ -1350,16 +1344,12 @@ protected:
for(int idxLevel = 0 ; idxLevel < int(remoteCellGroups.size()) ; ++idxLevel){
for(int idxHandle = 0 ; idxHandle < int(remoteCellGroups[idxLevel].size()) ; ++idxHandle){
if(remoteCellGroups[idxLevel][idxHandle].ptrSymb){
if(comm.processId() == 4)
std::cout << "Narval " << idxLevel << " " << idxHandle << std::endl;
starpu_data_unregister(remoteCellGroups[idxLevel][idxHandle].handleSymb);
starpu_data_unregister(remoteCellGroups[idxLevel][idxHandle].handleUp);
FAlignedMemory::DeallocBytes(remoteCellGroups[idxLevel][idxHandle].ptrSymb);
FAlignedMemory::DeallocBytes(remoteCellGroups[idxLevel][idxHandle].ptrUp);
if(remoteCellGroups[idxLevel][idxHandle].ptrDown){
if(comm.processId() == 4)
std::cout << "Narval " << idxLevel << " " << idxHandle << std::endl;
starpu_data_unregister(remoteCellGroups[idxLevel][idxHandle].handleDown);
FAlignedMemory::DeallocBytes(remoteCellGroups[idxLevel][idxHandle].ptrDown);
}
......@@ -1370,16 +1360,12 @@ protected:
{
for(int idxHandle = 0 ; idxHandle < int(remoteParticleGroupss.size()) ; ++idxHandle){
if(remoteParticleGroupss[idxHandle].ptrSymb){
if(comm.processId() == 4)
std::cout << "Narval part " << idxHandle << std::endl;
starpu_data_unregister(remoteParticleGroupss[idxHandle].handleSymb);
FAlignedMemory::DeallocBytes(remoteParticleGroupss[idxHandle].ptrSymb);
}
}
remoteParticleGroupss.clear();
}
if(comm.processId() == 4)
std::cout << "Done" << std::endl;
}
////////////////////////////////////////////////////////////////////////////
......@@ -2469,14 +2455,7 @@ protected:
STARPU_NAME, p2pOuterTaskNames.get(),
#else
//"P2P_out-nb_i_p_nb_i_p_s"
STARPU_NAME, taskNames.print("P2P_out", "%d, %lld, %lld, %d, %lld, %lld, %d, %lld, %lld, %lld, %lld, %d\n",
0,
0,
0,
0,
0,
0,
0,
STARPU_NAME, taskNames.print("P2P_out", "0, 0, 0, 0, 0, 0, 0, %lld, %lld, %lld, %lld, %d\n",
tree->getParticleGroup(idxGroup)->getStartingIndex(),
tree->getParticleGroup(idxGroup)->getEndingIndex(),
processesBlockInfos[tree->getHeight()-1][interactionid].firstIndex,
......
......@@ -88,9 +88,6 @@ int main(int argc, char* argv[]){
FHelpDescribeAndExit(argc, argv, "Test the blocked tree by counting the particles.",
FParameterDefinitions::OctreeHeight, FParameterDefinitions::NbParticles,
FParameterDefinitions::OctreeSubHeight, FParameterDefinitions::InputFile, LocalOptionBlocSize, Mapping);
//int provided = 0;
//MPI_Init_thread(&argc,&argv, MPI_THREAD_SERIALIZED, &provided);
// Get params
const int NbLevels = FParameters::getValue(argc,argv,FParameterDefinitions::OctreeHeight.options, 5);
......@@ -117,7 +114,7 @@ int main(int argc, char* argv[]){
OctreeClass tree(NbLevels, FParameters::getValue(argc,argv,FParameterDefinitions::OctreeSubHeight.options, 2),
loader.getBoxWidth(), loader.getCenterOfBox());
FTestParticleContainer<FReal> allParticles;
FPoint<FReal> allParticlesToSort[loader.getNumberOfParticles()];
FPoint<FReal> * allParticlesToSort = new FPoint<FReal>[loader.getNumberOfParticles()];
for(FSize idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
loader.fillParticle(&allParticlesToSort[idxPart]);//Same with file or not
}
......@@ -125,16 +122,17 @@ int main(int argc, char* argv[]){
std::vector<MortonIndex> distributedMortonIndex;
vector<vector<int>> sizeForEachGroup;
sortParticle(allParticlesToSort, NbLevels, groupSize, sizeForEachGroup, distributedMortonIndex, loader, nproc);
for(FSize idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
allParticles.push(allParticlesToSort[idxPart]);
tree.insert(allParticlesToSort[idxPart]);
}
delete allParticlesToSort;
allParticlesToSort = nullptr;
// Put the data into the tree
//GroupOctreeClass groupedTree(NbLevels, groupSize, &tree);
//GroupOctreeClass groupedTree(NbLevels, loader.getBoxWidth(), loader.getCenterOfBox(), groupSize, &allParticles, false);
GroupOctreeClass groupedTree(NbLevels, loader.getBoxWidth(), loader.getCenterOfBox(), groupSize, &allParticles, sizeForEachGroup, false);
//Check tree structure at leaf level
groupedTree.forEachCellLeaf<GroupContainerClass>([&](GroupCellClass gcell, GroupContainerClass* gleaf){
const ContainerClass* src = tree.getLeafSrc(gcell.getMortonIndex());
......@@ -149,13 +147,11 @@ int main(int argc, char* argv[]){
});
// Run the algorithm
FTic timerExecute;
GroupKernelClass groupkernel;
GroupAlgorithm groupalgo(&groupedTree,&groupkernel, distributedMortonIndex);
FTic timerExecute;
groupalgo.execute();
double elapsedTime = timerExecute.tacAndElapsed();
mpi_rank = groupalgo.getRank();
cout << "Executing time (implicit node " << mpi_rank << ") " << elapsedTime << "s\n";
timeAverage(mpi_rank, nproc, elapsedTime);
// Usual algorithm
......@@ -164,14 +160,12 @@ int main(int argc, char* argv[]){
algo.execute();
int rank = groupalgo.getRank();
for(int i = 2; i < groupedTree.getHeight(); ++i)//No task at level 0 and 1
{
if(groupedTree.getNbCellGroupAtLevel(i) < groupalgo.getNProc() && rank == 0)
std::cout << "Error at level " << i << std::endl;
}
// Validate the result
for(int idxLevel = 2 ; idxLevel < groupedTree.getHeight() ; ++idxLevel){
for(int idxGroup = 0 ; idxGroup < groupedTree.getNbCellGroupAtLevel(idxLevel) ; ++idxGroup){
//if(groupalgo.isDataOwned(idxGroup, groupedTree.getNbCellGroupAtLevel(idxLevel))){
if(groupalgo.isDataOwnedBerenger(groupedTree.getCellGroup(idxLevel, idxGroup)->getStartingIndex(), idxLevel)){
GroupOctreeClass::CellGroupClass* currentCells = groupedTree.getCellGroup(idxLevel, idxGroup);
currentCells->forEachCell([&](GroupCellClass gcell){
......@@ -194,7 +188,6 @@ int main(int argc, char* argv[]){
{
int idxLevel = groupedTree.getHeight()-1;
for(int idxGroup = 0 ; idxGroup < groupedTree.getNbCellGroupAtLevel(idxLevel) ; ++idxGroup){
//if(groupalgo.isDataOwned(idxGroup, groupedTree.getNbCellGroupAtLevel(idxLevel))){
if(groupalgo.isDataOwnedBerenger(groupedTree.getCellGroup(groupedTree.getHeight()-1, idxGroup)->getStartingIndex(), groupedTree.getHeight()-1)){
GroupOctreeClass::ParticleGroupClass* particleGroup = groupedTree.getParticleGroup(idxGroup);
GroupOctreeClass::CellGroupClass* cellGroup = groupedTree.getCellGroup(idxLevel, idxGroup);
......@@ -223,14 +216,16 @@ void timeAverage(int mpi_rank, int nproc, double elapsedTime)
if(mpi_rank == 0)
{
double sumElapsedTime = elapsedTime;
std::cout << "Executing time node 0 (implicit) : " << sumElapsedTime << "s" << std::endl;
for(int i = 1; i < nproc; ++i)
{
double tmp;
MPI_Recv(&tmp, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, 0);
sumElapsedTime += tmp;
std::cout << "Executing time node " << i << " (implicit) : " << tmp << "s" << std::endl;
}
sumElapsedTime = sumElapsedTime / (double)nproc;
std::cout << "Average time per node : " << sumElapsedTime << "s" << std::endl;
std::cout << "Average time per node (implicit) : " << sumElapsedTime << "s" << std::endl;
}
else
{
......
......@@ -49,6 +49,7 @@
void timeAverage(int mpi_rank, int nproc, double elapsedTime);
int main(int argc, char* argv[]){
setenv("STARPU_NCPU","1",1);
const FParameterNames LocalOptionBlocSize {
{"-bs"},
"The size of the block of the blocked tree"
......@@ -78,7 +79,6 @@ int main(int argc, char* argv[]){
const FSize NbParticles = FParameters::getValue(argc,argv,FParameterDefinitions::NbParticles.options, FSize(20));
const int groupSize = FParameters::getValue(argc,argv,LocalOptionBlocSize.options, 8);
const FSize totalNbParticles = (NbParticles*mpiComm.global().processCount());
// Load the particles
FRandomLoader<FReal> loader(NbParticles, 1.0, FPoint<FReal>(0,0,0), mpiComm.global().processId());
FAssertLF(loader.isOpen());
......@@ -99,12 +99,11 @@ int main(int argc, char* argv[]){
return position.data();
}
};
std::unique_ptr<TestParticle[]> particles(new TestParticle[loader.getNumberOfParticles()]);
memset(particles.get(), 0, sizeof(TestParticle) * loader.getNumberOfParticles());
for(FSize idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
loader.fillParticleAtMortonIndex(&(particles[idxPart].position), mpiComm.global().processId()*NbParticles + idxPart,NbLevels);
//loader.fillParticle(&(particles[idxPart].position));
//loader.fillParticleAtMortonIndex(&(particles[idxPart].position), mpiComm.global().processId()*NbParticles + idxPart,NbLevels);
loader.fillParticle(&(particles[idxPart].position));
}
// Sort in parallel
FVector<TestParticle> myParticles;
......@@ -144,7 +143,7 @@ int main(int argc, char* argv[]){
//Save particles in a file
if(mpiComm.global().processId() == 0){
std::cout << "Exchange particle to create the file" << std::endl;
std::cerr << "Exchange particle to create the file" << std::endl;
std::vector<TestParticle*> particlesGathered;
std::vector<int> sizeGathered;
......@@ -166,7 +165,7 @@ int main(int argc, char* argv[]){
for(int a : sizeGathered)
sum += a/sizeof(TestParticle);
if(sum != totalNbParticles)
std::cout << "Erreur sum : " << sum << " instead of " << totalNbParticles << std::endl;
std::cerr << "Erreur sum : " << sum << " instead of " << totalNbParticles << std::endl;
//Store in that bloody file
FFmaGenericWriter<FReal> writer("canard.fma");
writer.writeHeader(loader.getCenterOfBox(), loader.getBoxWidth(),totalNbParticles, particles[0]);
......@@ -174,7 +173,7 @@ int main(int argc, char* argv[]){
writer.writeArrayOfParticles(particlesGathered[i], sizeGathered[i]/sizeof(TestParticle));
for(TestParticle* ptr : particlesGathered)
delete ptr;
std::cout << "Done exchanging !" << std::endl;
std::cerr << "Done exchanging !" << std::endl;
}
else{
int sizeofParticle = sizeof(TestParticle)*myParticles.getSize();
......@@ -189,12 +188,11 @@ int main(int argc, char* argv[]){
&allParticles, true, leftLimite);
// Run the algorithm
FTic timerExecute;
GroupKernelClass groupkernel;
GroupAlgorithm groupalgo(mpiComm.global(), &groupedTree,&groupkernel);
FTic timerExecute;
groupalgo.execute();
double elapsedTime = timerExecute.tacAndElapsed();
std::cout << "Executing time (explicit node " << mpiComm.global().processId() << ") " << elapsedTime << "s\n";
mpiComm.global().barrier();
timeAverage(mpiComm.global().processId(), mpiComm.global().processCount(), elapsedTime);
......@@ -225,11 +223,11 @@ int main(int argc, char* argv[]){
FRandomLoader<FReal> loaderAll(NbParticles, 1.0, FPoint<FReal>(0,0,0), idxProc);
for(FSize idxPart = 0 ; idxPart < loaderAll.getNumberOfParticles() ; ++idxPart){
FPoint<FReal> pos;
//loaderAll.fillParticle(&pos);
loaderAll.fillParticleAtMortonIndex(&pos, idxProc*NbParticles + idxPart,NbLevels);
loaderAll.fillParticle(&pos);
//loaderAll.fillParticleAtMortonIndex(&pos, idxProc*NbParticles + idxPart,NbLevels);
tree.insert(pos);
}
}
}
// Usual algorithm
KernelClass kernels; // FTestKernels FBasicKernels
FmmClass algo(&tree,&kernels); //FFmmAlgorithm FFmmAlgorithmThread
......@@ -259,14 +257,16 @@ void timeAverage(int mpi_rank, int nproc, double elapsedTime)
if(mpi_rank == 0)
{
double sumElapsedTime = elapsedTime;
std::cout << "Executing time node 0 (explicit) : " << sumElapsedTime << "s" << std::endl;
for(int i = 1; i < nproc; ++i)
{
double tmp;
MPI_Recv(&tmp, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, 0);
sumElapsedTime += tmp;
std::cout << "Executing time node " << i << " (explicit) : " << tmp << "s" << std::endl;
}
sumElapsedTime = sumElapsedTime / (double)nproc;
std::cout << "Average time per node : " << sumElapsedTime << "s" << std::endl;
std::cout << "Average time per node (explicit) : " << sumElapsedTime << "s" << std::endl;
}
else
{
......
......@@ -49,13 +49,15 @@
#include <memory>
void timeAverage(int mpi_rank, int nproc, double elapsedTime);
int main(int argc, char* argv[]){
setenv("STARPU_NCPU","1",1);
const FParameterNames LocalOptionBlocSize { {"-bs"}, "The size of the block of the blocked tree"};
const FParameterNames LocalOptionNoValidate { {"-no-validation"}, "To avoid comparing with direct computation"};
FHelpDescribeAndExit(argc, argv, "Test the blocked tree by counting the particles.",
FParameterDefinitions::OctreeHeight,FParameterDefinitions::InputFile,
FParameterDefinitions::OctreeSubHeight,
FParameterDefinitions::OctreeSubHeight, FParameterDefinitions::NbParticles,
LocalOptionBlocSize, LocalOptionNoValidate);
typedef double FReal;
......@@ -82,9 +84,10 @@ int main(int argc, char* argv[]){
FMpi mpiComm(argc,argv);
const char* const filename = FParameters::getStr(argc,argv,FParameterDefinitions::InputFile.options, "../Data/test20k.fma");
const unsigned int TreeHeight = FParameters::getValue(argc, argv, FParameterDefinitions::OctreeHeight.options, 5);
const unsigned int SubTreeHeight = FParameters::getValue(argc, argv, FParameterDefinitions::OctreeSubHeight.options, 2);
const FSize NbParticles = FParameters::getValue(argc,argv,FParameterDefinitions::NbParticles.options, FSize(20));
const FSize totalNbParticles = (NbParticles*mpiComm.global().processCount());
// init particles position and physical value
struct TestParticle{
......@@ -93,30 +96,37 @@ int main(int argc, char* argv[]){
const FPoint<FReal>& getPosition(){
return position;
}
const unsigned int getWriteDataSize(void) const {
return sizeof(FReal);
}
const unsigned int getWriteDataNumber(void) const {
return 3;
}
const FReal* getPtrFirstData(void) const {
return position.data();
}
};
// open particle file
std::cout << "Opening : " << filename << "\n" << std::endl;
FMpiFmaGenericLoader<FReal> loader(filename,mpiComm.global());
FRandomLoader<FReal> loader(NbParticles, 1.0, FPoint<FReal>(0,0,0), mpiComm.global().processId());
FAssertLF(loader.isOpen());
TestParticle* allParticles = new TestParticle[loader.getMyNumberOfParticles()];
memset(allParticles,0,(unsigned int) (sizeof(TestParticle)* loader.getMyNumberOfParticles()));
for(FSize idxPart = 0 ; idxPart < loader.getMyNumberOfParticles() ; ++idxPart){
loader.fillParticle(&allParticles[idxPart].position,&allParticles[idxPart].physicalValue);
TestParticle* allParticles = new TestParticle[loader.getNumberOfParticles()];
memset(allParticles,0,(unsigned int) (sizeof(TestParticle)* loader.getNumberOfParticles()));
for(FSize idxPart = 0 ; idxPart < loader.getNumberOfParticles() ; ++idxPart){
loader.fillParticle(&allParticles[idxPart].position);
allParticles[idxPart].physicalValue = 0.1;
}
FVector<TestParticle> myParticles;
FLeafBalance balancer;
FMpiTreeBuilder< FReal,TestParticle >::DistributeArrayToContainer(mpiComm.global(),allParticles,
loader.getMyNumberOfParticles(),
loader.getNumberOfParticles(),
loader.getCenterOfBox(),
loader.getBoxWidth(),TreeHeight,
&myParticles, &balancer);
std::cout << "Creating & Inserting " << loader.getMyNumberOfParticles() << " particles ..." << std::endl;
std::cout << "For a total of " << loader.getNumberOfParticles() << " particles ..." << std::endl;
std::cout << "\tHeight : " << TreeHeight << " \t sub-height : " << SubTreeHeight << std::endl;
//std::cout << "\tHeight : " << TreeHeight << " \t sub-height : " << SubTreeHeight << std::endl;
// Each proc need to know the righest morton index
const FTreeCoordinate host = FCoordinateComputer::GetCoordinateFromPosition<FReal>(
......@@ -139,6 +149,47 @@ int main(int argc, char* argv[]){
FLOG(std::cout << "My last index is " << leftLimite << "\n");
FLOG(std::cout << "My left limite is " << myLeftLimite << "\n");
//Save particles in a file
if(mpiComm.global().processId() == 0){
std::cerr << "Exchange particle to create the file" << std::endl;
std::vector<TestParticle*> particlesGathered;
std::vector<int> sizeGathered;
//Ajout des mes particules
int sizeofParticle = sizeof(TestParticle)*myParticles.getSize();
sizeGathered.push_back(sizeofParticle);
particlesGathered.push_back(new TestParticle[sizeofParticle]);
memcpy(particlesGathered.back(), myParticles.data(), sizeofParticle);
//Recupération des particules des autres
for(int i = 1; i < mpiComm.global().processCount(); ++i)
{
int sizeReceive;
MPI_Recv(&sizeReceive, sizeof(sizeReceive), MPI_BYTE, i, 0, mpiComm.global().getComm(), MPI_STATUS_IGNORE);
sizeGathered.push_back(sizeReceive);
particlesGathered.push_back(new TestParticle[sizeReceive]);
MPI_Recv(particlesGathered.back(), sizeReceive, MPI_BYTE, i, 0, mpiComm.global().getComm(), MPI_STATUS_IGNORE);
}
int sum = 0;
for(int a : sizeGathered)
sum += a/sizeof(TestParticle);
if(sum != totalNbParticles)
std::cerr << "Erreur sum : " << sum << " instead of " << totalNbParticles << std::endl;
//Store in that bloody file
FFmaGenericWriter<FReal> writer("canard.fma");
writer.writeHeader(loader.getCenterOfBox(), loader.getBoxWidth(),totalNbParticles, allParticles[0]);
for(unsigned int i = 0; i < particlesGathered.size(); ++i)
writer.writeArrayOfParticles(particlesGathered[i], sizeGathered[i]/sizeof(TestParticle));
for(TestParticle* ptr : particlesGathered)
delete ptr;
std::cerr << "Done exchanging !" << std::endl;
}
else{
int sizeofParticle = sizeof(TestParticle)*myParticles.getSize();
MPI_Send(&sizeofParticle, sizeof(sizeofParticle), MPI_BYTE, 0, 0, mpiComm.global().getComm());//Send size
MPI_Send(myParticles.data(), sizeofParticle, MPI_BYTE, 0, 0, mpiComm.global().getComm());
MPI_Send(const_cast<MortonIndex*>(&leftLimite), sizeof(leftLimite), MPI_BYTE, 0, 0, mpiComm.global().getComm());
MPI_Send(const_cast<MortonIndex*>(&myLeftLimite), sizeof(myLeftLimite), MPI_BYTE, 0, 0, mpiComm.global().getComm());
}
// Put the data into the tree
FP2PParticleContainer<FReal> myParticlesInContainer;
......@@ -148,17 +199,16 @@ int main(int argc, char* argv[]){
}
GroupOctreeClass groupedTree(TreeHeight, loader.getBoxWidth(), loader.getCenterOfBox(), groupSize,
&myParticlesInContainer, true, leftLimite);
groupedTree.printInfoBlocks();
//groupedTree.printInfoBlocks();
timer.tac();
std::cout << "Done " << "(@Creating and Inserting Particles = "
<< timer.elapsed() << "s)." << std::endl;
//std::cerr << "Done " << "(@Creating and Inserting Particles = " << timer.elapsed() << "s)." << std::endl;
{ // -----------------------------------------------------
std::cout << "\nChebyshev FMM (ORDER="<< ORDER << ") ... " << std::endl;
//std::cout << "\nChebyshev FMM (ORDER="<< ORDER << ") ... " << std::endl;
timer.tic();
MatrixKernelClass MatrixKernel;
const MatrixKernelClass MatrixKernel;
// Create Matrix Kernel
GroupKernelClass groupkernel(TreeHeight, loader.getBoxWidth(), loader.getCenterOfBox(), &MatrixKernel);
// Run the algorithm
......@@ -166,7 +216,8 @@ int main(int argc, char* argv[]){
groupalgo.execute();
timer.tac();
std::cout << "Done " << "(@Algorithm = " << timer.elapsed() << "s)." << std::endl;
timeAverage(mpiComm.global().processId(), mpiComm.global().processCount(), timer.elapsed());
//std::cout << "Done " << "(@Algorithm = " << timer.elapsed() << "s)." << std::endl;
} // -----------------------------------------------------
......@@ -192,7 +243,7 @@ int main(int argc, char* argv[]){
KernelClass kernels(TreeHeight, loader.getBoxWidth(), loader.getCenterOfBox(), &MatrixKernel);
FmmClass algorithm(mpiComm.global(),&treeCheck, &kernels);
algorithm.execute();
std::cout << "Algo is over" << std::endl;
//std::cout << "Algo is over" << std::endl;
groupedTree.forEachCellWithLevel([&](GroupCellClass gcell, const int level){
const CellClass* cell = treeCheck.getCell(gcell.getMortonIndex(), level);
......@@ -274,10 +325,32 @@ int main(int argc, char* argv[]){
}
});
std::cout << "Comparing is over" << std::endl;
//std::cout << "Comparing is over" << std::endl;
}
return 0;
}
void timeAverage(int mpi_rank, int nproc, double elapsedTime)
{
if(mpi_rank == 0)
{
double sumElapsedTime = elapsedTime;
std::cout << "Executing time node 0 (explicit Cheby) : " << sumElapsedTime << "s" << std::endl;
for(int i = 1; i < nproc; ++i)
{
double tmp;
MPI_Recv(&tmp, 1, MPI_DOUBLE, i, 0, MPI_COMM_WORLD, 0);
sumElapsedTime += tmp;
std::cout << "Executing time node " << i << " (explicit Cheby) : " << tmp << "s" << std::endl;
}
sumElapsedTime = sumElapsedTime / (double)nproc;
std::cout << "Average time per node (explicit Cheby) : " << sumElapsedTime << "s" << std::endl;
}
else
{
MPI_Send(&elapsedTime, 1, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);
}
MPI_Barrier(MPI_COMM_WORLD);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment