24 #include <Teuchos_DefaultComm.hpp>
25 #include <Teuchos_TimeMonitor.hpp>
26 #include <Tpetra_MultiVector.hpp>
27 #include <Tpetra_Import.hpp>
29 #include <Epetra_Vector.h>
30 #include <Epetra_MpiComm.h>
31 #include <Epetra_Import.h>
43 using Teuchos::rcp_dynamic_cast;
44 using Teuchos::ArrayRCP;
45 using Teuchos::ArrayView;
46 using Teuchos::TimeMonitor;
51 typedef int TPETRA_LO;
52 typedef int TPETRA_GO;
53 typedef unsigned int ZOLTAN_LO;
54 typedef unsigned int ZOLTAN_GO;
55 #define MPI_ZOLTAN_GO_TYPE MPI_UNSIGNED
56 typedef double TPETRA_SCALAR;
61 RCP<Time> tmvMigrateN;
66 RCP<Time> emvMigrateN;
71 RCP<Time> ztnMigrateN;
73 using Teuchos::MpiComm;
76 enum testConstants {COORDDIM=3};
78 static void usage(
char *arg[]){
79 std::cout <<
"Usage:" << std::endl;
80 std::cout << arg[0] <<
" {num coords}" << std::endl;
86 TPETRA_LO numSequentialGlobalIds(TPETRA_GO numGlobalCoords,
int nprocs,
int rank)
88 TPETRA_LO share = numGlobalCoords / nprocs;
89 TPETRA_LO extra = numGlobalCoords % nprocs;
90 TPETRA_LO numLocalCoords = share;
94 return numLocalCoords;
97 void roundRobinGlobalIds(T numGlobalCoords,
int nprocs,
int rank,
101 T share = numGlobalCoords / nprocs;
102 T extra = numGlobalCoords % nprocs;
103 T numLocalCoords = share;
104 if (static_cast<T> (rank) < extra)
107 gids =
new T [numLocalCoords];
109 throw std::bad_alloc();
112 for (T i=rank; i < numGlobalCoords; i+=nprocs)
117 template <
typename T>
118 void subGroupGloballyIncreasingIds(T numGlobalCoords,
119 int nprocs,
int rank, T *&gids)
121 int numProcsLeftHalf = nprocs / 2;
122 T share = numGlobalCoords / nprocs;
123 T extra = numGlobalCoords % nprocs;
124 T numCoordsLeftHalf = 0;
125 T firstIdx = 0, endIdx = 0;
127 T endP = ((numProcsLeftHalf > rank) ? numProcsLeftHalf : rank);
129 for (T p=0; p < endP ; p++){
130 T numLocalCoords = share;
134 if (p < static_cast<T> (rank))
135 firstIdx += numLocalCoords;
137 if (p < static_cast<T> (numProcsLeftHalf))
138 numCoordsLeftHalf += numLocalCoords;
141 endIdx = firstIdx + share;
142 if (rank <
int(extra))
145 if (rank >= numProcsLeftHalf){
146 firstIdx -= numCoordsLeftHalf;
147 endIdx -= numCoordsLeftHalf;
150 int firstProc=0, endProc=0;
152 if (rank < numProcsLeftHalf){
154 endProc = numProcsLeftHalf;
157 firstProc = numProcsLeftHalf;
161 int numProcsInMyHalf = endProc - firstProc;
178 T numLocalCoords = endIdx - firstIdx;
179 gids =
new T [numLocalCoords];
181 throw std::bad_alloc();
183 T firstRow = firstIdx / numProcsInMyHalf;
184 T firstCol = (firstIdx % numProcsInMyHalf) + firstProc;
187 for (T row = firstRow;
static_cast<T
> (next) < numLocalCoords; row++){
188 T firstGid = row * nprocs + firstCol;
189 for (T col = firstCol;
static_cast<T
> (next) < numLocalCoords && col < static_cast<T> (endProc); col++){
190 gids[next++] = firstGid++;
192 firstCol = firstProc;
196 void timeEpetra(TPETRA_GO numGlobalCoords,
const RCP<
const MpiComm<int> > &comm,
bool);
198 timeTpetra (
const TPETRA_GO numGlobalCoords,
199 const Teuchos::RCP<
const Teuchos::Comm<int> >& comm,
200 const bool doMemory);
201 void timeZoltan(ZOLTAN_GO numGlobalCoords,
bool);
207 int main(
int narg,
char *arg[])
209 Tpetra::ScopeGuard tscope(&narg, &arg);
210 Teuchos::RCP<const Teuchos::Comm<int> > genComm = Tpetra::getDefaultComm();
211 Teuchos::RCP<const MpiComm<int> > comm =
212 rcp_dynamic_cast<
const MpiComm<int> >(genComm);
214 int rank = genComm->getRank();
222 TPETRA_GO numGlobalCoords = 0;
223 std::string theArg(arg[1]);
224 std::istringstream iss(theArg);
225 iss >> numGlobalCoords;
226 if (numGlobalCoords < genComm->getSize()){
233 std::cout << numGlobalCoords <<
" coordinates" << std::endl;
235 tmvBuild = TimeMonitor::getNewTimer(
"CONSEC build Tpetra");
236 tmvMigrate = TimeMonitor::getNewTimer(
"CONSEC migrate Tpetra");
237 tmvBuildN = TimeMonitor::getNewTimer(
"!CONSEC build Tpetra");
238 tmvMigrateN = TimeMonitor::getNewTimer(
"!CONSEC migrate Tpetra");
240 ztnBuild = TimeMonitor::getNewTimer(
"CONSEC build Zoltan1");
241 ztnMigrate = TimeMonitor::getNewTimer(
"CONSEC migrate Zoltan1");
242 ztnBuildN = TimeMonitor::getNewTimer(
"!CONSEC build Zoltan1");
243 ztnMigrateN = TimeMonitor::getNewTimer(
"!CONSEC migrate Zoltan1");
245 emvBuild = TimeMonitor::getNewTimer(
"CONSEC build Epetra");
246 emvMigrate = TimeMonitor::getNewTimer(
"CONSEC migrate Epetra");
247 emvBuildN = TimeMonitor::getNewTimer(
"!CONSEC build Epetra");
248 emvMigrateN = TimeMonitor::getNewTimer(
"!CONSEC migrate Epetra");
250 TimeMonitor::zeroOutTimers();
256 for (
int i=0; i < ntests; i++){
258 std::cout <<
"Zoltan test " << i+1 << std::endl;
259 timeZoltan(numGlobalCoords, i==ntests-1);
264 for (
int i=0; i < ntests; i++){
266 std::cout <<
"Epetra test " << i+1 << std::endl;
267 timeEpetra(numGlobalCoords, comm, i==ntests-1);
272 for (
int i=0; i < ntests; i++){
274 std::cout <<
"Tpetra test " << i+1 << std::endl;
275 timeTpetra(numGlobalCoords, comm, i==ntests-1);
280 TimeMonitor::summarize();
282 if (comm->getRank() == 0)
283 std::cout <<
"PASS" << std::endl;
287 timeTpetra (
const TPETRA_GO numGlobalCoords,
288 const Teuchos::RCP<
const Teuchos::Comm<int> >& comm,
292 using Teuchos::ArrayRCP;
293 using Teuchos::ArrayView;
297 typedef Tpetra::Map<TPETRA_LO, TPETRA_GO> map_type;
298 typedef Tpetra::MultiVector<TPETRA_SCALAR, TPETRA_LO, TPETRA_GO> MV;
299 typedef ArrayView<const TPETRA_SCALAR> coordList_t;
301 const int nprocs = comm->getSize ();
302 const int rank = comm->getRank ();
307 const TPETRA_LO numLocalCoords = numSequentialGlobalIds(numGlobalCoords, nprocs, rank);
309 RCP<const map_type> tmap;
311 TPETRA_SCALAR* coords = NULL;
313 Teuchos::TimeMonitor timeMon (*tmvBuild);
315 tmap = rcp (
new map_type (numGlobalCoords, numLocalCoords, 0, comm));
317 coords =
new TPETRA_SCALAR [COORDDIM * numLocalCoords];
318 memset (coords, 0,
sizeof(TPETRA_SCALAR) * numLocalCoords * COORDDIM);
320 coordList_t *avList =
new coordList_t [COORDDIM];
321 TPETRA_LO offset = 0;
323 for (
int dim = 0; dim < COORDDIM; ++dim) {
324 avList[dim] = coordList_t(coords + offset, numLocalCoords);
325 offset += numLocalCoords;
328 ArrayRCP<const coordList_t> vectors = arcp (avList, 0, COORDDIM);
329 mvector = rcp (
new MV (tmap, vectors.view (0, COORDDIM), COORDDIM));
332 if (rank == 0 && doMemory) {
334 std::cout <<
"Create mvector 1: " << nkb << std::endl;
340 ArrayRCP<const TPETRA_GO> newGidArray;
342 TPETRA_GO *newGids = NULL;
343 roundRobinGlobalIds<TPETRA_GO> (numGlobalCoords, nprocs, rank, newGids);
344 newGidArray = arcp<const TPETRA_GO> (newGids, 0, numLocalCoords,
true);
347 RCP<const map_type> newTmap;
348 RCP<Tpetra::Import<TPETRA_LO, TPETRA_GO> > importer;
351 Teuchos::TimeMonitor timeMon (*tmvMigrate);
353 newTmap = rcp (
new map_type (numGlobalCoords, newGidArray.view(0, numLocalCoords), 0, comm));
354 importer = rcp (
new Tpetra::Import<TPETRA_LO, TPETRA_GO> (tmap, newTmap));
355 newMvector = rcp (
new MV (newTmap, COORDDIM,
true));
357 newMvector->doImport (*mvector, *importer, Tpetra::INSERT);
358 mvector = newMvector;
363 if (rank == 0 && doMemory) {
365 std::cout <<
"Create mvector 2: " << nkb << std::endl;
371 RCP<Comm<int> > subComm;
374 int leftHalfNumProcs = nprocs / 2;
375 int *myHalfProcs = NULL;
377 if (rank < leftHalfNumProcs){
378 groupSize = leftHalfNumProcs;
379 myHalfProcs =
new int [groupSize];
380 for (
int i=0; i < groupSize; i++)
384 groupSize = nprocs - leftHalfNumProcs;
385 myHalfProcs =
new int [groupSize];
386 int firstNum = leftHalfNumProcs;
387 for (
int i=0; i < groupSize; i++)
388 myHalfProcs[i] = firstNum++;
391 ArrayView<const int> idView(myHalfProcs, groupSize);
392 subComm = comm->createSubcommunicator (idView);
393 delete [] myHalfProcs;
400 size_t globalSize = Teuchos::OrdinalTraits<size_t>::invalid ();
401 RCP<map_type> subMap;
404 Teuchos::TimeMonitor timeMon (*tmvBuildN);
406 ArrayView<const TPETRA_GO> gidList = mvector->getMap ()->getLocalElementList ();
407 subMap = rcp (
new map_type (globalSize, gidList, 0, subComm));
408 globalSize = subMap->getGlobalNumElements ();
411 RCP<MV> tmp = mvector->offsetViewNonConst (subMap, 0);
413 subMvector = rcp (
new MV (subMap, mvector->getNumVectors ()));
415 Tpetra::deep_copy (*subMvector, *tmp);
422 TPETRA_GO *increasingGids = NULL;
423 subGroupGloballyIncreasingIds<TPETRA_GO> (numGlobalCoords, nprocs,
424 rank, increasingGids);
426 ArrayRCP<const TPETRA_GO> incrGidArray (increasingGids, 0, numLocalCoords,
true);
428 RCP<const map_type> newSubMap;
429 RCP<Tpetra::Import<TPETRA_LO, TPETRA_GO> > subImporter;
430 RCP<MV> newSubMvector;
432 Teuchos::TimeMonitor timeMon (*tmvMigrateN);
435 rcp (
new map_type (globalSize, incrGidArray.view (0, numLocalCoords),
437 subImporter = rcp (
new Tpetra::Import<TPETRA_LO, TPETRA_GO> (subMap, newSubMap));
438 newSubMvector = rcp (
new MV (newSubMap, COORDDIM,
true));
439 newSubMvector->doImport (*subMvector, *subImporter, Tpetra::INSERT);
440 mvector = newSubMvector;
444 void timeEpetra(TPETRA_GO numGlobalCoords,
const RCP<
const MpiComm<int> > &comm,
447 RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > commPtr =
448 comm->getRawMpiComm();
450 RCP<Epetra_MpiComm> ecomm = rcp(
new Epetra_MpiComm((*commPtr)()));
452 int nprocs = comm->getSize();
453 int rank = comm->getRank();
458 TPETRA_LO numLocalCoords = numSequentialGlobalIds(numGlobalCoords, nprocs, rank);
461 emvBuild->incrementNumCalls();
463 RCP<Epetra_BlockMap> emap = rcp(
new Epetra_BlockMap(numGlobalCoords,
464 numLocalCoords, 1, 0, *ecomm));
466 TPETRA_SCALAR *coords =
new TPETRA_SCALAR [COORDDIM * numLocalCoords];
467 memset(coords, 0,
sizeof(TPETRA_SCALAR) * numLocalCoords * COORDDIM);
469 RCP<Epetra_MultiVector> mvector = rcp(
new Epetra_MultiVector(
470 View, *emap, coords, 1, COORDDIM));
474 if (rank==0 && doMemory){
476 std::cout <<
"Create mvector 1: " << nkb << std::endl;;
482 TPETRA_GO *newGids = NULL;
483 roundRobinGlobalIds<TPETRA_GO>(numGlobalCoords, nprocs, rank, newGids);
486 emvMigrate->incrementNumCalls();
488 RCP<Epetra_BlockMap> newMap = rcp(
new Epetra_BlockMap(numGlobalCoords,
489 numLocalCoords, newGids, 1, 0, *ecomm));
491 RCP<Epetra_Import> importer = rcp(
new Epetra_Import(*newMap, *emap));
493 RCP<Epetra_MultiVector> newMvector = rcp(
new Epetra_MultiVector(
496 newMvector->Import(*mvector, *importer, Insert);
498 mvector = newMvector;
504 if (rank==0 && doMemory){
506 std::cout <<
"Create mvector 2: " << nkb << std::endl;;
513 int leftHalfNumProcs = nprocs / 2;
514 int *myHalfProcs = NULL;
516 if (rank < leftHalfNumProcs){
517 groupSize = leftHalfNumProcs;
518 myHalfProcs =
new int [groupSize];
519 for (
int i=0; i < groupSize; i++)
523 groupSize = nprocs - leftHalfNumProcs;
524 myHalfProcs =
new int [groupSize];
525 int firstNum = leftHalfNumProcs;
526 for (
int i=0; i < groupSize; i++)
527 myHalfProcs[i] = firstNum++;
530 ArrayView<const int> idView(myHalfProcs, groupSize);
532 RCP<Comm<int> > newComm = comm->createSubcommunicator(idView);
533 RCP<MpiComm<int> > genSubComm = rcp_dynamic_cast<MpiComm<int> >(newComm);
535 commPtr = genSubComm->getRawMpiComm();
537 RCP<Epetra_MpiComm> subComm = rcp(
new Epetra_MpiComm((*commPtr)()));
539 delete [] myHalfProcs;
546 emvBuildN->incrementNumCalls();
548 RCP<Epetra_BlockMap> subMap = rcp(
new Epetra_BlockMap(-1,
549 numLocalCoords, newGids, 1, 0, *subComm));
551 TPETRA_SCALAR **avSubList =
new TPETRA_SCALAR * [COORDDIM];
553 for (
int dim=0; dim < COORDDIM; dim++)
554 (*mvector)(dim)->ExtractView(avSubList + dim);
556 RCP<Epetra_MultiVector> subMvector = rcp(
new Epetra_MultiVector(
557 View, *subMap, avSubList, COORDDIM));
559 mvector = subMvector;
570 TPETRA_GO *increasingGids = NULL;
571 subGroupGloballyIncreasingIds<TPETRA_GO>(numGlobalCoords, nprocs, rank,
574 emvMigrateN->start();
575 emvMigrateN->incrementNumCalls();
577 RCP<Epetra_BlockMap> newSubMap = rcp(
new Epetra_BlockMap(-1,
578 numLocalCoords, increasingGids, 1, 0, *subComm));
580 RCP<Epetra_Import> subImporter = rcp(
new Epetra_Import(
581 *subMap, *newSubMap));
583 RCP<Epetra_MultiVector> newSubMvector = rcp(
new Epetra_MultiVector(
584 *newSubMap, COORDDIM));
586 newSubMvector->Import(*subMvector, *subImporter, Insert);
588 mvector = newSubMvector;
592 delete [] increasingGids;
595 void timeZoltan(ZOLTAN_GO numGlobalCoords,
599 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
600 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
606 ZOLTAN_LO numLocalCoords = numSequentialGlobalIds(numGlobalCoords, nprocs, rank);
609 MPI_Exscan(&numLocalCoords, &offset, 1,
610 MPI_ZOLTAN_GO_TYPE, MPI_SUM, MPI_COMM_WORLD);
612 ZOLTAN_GO *gids =
new ZOLTAN_GO [numLocalCoords];
613 for (ZOLTAN_LO i=0; i < numLocalCoords; i++){
618 ztnBuild->incrementNumCalls();
620 struct Zoltan_DD_Struct *dd = NULL;
621 int rc = Zoltan_DD_Create(&dd, MPI_COMM_WORLD, 1, 1, 0, numLocalCoords, 0);
625 rc = Zoltan_DD_Update(dd, gids, NULL, NULL, NULL, numLocalCoords);
629 TPETRA_SCALAR *coords =
new TPETRA_SCALAR [COORDDIM * numLocalCoords];
630 memset(coords, 0,
sizeof(TPETRA_SCALAR) * numLocalCoords * COORDDIM);
634 if (rank==0 && doMemory){
636 std::cout <<
"Create mvector 1: " << nkb << std::endl;;
639 Zoltan_DD_Destroy(&dd);
644 ZOLTAN_GO *newGids = NULL;
645 roundRobinGlobalIds<ZOLTAN_GO>(numGlobalCoords, nprocs, rank, newGids);
648 ztnMigrate->incrementNumCalls();
650 struct Zoltan_DD_Struct *ddNew = NULL;
651 rc = Zoltan_DD_Create(&ddNew, MPI_COMM_WORLD, 1, 1, 0, numLocalCoords, 0);
655 rc = Zoltan_DD_Update(ddNew, newGids, NULL, NULL, NULL, numLocalCoords);
659 int *procOwners =
new int [numLocalCoords];
660 rc = Zoltan_DD_Find(ddNew, gids, NULL, NULL, NULL,
661 numLocalCoords, procOwners);
665 Zoltan_DD_Destroy(&ddNew);
667 struct Zoltan_Comm_Obj *commPlan = NULL;
671 rc = Zoltan_Comm_Create(&commPlan, numLocalCoords, procOwners, MPI_COMM_WORLD,
676 TPETRA_SCALAR *newCoords =
new TPETRA_SCALAR [COORDDIM * numReceive];
681 void *x =
static_cast<void *
>(coords);
682 char *charCoords =
static_cast<char *
>(x);
683 x =
static_cast<void *
>(newCoords);
684 char *charNewCoords =
static_cast<char *
>(x);
686 rc = Zoltan_Comm_Do(commPlan, tag, charCoords,
687 sizeof(TPETRA_SCALAR)*COORDDIM, charNewCoords);
694 Zoltan_Comm_Destroy(&commPlan);
698 if (rank==0 && doMemory){
700 std::cout <<
"Create mvector 2: " << nkb << std::endl;;
707 int leftHalfNumProcs = nprocs / 2;
708 int *myHalfProcs = NULL;
710 if (rank < leftHalfNumProcs){
711 groupSize = leftHalfNumProcs;
712 myHalfProcs =
new int [groupSize];
713 for (
int i=0; i < groupSize; i++)
717 groupSize = nprocs - leftHalfNumProcs;
718 myHalfProcs =
new int [groupSize];
719 for (
int i=0; i < groupSize; i++)
720 myHalfProcs[i] = i + leftHalfNumProcs;
723 MPI_Group group, subGroup;
726 MPI_Comm_group(MPI_COMM_WORLD, &group);
727 MPI_Group_incl(group, groupSize, myHalfProcs, &subGroup);
728 MPI_Comm_create(MPI_COMM_WORLD, subGroup, &subComm);
729 MPI_Group_free(&subGroup);
731 delete [] myHalfProcs;
737 ztnBuildN->incrementNumCalls();
739 struct Zoltan_DD_Struct *ddSub = NULL;
740 rc = Zoltan_DD_Create(&ddSub, subComm, 1, 1, 0, numLocalCoords, 0);
744 rc = Zoltan_DD_Update(ddSub, newGids, NULL, NULL, NULL, numLocalCoords);
750 Zoltan_DD_Destroy(&ddSub);
756 ZOLTAN_GO *increasingGids = NULL;
757 subGroupGloballyIncreasingIds<ZOLTAN_GO>(
758 numGlobalCoords, nprocs, rank, increasingGids);
762 ztnMigrateN->start();
763 ztnMigrateN->incrementNumCalls();
765 struct Zoltan_DD_Struct *ddNewSub = NULL;
766 rc = Zoltan_DD_Create(&ddNewSub, subComm, 1, 1, 0, numLocalCoords, 0);
770 rc = Zoltan_DD_Update(ddNewSub, increasingGids, NULL, NULL, NULL,
775 rc = Zoltan_DD_Find(ddNewSub, newGids, NULL, NULL, NULL, numLocalCoords, procOwners);
781 Zoltan_DD_Destroy(&ddNewSub);
783 struct Zoltan_Comm_Obj *subCommPlan = NULL;
786 rc = Zoltan_Comm_Create(&subCommPlan, numLocalCoords, procOwners, subComm,
791 delete [] procOwners;
793 TPETRA_SCALAR *newContigCoords =
new TPETRA_SCALAR [COORDDIM * numReceive];
797 x =
static_cast<void *
>(newContigCoords);
798 char *charNewContigCoords =
static_cast<char *
>(x);
800 rc = Zoltan_Comm_Do(subCommPlan, tag, charNewCoords,
801 sizeof(TPETRA_SCALAR)*COORDDIM, charNewContigCoords);
808 delete [] newContigCoords;
809 delete [] increasingGids;
810 Zoltan_Comm_Destroy(&subCommPlan);
813 int main(
int narg,
char *arg[])
815 Tpetra::ScopeGuard tscope(&narg, &arg);
816 Teuchos::RCP<const Teuchos::Comm<int> > genComm = Tpetra::getDefaultComm();
818 if (genComm->getRank() == 0){
819 std::cout <<
"Test not run because MPI is not available." << std::endl;
820 std::cout <<
"PASS" << std::endl;
int main(int narg, char **arg)
long getProcessKilobytes()
A gathering of useful namespace methods.