xref: /petsc/src/vec/is/sf/impls/basic/neighbor/sfneighbor.c (revision d2fd7bfc6f0fd2e1d083decbb7cc7d77e16824f0)
1 #include <../src/vec/is/sf/impls/basic/sfpack.h>
2 #include <../src/vec/is/sf/impls/basic/sfbasic.h>
3 
4 #if defined(PETSC_HAVE_MPI_NEIGHBORHOOD_COLLECTIVES)
5 
6 typedef struct {
7   SFBASICHEADER;
8   MPI_Comm      comms[2];       /* Communicators with distributed topology in both directions */
9   PetscBool     initialized[2]; /* Are the two communicators initialized? */
10   PetscMPIInt   *rootdispls,*rootcounts,*leafdispls,*leafcounts; /* displs/counts for non-distinguished ranks */
11   PetscInt      rootdegree,leafdegree; /* Number of non-distinguished root/leaf ranks, equal to outdegree or indegree in neigborhood collectives, depending on PetscSFDirection */
12 } PetscSF_Neighbor;
13 
14 /*===================================================================================*/
15 /*              Internal utility routines                                            */
16 /*===================================================================================*/
17 
18 /* Get the communicator with distributed graph topology, which is not cheap to build so we do it on demand (instead of at PetscSFSetUp time) */
19 static PetscErrorCode PetscSFGetDistComm_Neighbor(PetscSF sf,PetscSFDirection direction,MPI_Comm *distcomm)
20 {
21   PetscErrorCode    ierr;
22   PetscSF_Neighbor  *dat = (PetscSF_Neighbor*)sf->data;
23   PetscInt          nrootranks,ndrootranks,nleafranks,ndleafranks;
24   const PetscMPIInt *rootranks,*leafranks;
25   MPI_Comm          comm;
26 
27   PetscFunctionBegin;
28   ierr = PetscSFGetRootInfo_Basic(sf,&nrootranks,&ndrootranks,&rootranks,NULL,NULL);CHKERRQ(ierr);      /* Which ranks will access my roots (I am a destination) */
29   ierr = PetscSFGetLeafInfo_Basic(sf,&nleafranks,&ndleafranks,&leafranks,NULL,NULL,NULL);CHKERRQ(ierr); /* My leaves will access whose roots (I am a source) */
30 
31   if (!dat->initialized[direction]) {
32     const PetscMPIInt indegree  = nrootranks-ndrootranks,*sources      = rootranks+ndrootranks;
33     const PetscMPIInt outdegree = nleafranks-ndleafranks,*destinations = leafranks+ndleafranks;
34     MPI_Comm          *mycomm   = &dat->comms[direction];
35     ierr = PetscObjectGetComm((PetscObject)sf,&comm);CHKERRQ(ierr);
36     if (direction == PETSCSF_LEAF2ROOT_REDUCE) {
37       ierr = MPI_Dist_graph_create_adjacent(comm,indegree,sources,dat->rootcounts/*src weights*/,outdegree,destinations,dat->leafcounts/*dest weights*/,MPI_INFO_NULL,1/*reorder*/,mycomm);CHKERRQ(ierr);
38     } else { /* PETSCSF_ROOT2LEAF_BCAST, reverse src & dest */
39       ierr = MPI_Dist_graph_create_adjacent(comm,outdegree,destinations,dat->leafcounts/*src weights*/,indegree,sources,dat->rootcounts/*dest weights*/,MPI_INFO_NULL,1/*reorder*/,mycomm);CHKERRQ(ierr);
40     }
41     dat->initialized[direction] = PETSC_TRUE;
42   }
43   *distcomm = dat->comms[direction];
44   PetscFunctionReturn(0);
45 }
46 
47 static PetscErrorCode PetscSFPackGet_Neighbor(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,const void *rootdata,PetscMemType leafmtype,const void *leafdata,PetscSFPack *mylink)
48 {
49   PetscErrorCode       ierr;
50 
51   PetscFunctionBegin;
52   ierr = PetscSFPackGet_Basic_Common(sf,unit,rootmtype,rootdata,leafmtype,leafdata,1/*nrootreqs*/,1/*nleafreqs*/,mylink);CHKERRQ(ierr);
53   PetscFunctionReturn(0);
54 }
55 
56 /*===================================================================================*/
57 /*              Implementations of SF public APIs                                    */
58 /*===================================================================================*/
59 static PetscErrorCode PetscSFSetUp_Neighbor(PetscSF sf)
60 {
61   PetscErrorCode   ierr;
62   PetscSF_Neighbor *dat = (PetscSF_Neighbor*)sf->data;
63   PetscInt         i,j,nrootranks,ndrootranks,nleafranks,ndleafranks;
64   const PetscInt   *rootoffset,*leafoffset;
65   PetscMPIInt      m,n;
66 
67   PetscFunctionBegin;
68   ierr = PetscSFSetUp_Basic(sf);CHKERRQ(ierr);
69   ierr = PetscSFGetRootInfo_Basic(sf,&nrootranks,&ndrootranks,NULL,&rootoffset,NULL);CHKERRQ(ierr);
70   ierr = PetscSFGetLeafInfo_Basic(sf,&nleafranks,&ndleafranks,NULL,&leafoffset,NULL,NULL);CHKERRQ(ierr);
71 
72   dat->rootdegree = nrootranks-ndrootranks;
73   dat->leafdegree = nleafranks-ndleafranks;
74 
75   /* Only setup MPI displs/counts for non-distinguished ranks. Distinguished ranks use shared memory */
76   ierr = PetscMalloc4(dat->rootdegree,&dat->rootdispls,dat->rootdegree,&dat->rootcounts,dat->leafdegree,&dat->leafdispls,dat->leafdegree,&dat->leafcounts);CHKERRQ(ierr);
77   for (i=ndrootranks,j=0; i<nrootranks; i++,j++) {
78     ierr = PetscMPIIntCast(rootoffset[i]-rootoffset[ndrootranks],&m);CHKERRQ(ierr); dat->rootdispls[j] = m;
79     ierr = PetscMPIIntCast(rootoffset[i+1]-rootoffset[i],        &n);CHKERRQ(ierr); dat->rootcounts[j] = n;
80   }
81 
82   for (i=ndleafranks,j=0; i<nleafranks; i++,j++) {
83     ierr = PetscMPIIntCast(leafoffset[i]-leafoffset[ndleafranks],&m);CHKERRQ(ierr); dat->leafdispls[j] = m;
84     ierr = PetscMPIIntCast(leafoffset[i+1]-leafoffset[i],        &n);CHKERRQ(ierr); dat->leafcounts[j] = n;
85   }
86   PetscFunctionReturn(0);
87 }
88 
89 static PetscErrorCode PetscSFReset_Neighbor(PetscSF sf)
90 {
91   PetscErrorCode       ierr;
92   PetscInt             i;
93   PetscSF_Neighbor     *dat = (PetscSF_Neighbor*)sf->data;
94 
95   PetscFunctionBegin;
96   if (dat->inuse) SETERRQ(PetscObjectComm((PetscObject)sf),PETSC_ERR_ARG_WRONGSTATE,"Outstanding operation has not been completed");
97   ierr = PetscFree4(dat->rootdispls,dat->rootcounts,dat->leafdispls,dat->leafcounts);CHKERRQ(ierr);
98   for (i=0; i<2; i++) {
99     if (dat->initialized[i]) {
100       ierr = MPI_Comm_free(&dat->comms[i]);CHKERRQ(ierr);
101       dat->initialized[i] = PETSC_FALSE;
102     }
103   }
104   ierr = PetscSFReset_Basic(sf);CHKERRQ(ierr); /* Common part */
105   PetscFunctionReturn(0);
106 }
107 
108 static PetscErrorCode PetscSFDestroy_Neighbor(PetscSF sf)
109 {
110   PetscErrorCode ierr;
111 
112   PetscFunctionBegin;
113   ierr = PetscSFReset_Neighbor(sf);CHKERRQ(ierr);
114   ierr = PetscFree(sf->data);CHKERRQ(ierr);
115   PetscFunctionReturn(0);
116 }
117 
118 static PetscErrorCode PetscSFBcastAndOpBegin_Neighbor(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,const void *rootdata,PetscMemType leafmtype,void *leafdata,MPI_Op op)
119 {
120   PetscErrorCode       ierr;
121   PetscSFPack          link;
122   const PetscInt       *rootloc = NULL;
123   PetscSF_Neighbor     *dat = (PetscSF_Neighbor*)sf->data;
124   MPI_Comm             distcomm;
125 
126   PetscFunctionBegin;
127   ierr = PetscSFPackGet_Neighbor(sf,unit,rootmtype,rootdata,leafmtype,leafdata,&link);CHKERRQ(ierr);
128   ierr = PetscSFGetRootIndicesWithMemType_Basic(sf,rootmtype,&rootloc);CHKERRQ(ierr);
129   ierr = PetscSFPackRootData(sf,link,rootloc,rootdata,PETSC_TRUE);CHKERRQ(ierr);
130 
131   /* Do neighborhood alltoallv for non-distinguished ranks */
132   ierr = PetscSFGetDistComm_Neighbor(sf,PETSCSF_ROOT2LEAF_BCAST,&distcomm);CHKERRQ(ierr);
133   ierr = MPI_Start_ineighbor_alltoallv(dat->rootdegree,dat->leafdegree,link->rootbuf[rootmtype],dat->rootcounts,dat->rootdispls,unit,link->leafbuf[leafmtype],dat->leafcounts,dat->leafdispls,unit,distcomm,link->rootreqs[PETSCSF_ROOT2LEAF_BCAST][rootmtype]);CHKERRQ(ierr);
134   if (rootmtype != leafmtype) {ierr = PetscMemcpyWithMemType(leafmtype,rootmtype,link->selfbuf[leafmtype],link->selfbuf[rootmtype],link->selfbuflen*link->unitbytes);CHKERRQ(ierr);}
135   PetscFunctionReturn(0);
136 }
137 
138 static PetscErrorCode PetscSFReduceBegin_Neighbor(PetscSF sf,MPI_Datatype unit,PetscMemType leafmtype,const void *leafdata,PetscMemType rootmtype,void *rootdata,MPI_Op op)
139 {
140   PetscErrorCode       ierr;
141   const PetscInt       *leafloc = NULL;
142   PetscSFPack          link;
143   PetscSF_Neighbor     *dat = (PetscSF_Neighbor*)sf->data;
144   MPI_Comm             distcomm = MPI_COMM_NULL;
145 
146   PetscFunctionBegin;
147   ierr = PetscSFGetLeafIndicesWithMemType_Basic(sf,leafmtype,&leafloc);CHKERRQ(ierr);
148   ierr = PetscSFPackGet_Neighbor(sf,unit,rootmtype,rootdata,leafmtype,leafdata,&link);CHKERRQ(ierr);
149   ierr = PetscSFPackLeafData(sf,link,leafloc,leafdata,PETSC_TRUE);CHKERRQ(ierr);
150 
151   /* Do neighborhood alltoallv for non-distinguished ranks */
152   ierr = PetscSFGetDistComm_Neighbor(sf,PETSCSF_LEAF2ROOT_REDUCE,&distcomm);CHKERRQ(ierr);
153   ierr = MPI_Start_ineighbor_alltoallv(dat->leafdegree,dat->rootdegree,link->leafbuf[leafmtype],dat->leafcounts,dat->leafdispls,unit,link->rootbuf[rootmtype],dat->rootcounts,dat->rootdispls,unit,distcomm,link->rootreqs[PETSCSF_LEAF2ROOT_REDUCE][rootmtype]);CHKERRQ(ierr);
154   if (rootmtype != leafmtype) {ierr = PetscMemcpyWithMemType(rootmtype,leafmtype,link->selfbuf[rootmtype],link->selfbuf[leafmtype],link->selfbuflen*link->unitbytes);CHKERRQ(ierr);}
155   PetscFunctionReturn(0);
156 }
157 
158 static PetscErrorCode PetscSFFetchAndOpEnd_Neighbor(PetscSF sf,MPI_Datatype unit,PetscMemType rootmtype,void *rootdata,PetscMemType leafmtype,const void *leafdata,void *leafupdate,MPI_Op op)
159 {
160   PetscErrorCode       ierr;
161   PetscSFPack          link;
162   const PetscInt       *rootloc = NULL,*leafloc = NULL;
163   PetscSF_Neighbor     *dat = (PetscSF_Neighbor*)sf->data;
164   MPI_Comm             distcomm = MPI_COMM_NULL;
165 
166   PetscFunctionBegin;
167   ierr = PetscSFPackGetInUse(sf,unit,rootdata,leafdata,PETSC_OWN_POINTER,&link);CHKERRQ(ierr);
168   ierr = PetscSFPackWaitall_Basic(link,PETSCSF_LEAF2ROOT_REDUCE);CHKERRQ(ierr);
169   ierr = PetscSFGetRootIndicesWithMemType_Basic(sf,rootmtype,&rootloc);CHKERRQ(ierr);
170   ierr = PetscSFGetLeafIndicesWithMemType_Basic(sf,leafmtype,&leafloc);CHKERRQ(ierr);
171   /* Process local fetch-and-op */
172   ierr = PetscSFFetchAndOpRootData(sf,link,rootloc,rootdata,op,PETSC_TRUE);CHKERRQ(ierr);
173 
174   /* Bcast the updated root buffer back to leaves */
175   ierr = PetscSFGetDistComm_Neighbor(sf,PETSCSF_ROOT2LEAF_BCAST,&distcomm);CHKERRQ(ierr);
176   ierr = MPI_Start_neighbor_alltoallv(dat->rootdegree,dat->leafdegree,link->rootbuf[rootmtype],dat->rootcounts,dat->rootdispls,unit,link->leafbuf[leafmtype],dat->leafcounts,dat->leafdispls,unit,distcomm);CHKERRQ(ierr);
177   if (rootmtype != leafmtype) {ierr = PetscMemcpyWithMemType(leafmtype,rootmtype,link->selfbuf[leafmtype],link->selfbuf[rootmtype],link->selfbuflen*link->unitbytes);CHKERRQ(ierr);}
178   ierr = PetscSFUnpackAndOpLeafData(sf,link,leafloc,leafupdate,MPIU_REPLACE,PETSC_TRUE);CHKERRQ(ierr);
179   ierr = PetscSFPackReclaim(sf,&link);CHKERRQ(ierr);
180   PetscFunctionReturn(0);
181 }
182 
183 PETSC_INTERN PetscErrorCode PetscSFCreate_Neighbor(PetscSF sf)
184 {
185   PetscErrorCode   ierr;
186   PetscSF_Neighbor *dat;
187 
188   PetscFunctionBegin;
189   sf->ops->CreateEmbeddedSF     = PetscSFCreateEmbeddedSF_Basic;
190   sf->ops->CreateEmbeddedLeafSF = PetscSFCreateEmbeddedLeafSF_Basic;
191   sf->ops->BcastAndOpEnd        = PetscSFBcastAndOpEnd_Basic;
192   sf->ops->ReduceEnd            = PetscSFReduceEnd_Basic;
193   sf->ops->FetchAndOpBegin      = PetscSFFetchAndOpBegin_Basic;
194   sf->ops->GetLeafRanks         = PetscSFGetLeafRanks_Basic;
195   sf->ops->View                 = PetscSFView_Basic;
196 
197   sf->ops->SetUp                = PetscSFSetUp_Neighbor;
198   sf->ops->Reset                = PetscSFReset_Neighbor;
199   sf->ops->Destroy              = PetscSFDestroy_Neighbor;
200   sf->ops->BcastAndOpBegin      = PetscSFBcastAndOpBegin_Neighbor;
201   sf->ops->ReduceBegin          = PetscSFReduceBegin_Neighbor;
202   sf->ops->FetchAndOpEnd        = PetscSFFetchAndOpEnd_Neighbor;
203 
204   ierr = PetscNewLog(sf,&dat);CHKERRQ(ierr);
205   sf->data = (void*)dat;
206   PetscFunctionReturn(0);
207 }
208 #endif
209