68 else if (vecs.size() < 2)
75 typename std::vector< FullyDistVec<IT,NT> >::iterator it = vecs.begin();
76 std::shared_ptr<CommGrid> commGridPtr = it->getcommgrid();
77 MPI_Comm World = commGridPtr->GetWorld();
79 IT nglen = it->TotalLength();
80 IT cumloclen = it->MyLocLength();
82 for(; it != vecs.end(); ++it)
84 if(*(commGridPtr) != *(it->getcommgrid()))
89 nglen += it->TotalLength();
90 cumloclen += it->MyLocLength();
93 int nprocs = commGridPtr->GetSize();
95 std::vector< std::vector< NT > > data(
nprocs);
96 std::vector< std::vector< IT > > inds(
nprocs);
98 for(it = vecs.begin(); it != vecs.end(); ++it)
100 IT loclen = it->LocArrSize();
101 for(
IT i=0; i < loclen; ++i)
104 IT loffset = it->LengthUntil();
105 int owner = ConCat.Owner(gloffset+loffset+i, locind);
106 data[owner].push_back(it->arr[i]);
107 inds[owner].push_back(locind);
109 gloffset += it->TotalLength();
112 int * sendcnt =
new int[
nprocs];
113 int * sdispls =
new int[
nprocs];
114 for(
int i=0; i<
nprocs; ++i)
115 sendcnt[i] = (
int) data[i].size();
117 int * rdispls =
new int[
nprocs];
118 int * recvcnt =
new int[
nprocs];
119 MPI_Alltoall(sendcnt, 1, MPI_INT, recvcnt, 1, MPI_INT, World);
122 for(
int i=0; i<
nprocs-1; ++i)
124 sdispls[i+1] = sdispls[i] + sendcnt[i];
125 rdispls[i+1] = rdispls[i] + recvcnt[i];
127 IT totrecv = std::accumulate(recvcnt,recvcnt+
nprocs,
static_cast<IT>(0));
128 NT * senddatabuf =
new NT[cumloclen];
129 for(
int i=0; i<
nprocs; ++i)
131 std::copy(data[i].begin(), data[i].end(), senddatabuf+sdispls[i]);
132 std::vector<NT>().swap(data[i]);
134 NT * recvdatabuf =
new NT[totrecv];
135 MPI_Alltoallv(senddatabuf, sendcnt, sdispls,
MPIType<NT>(), recvdatabuf, recvcnt, rdispls,
MPIType<NT>(), World);
136 delete [] senddatabuf;
138 IT * sendindsbuf =
new IT[cumloclen];
139 for(
int i=0; i<
nprocs; ++i)
141 std::copy(inds[i].begin(), inds[i].end(), sendindsbuf+sdispls[i]);
142 std::vector<IT>().swap(inds[i]);
144 IT * recvindsbuf =
new IT[totrecv];
145 MPI_Alltoallv(sendindsbuf, sendcnt, sdispls,
MPIType<IT>(), recvindsbuf, recvcnt, rdispls,
MPIType<IT>(), World);
146 DeleteAll(sendindsbuf, sendcnt, sdispls);
148 for(
int i=0; i<
nprocs; ++i)
150 for(
int j = rdispls[i]; j < rdispls[i] + recvcnt[i]; ++j)
152 ConCat.arr[recvindsbuf[j]] = recvdatabuf[j];
155 DeleteAll(recvindsbuf, recvcnt, rdispls);
451 int phases, NUO hardThreshold, IU selectNum, IU recoverNum, NUO recoverPct,
int kselectVersion,
int computationKernel,
int64_t perProcessMemory)
453 typedef typename UDERA::LocalIT LIA;
454 typedef typename UDERB::LocalIT LIB;
455 typedef typename UDERO::LocalIT LIC;
458 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
459 if(
A.getncol() !=
B.getnrow())
461 std::ostringstream outs;
462 outs <<
"Can not multiply, dimensions does not match"<< std::endl;
463 outs <<
A.getncol() <<
" != " <<
B.getnrow() << std::endl;
468 if(phases <1 || phases >=
A.getncol())
470 SpParHelper::Print(
"MemEfficientSpGEMM: The value of phases is too small or large. Resetting to 1.\n");
475 std::shared_ptr<CommGrid> GridC =
ProductGrid((
A.commGrid).get(), (
B.commGrid).get(), stages, dummy, dummy);
477 double t0, t1, t2, t3, t4, t5;
479 MPI_Barrier(
A.getcommgrid()->GetWorld());
482 if(perProcessMemory>0)
485 MPI_Comm World = GridC->GetWorld();
486 MPI_Comm_size(World,&p);
488 int64_t perNNZMem_in =
sizeof(IU)*2 +
sizeof(NU1);
489 int64_t perNNZMem_out =
sizeof(IU)*2 +
sizeof(NUO);
495 int64_t inputMem = gannz * perNNZMem_in * 4;
499 int64_t asquareMem = asquareNNZ * perNNZMem_out * 2;
503 int64_t d = ceil( (asquareNNZ * sqrt(p))/
B.getlocalcols() );
505 int64_t k = std::min(
int64_t(std::max(selectNum, recoverNum)), d );
506 int64_t kselectmem =
B.getlocalcols() * k * 8 * 3;
509 int64_t outputNNZ = (
B.getlocalcols() * k)/sqrt(p);
510 int64_t outputMem = outputNNZ * perNNZMem_in * 2;
513 int64_t remainingMem = perProcessMemory*1000000000 - inputMem - outputMem;
516 phases = 1 + (asquareMem+kselectmem) / remainingMem;
524 std::cout <<
"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n Warning: input and output memory requirement is greater than per-process avaiable memory. Keeping phase to the value supplied at the command line. The program may go out of memory and crash! \n !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << std::endl;
526#ifdef SHOW_MEMORY_USAGE
527 int64_t maxMemory = kselectmem/phases + inputMem + outputMem + asquareMem / phases;
528 if(maxMemory>1000000000)
529 std::cout <<
"phases: " << phases <<
": per process memory: " << perProcessMemory <<
" GB asquareMem: " << asquareMem/1000000000.00 <<
" GB" <<
" inputMem: " << inputMem/1000000000.00 <<
" GB" <<
" outputMem: " << outputMem/1000000000.00 <<
" GB" <<
" kselectmem: " << kselectmem/1000000000.00 <<
" GB" << std::endl;
531 std::cout <<
"phases: " << phases <<
": per process memory: " << perProcessMemory <<
" GB asquareMem: " << asquareMem/1000000.00 <<
" MB" <<
" inputMem: " << inputMem/1000000.00 <<
" MB" <<
" outputMem: " << outputMem/1000000.00 <<
" MB" <<
" kselectmem: " << kselectmem/1000000.00 <<
" MB" << std::endl;
542 MPI_Barrier(
A.getcommgrid()->GetWorld());
547 LIA C_m =
A.spSeq->getnrow();
548 LIB C_n =
B.spSeq->getncol();
550 std::vector< UDERB > PiecesOfB;
551 UDERB CopyB = *(
B.spSeq);
553 CopyB.ColSplit(phases, PiecesOfB);
554 MPI_Barrier(GridC->GetWorld());
559 static_assert(std::is_same<LIA, LIB>::value,
"local index types for both input matrices should be the same");
560 static_assert(std::is_same<LIA, LIC>::value,
"local index types for input and output matrices should be the same");
569 std::vector< UDERO > toconcatenate;
571 int Aself = (
A.commGrid)->GetRankInProcRow();
572 int Bself = (
B.commGrid)->GetRankInProcCol();
574 for(
int p = 0; p< phases; ++p)
577 std::vector< SpTuples<LIC,NUO> *> tomerge;
578 for(
int i = 0; i < stages; ++i)
580 std::vector<LIA> ess;
581 if(i == Aself) ARecv =
A.spSeq;
584 ess.resize(UDERA::esscount);
585 for(
int j=0; j< UDERA::esscount; ++j)
586 ess[j] = ARecvSizes[j][i];
591 MPI_Barrier(
A.getcommgrid()->GetWorld());
596 MPI_Barrier(
A.getcommgrid()->GetWorld());
602 if(i == Bself) BRecv = &(PiecesOfB[p]);
605 ess.resize(UDERB::esscount);
606 for(
int j=0; j< UDERB::esscount; ++j)
607 ess[j] = BRecvSizes[j][i];
611 MPI_Barrier(
A.getcommgrid()->GetWorld());
612 double t2=MPI_Wtime();
616 MPI_Barrier(
A.getcommgrid()->GetWorld());
617 double t3=MPI_Wtime();
623 MPI_Barrier(
A.getcommgrid()->GetWorld());
624 double t4=MPI_Wtime();
628 else if(computationKernel == 2) C_cont=
LocalSpGEMM<SR, NUO>(*ARecv, *BRecv,i != Aself, i != Bself);
631 MPI_Barrier(
A.getcommgrid()->GetWorld());
632 double t5=MPI_Wtime();
637 tomerge.push_back(C_cont);
643#ifdef SHOW_MEMORY_USAGE
644 int64_t gcnnz_unmerged, lcnnz_unmerged = 0;
645 for(
size_t i = 0; i < tomerge.size(); ++i)
647 lcnnz_unmerged += tomerge[i]->getnnz();
649 MPI_Allreduce(&lcnnz_unmerged, &gcnnz_unmerged, 1,
MPIType<int64_t>(), MPI_MAX, MPI_COMM_WORLD);
650 int64_t summa_memory = gcnnz_unmerged*20;
654 if(summa_memory>1000000000)
655 std::cout << p+1 <<
". unmerged: " << summa_memory/1000000000.00 <<
"GB " ;
657 std::cout << p+1 <<
". unmerged: " << summa_memory/1000000.00 <<
" MB " ;
663 MPI_Barrier(
A.getcommgrid()->GetWorld());
664 double t6=MPI_Wtime();
671#ifdef SHOW_MEMORY_USAGE
672 int64_t gcnnz_merged, lcnnz_merged ;
673 lcnnz_merged = OnePieceOfC_tuples->
getnnz();
674 MPI_Allreduce(&lcnnz_merged, &gcnnz_merged, 1,
MPIType<int64_t>(), MPI_MAX, MPI_COMM_WORLD);
677 int64_t merge_memory = gcnnz_merged*2*20;
681 if(merge_memory>1000000000)
682 std::cout <<
" merged: " << merge_memory/1000000000.00 <<
"GB " ;
684 std::cout <<
" merged: " << merge_memory/1000000.00 <<
" MB " ;
690 MPI_Barrier(
A.getcommgrid()->GetWorld());
691 double t7=MPI_Wtime();
694 UDERO * OnePieceOfC =
new UDERO(* OnePieceOfC_tuples,
false);
695 delete OnePieceOfC_tuples;
698 MCLPruneRecoverySelect(OnePieceOfC_mat, hardThreshold, selectNum, recoverNum, recoverPct, kselectVersion);
700#ifdef SHOW_MEMORY_USAGE
701 int64_t gcnnz_pruned, lcnnz_pruned ;
703 MPI_Allreduce(&lcnnz_pruned, &gcnnz_pruned, 1,
MPIType<int64_t>(), MPI_MAX, MPI_COMM_WORLD);
707 int64_t prune_memory = gcnnz_pruned*2*20;
712 if(prune_memory>1000000000)
713 std::cout <<
"Prune: " << prune_memory/1000000000.00 <<
"GB " << std::endl ;
715 std::cout <<
"Prune: " << prune_memory/1000000.00 <<
" MB " << std::endl ;
721 toconcatenate.push_back(OnePieceOfC_mat.
seq());
724 UDERO *
C =
new UDERO(0,C_m, C_n,0);
725 C->ColConcatenate(toconcatenate);
807 typedef typename UDERA::LocalIT LIA;
808 typedef typename UDERB::LocalIT LIB;
809 typedef typename UDERO::LocalIT LIC;
811 static_assert(std::is_same<LIA, LIB>::value,
"local index types for both input matrices should be the same");
812 static_assert(std::is_same<LIA, LIC>::value,
"local index types for input and output matrices should be the same");
815 std::shared_ptr<CommGrid> GridC =
ProductGrid((
A.commGrid).get(), (
B.commGrid).get(), stages, dummy, dummy);
816 LIA C_m =
A.spSeq->getnrow();
817 LIB C_n =
B.spSeq->getncol();
819 UDERA * A1seq =
new UDERA();
820 UDERA * A2seq =
new UDERA();
821 UDERB * B1seq =
new UDERB();
822 UDERB * B2seq =
new UDERB();
823 (
A.spSeq)->Split( *A1seq, *A2seq);
824 const_cast< UDERB*
>(
B.spSeq)->Transpose();
825 (
B.spSeq)->Split( *B1seq, *B2seq);
828 const_cast< UDERB*
>(B1seq)->Transpose();
829 const_cast< UDERB*
>(B2seq)->Transpose();
840 std::vector< SpTuples<LIC,NUO> *> tomerge;
842 int Aself = (
A.commGrid)->GetRankInProcRow();
843 int Bself = (
B.commGrid)->GetRankInProcCol();
845 for(
int i = 0; i < stages; ++i)
847 std::vector<LIA> ess;
854 ess.resize(UDERA::esscount);
855 for(
int j=0; j< UDERA::esscount; ++j)
857 ess[j] = ARecvSizes[j][i];
869 ess.resize(UDERB::esscount);
870 for(
int j=0; j< UDERB::esscount; ++j)
872 ess[j] = BRecvSizes[j][i];
897 tomerge.push_back(C_cont);
901 if(clearA)
delete A1seq;
902 if(clearB)
delete B1seq;
909 for(
int i = 0; i < stages; ++i)
911 std::vector<LIA> ess;
918 ess.resize(UDERA::esscount);
919 for(
int j=0; j< UDERA::esscount; ++j)
921 ess[j] = ARecvSizes[j][i];
935 ess.resize(UDERB::esscount);
936 for(
int j=0; j< UDERB::esscount; ++j)
938 ess[j] = BRecvSizes[j][i];
961 tomerge.push_back(C_cont);
975 (
A.spSeq)->Merge(*A1seq, *A2seq);
989 (
B.spSeq)->Merge(*B1seq, *B2seq);
992 const_cast< UDERB*
>(
B.spSeq)->Transpose();
995 UDERO *
C =
new UDERO(
MergeAll<SR>(tomerge, C_m, C_n,
true),
false);
1115 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
1121 std::shared_ptr<CommGrid> GridC =
ProductGrid((
A.commGrid).get(), (
B.commGrid).get(), stages, dummy, dummy);
1122 IU C_m =
A.spSeq->getnrow();
1123 IU C_n =
B.spSeq->getncol();
1134 UDERA ** ARecv =
new UDERA* [stages];
1135 UDERB ** BRecv =
new UDERB* [stages];
1139 std::vector< std::vector<MPI_Request> > ABCastIndarrayReq;
1140 std::vector< std::vector<MPI_Request> > ABCastNumarrayReq;
1141 std::vector< std::vector<MPI_Request> > BBCastIndarrayReq;
1142 std::vector< std::vector<MPI_Request> > BBCastNumarrayReq;
1143 for(
int i = 0; i < stages; i++){
1144 ABCastIndarrayReq.push_back( std::vector<MPI_Request>(Aarrinfo.
indarrs.size(), MPI_REQUEST_NULL) );
1145 ABCastNumarrayReq.push_back( std::vector<MPI_Request>(Aarrinfo.
numarrs.size(), MPI_REQUEST_NULL) );
1146 BBCastIndarrayReq.push_back( std::vector<MPI_Request>(Barrinfo.
indarrs.size(), MPI_REQUEST_NULL) );
1147 BBCastNumarrayReq.push_back( std::vector<MPI_Request>(Barrinfo.
numarrs.size(), MPI_REQUEST_NULL) );
1150 int Aself = (
A.commGrid)->GetRankInProcRow();
1151 int Bself = (
B.commGrid)->GetRankInProcCol();
1153 std::vector< SpTuples<IU,NUO> *> tomerge;
1155 for(
int i = 0; i < stages; ++i){
1156 std::vector<IU> ess;
1157 if(i == Aself) ARecv[i] =
A.spSeq;
1159 ess.resize(UDERA::esscount);
1160 for(
int j=0; j< UDERA::esscount; ++j) ess[j] = ARecvSizes[j][i];
1161 ARecv[i] =
new UDERA();
1167 if(i == Bself) BRecv[i] =
B.spSeq;
1169 ess.resize(UDERB::esscount);
1170 for(
int j=0; j< UDERB::esscount; ++j) ess[j] = BRecvSizes[j][i];
1171 BRecv[i] =
new UDERB();
1176 MPI_Waitall(ABCastIndarrayReq[i-1].
size(), ABCastIndarrayReq[i-1].data(), MPI_STATUSES_IGNORE);
1177 MPI_Waitall(ABCastNumarrayReq[i-1].
size(), ABCastNumarrayReq[i-1].data(), MPI_STATUSES_IGNORE);
1178 MPI_Waitall(BBCastIndarrayReq[i-1].
size(), BBCastIndarrayReq[i-1].data(), MPI_STATUSES_IGNORE);
1179 MPI_Waitall(BBCastNumarrayReq[i-1].
size(), BBCastNumarrayReq[i-1].data(), MPI_STATUSES_IGNORE);
1182 (*(ARecv[i-1]), *(BRecv[i-1]),
1185 if(!C_cont->
isZero()) tomerge.push_back(C_cont);
1188 std::vector< SpTuples<IU,NUO> *>().swap(tomerge);
1189 tomerge.push_back(C_tuples);
1191 #ifdef COMBBLAS_DEBUG
1192 std::ostringstream outs;
1193 outs << i <<
"th SUMMA iteration"<< std::endl;
1198 MPI_Waitall(ABCastIndarrayReq[stages-1].
size(), ABCastIndarrayReq[stages-1].data(), MPI_STATUSES_IGNORE);
1199 MPI_Waitall(ABCastNumarrayReq[stages-1].
size(), ABCastNumarrayReq[stages-1].data(), MPI_STATUSES_IGNORE);
1200 MPI_Waitall(BBCastIndarrayReq[stages-1].
size(), BBCastIndarrayReq[stages-1].data(), MPI_STATUSES_IGNORE);
1201 MPI_Waitall(BBCastNumarrayReq[stages-1].
size(), BBCastNumarrayReq[stages-1].data(), MPI_STATUSES_IGNORE);
1204 (*(ARecv[stages-1]), *(BRecv[stages-1]),
1207 if(!C_cont->
isZero()) tomerge.push_back(C_cont);
1209 if(clearA &&
A.spSeq != NULL) {
1213 if(clearB &&
B.spSeq != NULL) {
1226 std::vector< SpTuples<IU,NUO> *>().swap(tomerge);
1228 UDERO *
C =
new UDERO(*C_tuples,
false);
1730 y.glen =
A.getnrow();
1732 MPI_Comm World = x.commGrid->GetWorld();
1733 MPI_Comm ColWorld = x.commGrid->GetColWorld();
1734 MPI_Comm RowWorld = x.commGrid->GetRowWorld();
1740 IVT *trxnums, *numacc;
1743 double t0=MPI_Wtime();
1746 TransposeVector(World, x, trxlocnz, lenuntil, trxinds, trxnums, indexisvalue);
1749 double t1=MPI_Wtime();
1753 if(x.commGrid->GetGridRows() > 1)
1755 AllGatherVector(ColWorld, trxlocnz, lenuntil, trxinds, trxnums, indacc, numacc, accnz, indexisvalue);
1765 MPI_Comm_size(RowWorld, &rowneighs);
1766 int * sendcnt =
new int[rowneighs]();
1772 double t2=MPI_Wtime();
1775 LocalSpMV<SR>(
A, rowneighs, optbuf, indacc, numacc, sendindbuf, sendnumbuf, sdispls, sendcnt, accnz, indexisvalue, SPA);
1778 double t3=MPI_Wtime();
1783 if(x.commGrid->GetGridCols() == 1)
1785 y.ind.resize(sendcnt[0]);
1786 y.num.resize(sendcnt[0]);
1792#pragma omp parallel for
1794 for(
int i=0; i<sendcnt[0]; i++)
1796 y.ind[i] = optbuf.
inds[i];
1797 y.num[i] = optbuf.
nums[i];
1803#pragma omp parallel for
1805 for(
int i=0; i<sendcnt[0]; i++)
1807 y.ind[i] = sendindbuf[i];
1808 y.num[i] = sendnumbuf[i];
1810 DeleteAll(sendindbuf, sendnumbuf,sdispls);
1815 int * rdispls =
new int[rowneighs];
1816 int * recvcnt =
new int[rowneighs];
1817 MPI_Alltoall(sendcnt, 1, MPI_INT, recvcnt, 1, MPI_INT, RowWorld);
1821 for(
int i=0; i<rowneighs-1; ++i)
1823 rdispls[i+1] = rdispls[i] + recvcnt[i];
1826 int totrecv = std::accumulate(recvcnt,recvcnt+rowneighs,0);
1828 OVT * recvnumbuf =
new OVT[totrecv];
1831 double t4=MPI_Wtime();
1842 MPI_Alltoallv(sendnumbuf, sendcnt, sdispls,
MPIType<OVT>(), recvnumbuf, recvcnt, rdispls,
MPIType<OVT>(), RowWorld);
1843 DeleteAll(sendindbuf, sendnumbuf, sendcnt, sdispls);
1846 double t5=MPI_Wtime();
1851 double t6=MPI_Wtime();
1855 std::vector<IU>().swap(y.ind);
1856 std::vector<OVT>().swap(y.num);
1858 std::vector<int32_t *> indsvec(rowneighs);
1859 std::vector<OVT *> numsvec(rowneighs);
1862#pragma omp parallel for
1864 for(
int i=0; i<rowneighs; i++)
1866 indsvec[i] = recvindbuf+rdispls[i];
1867 numsvec[i] = recvnumbuf+rdispls[i];
1875 DeleteAll(recvcnt, rdispls,recvindbuf, recvnumbuf);
1877 double t7=MPI_Wtime();
2011 MPI_Comm World = x.commGrid->GetWorld();
2012 MPI_Comm ColWorld = x.commGrid->GetColWorld();
2013 MPI_Comm RowWorld = x.commGrid->GetRowWorld();
2015 int xlocnz = (int) x.getlocnnz();
2017 int roffst = x.RowLenUntil();
2020 int diagneigh = x.commGrid->GetComplementRank();
2022 MPI_Sendrecv(&xlocnz, 1, MPI_INT, diagneigh,
TRX, &trxlocnz, 1, MPI_INT, diagneigh,
TRX, World, &status);
2023 MPI_Sendrecv(&roffst, 1, MPI_INT, diagneigh,
TROST, &offset, 1, MPI_INT, diagneigh,
TROST, World, &status);
2025 IU * trxinds =
new IU[trxlocnz];
2026 NUV * trxnums =
new NUV[trxlocnz];
2027 MPI_Sendrecv(
const_cast<IU*
>(
SpHelper::p2a(x.ind)), xlocnz,
MPIType<IU>(), diagneigh,
TRX, trxinds, trxlocnz,
MPIType<IU>(), diagneigh,
TRX, World, &status);
2028 MPI_Sendrecv(
const_cast<NUV*
>(
SpHelper::p2a(x.num)), xlocnz,
MPIType<NUV>(), diagneigh,
TRX, trxnums, trxlocnz,
MPIType<NUV>(), diagneigh,
TRX, World, &status);
2029 std::transform(trxinds, trxinds+trxlocnz, trxinds, std::bind2nd(std::plus<IU>(), offset));
2031 int colneighs, colrank;
2032 MPI_Comm_size(ColWorld, &colneighs);
2033 MPI_Comm_rank(ColWorld, &colrank);
2034 int * colnz =
new int[colneighs];
2035 colnz[colrank] = trxlocnz;
2036 MPI_Allgather(MPI_IN_PLACE, 1, MPI_INT, colnz, 1, MPI_INT, ColWorld);
2037 int * dpls =
new int[colneighs]();
2038 std::partial_sum(colnz, colnz+colneighs-1, dpls+1);
2039 int accnz = std::accumulate(colnz, colnz+colneighs, 0);
2040 IU * indacc =
new IU[accnz];
2041 NUV * numacc =
new NUV[accnz];
2050 std::vector< int32_t > indy;
2051 std::vector< T_promote > numy;
2054 for(
int i=0; i< accnz; ++i) tmpindacc[i] = indacc[i];
2063 IU yintlen = y.MyRowLength();
2066 MPI_Comm_size(RowWorld,&rowneighs);
2067 std::vector< std::vector<IU> > sendind(rowneighs);
2068 std::vector< std::vector<T_promote> > sendnum(rowneighs);
2069 typename std::vector<int32_t>::size_type outnz = indy.size();
2070 for(
typename std::vector<IU>::size_type i=0; i< outnz; ++i)
2073 int rown = y.OwnerWithinRow(yintlen,
static_cast<IU
>(indy[i]), locind);
2074 sendind[rown].push_back(locind);
2075 sendnum[rown].push_back(numy[i]);
2078 IU * sendindbuf =
new IU[outnz];
2080 int * sendcnt =
new int[rowneighs];
2081 int * sdispls =
new int[rowneighs];
2082 for(
int i=0; i<rowneighs; ++i)
2083 sendcnt[i] = sendind[i].
size();
2085 int * rdispls =
new int[rowneighs];
2086 int * recvcnt =
new int[rowneighs];
2087 MPI_Alltoall(sendcnt, 1, MPI_INT, recvcnt, 1, MPI_INT, RowWorld);
2091 for(
int i=0; i<rowneighs-1; ++i)
2093 sdispls[i+1] = sdispls[i] + sendcnt[i];
2094 rdispls[i+1] = rdispls[i] + recvcnt[i];
2096 int totrecv = std::accumulate(recvcnt,recvcnt+rowneighs,0);
2097 IU * recvindbuf =
new IU[totrecv];
2100 for(
int i=0; i<rowneighs; ++i)
2102 std::copy(sendind[i].begin(), sendind[i].end(), sendindbuf+sdispls[i]);
2103 std::vector<IU>().swap(sendind[i]);
2105 for(
int i=0; i<rowneighs; ++i)
2107 std::copy(sendnum[i].begin(), sendnum[i].end(), sendnumbuf+sdispls[i]);
2108 std::vector<T_promote>().swap(sendnum[i]);
2110 MPI_Alltoallv(sendindbuf, sendcnt, sdispls,
MPIType<IU>(), recvindbuf, recvcnt, rdispls,
MPIType<IU>(), RowWorld);
2114 DeleteAll(sendcnt, recvcnt, sdispls, rdispls);
2117 IU ysize = y.MyLocLength();
2119 bool * isthere =
new bool[ysize];
2120 std::vector<IU> nzinds;
2121 std::fill_n(isthere, ysize,
false);
2123 for(
int i=0; i< totrecv; ++i)
2125 if(!isthere[recvindbuf[i]])
2127 localy[recvindbuf[i]] = recvnumbuf[i];
2128 nzinds.push_back(recvindbuf[i]);
2129 isthere[recvindbuf[i]] =
true;
2133 localy[recvindbuf[i]] = SR::add(localy[recvindbuf[i]], recvnumbuf[i]);
2136 DeleteAll(isthere, recvindbuf, recvnumbuf);
2137 sort(nzinds.begin(), nzinds.end());
2138 int nnzy = nzinds.size();
2141 for(
int i=0; i< nnzy; ++i)
2143 y.ind[i] = nzinds[i];
2144 y.num[i] = localy[nzinds[i]];
2337 if(*(V.commGrid) == *(W.commGrid))
2340 if(V.TotalLength() != W.TotalLength())
2342 std::ostringstream outs;
2343 outs <<
"Vector dimensions don't match (" << V.TotalLength() <<
" vs " << W.TotalLength() <<
") for EWiseApply (short version)\n";
2353 nthreads = omp_get_num_threads();
2357 Product.glen = V.glen;
2359 IU spsize = V.getlocnnz();
2362 std::vector<std::vector<IU>> tProductInd(nthreads);
2363 std::vector<std::vector<T_promote>> tProductVal(nthreads);
2366 perthread =
size/nthreads;
2368 perthread = spsize/nthreads;
2376 curthread = omp_get_thread_num();
2378 IU tStartIdx = perthread * curthread;
2379 IU tNextIdx = perthread * (curthread+1);
2383 if(curthread == nthreads-1) tNextIdx =
size;
2386 auto it = std::lower_bound (V.ind.begin(), V.ind.end(), tStartIdx);
2387 IU tSpIdx = (IU) std::distance(V.ind.begin(), it);
2390 for(IU tIdx=tStartIdx; tIdx < tNextIdx; ++tIdx)
2392 if(tSpIdx < spsize && V.ind[tSpIdx] < tNextIdx && V.ind[tSpIdx] == tIdx)
2394 if (_doOp(V.num[tSpIdx], W.arr[tIdx],
false,
false))
2396 tProductInd[curthread].push_back(tIdx);
2397 tProductVal[curthread].push_back (_binary_op(V.num[tSpIdx], W.arr[tIdx],
false,
false));
2403 if (_doOp(Vzero, W.arr[tIdx],
true,
false))
2405 tProductInd[curthread].push_back(tIdx);
2406 tProductVal[curthread].push_back (_binary_op(Vzero, W.arr[tIdx],
true,
false));
2413 if(curthread == nthreads-1) tNextIdx = spsize;
2414 for(IU tSpIdx=tStartIdx; tSpIdx < tNextIdx; ++tSpIdx)
2416 if (_doOp(V.num[tSpIdx], W.arr[V.ind[tSpIdx]],
false,
false))
2419 tProductInd[curthread].push_back( V.ind[tSpIdx]);
2420 tProductVal[curthread].push_back (_binary_op(V.num[tSpIdx], W.arr[V.ind[tSpIdx]],
false,
false));
2426 std::vector<IU> tdisp(nthreads+1);
2428 for(
int i=0; i<nthreads; ++i)
2430 tdisp[i+1] = tdisp[i] + tProductInd[i].size();
2434 Product.ind.resize(tdisp[nthreads]);
2435 Product.num.resize(tdisp[nthreads]);
2443 curthread = omp_get_thread_num();
2445 std::copy(tProductInd[curthread].begin(), tProductInd[curthread].end(), Product.ind.data() + tdisp[curthread]);
2446 std::copy(tProductVal[curthread].begin() , tProductVal[curthread].end(), Product.num.data() + tdisp[curthread]);
2453 std::cout <<
"Grids are not comparable for EWiseApply" << std::endl;
2921 MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
2922 typedef typename UDERO::LocalIT LIC;
2923 typedef typename UDER1::LocalIT LIA;
2924 typedef typename UDER2::LocalIT LIB;
2927 double t0, t1, t2, t3;
2933 if(
A.getncol() !=
B.getnrow()){
2934 std::ostringstream outs;
2935 outs <<
"Can not multiply, dimensions does not match"<< std::endl;
2936 outs <<
A.getncol() <<
" != " <<
B.getnrow() << std::endl;
2944 vector<LIB> divisions3d;
2947 B.CalculateColSplitDistributionOfLayer(divisions3d);
2957 std::shared_ptr<CommGrid> GridC =
ProductGrid((
A.GetLayerMat()->getcommgrid()).get(),
2958 (
B.GetLayerMat()->getcommgrid()).get(),
2959 stages, dummy, dummy);
2960 IU C_m =
A.GetLayerMat()->seqptr()->getnrow();
2961 IU C_n =
B.GetLayerMat()->seqptr()->getncol();
2972 std::vector< SpTuples<IU,NUO> *> tomerge;
2974 int Aself = (
A.GetLayerMat()->
getcommgrid())->GetRankInProcRow();
2975 int Bself = (
B.GetLayerMat()->
getcommgrid())->GetRankInProcCol();
2977 double Abcast_time = 0;
2978 double Bbcast_time = 0;
2979 double Local_multiplication_time = 0;
2981 for(
int i = 0; i < stages; ++i) {
2982 std::vector<IU> ess;
2985 ARecv =
A.GetLayerMat()->seqptr();
2988 ess.resize(UDER1::esscount);
2989 for(
int j=0; j<UDER1::esscount; ++j) {
2990 ess[j] = ARecvSizes[j][i];
2992 ARecv =
new UDER1();
3003 for(
unsigned int idx = 0; idx < Aarrinfo.
indarrs.size(); ++idx) {
3007 for(
unsigned int idx = 0; idx < Aarrinfo.
numarrs.size(); ++idx) {
3012 Abcast_time += (t3-t2);
3016 BRecv =
B.GetLayerMat()->seqptr();
3019 ess.resize(UDER2::esscount);
3020 for(
int j=0; j<UDER2::esscount; ++j) {
3021 ess[j] = BRecvSizes[j][i];
3023 BRecv =
new UDER2();
3026 MPI_Barrier(
A.GetLayerMat()->getcommgrid()->GetWorld());
3035 for(
unsigned int idx = 0; idx < Barrinfo.
indarrs.size(); ++idx) {
3038 for(
unsigned int idx = 0; idx < Barrinfo.
numarrs.size(); ++idx) {
3043 Bbcast_time += (t3-t2);
3056 Local_multiplication_time += (t3-t2);
3059 if(!C_cont->
isZero()) tomerge.push_back(C_cont);
3077 fprintf(stderr,
"[SUMMA3D]\tAbcast_time: %lf\n", Abcast_time);
3078 fprintf(stderr,
"[SUMMA3D]\tBbcast_time: %lf\n", Bbcast_time);
3079 fprintf(stderr,
"[SUMMA3D]\tLocal_multiplication_time: %lf\n", Local_multiplication_time);
3080 fprintf(stderr,
"[SUMMA3D]\tMerge_layer_time: %lf\n", (t3-t2));
3088 if(myrank == 0) fprintf(stderr,
"[SUMMA3D]\tSUMMA time: %lf\n", (t1-t0));
3097 MPI_Datatype MPI_tuple;
3098 MPI_Type_contiguous(
sizeof(std::tuple<LIC,LIC,NUO>), MPI_CHAR, &MPI_tuple);
3099 MPI_Type_commit(&MPI_tuple);
3106 int * sendcnt =
new int[
A.getcommgrid3D()->GetGridLayers()];
3107 int * sendprfl =
new int[
A.getcommgrid3D()->GetGridLayers()*3];
3108 int * sdispls =
new int[
A.getcommgrid3D()->GetGridLayers()]();
3109 int * recvcnt =
new int[
A.getcommgrid3D()->GetGridLayers()];
3110 int * recvprfl =
new int[
A.getcommgrid3D()->GetGridLayers()*3];
3111 int * rdispls =
new int[
A.getcommgrid3D()->GetGridLayers()]();
3113 vector<IU> divisions3dPrefixSum(divisions3d.size());
3114 divisions3dPrefixSum[0] = 0;
3115 std::partial_sum(divisions3d.begin(), divisions3d.end()-1, divisions3dPrefixSum.begin()+1);
3117 IU totsend = C_tuples->
getnnz();
3119#pragma omp parallel for
3120 for(
int i=0; i <
A.getcommgrid3D()->GetGridLayers(); ++i){
3121 IU start_col = divisions3dPrefixSum[i];
3122 IU end_col = divisions3dPrefixSum[i] + divisions3d[i];
3123 std::tuple<IU, IU, NUO> search_tuple_start(0, start_col, NUO());
3124 std::tuple<IU, IU, NUO> search_tuple_end(0, end_col, NUO());
3125 std::tuple<IU, IU, NUO>* start_it = std::lower_bound(C_tuples->
tuples, C_tuples->
tuples + C_tuples->
getnnz(), search_tuple_start, comp);
3126 std::tuple<IU, IU, NUO>* end_it = std::lower_bound(C_tuples->
tuples, C_tuples->
tuples + C_tuples->
getnnz(), search_tuple_end, comp);
3128 sendcnt[i] = (int)(end_it - start_it);
3129 sendprfl[i*3+0] = (int)(sendcnt[i]);
3130 sendprfl[i*3+1] = (int)(
A.GetLayerMat()->seqptr()->getnrow());
3131 sendprfl[i*3+2] = (int)(divisions3d[i]);
3133 std::partial_sum(sendcnt, sendcnt+
A.getcommgrid3D()->GetGridLayers()-1, sdispls+1);
3136 for(
int i=0; i <
A.getcommgrid3D()->GetGridLayers(); ++i){
3137#pragma omp parallel for schedule(static)
3138 for(
int j = 0; j < sendcnt[i]; j++){
3139 std::get<1>(C_tuples->
tuples[sdispls[i]+j]) = std::get<1>(C_tuples->
tuples[sdispls[i]+j]) - divisions3dPrefixSum[i];
3143 MPI_Alltoall(sendprfl, 3, MPI_INT, recvprfl, 3, MPI_INT,
A.getcommgrid3D()->GetFiberWorld());
3145 for(
int i = 0; i <
A.getcommgrid3D()->GetGridLayers(); i++) recvcnt[i] = recvprfl[i*3];
3146 std::partial_sum(recvcnt, recvcnt+
A.getcommgrid3D()->GetGridLayers()-1, rdispls+1);
3147 IU totrecv = std::accumulate(recvcnt,recvcnt+
A.getcommgrid3D()->GetGridLayers(),
static_cast<IU
>(0));
3148 std::tuple<LIC,LIC,NUO>* recvTuples =
static_cast<std::tuple<LIC,LIC,NUO>*
> (::operator
new (
sizeof(std::tuple<LIC,LIC,NUO>[totrecv])));
3153 MPI_Alltoallv(C_tuples->
tuples, sendcnt, sdispls, MPI_tuple, recvTuples, recvcnt, rdispls, MPI_tuple,
A.getcommgrid3D()->GetFiberWorld());
3157 if(myrank == 0) fprintf(stderr,
"[SUMMA3D]\tAlltoallv: %lf\n", (t3-t2));
3159 vector<SpTuples<IU, NUO>*> recvChunks(
A.getcommgrid3D()->GetGridLayers());
3160#pragma omp parallel for
3161 for (
int i = 0; i <
A.getcommgrid3D()->GetGridLayers(); i++){
3162 recvChunks[i] =
new SpTuples<LIC, NUO>(recvcnt[i], recvprfl[i*3+1], recvprfl[i*3+2], recvTuples + rdispls[i],
true,
false);
3168 MPI_Type_free(&MPI_tuple);
3175 if(myrank == 0) fprintf(stderr,
"[SUMMA3D]\tReduction time: %lf\n", (t1-t0));
3186 if(myrank == 0) fprintf(stderr,
"[SUMMA3D]\tMerge_fiber_time: %lf\n", (t1-t0));
3189 UDERO * localResultant =
new UDERO(*merged_tuples,
false);
3190 delete merged_tuples;
3194 ::operator
delete(recvTuples);
3195 for(
int i = 0; i < recvChunks.size(); i++){
3196 recvChunks[i]->tuples_deleted =
true;
3197 delete recvChunks[i];
3199 vector<SpTuples<IU,NUO>*>().swap(recvChunks);
3204 std::shared_ptr<CommGrid3D> grid3d;
3205 grid3d.reset(
new CommGrid3D(
A.getcommgrid3D()->GetWorld(),
A.getcommgrid3D()->GetGridLayers(),
A.getcommgrid3D()->GetGridRows(),
A.getcommgrid3D()->GetGridCols(),
A.isSpecial()));
3216 int phases, NUO hardThreshold, IU selectNum, IU recoverNum, NUO recoverPct,
int kselectVersion,
int computationKernel,
int64_t perProcessMemory){
3218 MPI_Comm_rank(MPI_COMM_WORLD,&myrank);
3219 typedef typename UDERA::LocalIT LIA;
3220 typedef typename UDERB::LocalIT LIB;
3221 typedef typename UDERO::LocalIT LIC;
3226 if(
A.getncol() !=
B.getnrow()){
3227 std::ostringstream outs;
3228 outs <<
"Can not multiply, dimensions does not match"<< std::endl;
3229 outs <<
A.getncol() <<
" != " <<
B.getnrow() << std::endl;
3237 if(phases < 1 || phases >=
B.getncol()){
3238 SpParHelper::Print(
"[MemEfficientSpGEMM3D]\tThe value of phases is too small or large. Resetting to 1.\n");
3241 double t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
3243 MPI_Barrier(
B.getcommgrid3D()->GetWorld());
3250 if(perProcessMemory > 0) {
3251 int p, calculatedPhases;
3252 MPI_Comm_size(
A.getcommgrid3D()->GetLayerWorld(),&p);
3253 int64_t perNNZMem_in =
sizeof(IU)*2 +
sizeof(NU1);
3254 int64_t perNNZMem_out =
sizeof(IU)*2 +
sizeof(NUO);
3256 int64_t lannz =
A.GetLayerMat()->getlocalnnz();
3259 MPI_Allreduce(&lannz, &gannz, 1,
MPIType<int64_t>(), MPI_MAX,
A.getcommgrid3D()->GetWorld());
3261 int64_t ginputMem = gannz * perNNZMem_in * 5;
3267 MPI_Allreduce(&asquareNNZ, &gasquareNNZ, 1,
MPIType<int64_t>(), MPI_MAX,
A.getcommgrid3D()->GetFiberWorld());
3270 int64_t gasquareMem = gasquareNNZ * perNNZMem_out * 2;
3272 int64_t d = ceil( ( ( gasquareNNZ /
B.getcommgrid3D()->GetGridLayers() ) * sqrt(p) ) /
B.GetLayerMat()->getlocalcols() );
3274 int64_t k = std::min(
int64_t(std::max(selectNum, recoverNum)), d );
3277 int64_t postKselectOutputNNZ = ceil(( (
B.GetLayerMat()->getlocalcols() /
B.getcommgrid3D()->GetGridLayers() ) * k)/sqrt(p));
3278 int64_t postKselectOutputMem = postKselectOutputNNZ * perNNZMem_out * 2;
3279 double remainingMem = perProcessMemory*1000000000 - ginputMem - postKselectOutputMem;
3280 int64_t kselectMem =
B.GetLayerMat()->getlocalcols() * k *
sizeof(NUO) * 3;
3283 if(remainingMem > 0){
3284 calculatedPhases = ceil( (gasquareMem + kselectMem) / remainingMem );
3286 else calculatedPhases = -1;
3288 int gCalculatedPhases;
3289 MPI_Allreduce(&calculatedPhases, &gCalculatedPhases, 1, MPI_INT, MPI_MAX,
A.getcommgrid3D()->GetFiberWorld());
3290 if(gCalculatedPhases > phases) phases = gCalculatedPhases;
3296 MPI_Barrier(
B.getcommgrid3D()->GetWorld());
3306 vector<LIB> divisions3d;
3309 B.CalculateColSplitDistributionOfLayer(divisions3d);
3315 vector<UDERB*> PiecesOfB;
3316 vector<UDERB*> tempPiecesOfB;
3317 UDERB CopyB = *(
B.GetLayerMat()->seqptr());
3318 CopyB.ColSplit(divisions3d, tempPiecesOfB);
3319 for(
int i = 0; i < tempPiecesOfB.size(); i++){
3320 vector<UDERB*> temp;
3321 tempPiecesOfB[i]->ColSplit(phases, temp);
3322 for(
int j = 0; j < temp.size(); j++){
3323 PiecesOfB.push_back(temp[j]);
3327 vector<UDERO> toconcatenate;
3332 for(
int p = 0; p < phases; p++){
3337 vector<LIB> lbDivisions3d;
3338 LIB totalLocalColumnInvolved = 0;
3339 vector<UDERB*> targetPiecesOfB;
3340 for(
int i = 0; i < PiecesOfB.size(); i++){
3341 if(i % phases == p){
3342 targetPiecesOfB.push_back(
new UDERB(*(PiecesOfB[i])));
3343 lbDivisions3d.push_back(PiecesOfB[i]->getncol());
3344 totalLocalColumnInvolved += PiecesOfB[i]->getncol();
3351 UDERB * OnePieceOfB =
new UDERB(0, (
B.GetLayerMat())->seqptr()->getnrow(), totalLocalColumnInvolved, 0);
3352 OnePieceOfB->ColConcatenate(targetPiecesOfB);
3353 vector<UDERB*>().swap(targetPiecesOfB);
3368 std::shared_ptr<CommGrid> GridC =
ProductGrid((
A.GetLayerMat()->getcommgrid()).get(),
3370 stages, dummy, dummy);
3371 LIA C_m =
A.GetLayerMat()->seqptr()->getnrow();
3372 LIB C_n = OnePieceOfBLayer.
seqptr()->getncol();
3383 std::vector< SpTuples<LIC,NUO> *> tomerge;
3385 int Aself = (
A.GetLayerMat()->getcommgrid())->GetRankInProcRow();
3386 int Bself = (OnePieceOfBLayer.
getcommgrid())->GetRankInProcCol();
3388 double Abcast_time = 0;
3389 double Bbcast_time = 0;
3390 double Local_multiplication_time = 0;
3392 for(
int i = 0; i < stages; ++i) {
3393 std::vector<LIA> ess;
3396 ARecv =
A.GetLayerMat()->seqptr();
3399 ess.resize(UDERA::esscount);
3400 for(
int j=0; j<UDERA::esscount; ++j) {
3401 ess[j] = ARecvSizes[j][i];
3403 ARecv =
new UDERA();
3414 for(
unsigned int idx = 0; idx < Aarrinfo.
indarrs.size(); ++idx) {
3418 for(
unsigned int idx = 0; idx < Aarrinfo.
numarrs.size(); ++idx) {
3424 Abcast_time += (t3-t2);
3428 BRecv = OnePieceOfBLayer.
seqptr();
3431 ess.resize(UDERB::esscount);
3432 for(
int j=0; j<UDERB::esscount; ++j) {
3433 ess[j] = BRecvSizes[j][i];
3435 BRecv =
new UDERB();
3438 MPI_Barrier(
A.GetLayerMat()->getcommgrid()->GetWorld());
3447 for(
unsigned int idx = 0; idx < Barrinfo.
indarrs.size(); ++idx) {
3450 for(
unsigned int idx = 0; idx < Barrinfo.
numarrs.size(); ++idx) {
3456 Bbcast_time += (t3-t2);
3463 if(computationKernel == 1){
3470 else if(computationKernel == 2){
3481 Local_multiplication_time += (t3-t2);
3484 if(!C_cont->
isZero()) tomerge.push_back(C_cont);
3495 else if(computationKernel == 2) C_tuples =
MultiwayMerge<SR>(tomerge, C_m, C_n,
true);
3504 fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tAbcast_time: %lf\n", p, Abcast_time);
3505 fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tBbcast_time: %lf\n", p, Bbcast_time);
3506 fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tLocal_multiplication_time: %lf\n", p, Local_multiplication_time);
3507 fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tSUMMA Merge time: %lf\n", p, (t3-t2));
3516 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tSUMMA time: %lf\n", p, (t1-t0));
3526 MPI_Datatype MPI_tuple;
3527 MPI_Type_contiguous(
sizeof(std::tuple<LIC,LIC,NUO>), MPI_CHAR, &MPI_tuple);
3528 MPI_Type_commit(&MPI_tuple);
3535 int * sendcnt =
new int[
A.getcommgrid3D()->GetGridLayers()];
3536 int * sendprfl =
new int[
A.getcommgrid3D()->GetGridLayers()*3];
3537 int * sdispls =
new int[
A.getcommgrid3D()->GetGridLayers()]();
3538 int * recvcnt =
new int[
A.getcommgrid3D()->GetGridLayers()];
3539 int * recvprfl =
new int[
A.getcommgrid3D()->GetGridLayers()*3];
3540 int * rdispls =
new int[
A.getcommgrid3D()->GetGridLayers()]();
3542 vector<LIC> lbDivisions3dPrefixSum(lbDivisions3d.size());
3543 lbDivisions3dPrefixSum[0] = 0;
3544 std::partial_sum(lbDivisions3d.begin(), lbDivisions3d.end()-1, lbDivisions3dPrefixSum.begin()+1);
3546 LIC totsend = C_tuples->
getnnz();
3549 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tAllocation of alltoall information: %lf\n", p, (t3-t2));
3555#pragma omp parallel for
3556 for(
int i=0; i <
A.getcommgrid3D()->GetGridLayers(); ++i){
3557 LIC start_col = lbDivisions3dPrefixSum[i];
3558 LIC end_col = lbDivisions3dPrefixSum[i] + lbDivisions3d[i];
3559 std::tuple<LIC, LIC, NUO> search_tuple_start(0, start_col, NUO());
3560 std::tuple<LIC, LIC, NUO> search_tuple_end(0, end_col, NUO());
3561 std::tuple<LIC, LIC, NUO>* start_it = std::lower_bound(C_tuples->
tuples, C_tuples->
tuples + C_tuples->
getnnz(), search_tuple_start, comp);
3562 std::tuple<LIC, LIC, NUO>* end_it = std::lower_bound(C_tuples->
tuples, C_tuples->
tuples + C_tuples->
getnnz(), search_tuple_end, comp);
3564 sendcnt[i] = (int)(end_it - start_it);
3565 sendprfl[i*3+0] = (int)(sendcnt[i]);
3566 sendprfl[i*3+1] = (int)(
A.GetLayerMat()->seqptr()->getnrow());
3567 sendprfl[i*3+2] = (int)(lbDivisions3d[i]);
3569 std::partial_sum(sendcnt, sendcnt+
A.getcommgrid3D()->GetGridLayers()-1, sdispls+1);
3572 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tGetting Alltoall data ready: %lf\n", p, (t3-t2));
3579 for(
int i=0; i <
A.getcommgrid3D()->GetGridLayers(); ++i){
3580#pragma omp parallel for schedule(static)
3581 for(
int j = 0; j < sendcnt[i]; j++){
3582 std::get<1>(C_tuples->
tuples[sdispls[i]+j]) = std::get<1>(C_tuples->
tuples[sdispls[i]+j]) - lbDivisions3dPrefixSum[i];
3587 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tGetting Alltoallv data ready: %lf\n", p, (t3-t2));
3593 MPI_Alltoall(sendprfl, 3, MPI_INT, recvprfl, 3, MPI_INT,
A.getcommgrid3D()->GetFiberWorld());
3596 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tAlltoall: %lf\n", p, (t3-t2));
3601 for(
int i = 0; i <
A.getcommgrid3D()->GetGridLayers(); i++) recvcnt[i] = recvprfl[i*3];
3602 std::partial_sum(recvcnt, recvcnt+
A.getcommgrid3D()->GetGridLayers()-1, rdispls+1);
3603 LIC totrecv = std::accumulate(recvcnt,recvcnt+
A.getcommgrid3D()->GetGridLayers(),
static_cast<IU
>(0));
3604 std::tuple<LIC,LIC,NUO>* recvTuples =
static_cast<std::tuple<LIC,LIC,NUO>*
> (::operator
new (
sizeof(std::tuple<LIC,LIC,NUO>[totrecv])));
3607 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tAllocation of receive data: %lf\n", p, (t3-t2));
3613 MPI_Alltoallv(C_tuples->
tuples, sendcnt, sdispls, MPI_tuple, recvTuples, recvcnt, rdispls, MPI_tuple,
A.getcommgrid3D()->GetFiberWorld());
3617 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tAlltoallv: %lf\n", p, (t3-t2));
3622 vector<SpTuples<LIC, NUO>*> recvChunks(
A.getcommgrid3D()->GetGridLayers());
3623#pragma omp parallel for
3624 for (
int i = 0; i <
A.getcommgrid3D()->GetGridLayers(); i++){
3625 recvChunks[i] =
new SpTuples<LIC, NUO>(recvcnt[i], recvprfl[i*3+1], recvprfl[i*3+2], recvTuples + rdispls[i],
true,
false);
3629 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\trecvChunks creation: %lf\n", p, (t3-t2));
3638 MPI_Type_free(&MPI_tuple);
3641 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tMemory freeing: %lf\n", p, (t3-t2));
3650 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tReduction time: %lf\n", p, (t1-t0));
3660 if(computationKernel == 1) merged_tuples =
MultiwayMergeHash<SR, LIC, NUO>(recvChunks, recvChunks[0]->getnrow(), recvChunks[0]->getncol(),
false,
false);
3661 else if(computationKernel == 2) merged_tuples =
MultiwayMerge<SR, LIC, NUO>(recvChunks, recvChunks[0]->getnrow(), recvChunks[0]->getncol(),
false);
3665 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\t3D Merge time: %lf\n", p, (t1-t0));
3674 ::operator
delete(recvTuples);
3675 for(
int i = 0; i < recvChunks.size(); i++){
3676 recvChunks[i]->tuples_deleted =
true;
3677 delete recvChunks[i];
3679 vector<SpTuples<LIC,NUO>*>().swap(recvChunks);
3683 UDERO * phaseResultant =
new UDERO(*merged_tuples,
false);
3684 delete merged_tuples;
3686 MCLPruneRecoverySelect(phaseResultantLayer, hardThreshold, selectNum, recoverNum, recoverPct, kselectVersion);
3690 if(myrank == 0) fprintf(stderr,
"[MemEfficientSpGEMM3D]\tPhase: %d\tMCLPruneRecoverySelect time: %lf\n",p, (t1-t0));
3692 toconcatenate.push_back(phaseResultantLayer.
seq());
3694 if(myrank == 0) fprintf(stderr,
"***\n");
3697 for(
int i = 0; i < PiecesOfB.size(); i++)
delete PiecesOfB[i];
3699 std::shared_ptr<CommGrid3D> grid3d;
3700 grid3d.reset(
new CommGrid3D(
A.getcommgrid3D()->GetWorld(),
A.getcommgrid3D()->GetGridLayers(),
A.getcommgrid3D()->GetGridRows(),
A.getcommgrid3D()->GetGridCols(),
A.isSpecial()));
3701 UDERO * localResultant =
new UDERO(0,
A.GetLayerMat()->seqptr()->getnrow(), divisions3d[
A.getcommgrid3D()->GetRankInFiber()], 0);
3702 localResultant->ColConcatenate(toconcatenate);