21 #include <Teuchos_DefaultComm.hpp>
22 #include <Teuchos_TimeMonitor.hpp>
23 #include <Tpetra_MultiVector.hpp>
24 #include <Tpetra_Import.hpp>
26 #include <Epetra_Vector.h>
27 #include <Epetra_MpiComm.h>
28 #include <Epetra_Import.h>
40 using Teuchos::rcp_dynamic_cast;
41 using Teuchos::ArrayRCP;
42 using Teuchos::ArrayView;
43 using Teuchos::TimeMonitor;
48 typedef int TPETRA_LO;
49 typedef int TPETRA_GO;
50 typedef unsigned int ZOLTAN_LO;
51 typedef unsigned int ZOLTAN_GO;
52 #define MPI_ZOLTAN_GO_TYPE MPI_UNSIGNED
53 typedef double TPETRA_SCALAR;
58 RCP<Time> tmvMigrateN;
63 RCP<Time> emvMigrateN;
68 RCP<Time> ztnMigrateN;
70 using Teuchos::MpiComm;
73 enum testConstants {COORDDIM=3};
75 static void usage(
char *arg[]){
76 std::cout <<
"Usage:" << std::endl;
77 std::cout << arg[0] <<
" {num coords}" << std::endl;
83 TPETRA_LO numSequentialGlobalIds(TPETRA_GO numGlobalCoords,
int nprocs,
int rank)
85 TPETRA_LO share = numGlobalCoords / nprocs;
86 TPETRA_LO extra = numGlobalCoords % nprocs;
87 TPETRA_LO numLocalCoords = share;
91 return numLocalCoords;
94 void roundRobinGlobalIds(T numGlobalCoords,
int nprocs,
int rank,
98 T share = numGlobalCoords / nprocs;
99 T extra = numGlobalCoords % nprocs;
100 T numLocalCoords = share;
101 if (static_cast<T> (rank) < extra)
104 gids =
new T [numLocalCoords];
106 throw std::bad_alloc();
109 for (T i=rank; i < numGlobalCoords; i+=nprocs)
114 template <
typename T>
115 void subGroupGloballyIncreasingIds(T numGlobalCoords,
116 int nprocs,
int rank, T *&gids)
118 int numProcsLeftHalf = nprocs / 2;
119 T share = numGlobalCoords / nprocs;
120 T extra = numGlobalCoords % nprocs;
121 T numCoordsLeftHalf = 0;
122 T firstIdx = 0, endIdx = 0;
124 T endP = ((numProcsLeftHalf > rank) ? numProcsLeftHalf : rank);
126 for (T p=0; p < endP ; p++){
127 T numLocalCoords = share;
131 if (p < static_cast<T> (rank))
132 firstIdx += numLocalCoords;
134 if (p < static_cast<T> (numProcsLeftHalf))
135 numCoordsLeftHalf += numLocalCoords;
138 endIdx = firstIdx + share;
139 if (rank <
int(extra))
142 if (rank >= numProcsLeftHalf){
143 firstIdx -= numCoordsLeftHalf;
144 endIdx -= numCoordsLeftHalf;
147 int firstProc=0, endProc=0;
149 if (rank < numProcsLeftHalf){
151 endProc = numProcsLeftHalf;
154 firstProc = numProcsLeftHalf;
158 int numProcsInMyHalf = endProc - firstProc;
175 T numLocalCoords = endIdx - firstIdx;
176 gids =
new T [numLocalCoords];
178 throw std::bad_alloc();
180 T firstRow = firstIdx / numProcsInMyHalf;
181 T firstCol = (firstIdx % numProcsInMyHalf) + firstProc;
184 for (T row = firstRow;
static_cast<T
> (next) < numLocalCoords; row++){
185 T firstGid = row * nprocs + firstCol;
186 for (T col = firstCol;
static_cast<T
> (next) < numLocalCoords && col < static_cast<T> (endProc); col++){
187 gids[next++] = firstGid++;
189 firstCol = firstProc;
193 void timeEpetra(TPETRA_GO numGlobalCoords,
const RCP<
const MpiComm<int> > &comm,
bool);
195 timeTpetra (
const TPETRA_GO numGlobalCoords,
196 const Teuchos::RCP<
const Teuchos::Comm<int> >& comm,
197 const bool doMemory);
198 void timeZoltan(ZOLTAN_GO numGlobalCoords,
bool);
204 int main(
int narg,
char *arg[])
206 Tpetra::ScopeGuard tscope(&narg, &arg);
207 Teuchos::RCP<const Teuchos::Comm<int> > genComm = Tpetra::getDefaultComm();
208 Teuchos::RCP<const MpiComm<int> > comm =
209 rcp_dynamic_cast<
const MpiComm<int> >(genComm);
211 int rank = genComm->getRank();
219 TPETRA_GO numGlobalCoords = 0;
220 std::string theArg(arg[1]);
221 std::istringstream iss(theArg);
222 iss >> numGlobalCoords;
223 if (numGlobalCoords < genComm->getSize()){
230 std::cout << numGlobalCoords <<
" coordinates" << std::endl;
232 tmvBuild = TimeMonitor::getNewTimer(
"CONSEC build Tpetra");
233 tmvMigrate = TimeMonitor::getNewTimer(
"CONSEC migrate Tpetra");
234 tmvBuildN = TimeMonitor::getNewTimer(
"!CONSEC build Tpetra");
235 tmvMigrateN = TimeMonitor::getNewTimer(
"!CONSEC migrate Tpetra");
237 ztnBuild = TimeMonitor::getNewTimer(
"CONSEC build Zoltan1");
238 ztnMigrate = TimeMonitor::getNewTimer(
"CONSEC migrate Zoltan1");
239 ztnBuildN = TimeMonitor::getNewTimer(
"!CONSEC build Zoltan1");
240 ztnMigrateN = TimeMonitor::getNewTimer(
"!CONSEC migrate Zoltan1");
242 emvBuild = TimeMonitor::getNewTimer(
"CONSEC build Epetra");
243 emvMigrate = TimeMonitor::getNewTimer(
"CONSEC migrate Epetra");
244 emvBuildN = TimeMonitor::getNewTimer(
"!CONSEC build Epetra");
245 emvMigrateN = TimeMonitor::getNewTimer(
"!CONSEC migrate Epetra");
247 TimeMonitor::zeroOutTimers();
253 for (
int i=0; i < ntests; i++){
255 std::cout <<
"Zoltan test " << i+1 << std::endl;
256 timeZoltan(numGlobalCoords, i==ntests-1);
261 for (
int i=0; i < ntests; i++){
263 std::cout <<
"Epetra test " << i+1 << std::endl;
264 timeEpetra(numGlobalCoords, comm, i==ntests-1);
269 for (
int i=0; i < ntests; i++){
271 std::cout <<
"Tpetra test " << i+1 << std::endl;
272 timeTpetra(numGlobalCoords, comm, i==ntests-1);
277 TimeMonitor::summarize();
279 if (comm->getRank() == 0)
280 std::cout <<
"PASS" << std::endl;
284 timeTpetra (
const TPETRA_GO numGlobalCoords,
285 const Teuchos::RCP<
const Teuchos::Comm<int> >& comm,
289 using Teuchos::ArrayRCP;
290 using Teuchos::ArrayView;
294 typedef Tpetra::Map<TPETRA_LO, TPETRA_GO> map_type;
295 typedef Tpetra::MultiVector<TPETRA_SCALAR, TPETRA_LO, TPETRA_GO> MV;
296 typedef ArrayView<const TPETRA_SCALAR> coordList_t;
298 const int nprocs = comm->getSize ();
299 const int rank = comm->getRank ();
304 const TPETRA_LO numLocalCoords = numSequentialGlobalIds(numGlobalCoords, nprocs, rank);
306 RCP<const map_type> tmap;
308 TPETRA_SCALAR* coords = NULL;
310 Teuchos::TimeMonitor timeMon (*tmvBuild);
312 tmap = rcp (
new map_type (numGlobalCoords, numLocalCoords, 0, comm));
314 coords =
new TPETRA_SCALAR [COORDDIM * numLocalCoords];
315 memset (coords, 0,
sizeof(TPETRA_SCALAR) * numLocalCoords * COORDDIM);
317 coordList_t *avList =
new coordList_t [COORDDIM];
318 TPETRA_LO offset = 0;
320 for (
int dim = 0; dim < COORDDIM; ++dim) {
321 avList[dim] = coordList_t(coords + offset, numLocalCoords);
322 offset += numLocalCoords;
325 ArrayRCP<const coordList_t> vectors = arcp (avList, 0, COORDDIM);
326 mvector = rcp (
new MV (tmap, vectors.view (0, COORDDIM), COORDDIM));
329 if (rank == 0 && doMemory) {
331 std::cout <<
"Create mvector 1: " << nkb << std::endl;
337 ArrayRCP<const TPETRA_GO> newGidArray;
339 TPETRA_GO *newGids = NULL;
340 roundRobinGlobalIds<TPETRA_GO> (numGlobalCoords, nprocs, rank, newGids);
341 newGidArray = arcp<const TPETRA_GO> (newGids, 0, numLocalCoords,
true);
344 RCP<const map_type> newTmap;
345 RCP<Tpetra::Import<TPETRA_LO, TPETRA_GO> > importer;
348 Teuchos::TimeMonitor timeMon (*tmvMigrate);
350 newTmap = rcp (
new map_type (numGlobalCoords, newGidArray.view(0, numLocalCoords), 0, comm));
351 importer = rcp (
new Tpetra::Import<TPETRA_LO, TPETRA_GO> (tmap, newTmap));
352 newMvector = rcp (
new MV (newTmap, COORDDIM,
true));
354 newMvector->doImport (*mvector, *importer, Tpetra::INSERT);
355 mvector = newMvector;
360 if (rank == 0 && doMemory) {
362 std::cout <<
"Create mvector 2: " << nkb << std::endl;
368 RCP<Comm<int> > subComm;
371 int leftHalfNumProcs = nprocs / 2;
372 int *myHalfProcs = NULL;
374 if (rank < leftHalfNumProcs){
375 groupSize = leftHalfNumProcs;
376 myHalfProcs =
new int [groupSize];
377 for (
int i=0; i < groupSize; i++)
381 groupSize = nprocs - leftHalfNumProcs;
382 myHalfProcs =
new int [groupSize];
383 int firstNum = leftHalfNumProcs;
384 for (
int i=0; i < groupSize; i++)
385 myHalfProcs[i] = firstNum++;
388 ArrayView<const int> idView(myHalfProcs, groupSize);
389 subComm = comm->createSubcommunicator (idView);
390 delete [] myHalfProcs;
397 size_t globalSize = Teuchos::OrdinalTraits<size_t>::invalid ();
398 RCP<map_type> subMap;
401 Teuchos::TimeMonitor timeMon (*tmvBuildN);
403 ArrayView<const TPETRA_GO> gidList = mvector->getMap ()->getLocalElementList ();
404 subMap = rcp (
new map_type (globalSize, gidList, 0, subComm));
405 globalSize = subMap->getGlobalNumElements ();
408 RCP<MV> tmp = mvector->offsetViewNonConst (subMap, 0);
410 subMvector = rcp (
new MV (subMap, mvector->getNumVectors ()));
412 Tpetra::deep_copy (*subMvector, *tmp);
419 TPETRA_GO *increasingGids = NULL;
420 subGroupGloballyIncreasingIds<TPETRA_GO> (numGlobalCoords, nprocs,
421 rank, increasingGids);
423 ArrayRCP<const TPETRA_GO> incrGidArray (increasingGids, 0, numLocalCoords,
true);
425 RCP<const map_type> newSubMap;
426 RCP<Tpetra::Import<TPETRA_LO, TPETRA_GO> > subImporter;
427 RCP<MV> newSubMvector;
429 Teuchos::TimeMonitor timeMon (*tmvMigrateN);
432 rcp (
new map_type (globalSize, incrGidArray.view (0, numLocalCoords),
434 subImporter = rcp (
new Tpetra::Import<TPETRA_LO, TPETRA_GO> (subMap, newSubMap));
435 newSubMvector = rcp (
new MV (newSubMap, COORDDIM,
true));
436 newSubMvector->doImport (*subMvector, *subImporter, Tpetra::INSERT);
437 mvector = newSubMvector;
441 void timeEpetra(TPETRA_GO numGlobalCoords,
const RCP<
const MpiComm<int> > &comm,
444 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > commPtr =
445 comm->getRawMpiComm();
447 RCP<Epetra_MpiComm> ecomm = rcp(
new Epetra_MpiComm((*commPtr)()));
449 int nprocs = comm->getSize();
450 int rank = comm->getRank();
455 TPETRA_LO numLocalCoords = numSequentialGlobalIds(numGlobalCoords, nprocs, rank);
458 emvBuild->incrementNumCalls();
460 RCP<Epetra_BlockMap> emap = rcp(
new Epetra_BlockMap(numGlobalCoords,
461 numLocalCoords, 1, 0, *ecomm));
463 TPETRA_SCALAR *coords =
new TPETRA_SCALAR [COORDDIM * numLocalCoords];
464 memset(coords, 0,
sizeof(TPETRA_SCALAR) * numLocalCoords * COORDDIM);
466 RCP<Epetra_MultiVector> mvector = rcp(
new Epetra_MultiVector(
467 View, *emap, coords, 1, COORDDIM));
471 if (rank==0 && doMemory){
473 std::cout <<
"Create mvector 1: " << nkb << std::endl;;
479 TPETRA_GO *newGids = NULL;
480 roundRobinGlobalIds<TPETRA_GO>(numGlobalCoords, nprocs, rank, newGids);
483 emvMigrate->incrementNumCalls();
485 RCP<Epetra_BlockMap> newMap = rcp(
new Epetra_BlockMap(numGlobalCoords,
486 numLocalCoords, newGids, 1, 0, *ecomm));
488 RCP<Epetra_Import> importer = rcp(
new Epetra_Import(*newMap, *emap));
490 RCP<Epetra_MultiVector> newMvector = rcp(
new Epetra_MultiVector(
493 newMvector->Import(*mvector, *importer, Insert);
495 mvector = newMvector;
501 if (rank==0 && doMemory){
503 std::cout <<
"Create mvector 2: " << nkb << std::endl;;
510 int leftHalfNumProcs = nprocs / 2;
511 int *myHalfProcs = NULL;
513 if (rank < leftHalfNumProcs){
514 groupSize = leftHalfNumProcs;
515 myHalfProcs =
new int [groupSize];
516 for (
int i=0; i < groupSize; i++)
520 groupSize = nprocs - leftHalfNumProcs;
521 myHalfProcs =
new int [groupSize];
522 int firstNum = leftHalfNumProcs;
523 for (
int i=0; i < groupSize; i++)
524 myHalfProcs[i] = firstNum++;
527 ArrayView<const int> idView(myHalfProcs, groupSize);
529 RCP<Comm<int> > newComm = comm->createSubcommunicator(idView);
530 RCP<MpiComm<int> > genSubComm = rcp_dynamic_cast<MpiComm<int> >(newComm);
532 commPtr = genSubComm->getRawMpiComm();
534 RCP<Epetra_MpiComm> subComm = rcp(
new Epetra_MpiComm((*commPtr)()));
536 delete [] myHalfProcs;
543 emvBuildN->incrementNumCalls();
545 RCP<Epetra_BlockMap> subMap = rcp(
new Epetra_BlockMap(-1,
546 numLocalCoords, newGids, 1, 0, *subComm));
548 TPETRA_SCALAR **avSubList =
new TPETRA_SCALAR * [COORDDIM];
550 for (
int dim=0; dim < COORDDIM; dim++)
551 (*mvector)(dim)->ExtractView(avSubList + dim);
553 RCP<Epetra_MultiVector> subMvector = rcp(
new Epetra_MultiVector(
554 View, *subMap, avSubList, COORDDIM));
556 mvector = subMvector;
567 TPETRA_GO *increasingGids = NULL;
568 subGroupGloballyIncreasingIds<TPETRA_GO>(numGlobalCoords, nprocs, rank,
571 emvMigrateN->start();
572 emvMigrateN->incrementNumCalls();
574 RCP<Epetra_BlockMap> newSubMap = rcp(
new Epetra_BlockMap(-1,
575 numLocalCoords, increasingGids, 1, 0, *subComm));
577 RCP<Epetra_Import> subImporter = rcp(
new Epetra_Import(
578 *subMap, *newSubMap));
580 RCP<Epetra_MultiVector> newSubMvector = rcp(
new Epetra_MultiVector(
581 *newSubMap, COORDDIM));
583 newSubMvector->Import(*subMvector, *subImporter, Insert);
585 mvector = newSubMvector;
589 delete [] increasingGids;
592 void timeZoltan(ZOLTAN_GO numGlobalCoords,
596 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
597 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
603 ZOLTAN_LO numLocalCoords = numSequentialGlobalIds(numGlobalCoords, nprocs, rank);
606 MPI_Exscan(&numLocalCoords, &offset, 1,
607 MPI_ZOLTAN_GO_TYPE, MPI_SUM, MPI_COMM_WORLD);
609 ZOLTAN_GO *gids =
new ZOLTAN_GO [numLocalCoords];
610 for (ZOLTAN_LO i=0; i < numLocalCoords; i++){
615 ztnBuild->incrementNumCalls();
617 struct Zoltan_DD_Struct *dd = NULL;
618 int rc = Zoltan_DD_Create(&dd, MPI_COMM_WORLD, 1, 1, 0, numLocalCoords, 0);
622 rc = Zoltan_DD_Update(dd, gids, NULL, NULL, NULL, numLocalCoords);
626 TPETRA_SCALAR *coords =
new TPETRA_SCALAR [COORDDIM * numLocalCoords];
627 memset(coords, 0,
sizeof(TPETRA_SCALAR) * numLocalCoords * COORDDIM);
631 if (rank==0 && doMemory){
633 std::cout <<
"Create mvector 1: " << nkb << std::endl;;
636 Zoltan_DD_Destroy(&dd);
641 ZOLTAN_GO *newGids = NULL;
642 roundRobinGlobalIds<ZOLTAN_GO>(numGlobalCoords, nprocs, rank, newGids);
645 ztnMigrate->incrementNumCalls();
647 struct Zoltan_DD_Struct *ddNew = NULL;
648 rc = Zoltan_DD_Create(&ddNew, MPI_COMM_WORLD, 1, 1, 0, numLocalCoords, 0);
652 rc = Zoltan_DD_Update(ddNew, newGids, NULL, NULL, NULL, numLocalCoords);
656 int *procOwners =
new int [numLocalCoords];
657 rc = Zoltan_DD_Find(ddNew, gids, NULL, NULL, NULL,
658 numLocalCoords, procOwners);
662 Zoltan_DD_Destroy(&ddNew);
664 struct Zoltan_Comm_Obj *commPlan = NULL;
668 rc = Zoltan_Comm_Create(&commPlan, numLocalCoords, procOwners, MPI_COMM_WORLD,
673 TPETRA_SCALAR *newCoords =
new TPETRA_SCALAR [COORDDIM * numReceive];
678 void *x =
static_cast<void *
>(coords);
679 char *charCoords =
static_cast<char *
>(x);
680 x =
static_cast<void *
>(newCoords);
681 char *charNewCoords =
static_cast<char *
>(x);
683 rc = Zoltan_Comm_Do(commPlan, tag, charCoords,
684 sizeof(TPETRA_SCALAR)*COORDDIM, charNewCoords);
691 Zoltan_Comm_Destroy(&commPlan);
695 if (rank==0 && doMemory){
697 std::cout <<
"Create mvector 2: " << nkb << std::endl;;
704 int leftHalfNumProcs = nprocs / 2;
705 int *myHalfProcs = NULL;
707 if (rank < leftHalfNumProcs){
708 groupSize = leftHalfNumProcs;
709 myHalfProcs =
new int [groupSize];
710 for (
int i=0; i < groupSize; i++)
714 groupSize = nprocs - leftHalfNumProcs;
715 myHalfProcs =
new int [groupSize];
716 for (
int i=0; i < groupSize; i++)
717 myHalfProcs[i] = i + leftHalfNumProcs;
720 MPI_Group group, subGroup;
723 MPI_Comm_group(MPI_COMM_WORLD, &group);
724 MPI_Group_incl(group, groupSize, myHalfProcs, &subGroup);
725 MPI_Comm_create(MPI_COMM_WORLD, subGroup, &subComm);
726 MPI_Group_free(&subGroup);
728 delete [] myHalfProcs;
734 ztnBuildN->incrementNumCalls();
736 struct Zoltan_DD_Struct *ddSub = NULL;
737 rc = Zoltan_DD_Create(&ddSub, subComm, 1, 1, 0, numLocalCoords, 0);
741 rc = Zoltan_DD_Update(ddSub, newGids, NULL, NULL, NULL, numLocalCoords);
747 Zoltan_DD_Destroy(&ddSub);
753 ZOLTAN_GO *increasingGids = NULL;
754 subGroupGloballyIncreasingIds<ZOLTAN_GO>(
755 numGlobalCoords, nprocs, rank, increasingGids);
759 ztnMigrateN->start();
760 ztnMigrateN->incrementNumCalls();
762 struct Zoltan_DD_Struct *ddNewSub = NULL;
763 rc = Zoltan_DD_Create(&ddNewSub, subComm, 1, 1, 0, numLocalCoords, 0);
767 rc = Zoltan_DD_Update(ddNewSub, increasingGids, NULL, NULL, NULL,
772 rc = Zoltan_DD_Find(ddNewSub, newGids, NULL, NULL, NULL, numLocalCoords, procOwners);
778 Zoltan_DD_Destroy(&ddNewSub);
780 struct Zoltan_Comm_Obj *subCommPlan = NULL;
783 rc = Zoltan_Comm_Create(&subCommPlan, numLocalCoords, procOwners, subComm,
788 delete [] procOwners;
790 TPETRA_SCALAR *newContigCoords =
new TPETRA_SCALAR [COORDDIM * numReceive];
794 x =
static_cast<void *
>(newContigCoords);
795 char *charNewContigCoords =
static_cast<char *
>(x);
797 rc = Zoltan_Comm_Do(subCommPlan, tag, charNewCoords,
798 sizeof(TPETRA_SCALAR)*COORDDIM, charNewContigCoords);
805 delete [] newContigCoords;
806 delete [] increasingGids;
807 Zoltan_Comm_Destroy(&subCommPlan);
810 int main(
int narg,
char *arg[])
812 Tpetra::ScopeGuard tscope(&narg, &arg);
813 Teuchos::RCP<const Teuchos::Comm<int> > genComm = Tpetra::getDefaultComm();
815 if (genComm->getRank() == 0){
816 std::cout <<
"Test not run because MPI is not available." << std::endl;
817 std::cout <<
"PASS" << std::endl;
int main(int narg, char **arg)
long getProcessKilobytes()
A gathering of useful namespace methods.