xref: /petsc/src/vec/is/sf/impls/basic/sfbasic.c (revision 834855d6effb0d027771461c8e947ee1ce5a1e17)
140e23c03SJunchao Zhang #include <../src/vec/is/sf/impls/basic/sfbasic.h>
2cd620004SJunchao Zhang #include <../src/vec/is/sf/impls/basic/sfpack.h>
353dd6d7dSJunchao Zhang #include <petsc/private/viewerimpl.h>
4b23bfdefSJunchao Zhang 
5f5d27ee7SJunchao Zhang // Init persistent MPI send/recv requests
PetscSFLinkInitMPIRequests_Persistent_Basic(PetscSF sf,PetscSFLink link,PetscSFDirection direction)6f5d27ee7SJunchao Zhang static PetscErrorCode PetscSFLinkInitMPIRequests_Persistent_Basic(PetscSF sf, PetscSFLink link, PetscSFDirection direction)
7f5d27ee7SJunchao Zhang {
8f5d27ee7SJunchao Zhang   PetscSF_Basic     *bas = (PetscSF_Basic *)sf->data;
96497c311SBarry Smith   PetscInt           cnt;
106497c311SBarry Smith   PetscMPIInt        nrootranks, ndrootranks, nleafranks, ndleafranks;
11f5d27ee7SJunchao Zhang   const PetscInt    *rootoffset, *leafoffset;
12f5d27ee7SJunchao Zhang   MPI_Aint           disp;
13f5d27ee7SJunchao Zhang   MPI_Comm           comm          = PetscObjectComm((PetscObject)sf);
14f5d27ee7SJunchao Zhang   MPI_Datatype       unit          = link->unit;
15f5d27ee7SJunchao Zhang   const PetscMemType rootmtype_mpi = link->rootmtype_mpi, leafmtype_mpi = link->leafmtype_mpi; /* Used to select buffers passed to MPI */
16f5d27ee7SJunchao Zhang   const PetscInt     rootdirect_mpi = link->rootdirect_mpi, leafdirect_mpi = link->leafdirect_mpi;
17f5d27ee7SJunchao Zhang 
18f5d27ee7SJunchao Zhang   PetscFunctionBegin;
19f5d27ee7SJunchao Zhang   if (bas->rootbuflen[PETSCSF_REMOTE] && !link->rootreqsinited[direction][rootmtype_mpi][rootdirect_mpi]) {
20f5d27ee7SJunchao Zhang     PetscCall(PetscSFGetRootInfo_Basic(sf, &nrootranks, &ndrootranks, NULL, &rootoffset, NULL));
21f5d27ee7SJunchao Zhang     if (direction == PETSCSF_LEAF2ROOT) {
226497c311SBarry Smith       for (PetscMPIInt i = ndrootranks, j = 0; i < nrootranks; i++, j++) {
23f5d27ee7SJunchao Zhang         disp = (rootoffset[i] - rootoffset[ndrootranks]) * link->unitbytes;
24f5d27ee7SJunchao Zhang         cnt  = rootoffset[i + 1] - rootoffset[i];
25f5d27ee7SJunchao Zhang         PetscCallMPI(MPIU_Recv_init(link->rootbuf[PETSCSF_REMOTE][rootmtype_mpi] + disp, cnt, unit, bas->iranks[i], link->tag, comm, link->rootreqs[direction][rootmtype_mpi][rootdirect_mpi] + j));
26f5d27ee7SJunchao Zhang       }
27f5d27ee7SJunchao Zhang     } else { /* PETSCSF_ROOT2LEAF */
286497c311SBarry Smith       for (PetscMPIInt i = ndrootranks, j = 0; i < nrootranks; i++, j++) {
29f5d27ee7SJunchao Zhang         disp = (rootoffset[i] - rootoffset[ndrootranks]) * link->unitbytes;
30f5d27ee7SJunchao Zhang         cnt  = rootoffset[i + 1] - rootoffset[i];
31f5d27ee7SJunchao Zhang         PetscCallMPI(MPIU_Send_init(link->rootbuf[PETSCSF_REMOTE][rootmtype_mpi] + disp, cnt, unit, bas->iranks[i], link->tag, comm, link->rootreqs[direction][rootmtype_mpi][rootdirect_mpi] + j));
32f5d27ee7SJunchao Zhang       }
33f5d27ee7SJunchao Zhang     }
34f5d27ee7SJunchao Zhang     link->rootreqsinited[direction][rootmtype_mpi][rootdirect_mpi] = PETSC_TRUE;
35f5d27ee7SJunchao Zhang   }
36f5d27ee7SJunchao Zhang 
37f5d27ee7SJunchao Zhang   if (sf->leafbuflen[PETSCSF_REMOTE] && !link->leafreqsinited[direction][leafmtype_mpi][leafdirect_mpi]) {
38f5d27ee7SJunchao Zhang     PetscCall(PetscSFGetLeafInfo_Basic(sf, &nleafranks, &ndleafranks, NULL, &leafoffset, NULL, NULL));
39f5d27ee7SJunchao Zhang     if (direction == PETSCSF_LEAF2ROOT) {
406497c311SBarry Smith       for (PetscMPIInt i = ndleafranks, j = 0; i < nleafranks; i++, j++) {
41f5d27ee7SJunchao Zhang         disp = (leafoffset[i] - leafoffset[ndleafranks]) * link->unitbytes;
42f5d27ee7SJunchao Zhang         cnt  = leafoffset[i + 1] - leafoffset[i];
43f5d27ee7SJunchao Zhang         PetscCallMPI(MPIU_Send_init(link->leafbuf[PETSCSF_REMOTE][leafmtype_mpi] + disp, cnt, unit, sf->ranks[i], link->tag, comm, link->leafreqs[direction][leafmtype_mpi][leafdirect_mpi] + j));
44f5d27ee7SJunchao Zhang       }
45f5d27ee7SJunchao Zhang     } else { /* PETSCSF_ROOT2LEAF */
466497c311SBarry Smith       for (PetscMPIInt i = ndleafranks, j = 0; i < nleafranks; i++, j++) {
47f5d27ee7SJunchao Zhang         disp = (leafoffset[i] - leafoffset[ndleafranks]) * link->unitbytes;
48f5d27ee7SJunchao Zhang         cnt  = leafoffset[i + 1] - leafoffset[i];
49f5d27ee7SJunchao Zhang         PetscCallMPI(MPIU_Recv_init(link->leafbuf[PETSCSF_REMOTE][leafmtype_mpi] + disp, cnt, unit, sf->ranks[i], link->tag, comm, link->leafreqs[direction][leafmtype_mpi][leafdirect_mpi] + j));
50f5d27ee7SJunchao Zhang       }
51f5d27ee7SJunchao Zhang     }
52f5d27ee7SJunchao Zhang     link->leafreqsinited[direction][leafmtype_mpi][leafdirect_mpi] = PETSC_TRUE;
53f5d27ee7SJunchao Zhang   }
54f5d27ee7SJunchao Zhang   PetscFunctionReturn(PETSC_SUCCESS);
55f5d27ee7SJunchao Zhang }
56f5d27ee7SJunchao Zhang 
57f5d27ee7SJunchao Zhang // Start MPI requests. If use non-GPU aware MPI, we might need to copy data from device buf to host buf
PetscSFLinkStartCommunication_Persistent_Basic(PetscSF sf,PetscSFLink link,PetscSFDirection direction)58f5d27ee7SJunchao Zhang static PetscErrorCode PetscSFLinkStartCommunication_Persistent_Basic(PetscSF sf, PetscSFLink link, PetscSFDirection direction)
59f5d27ee7SJunchao Zhang {
60646b835dSJunchao Zhang   PetscMPIInt    nsreqs = 0, nrreqs = 0;
61646b835dSJunchao Zhang   MPI_Request   *sreqs = NULL, *rreqs = NULL;
62f5d27ee7SJunchao Zhang   PetscSF_Basic *bas = (PetscSF_Basic *)sf->data;
63646b835dSJunchao Zhang   PetscInt       sbuflen, rbuflen;
64f5d27ee7SJunchao Zhang 
65f5d27ee7SJunchao Zhang   PetscFunctionBegin;
66646b835dSJunchao Zhang   rbuflen = (direction == PETSCSF_ROOT2LEAF) ? sf->leafbuflen[PETSCSF_REMOTE] : bas->rootbuflen[PETSCSF_REMOTE];
67646b835dSJunchao Zhang   if (rbuflen) {
68f5d27ee7SJunchao Zhang     if (direction == PETSCSF_ROOT2LEAF) {
69646b835dSJunchao Zhang       nrreqs = sf->nleafreqs;
70646b835dSJunchao Zhang       PetscCall(PetscSFLinkGetMPIBuffersAndRequests(sf, link, direction, NULL, NULL, NULL, &rreqs));
71f5d27ee7SJunchao Zhang     } else { /* leaf to root */
72646b835dSJunchao Zhang       nrreqs = bas->nrootreqs;
73646b835dSJunchao Zhang       PetscCall(PetscSFLinkGetMPIBuffersAndRequests(sf, link, direction, NULL, NULL, &rreqs, NULL));
74f5d27ee7SJunchao Zhang     }
75f5d27ee7SJunchao Zhang   }
76f5d27ee7SJunchao Zhang 
77646b835dSJunchao Zhang   sbuflen = (direction == PETSCSF_ROOT2LEAF) ? bas->rootbuflen[PETSCSF_REMOTE] : sf->leafbuflen[PETSCSF_REMOTE];
78646b835dSJunchao Zhang   if (sbuflen) {
79f5d27ee7SJunchao Zhang     if (direction == PETSCSF_ROOT2LEAF) {
80646b835dSJunchao Zhang       nsreqs = bas->nrootreqs;
81f5d27ee7SJunchao Zhang       PetscCall(PetscSFLinkCopyRootBufferInCaseNotUseGpuAwareMPI(sf, link, PETSC_TRUE /*device2host before sending */));
82646b835dSJunchao Zhang       PetscCall(PetscSFLinkGetMPIBuffersAndRequests(sf, link, direction, NULL, NULL, &sreqs, NULL));
83f5d27ee7SJunchao Zhang     } else { /* leaf to root */
84646b835dSJunchao Zhang       nsreqs = sf->nleafreqs;
85f5d27ee7SJunchao Zhang       PetscCall(PetscSFLinkCopyLeafBufferInCaseNotUseGpuAwareMPI(sf, link, PETSC_TRUE));
86646b835dSJunchao Zhang       PetscCall(PetscSFLinkGetMPIBuffersAndRequests(sf, link, direction, NULL, NULL, NULL, &sreqs));
87f5d27ee7SJunchao Zhang     }
88f5d27ee7SJunchao Zhang   }
89646b835dSJunchao Zhang   PetscCall(PetscSFLinkSyncStreamBeforeCallMPI(sf, link)); // need to sync the stream to make BOTH sendbuf and recvbuf ready
90646b835dSJunchao Zhang   if (rbuflen) PetscCallMPI(MPI_Startall_irecv(rbuflen, link->unit, nrreqs, rreqs));
91646b835dSJunchao Zhang   if (sbuflen) PetscCallMPI(MPI_Startall_isend(sbuflen, link->unit, nsreqs, sreqs));
92f5d27ee7SJunchao Zhang   PetscFunctionReturn(PETSC_SUCCESS);
93f5d27ee7SJunchao Zhang }
94f5d27ee7SJunchao Zhang 
95f5d27ee7SJunchao Zhang #if defined(PETSC_HAVE_MPIX_STREAM)
96f5d27ee7SJunchao Zhang // issue MPIX_Isend/Irecv_enqueue()
PetscSFLinkStartCommunication_MPIX_Stream(PetscSF sf,PetscSFLink link,PetscSFDirection direction)97f5d27ee7SJunchao Zhang static PetscErrorCode PetscSFLinkStartCommunication_MPIX_Stream(PetscSF sf, PetscSFLink link, PetscSFDirection direction)
98f5d27ee7SJunchao Zhang {
99f5d27ee7SJunchao Zhang   PetscSF_Basic     *bas = (PetscSF_Basic *)sf->data;
1006497c311SBarry Smith   PetscInt           i, j;
1016497c311SBarry Smith   PetscMPIInt        nrootranks, ndrootranks, nleafranks, ndleafranks, cnt;
102f5d27ee7SJunchao Zhang   const PetscInt    *rootoffset, *leafoffset;
103f5d27ee7SJunchao Zhang   MPI_Aint           disp;
104f5d27ee7SJunchao Zhang   MPI_Comm           stream_comm   = sf->stream_comm;
105f5d27ee7SJunchao Zhang   MPI_Datatype       unit          = link->unit;
106f5d27ee7SJunchao Zhang   const PetscMemType rootmtype_mpi = link->rootmtype_mpi, leafmtype_mpi = link->leafmtype_mpi; /* Used to select buffers passed to MPI */
107f5d27ee7SJunchao Zhang   const PetscInt     rootdirect_mpi = link->rootdirect_mpi, leafdirect_mpi = link->leafdirect_mpi;
108f5d27ee7SJunchao Zhang 
109f5d27ee7SJunchao Zhang   PetscFunctionBegin;
110f5d27ee7SJunchao Zhang   if (bas->rootbuflen[PETSCSF_REMOTE]) {
111f5d27ee7SJunchao Zhang     PetscCall(PetscSFGetRootInfo_Basic(sf, &nrootranks, &ndrootranks, NULL, &rootoffset, NULL));
112f5d27ee7SJunchao Zhang     if (direction == PETSCSF_LEAF2ROOT) {
113f5d27ee7SJunchao Zhang       for (i = ndrootranks, j = 0; i < nrootranks; i++, j++) {
114f5d27ee7SJunchao Zhang         disp = (rootoffset[i] - rootoffset[ndrootranks]) * link->unitbytes;
1156497c311SBarry Smith         cnt  = (PetscMPIInt)(rootoffset[i + 1] - rootoffset[i]);
116f5d27ee7SJunchao Zhang         PetscCallMPI(MPIX_Irecv_enqueue(link->rootbuf[PETSCSF_REMOTE][rootmtype_mpi] + disp, cnt, unit, bas->iranks[i], link->tag, stream_comm, link->rootreqs[direction][rootmtype_mpi][rootdirect_mpi] + j));
117f5d27ee7SJunchao Zhang       }
118f5d27ee7SJunchao Zhang     } else { // PETSCSF_ROOT2LEAF
119f5d27ee7SJunchao Zhang       for (i = ndrootranks, j = 0; i < nrootranks; i++, j++) {
120f5d27ee7SJunchao Zhang         disp = (rootoffset[i] - rootoffset[ndrootranks]) * link->unitbytes;
1216497c311SBarry Smith         cnt  = (PetscMPIInt)(rootoffset[i + 1] - rootoffset[i]);
122f5d27ee7SJunchao Zhang         // no need to sync the gpu stream!
123f5d27ee7SJunchao Zhang         PetscCallMPI(MPIX_Isend_enqueue(link->rootbuf[PETSCSF_REMOTE][rootmtype_mpi] + disp, cnt, unit, bas->iranks[i], link->tag, stream_comm, link->rootreqs[direction][rootmtype_mpi][rootdirect_mpi] + j));
124f5d27ee7SJunchao Zhang       }
125f5d27ee7SJunchao Zhang     }
126f5d27ee7SJunchao Zhang   }
127f5d27ee7SJunchao Zhang 
128f5d27ee7SJunchao Zhang   if (sf->leafbuflen[PETSCSF_REMOTE]) {
129f5d27ee7SJunchao Zhang     PetscCall(PetscSFGetLeafInfo_Basic(sf, &nleafranks, &ndleafranks, NULL, &leafoffset, NULL, NULL));
130f5d27ee7SJunchao Zhang     if (direction == PETSCSF_LEAF2ROOT) {
131f5d27ee7SJunchao Zhang       for (i = ndleafranks, j = 0; i < nleafranks; i++, j++) {
132f5d27ee7SJunchao Zhang         disp = (leafoffset[i] - leafoffset[ndleafranks]) * link->unitbytes;
1336497c311SBarry Smith         cnt  = (PetscMPIInt)(leafoffset[i + 1] - leafoffset[i]);
134f5d27ee7SJunchao Zhang         // no need to sync the gpu stream!
135f5d27ee7SJunchao Zhang         PetscCallMPI(MPIX_Isend_enqueue(link->leafbuf[PETSCSF_REMOTE][leafmtype_mpi] + disp, cnt, unit, sf->ranks[i], link->tag, stream_comm, link->leafreqs[direction][leafmtype_mpi][leafdirect_mpi] + j));
136f5d27ee7SJunchao Zhang       }
137f5d27ee7SJunchao Zhang     } else { // PETSCSF_ROOT2LEAF
138f5d27ee7SJunchao Zhang       for (i = ndleafranks, j = 0; i < nleafranks; i++, j++) {
139f5d27ee7SJunchao Zhang         disp = (leafoffset[i] - leafoffset[ndleafranks]) * link->unitbytes;
1406497c311SBarry Smith         cnt  = (PetscMPIInt)(leafoffset[i + 1] - leafoffset[i]);
141f5d27ee7SJunchao Zhang         PetscCallMPI(MPIX_Irecv_enqueue(link->leafbuf[PETSCSF_REMOTE][leafmtype_mpi] + disp, cnt, unit, sf->ranks[i], link->tag, stream_comm, link->leafreqs[direction][leafmtype_mpi][leafdirect_mpi] + j));
142f5d27ee7SJunchao Zhang       }
143f5d27ee7SJunchao Zhang     }
144f5d27ee7SJunchao Zhang   }
145f5d27ee7SJunchao Zhang   PetscFunctionReturn(PETSC_SUCCESS);
146f5d27ee7SJunchao Zhang }
147f5d27ee7SJunchao Zhang 
PetscSFLinkFinishCommunication_MPIX_Stream(PetscSF sf,PetscSFLink link,PetscSFDirection direction)148f5d27ee7SJunchao Zhang static PetscErrorCode PetscSFLinkFinishCommunication_MPIX_Stream(PetscSF sf, PetscSFLink link, PetscSFDirection direction)
149f5d27ee7SJunchao Zhang {
150f5d27ee7SJunchao Zhang   PetscSF_Basic     *bas           = (PetscSF_Basic *)sf->data;
151f5d27ee7SJunchao Zhang   const PetscMemType rootmtype_mpi = link->rootmtype_mpi, leafmtype_mpi = link->leafmtype_mpi;
152f5d27ee7SJunchao Zhang   const PetscInt     rootdirect_mpi = link->rootdirect_mpi, leafdirect_mpi = link->leafdirect_mpi;
153f5d27ee7SJunchao Zhang 
154f5d27ee7SJunchao Zhang   PetscFunctionBegin;
155f5d27ee7SJunchao Zhang   PetscCallMPI(MPIX_Waitall_enqueue(bas->nrootreqs, link->rootreqs[direction][rootmtype_mpi][rootdirect_mpi], MPI_STATUSES_IGNORE));
156f5d27ee7SJunchao Zhang   PetscCallMPI(MPIX_Waitall_enqueue(sf->nleafreqs, link->leafreqs[direction][leafmtype_mpi][leafdirect_mpi], MPI_STATUSES_IGNORE));
157f5d27ee7SJunchao Zhang   PetscFunctionReturn(PETSC_SUCCESS);
158f5d27ee7SJunchao Zhang }
159f5d27ee7SJunchao Zhang #endif
160f5d27ee7SJunchao Zhang 
PetscSFSetCommunicationOps_Basic(PetscSF sf,PetscSFLink link)161f5d27ee7SJunchao Zhang static PetscErrorCode PetscSFSetCommunicationOps_Basic(PetscSF sf, PetscSFLink link)
162f5d27ee7SJunchao Zhang {
163f5d27ee7SJunchao Zhang   PetscFunctionBegin;
164f5d27ee7SJunchao Zhang   link->InitMPIRequests    = PetscSFLinkInitMPIRequests_Persistent_Basic;
165f5d27ee7SJunchao Zhang   link->StartCommunication = PetscSFLinkStartCommunication_Persistent_Basic;
166f5d27ee7SJunchao Zhang #if defined(PETSC_HAVE_MPIX_STREAM)
1676677b1c1SJunchao Zhang   const PetscMemType rootmtype_mpi = link->rootmtype_mpi, leafmtype_mpi = link->leafmtype_mpi;
168f5d27ee7SJunchao Zhang   if (sf->use_stream_aware_mpi && (PetscMemTypeDevice(rootmtype_mpi) || PetscMemTypeDevice(leafmtype_mpi))) {
169f5d27ee7SJunchao Zhang     link->StartCommunication  = PetscSFLinkStartCommunication_MPIX_Stream;
170f5d27ee7SJunchao Zhang     link->FinishCommunication = PetscSFLinkFinishCommunication_MPIX_Stream;
171f5d27ee7SJunchao Zhang   }
172f5d27ee7SJunchao Zhang #endif
173f5d27ee7SJunchao Zhang   PetscFunctionReturn(PETSC_SUCCESS);
174f5d27ee7SJunchao Zhang }
175f5d27ee7SJunchao Zhang 
17640e23c03SJunchao Zhang /*===================================================================================*/
17740e23c03SJunchao Zhang /*              SF public interface implementations                                  */
17840e23c03SJunchao Zhang /*===================================================================================*/
PetscSFSetUp_Basic(PetscSF sf)179d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFSetUp_Basic(PetscSF sf)
180d71ae5a4SJacob Faibussowitsch {
181b23bfdefSJunchao Zhang   PetscSF_Basic *bas = (PetscSF_Basic *)sf->data;
1826497c311SBarry Smith   PetscInt      *rlengths, *ilengths;
1836497c311SBarry Smith   PetscMPIInt    nRemoteRootRanks, nRemoteLeafRanks;
18440e23c03SJunchao Zhang   PetscMPIInt    rank, niranks, *iranks, tag;
18595fce210SBarry Smith   MPI_Comm       comm;
186b5a8e515SJed Brown   MPI_Group      group;
18740e23c03SJunchao Zhang   MPI_Request   *rootreqs, *leafreqs;
18895fce210SBarry Smith 
18995fce210SBarry Smith   PetscFunctionBegin;
1909566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_group(PETSC_COMM_SELF, &group));
1919566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUpRanks(sf, group));
1929566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Group_free(&group));
1939566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)sf, &comm));
1949566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetNewTag((PetscObject)sf, &tag));
1959566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
19695fce210SBarry Smith   /*
19795fce210SBarry Smith    * Inform roots about how many leaves and from which ranks
19895fce210SBarry Smith    */
1999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(sf->nranks, &rlengths));
200cd620004SJunchao Zhang   /* Determine number, sending ranks and length of incoming */
201*ac530a7eSPierre Jolivet   for (PetscMPIInt i = 0; i < sf->nranks; i++) rlengths[i] = sf->roffset[i + 1] - sf->roffset[i]; /* Number of roots referenced by my leaves; for rank sf->ranks[i] */
20271438e86SJunchao Zhang   nRemoteRootRanks = sf->nranks - sf->ndranks;
20316cd844bSPierre Jolivet   PetscCall(PetscCommBuildTwoSided(comm, 1, MPIU_INT, nRemoteRootRanks, PetscSafePointerPlusOffset(sf->ranks, sf->ndranks), PetscSafePointerPlusOffset(rlengths, sf->ndranks), &niranks, &iranks, (void **)&ilengths));
204c943f53fSJed Brown 
2050b899082SJunchao Zhang   /* Sort iranks. See use of VecScatterGetRemoteOrdered_Private() in MatGetBrowsOfAoCols_MPIAIJ() on why.
2060b899082SJunchao Zhang      We could sort ranks there at the price of allocating extra working arrays. Presumably, niranks is
2070b899082SJunchao Zhang      small and the sorting is cheap.
2080b899082SJunchao Zhang    */
2099566063dSJacob Faibussowitsch   PetscCall(PetscSortMPIIntWithIntArray(niranks, iranks, ilengths));
2100b899082SJunchao Zhang 
211c943f53fSJed Brown   /* Partition into distinguished and non-distinguished incoming ranks */
212c943f53fSJed Brown   bas->ndiranks = sf->ndranks;
213c943f53fSJed Brown   bas->niranks  = bas->ndiranks + niranks;
2149566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(bas->niranks, &bas->iranks, bas->niranks + 1, &bas->ioffset));
215c943f53fSJed Brown   bas->ioffset[0] = 0;
2166497c311SBarry Smith   for (PetscMPIInt i = 0; i < bas->ndiranks; i++) {
217c943f53fSJed Brown     bas->iranks[i]      = sf->ranks[i];
218c943f53fSJed Brown     bas->ioffset[i + 1] = bas->ioffset[i] + rlengths[i];
219c943f53fSJed Brown   }
220c9cc58a2SBarry Smith   PetscCheck(bas->ndiranks <= 1 && (bas->ndiranks != 1 || bas->iranks[0] == rank), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Broken setup for shared ranks");
2216497c311SBarry Smith   for (PetscMPIInt i = bas->ndiranks; i < bas->niranks; i++) {
222c943f53fSJed Brown     bas->iranks[i]      = iranks[i - bas->ndiranks];
223c943f53fSJed Brown     bas->ioffset[i + 1] = bas->ioffset[i] + ilengths[i - bas->ndiranks];
224c943f53fSJed Brown   }
2256497c311SBarry Smith   bas->itotal = bas->ioffset[bas->niranks];
2269566063dSJacob Faibussowitsch   PetscCall(PetscFree(rlengths));
2279566063dSJacob Faibussowitsch   PetscCall(PetscFree(iranks));
2289566063dSJacob Faibussowitsch   PetscCall(PetscFree(ilengths));
22995fce210SBarry Smith 
23095fce210SBarry Smith   /* Send leaf identities to roots */
23171438e86SJunchao Zhang   nRemoteLeafRanks = bas->niranks - bas->ndiranks;
2329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(bas->itotal, &bas->irootloc));
2339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nRemoteLeafRanks, &rootreqs, nRemoteRootRanks, &leafreqs));
2346497c311SBarry Smith   for (PetscMPIInt i = bas->ndiranks; i < bas->niranks; i++) PetscCallMPI(MPIU_Irecv(bas->irootloc + bas->ioffset[i], bas->ioffset[i + 1] - bas->ioffset[i], MPIU_INT, bas->iranks[i], tag, comm, &rootreqs[i - bas->ndiranks]));
2356497c311SBarry Smith   for (PetscMPIInt i = 0; i < sf->nranks; i++) {
236c87b50c4SJunchao Zhang     PetscInt npoints = sf->roffset[i + 1] - sf->roffset[i];
23740e23c03SJunchao Zhang     if (i < sf->ndranks) {
23808401ef6SPierre Jolivet       PetscCheck(sf->ranks[i] == rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot interpret distinguished leaf rank");
23908401ef6SPierre Jolivet       PetscCheck(bas->iranks[0] == rank, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Cannot interpret distinguished root rank");
24008401ef6SPierre Jolivet       PetscCheck(npoints == bas->ioffset[1] - bas->ioffset[0], PETSC_COMM_SELF, PETSC_ERR_PLIB, "Distinguished rank exchange has mismatched lengths");
2419566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(bas->irootloc + bas->ioffset[0], sf->rremote + sf->roffset[i], npoints));
242c943f53fSJed Brown       continue;
243c943f53fSJed Brown     }
2449566063dSJacob Faibussowitsch     PetscCallMPI(MPIU_Isend(sf->rremote + sf->roffset[i], npoints, MPIU_INT, sf->ranks[i], tag, comm, &leafreqs[i - sf->ndranks]));
245bf39f1bfSJed Brown   }
2469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(nRemoteLeafRanks, rootreqs, MPI_STATUSES_IGNORE));
2479566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall(nRemoteRootRanks, leafreqs, MPI_STATUSES_IGNORE));
24895fce210SBarry Smith 
24971438e86SJunchao Zhang   sf->nleafreqs  = nRemoteRootRanks;
25071438e86SJunchao Zhang   bas->nrootreqs = nRemoteLeafRanks;
251eb02082bSJunchao Zhang 
25271438e86SJunchao Zhang   /* Setup fields related to packing, such as rootbuflen[] */
2539566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUpPackFields(sf));
2549566063dSJacob Faibussowitsch   PetscCall(PetscFree2(rootreqs, leafreqs));
2553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
25695fce210SBarry Smith }
25795fce210SBarry Smith 
PetscSFReset_Basic(PetscSF sf)258d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFReset_Basic(PetscSF sf)
259d71ae5a4SJacob Faibussowitsch {
260cd620004SJunchao Zhang   PetscSF_Basic *bas  = (PetscSF_Basic *)sf->data;
26171438e86SJunchao Zhang   PetscSFLink    link = bas->avail, next;
26295fce210SBarry Smith 
26395fce210SBarry Smith   PetscFunctionBegin;
26428b400f6SJacob Faibussowitsch   PetscCheck(!bas->inuse, PetscObjectComm((PetscObject)sf), PETSC_ERR_ARG_WRONGSTATE, "Outstanding operation has not been completed");
2659566063dSJacob Faibussowitsch   PetscCall(PetscFree2(bas->iranks, bas->ioffset));
2669566063dSJacob Faibussowitsch   PetscCall(PetscFree(bas->irootloc));
26771438e86SJunchao Zhang 
2687fd2d3dbSJunchao Zhang #if defined(PETSC_HAVE_DEVICE)
2696497c311SBarry Smith   for (int i = 0; i < 2; i++) PetscCall(PetscSFFree(sf, PETSC_MEMTYPE_DEVICE, bas->irootloc_d[i]));
270eb02082bSJunchao Zhang #endif
27171438e86SJunchao Zhang 
27271438e86SJunchao Zhang #if defined(PETSC_HAVE_NVSHMEM)
2739566063dSJacob Faibussowitsch   PetscCall(PetscSFReset_Basic_NVSHMEM(sf));
27471438e86SJunchao Zhang #endif
27571438e86SJunchao Zhang 
2769371c9d4SSatish Balay   for (; link; link = next) {
2779371c9d4SSatish Balay     next = link->next;
2789371c9d4SSatish Balay     PetscCall(PetscSFLinkDestroy(sf, link));
2799371c9d4SSatish Balay   }
28071438e86SJunchao Zhang   bas->avail = NULL;
2819566063dSJacob Faibussowitsch   PetscCall(PetscSFResetPackFields(sf));
2823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28395fce210SBarry Smith }
28495fce210SBarry Smith 
PetscSFDestroy_Basic(PetscSF sf)285d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFDestroy_Basic(PetscSF sf)
286d71ae5a4SJacob Faibussowitsch {
28795fce210SBarry Smith   PetscFunctionBegin;
2889566063dSJacob Faibussowitsch   PetscCall(PetscSFReset_Basic(sf));
2899566063dSJacob Faibussowitsch   PetscCall(PetscFree(sf->data));
2903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
29195fce210SBarry Smith }
29295fce210SBarry Smith 
29362152dedSBarry Smith #if defined(PETSC_USE_SINGLE_LIBRARY)
29462152dedSBarry Smith   #include <petscmat.h>
29562152dedSBarry Smith 
PetscSFView_Basic_PatternAndSizes(PetscSF sf,PetscViewer viewer)296d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFView_Basic_PatternAndSizes(PetscSF sf, PetscViewer viewer)
297d71ae5a4SJacob Faibussowitsch {
29862152dedSBarry Smith   PetscSF_Basic     *bas = (PetscSF_Basic *)sf->data;
2996497c311SBarry Smith   PetscMPIInt        nrootranks, ndrootranks;
30062152dedSBarry Smith   const PetscInt    *rootoffset;
30162152dedSBarry Smith   PetscMPIInt        rank, size;
30253dd6d7dSJunchao Zhang   const PetscMPIInt *rootranks;
30362152dedSBarry Smith   MPI_Comm           comm = PetscObjectComm((PetscObject)sf);
30453dd6d7dSJunchao Zhang   PetscScalar        unitbytes;
30562152dedSBarry Smith   Mat                A;
30662152dedSBarry Smith 
30762152dedSBarry Smith   PetscFunctionBegin;
3089566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
3099566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
31053dd6d7dSJunchao Zhang   /* PetscSFView is most useful for the SF used in VecScatterBegin/End in MatMult etc, where we do
31153dd6d7dSJunchao Zhang     PetscSFBcast, i.e., roots send data to leaves.  We dump the communication pattern into a matrix
31253dd6d7dSJunchao Zhang     in senders' view point: how many bytes I will send to my neighbors.
31353dd6d7dSJunchao Zhang 
31453dd6d7dSJunchao Zhang     Looking at a column of the matrix, one can also know how many bytes the rank will receive from others.
31553dd6d7dSJunchao Zhang 
31653dd6d7dSJunchao Zhang     If PetscSFLink bas->inuse is available, we can use that to get tree vertex size. But that would give
31753dd6d7dSJunchao Zhang     different interpretations for the same SF for different data types. Since we most care about VecScatter,
31853dd6d7dSJunchao Zhang     we uniformly treat each vertex as a PetscScalar.
31953dd6d7dSJunchao Zhang   */
32053dd6d7dSJunchao Zhang   unitbytes = (PetscScalar)sizeof(PetscScalar);
32153dd6d7dSJunchao Zhang 
3229566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootInfo_Basic(sf, &nrootranks, &ndrootranks, &rootranks, &rootoffset, NULL));
3239566063dSJacob Faibussowitsch   PetscCall(MatCreateAIJ(comm, 1, 1, size, size, 1, NULL, nrootranks - ndrootranks, NULL, &A));
3249566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(A, "__petsc_internal__")); /* To prevent the internal A from taking any command line options */
325835f2295SStefano Zampini   for (PetscMPIInt i = 0; i < nrootranks; i++) PetscCall(MatSetValue(A, rank, bas->iranks[i], (rootoffset[i + 1] - rootoffset[i]) * unitbytes, INSERT_VALUES));
3269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
3279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
3289566063dSJacob Faibussowitsch   PetscCall(MatView(A, viewer));
3299566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&A));
3303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
33162152dedSBarry Smith }
33262152dedSBarry Smith #endif
33362152dedSBarry Smith 
PetscSFView_Basic(PetscSF sf,PetscViewer viewer)334d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFView_Basic(PetscSF sf, PetscViewer viewer)
335d71ae5a4SJacob Faibussowitsch {
33653dd6d7dSJunchao Zhang   PetscBool isascii;
33795fce210SBarry Smith 
33895fce210SBarry Smith   PetscFunctionBegin;
3399566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
3409566063dSJacob Faibussowitsch   if (isascii && viewer->format != PETSC_VIEWER_ASCII_MATLAB) PetscCall(PetscViewerASCIIPrintf(viewer, "  MultiSF sort=%s\n", sf->rankorder ? "rank-order" : "unordered"));
34162152dedSBarry Smith #if defined(PETSC_USE_SINGLE_LIBRARY)
34253dd6d7dSJunchao Zhang   else {
34353dd6d7dSJunchao Zhang     PetscBool isdraw, isbinary;
3449566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERDRAW, &isdraw));
3459566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERBINARY, &isbinary));
34648a46eb9SPierre Jolivet     if ((isascii && viewer->format == PETSC_VIEWER_ASCII_MATLAB) || isdraw || isbinary) PetscCall(PetscSFView_Basic_PatternAndSizes(sf, viewer));
34762152dedSBarry Smith   }
34862152dedSBarry Smith #endif
3493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35095fce210SBarry Smith }
35195fce210SBarry Smith 
PetscSFBcastBegin_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,const void * rootdata,PetscMemType leafmtype,void * leafdata,MPI_Op op)352f5d27ee7SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFBcastBegin_Basic(PetscSF sf, MPI_Datatype unit, PetscMemType rootmtype, const void *rootdata, PetscMemType leafmtype, void *leafdata, MPI_Op op)
353d71ae5a4SJacob Faibussowitsch {
354cd620004SJunchao Zhang   PetscSFLink link = NULL;
35595fce210SBarry Smith 
35695fce210SBarry Smith   PetscFunctionBegin;
35771438e86SJunchao Zhang   /* Create a communication link, which provides buffers, MPI requests etc (if MPI is used) */
3589566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkCreate(sf, unit, rootmtype, rootdata, leafmtype, leafdata, op, PETSCSF_BCAST, &link));
35971438e86SJunchao Zhang   /* Pack rootdata to rootbuf for remote communication */
3609566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkPackRootData(sf, link, PETSCSF_REMOTE, rootdata));
3616497c311SBarry Smith   /* Start communication, e.g., post MPIU_Isend */
3629566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkStartCommunication(sf, link, PETSCSF_ROOT2LEAF));
36371438e86SJunchao Zhang   /* Do local scatter (i.e., self to self communication), which overlaps with the remote communication above */
3649566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkScatterLocal(sf, link, PETSCSF_ROOT2LEAF, (void *)rootdata, leafdata, op));
3653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36695fce210SBarry Smith }
36795fce210SBarry Smith 
PetscSFBcastEnd_Basic(PetscSF sf,MPI_Datatype unit,const void * rootdata,void * leafdata,MPI_Op op)368d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFBcastEnd_Basic(PetscSF sf, MPI_Datatype unit, const void *rootdata, void *leafdata, MPI_Op op)
369d71ae5a4SJacob Faibussowitsch {
370cd620004SJunchao Zhang   PetscSFLink link = NULL;
37195fce210SBarry Smith 
37295fce210SBarry Smith   PetscFunctionBegin;
373cd620004SJunchao Zhang   /* Retrieve the link used in XxxBegin() with root/leafdata as key */
3749566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkGetInUse(sf, unit, rootdata, leafdata, PETSC_OWN_POINTER, &link));
37571438e86SJunchao Zhang   /* Finish remote communication, e.g., post MPI_Waitall */
3769566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkFinishCommunication(sf, link, PETSCSF_ROOT2LEAF));
37771438e86SJunchao Zhang   /* Unpack data in leafbuf to leafdata for remote communication */
3789566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkUnpackLeafData(sf, link, PETSCSF_REMOTE, leafdata, op));
37971438e86SJunchao Zhang   /* Recycle the link */
3809566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkReclaim(sf, &link));
3813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
382cd620004SJunchao Zhang }
383cd620004SJunchao Zhang 
384cd620004SJunchao Zhang /* Shared by ReduceBegin and FetchAndOpBegin */
PetscSFLeafToRootBegin_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType leafmtype,const void * leafdata,PetscMemType rootmtype,void * rootdata,MPI_Op op,PetscSFOperation sfop,PetscSFLink * out)385d71ae5a4SJacob Faibussowitsch static inline PetscErrorCode PetscSFLeafToRootBegin_Basic(PetscSF sf, MPI_Datatype unit, PetscMemType leafmtype, const void *leafdata, PetscMemType rootmtype, void *rootdata, MPI_Op op, PetscSFOperation sfop, PetscSFLink *out)
386d71ae5a4SJacob Faibussowitsch {
38771438e86SJunchao Zhang   PetscSFLink link = NULL;
388cd620004SJunchao Zhang 
389cd620004SJunchao Zhang   PetscFunctionBegin;
3909566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkCreate(sf, unit, rootmtype, rootdata, leafmtype, leafdata, op, sfop, &link));
3919566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkPackLeafData(sf, link, PETSCSF_REMOTE, leafdata));
3929566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkStartCommunication(sf, link, PETSCSF_LEAF2ROOT));
393cd620004SJunchao Zhang   *out = link;
3943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
39595fce210SBarry Smith }
39695fce210SBarry Smith 
39795fce210SBarry Smith /* leaf -> root with reduction */
PetscSFReduceBegin_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType leafmtype,const void * leafdata,PetscMemType rootmtype,void * rootdata,MPI_Op op)398f5d27ee7SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFReduceBegin_Basic(PetscSF sf, MPI_Datatype unit, PetscMemType leafmtype, const void *leafdata, PetscMemType rootmtype, void *rootdata, MPI_Op op)
399d71ae5a4SJacob Faibussowitsch {
400cd620004SJunchao Zhang   PetscSFLink link = NULL;
40195fce210SBarry Smith 
40295fce210SBarry Smith   PetscFunctionBegin;
4039566063dSJacob Faibussowitsch   PetscCall(PetscSFLeafToRootBegin_Basic(sf, unit, leafmtype, leafdata, rootmtype, rootdata, op, PETSCSF_REDUCE, &link));
4049566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkScatterLocal(sf, link, PETSCSF_LEAF2ROOT, rootdata, (void *)leafdata, op));
4053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40695fce210SBarry Smith }
40795fce210SBarry Smith 
PetscSFReduceEnd_Basic(PetscSF sf,MPI_Datatype unit,const void * leafdata,void * rootdata,MPI_Op op)408d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFReduceEnd_Basic(PetscSF sf, MPI_Datatype unit, const void *leafdata, void *rootdata, MPI_Op op)
409d71ae5a4SJacob Faibussowitsch {
410cd620004SJunchao Zhang   PetscSFLink link = NULL;
41195fce210SBarry Smith 
41295fce210SBarry Smith   PetscFunctionBegin;
4139566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkGetInUse(sf, unit, rootdata, leafdata, PETSC_OWN_POINTER, &link));
4149566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkFinishCommunication(sf, link, PETSCSF_LEAF2ROOT));
4159566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkUnpackRootData(sf, link, PETSCSF_REMOTE, rootdata, op));
4169566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkReclaim(sf, &link));
4173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41895fce210SBarry Smith }
41995fce210SBarry Smith 
PetscSFFetchAndOpBegin_Basic(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,void * rootdata,PetscMemType leafmtype,const void * leafdata,void * leafupdate,MPI_Op op)420d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFFetchAndOpBegin_Basic(PetscSF sf, MPI_Datatype unit, PetscMemType rootmtype, void *rootdata, PetscMemType leafmtype, const void *leafdata, void *leafupdate, MPI_Op op)
421d71ae5a4SJacob Faibussowitsch {
422cd620004SJunchao Zhang   PetscSFLink link = NULL;
42395fce210SBarry Smith 
42495fce210SBarry Smith   PetscFunctionBegin;
4259566063dSJacob Faibussowitsch   PetscCall(PetscSFLeafToRootBegin_Basic(sf, unit, leafmtype, leafdata, rootmtype, rootdata, op, PETSCSF_FETCH, &link));
4269566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkFetchAndOpLocal(sf, link, rootdata, leafdata, leafupdate, op));
4273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
42895fce210SBarry Smith }
42995fce210SBarry Smith 
PetscSFFetchAndOpEnd_Basic(PetscSF sf,MPI_Datatype unit,void * rootdata,const void * leafdata,void * leafupdate,MPI_Op op)430f5d27ee7SJunchao Zhang PETSC_INTERN PetscErrorCode PetscSFFetchAndOpEnd_Basic(PetscSF sf, MPI_Datatype unit, void *rootdata, const void *leafdata, void *leafupdate, MPI_Op op)
431d71ae5a4SJacob Faibussowitsch {
432cd620004SJunchao Zhang   PetscSFLink link = NULL;
43395fce210SBarry Smith 
43495fce210SBarry Smith   PetscFunctionBegin;
4359566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkGetInUse(sf, unit, rootdata, leafdata, PETSC_OWN_POINTER, &link));
43695fce210SBarry Smith   /* This implementation could be changed to unpack as receives arrive, at the cost of non-determinism */
4379566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkFinishCommunication(sf, link, PETSCSF_LEAF2ROOT));
438cd620004SJunchao Zhang   /* Do fetch-and-op, the (remote) update results are in rootbuf */
4399566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkFetchAndOpRemote(sf, link, rootdata, op));
440cd620004SJunchao Zhang   /* Bcast rootbuf to leafupdate */
4419566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkStartCommunication(sf, link, PETSCSF_ROOT2LEAF));
4429566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkFinishCommunication(sf, link, PETSCSF_ROOT2LEAF));
443b23bfdefSJunchao Zhang   /* Unpack and insert fetched data into leaves */
4449566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkUnpackLeafData(sf, link, PETSCSF_REMOTE, leafupdate, MPI_REPLACE));
4459566063dSJacob Faibussowitsch   PetscCall(PetscSFLinkReclaim(sf, &link));
4463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44795fce210SBarry Smith }
44895fce210SBarry Smith 
PetscSFGetLeafRanks_Basic(PetscSF sf,PetscMPIInt * niranks,const PetscMPIInt ** iranks,const PetscInt ** ioffset,const PetscInt ** irootloc)4496497c311SBarry Smith PETSC_INTERN PetscErrorCode PetscSFGetLeafRanks_Basic(PetscSF sf, PetscMPIInt *niranks, const PetscMPIInt **iranks, const PetscInt **ioffset, const PetscInt **irootloc)
450d71ae5a4SJacob Faibussowitsch {
4518750ddebSJunchao Zhang   PetscSF_Basic *bas = (PetscSF_Basic *)sf->data;
4528750ddebSJunchao Zhang 
4538750ddebSJunchao Zhang   PetscFunctionBegin;
4548750ddebSJunchao Zhang   if (niranks) *niranks = bas->niranks;
4558750ddebSJunchao Zhang   if (iranks) *iranks = bas->iranks;
4568750ddebSJunchao Zhang   if (ioffset) *ioffset = bas->ioffset;
4578750ddebSJunchao Zhang   if (irootloc) *irootloc = bas->irootloc;
4583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4598750ddebSJunchao Zhang }
4608750ddebSJunchao Zhang 
461da81f932SPierre Jolivet /* An optimized PetscSFCreateEmbeddedRootSF. We aggressively make use of the established communication on sf.
462f659e5c7SJunchao Zhang    We need one bcast on sf, and no communication anymore to build the embedded sf. Note that selected[]
463f659e5c7SJunchao Zhang    was sorted before calling the routine.
464f659e5c7SJunchao Zhang  */
PetscSFCreateEmbeddedRootSF_Basic(PetscSF sf,PetscInt nselected,const PetscInt * selected,PetscSF * newsf)465d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFCreateEmbeddedRootSF_Basic(PetscSF sf, PetscInt nselected, const PetscInt *selected, PetscSF *newsf)
466d71ae5a4SJacob Faibussowitsch {
467f659e5c7SJunchao Zhang   PetscSF            esf;
4686497c311SBarry Smith   PetscInt          *esf_roffset, *esf_rmine, *esf_rremote;
4696497c311SBarry Smith   PetscInt           j, p, q, nroots, esf_nleaves, *new_ilocal, minleaf, maxleaf, maxlocal;
4708e3a54c0SPierre Jolivet   char              *rootdata, *leafdata, *leafmem; /* Only stores 0 or 1, so we can save memory with char */
4716497c311SBarry Smith   PetscMPIInt       *esf_ranks, nranks, ndranks, niranks, esf_nranks, esf_ndranks, ndiranks;
472f659e5c7SJunchao Zhang   const PetscMPIInt *ranks, *iranks;
473cd620004SJunchao Zhang   const PetscInt    *roffset, *rmine, *rremote, *ioffset, *irootloc;
474f659e5c7SJunchao Zhang   PetscBool          connected;
475f659e5c7SJunchao Zhang   PetscSFNode       *new_iremote;
476f659e5c7SJunchao Zhang   PetscSF_Basic     *bas;
477f659e5c7SJunchao Zhang 
478f659e5c7SJunchao Zhang   PetscFunctionBegin;
4799566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)sf), &esf));
4809566063dSJacob Faibussowitsch   PetscCall(PetscSFSetFromOptions(esf));
4819566063dSJacob Faibussowitsch   PetscCall(PetscSFSetType(esf, PETSCSFBASIC)); /* This optimized routine can only create a basic sf */
482f659e5c7SJunchao Zhang 
483cd620004SJunchao Zhang   /* Find out which leaves are still connected to roots in the embedded sf by doing a Bcast */
4849566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL));
4859566063dSJacob Faibussowitsch   PetscCall(PetscSFGetLeafRange(sf, &minleaf, &maxleaf));
486cd620004SJunchao Zhang   maxlocal = maxleaf - minleaf + 1;
4879566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(nroots, &rootdata, maxlocal, &leafmem));
4888e3a54c0SPierre Jolivet   leafdata = PetscSafePointerPlusOffset(leafmem, -minleaf);
489f659e5c7SJunchao Zhang   /* Tag selected roots */
4906497c311SBarry Smith   for (PetscInt i = 0; i < nselected; ++i) rootdata[selected[i]] = 1;
491f659e5c7SJunchao Zhang 
4929566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastBegin(sf, MPI_CHAR, rootdata, leafdata, MPI_REPLACE));
4939566063dSJacob Faibussowitsch   PetscCall(PetscSFBcastEnd(sf, MPI_CHAR, rootdata, leafdata, MPI_REPLACE));
4949566063dSJacob Faibussowitsch   PetscCall(PetscSFGetLeafInfo_Basic(sf, &nranks, &ndranks, &ranks, &roffset, &rmine, &rremote)); /* Get send info */
495cd620004SJunchao Zhang   esf_nranks = esf_ndranks = esf_nleaves = 0;
4966497c311SBarry Smith   for (PetscMPIInt i = 0; i < nranks; i++) {
497cd620004SJunchao Zhang     connected = PETSC_FALSE; /* Is this process still connected to this remote root rank? */
4989371c9d4SSatish Balay     for (j = roffset[i]; j < roffset[i + 1]; j++) {
4999371c9d4SSatish Balay       if (leafdata[rmine[j]]) {
5009371c9d4SSatish Balay         esf_nleaves++;
5019371c9d4SSatish Balay         connected = PETSC_TRUE;
5029371c9d4SSatish Balay       }
5039371c9d4SSatish Balay     }
5049371c9d4SSatish Balay     if (connected) {
5059371c9d4SSatish Balay       esf_nranks++;
5069371c9d4SSatish Balay       if (i < ndranks) esf_ndranks++;
5079371c9d4SSatish Balay     }
508f659e5c7SJunchao Zhang   }
509f659e5c7SJunchao Zhang 
510f659e5c7SJunchao Zhang   /* Set graph of esf and also set up its outgoing communication (i.e., send info), which is usually done by PetscSFSetUpRanks */
5119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(esf_nleaves, &new_ilocal));
5129566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(esf_nleaves, &new_iremote));
5139566063dSJacob Faibussowitsch   PetscCall(PetscMalloc4(esf_nranks, &esf_ranks, esf_nranks + 1, &esf_roffset, esf_nleaves, &esf_rmine, esf_nleaves, &esf_rremote));
514f659e5c7SJunchao Zhang   p              = 0; /* Counter for connected root ranks */
515f659e5c7SJunchao Zhang   q              = 0; /* Counter for connected leaves */
516f659e5c7SJunchao Zhang   esf_roffset[0] = 0;
5176497c311SBarry Smith   for (PetscMPIInt i = 0; i < nranks; i++) { /* Scan leaf data again to fill esf arrays */
518f659e5c7SJunchao Zhang     connected = PETSC_FALSE;
519cd620004SJunchao Zhang     for (j = roffset[i]; j < roffset[i + 1]; j++) {
520cd620004SJunchao Zhang       if (leafdata[rmine[j]]) {
521f659e5c7SJunchao Zhang         esf_rmine[q] = new_ilocal[q] = rmine[j];
522f659e5c7SJunchao Zhang         esf_rremote[q]               = rremote[j];
523f659e5c7SJunchao Zhang         new_iremote[q].index         = rremote[j];
524f659e5c7SJunchao Zhang         new_iremote[q].rank          = ranks[i];
525f659e5c7SJunchao Zhang         connected                    = PETSC_TRUE;
526f659e5c7SJunchao Zhang         q++;
527f659e5c7SJunchao Zhang       }
528f659e5c7SJunchao Zhang     }
529f659e5c7SJunchao Zhang     if (connected) {
530f659e5c7SJunchao Zhang       esf_ranks[p]       = ranks[i];
531f659e5c7SJunchao Zhang       esf_roffset[p + 1] = q;
532f659e5c7SJunchao Zhang       p++;
533f659e5c7SJunchao Zhang     }
534f659e5c7SJunchao Zhang   }
535f659e5c7SJunchao Zhang 
536f659e5c7SJunchao Zhang   /* SetGraph internally resets the SF, so we only set its fields after the call */
5379566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(esf, nroots, esf_nleaves, new_ilocal, PETSC_OWN_POINTER, new_iremote, PETSC_OWN_POINTER));
538f659e5c7SJunchao Zhang   esf->nranks    = esf_nranks;
539f659e5c7SJunchao Zhang   esf->ndranks   = esf_ndranks;
540f659e5c7SJunchao Zhang   esf->ranks     = esf_ranks;
541f659e5c7SJunchao Zhang   esf->roffset   = esf_roffset;
542f659e5c7SJunchao Zhang   esf->rmine     = esf_rmine;
543f659e5c7SJunchao Zhang   esf->rremote   = esf_rremote;
544cd620004SJunchao Zhang   esf->nleafreqs = esf_nranks - esf_ndranks;
545f659e5c7SJunchao Zhang 
546f659e5c7SJunchao Zhang   /* Set up the incoming communication (i.e., recv info) stored in esf->data, which is usually done by PetscSFSetUp_Basic */
547f659e5c7SJunchao Zhang   bas = (PetscSF_Basic *)esf->data;
5489566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootInfo_Basic(sf, &niranks, &ndiranks, &iranks, &ioffset, &irootloc)); /* Get recv info */
549f659e5c7SJunchao Zhang   /* Embedded sf always has simpler communication than the original one. We might allocate longer arrays than needed here. But we
550cd620004SJunchao Zhang      we do not care since these arrays are usually short. The benefit is we can fill these arrays by just parsing irootloc once.
551f659e5c7SJunchao Zhang    */
5529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(niranks, &bas->iranks, niranks + 1, &bas->ioffset));
5539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(ioffset[niranks], &bas->irootloc));
554f659e5c7SJunchao Zhang   bas->niranks = bas->ndiranks = bas->ioffset[0] = 0;
555f659e5c7SJunchao Zhang   p                                              = 0; /* Counter for connected leaf ranks */
556f659e5c7SJunchao Zhang   q                                              = 0; /* Counter for connected roots */
5576497c311SBarry Smith   for (PetscMPIInt i = 0; i < niranks; i++) {
558f659e5c7SJunchao Zhang     connected = PETSC_FALSE; /* Is the current process still connected to this remote leaf rank? */
559f659e5c7SJunchao Zhang     for (j = ioffset[i]; j < ioffset[i + 1]; j++) {
560cd620004SJunchao Zhang       if (rootdata[irootloc[j]]) {
561f659e5c7SJunchao Zhang         bas->irootloc[q++] = irootloc[j];
562f659e5c7SJunchao Zhang         connected          = PETSC_TRUE;
563f659e5c7SJunchao Zhang       }
564f659e5c7SJunchao Zhang     }
565f659e5c7SJunchao Zhang     if (connected) {
566f659e5c7SJunchao Zhang       bas->niranks++;
567f659e5c7SJunchao Zhang       if (i < ndiranks) bas->ndiranks++; /* Note that order of ranks (including distinguished ranks) is kept */
568f659e5c7SJunchao Zhang       bas->iranks[p]      = iranks[i];
569f659e5c7SJunchao Zhang       bas->ioffset[p + 1] = q;
570f659e5c7SJunchao Zhang       p++;
571f659e5c7SJunchao Zhang     }
572f659e5c7SJunchao Zhang   }
573f659e5c7SJunchao Zhang   bas->itotal     = q;
574cd620004SJunchao Zhang   bas->nrootreqs  = bas->niranks - bas->ndiranks;
575cd620004SJunchao Zhang   esf->persistent = PETSC_TRUE;
576cd620004SJunchao Zhang   /* Setup packing related fields */
5779566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUpPackFields(esf));
578f659e5c7SJunchao Zhang 
57920c24465SJunchao Zhang   /* Copy from PetscSFSetUp(), since this method wants to skip PetscSFSetUp(). */
58020c24465SJunchao Zhang #if defined(PETSC_HAVE_CUDA)
58120c24465SJunchao Zhang   if (esf->backend == PETSCSF_BACKEND_CUDA) {
58271438e86SJunchao Zhang     esf->ops->Malloc = PetscSFMalloc_CUDA;
58371438e86SJunchao Zhang     esf->ops->Free   = PetscSFFree_CUDA;
58420c24465SJunchao Zhang   }
58520c24465SJunchao Zhang #endif
58620c24465SJunchao Zhang 
58759af0bd3SScott Kruger #if defined(PETSC_HAVE_HIP)
58859af0bd3SScott Kruger   /* TODO: Needs debugging */
58959af0bd3SScott Kruger   if (esf->backend == PETSCSF_BACKEND_HIP) {
59059af0bd3SScott Kruger     esf->ops->Malloc = PetscSFMalloc_HIP;
59159af0bd3SScott Kruger     esf->ops->Free   = PetscSFFree_HIP;
59259af0bd3SScott Kruger   }
59359af0bd3SScott Kruger #endif
59459af0bd3SScott Kruger 
59520c24465SJunchao Zhang #if defined(PETSC_HAVE_KOKKOS)
59620c24465SJunchao Zhang   if (esf->backend == PETSCSF_BACKEND_KOKKOS) {
59720c24465SJunchao Zhang     esf->ops->Malloc = PetscSFMalloc_Kokkos;
59820c24465SJunchao Zhang     esf->ops->Free   = PetscSFFree_Kokkos;
59920c24465SJunchao Zhang   }
60020c24465SJunchao Zhang #endif
601f659e5c7SJunchao Zhang   esf->setupcalled = PETSC_TRUE; /* We have done setup ourselves! */
6029566063dSJacob Faibussowitsch   PetscCall(PetscFree2(rootdata, leafmem));
603f659e5c7SJunchao Zhang   *newsf = esf;
6043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
605f659e5c7SJunchao Zhang }
606f659e5c7SJunchao Zhang 
PetscSFCreate_Basic(PetscSF sf)607d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode PetscSFCreate_Basic(PetscSF sf)
608d71ae5a4SJacob Faibussowitsch {
60940e23c03SJunchao Zhang   PetscSF_Basic *dat;
61095fce210SBarry Smith 
61195fce210SBarry Smith   PetscFunctionBegin;
61295fce210SBarry Smith   sf->ops->SetUp                = PetscSFSetUp_Basic;
61395fce210SBarry Smith   sf->ops->Reset                = PetscSFReset_Basic;
61495fce210SBarry Smith   sf->ops->Destroy              = PetscSFDestroy_Basic;
61595fce210SBarry Smith   sf->ops->View                 = PetscSFView_Basic;
616ad227feaSJunchao Zhang   sf->ops->BcastBegin           = PetscSFBcastBegin_Basic;
617ad227feaSJunchao Zhang   sf->ops->BcastEnd             = PetscSFBcastEnd_Basic;
61895fce210SBarry Smith   sf->ops->ReduceBegin          = PetscSFReduceBegin_Basic;
61995fce210SBarry Smith   sf->ops->ReduceEnd            = PetscSFReduceEnd_Basic;
62095fce210SBarry Smith   sf->ops->FetchAndOpBegin      = PetscSFFetchAndOpBegin_Basic;
62195fce210SBarry Smith   sf->ops->FetchAndOpEnd        = PetscSFFetchAndOpEnd_Basic;
6228750ddebSJunchao Zhang   sf->ops->GetLeafRanks         = PetscSFGetLeafRanks_Basic;
62372502a1fSJunchao Zhang   sf->ops->CreateEmbeddedRootSF = PetscSFCreateEmbeddedRootSF_Basic;
624f5d27ee7SJunchao Zhang   sf->ops->SetCommunicationOps  = PetscSFSetCommunicationOps_Basic;
62595fce210SBarry Smith 
6266677b1c1SJunchao Zhang   sf->persistent = PETSC_TRUE; // currently SFBASIC always uses persistent send/recv
6276677b1c1SJunchao Zhang   sf->collective = PETSC_FALSE;
6286677b1c1SJunchao Zhang 
6294dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&dat));
63040e23c03SJunchao Zhang   sf->data = (void *)dat;
6313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
63295fce210SBarry Smith }
633