xref: /petsc/src/vec/is/sf/impls/window/sfwindow.c (revision fef353a4b7d6ea90a49c0912b64f64e31ef80aa8)
1af0996ceSBarry Smith #include <petsc/private/sfimpl.h> /*I "petscsf.h" I*/
295fce210SBarry Smith 
395fce210SBarry Smith typedef struct _n_PetscSFDataLink *PetscSFDataLink;
495fce210SBarry Smith typedef struct _n_PetscSFWinLink  *PetscSFWinLink;
595fce210SBarry Smith 
695fce210SBarry Smith typedef struct {
795fce210SBarry Smith   PetscSFWindowSyncType   sync;   /* FENCE, LOCK, or ACTIVE synchronization */
85b0d146aSStefano Zampini   PetscSFDataLink         link;   /* List of MPI data types, lazily constructed for each data type */
995fce210SBarry Smith   PetscSFWinLink          wins;   /* List of active windows */
105b0d146aSStefano Zampini   PetscSFWindowFlavorType flavor; /* Current PETSCSF_WINDOW_FLAVOR_ */
115b0d146aSStefano Zampini   PetscSF                 dynsf;
125b0d146aSStefano Zampini   MPI_Info                info;
1395fce210SBarry Smith } PetscSF_Window;
1495fce210SBarry Smith 
1595fce210SBarry Smith struct _n_PetscSFDataLink {
1695fce210SBarry Smith   MPI_Datatype    unit;
1795fce210SBarry Smith   MPI_Datatype   *mine;
1895fce210SBarry Smith   MPI_Datatype   *remote;
1995fce210SBarry Smith   PetscSFDataLink next;
2095fce210SBarry Smith };
2195fce210SBarry Smith 
2295fce210SBarry Smith struct _n_PetscSFWinLink {
2395fce210SBarry Smith   PetscBool               inuse;
2495fce210SBarry Smith   size_t                  bytes;
2595fce210SBarry Smith   void                   *addr;
265b0d146aSStefano Zampini   void                   *paddr;
2795fce210SBarry Smith   MPI_Win                 win;
28684a874aSStefano Zampini   MPI_Request            *reqs;
295b0d146aSStefano Zampini   PetscSFWindowFlavorType flavor;
305b0d146aSStefano Zampini   MPI_Aint               *dyn_target_addr;
3195fce210SBarry Smith   PetscBool               epoch;
3295fce210SBarry Smith   PetscSFWinLink          next;
3395fce210SBarry Smith };
3495fce210SBarry Smith 
354c8fdceaSLisandro Dalcin const char *const PetscSFWindowSyncTypes[]   = {"FENCE", "LOCK", "ACTIVE", "PetscSFWindowSyncType", "PETSCSF_WINDOW_SYNC_", NULL};
364c8fdceaSLisandro Dalcin const char *const PetscSFWindowFlavorTypes[] = {"CREATE", "DYNAMIC", "ALLOCATE", "SHARED", "PetscSFWindowFlavorType", "PETSCSF_WINDOW_FLAVOR_", NULL};
3795fce210SBarry Smith 
38820f2d46SBarry Smith /* Built-in MPI_Ops act elementwise inside MPI_Accumulate, but cannot be used with composite types inside collectives (MPI_Allreduce) */
39d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowOpTranslate(MPI_Op *op)
40d71ae5a4SJacob Faibussowitsch {
4195fce210SBarry Smith   PetscFunctionBegin;
4295fce210SBarry Smith   if (*op == MPIU_SUM) *op = MPI_SUM;
4395fce210SBarry Smith   else if (*op == MPIU_MAX) *op = MPI_MAX;
4495fce210SBarry Smith   else if (*op == MPIU_MIN) *op = MPI_MIN;
4595fce210SBarry Smith   PetscFunctionReturn(0);
4695fce210SBarry Smith }
4795fce210SBarry Smith 
4895fce210SBarry Smith /*@C
4995fce210SBarry Smith    PetscSFWindowGetDataTypes - gets composite local and remote data types for each rank
5095fce210SBarry Smith 
5195fce210SBarry Smith    Not Collective
5295fce210SBarry Smith 
534165533cSJose E. Roman    Input Parameters:
54cab54364SBarry Smith +  sf - star forest of type `PETSCSFWINDOW`
5595fce210SBarry Smith -  unit - data type for each node
5695fce210SBarry Smith 
574165533cSJose E. Roman    Output Parameters:
5895fce210SBarry Smith +  localtypes - types describing part of local leaf buffer referencing each remote rank
5995fce210SBarry Smith -  remotetypes - types describing part of remote root buffer referenced for each remote rank
6095fce210SBarry Smith 
6195fce210SBarry Smith    Level: developer
6295fce210SBarry Smith 
63cab54364SBarry Smith .seealso: `PetscSF`, `PETSCSFWINDOW`, `PetscSFSetGraph()`, `PetscSFView()`
6495fce210SBarry Smith @*/
65d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowGetDataTypes(PetscSF sf, MPI_Datatype unit, const MPI_Datatype **localtypes, const MPI_Datatype **remotetypes)
66d71ae5a4SJacob Faibussowitsch {
6795fce210SBarry Smith   PetscSF_Window    *w = (PetscSF_Window *)sf->data;
6895fce210SBarry Smith   PetscSFDataLink    link;
6995fce210SBarry Smith   PetscInt           i, nranks;
7095fce210SBarry Smith   const PetscInt    *roffset, *rmine, *rremote;
7195fce210SBarry Smith   const PetscMPIInt *ranks;
7295fce210SBarry Smith 
7395fce210SBarry Smith   PetscFunctionBegin;
7495fce210SBarry Smith   /* Look for types in cache */
7595fce210SBarry Smith   for (link = w->link; link; link = link->next) {
7695fce210SBarry Smith     PetscBool match;
779566063dSJacob Faibussowitsch     PetscCall(MPIPetsc_Type_compare(unit, link->unit, &match));
7895fce210SBarry Smith     if (match) {
7995fce210SBarry Smith       *localtypes  = link->mine;
8095fce210SBarry Smith       *remotetypes = link->remote;
8195fce210SBarry Smith       PetscFunctionReturn(0);
8295fce210SBarry Smith     }
8395fce210SBarry Smith   }
8495fce210SBarry Smith 
8595fce210SBarry Smith   /* Create new composite types for each send rank */
869566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, &roffset, &rmine, &rremote));
879566063dSJacob Faibussowitsch   PetscCall(PetscNew(&link));
889566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_dup(unit, &link->unit));
899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(nranks, &link->mine, nranks, &link->remote));
9095fce210SBarry Smith   for (i = 0; i < nranks; i++) {
915b0d146aSStefano Zampini     PetscInt     rcount = roffset[i + 1] - roffset[i];
9295fce210SBarry Smith     PetscMPIInt *rmine, *rremote;
9395fce210SBarry Smith #if !defined(PETSC_USE_64BIT_INDICES)
9495fce210SBarry Smith     rmine   = sf->rmine + sf->roffset[i];
9595fce210SBarry Smith     rremote = sf->rremote + sf->roffset[i];
9695fce210SBarry Smith #else
9795fce210SBarry Smith     PetscInt j;
989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(rcount, &rmine, rcount, &rremote));
9995fce210SBarry Smith     for (j = 0; j < rcount; j++) {
1009566063dSJacob Faibussowitsch       PetscCall(PetscMPIIntCast(sf->rmine[sf->roffset[i] + j], rmine + j));
1019566063dSJacob Faibussowitsch       PetscCall(PetscMPIIntCast(sf->rremote[sf->roffset[i] + j], rremote + j));
10295fce210SBarry Smith     }
10395fce210SBarry Smith #endif
1045b0d146aSStefano Zampini 
1059566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_indexed_block(rcount, 1, rmine, link->unit, &link->mine[i]));
1069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_create_indexed_block(rcount, 1, rremote, link->unit, &link->remote[i]));
10795fce210SBarry Smith #if defined(PETSC_USE_64BIT_INDICES)
1089566063dSJacob Faibussowitsch     PetscCall(PetscFree2(rmine, rremote));
10995fce210SBarry Smith #endif
1109566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&link->mine[i]));
1119566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_commit(&link->remote[i]));
11295fce210SBarry Smith   }
11395fce210SBarry Smith   link->next = w->link;
11495fce210SBarry Smith   w->link    = link;
11595fce210SBarry Smith 
11695fce210SBarry Smith   *localtypes  = link->mine;
11795fce210SBarry Smith   *remotetypes = link->remote;
11895fce210SBarry Smith   PetscFunctionReturn(0);
11995fce210SBarry Smith }
12095fce210SBarry Smith 
12195fce210SBarry Smith /*@C
122cab54364SBarry Smith    PetscSFWindowSetFlavorType - Set flavor type for `MPI_Win` creation
1235b0d146aSStefano Zampini 
1245b0d146aSStefano Zampini    Logically Collective
1255b0d146aSStefano Zampini 
1264165533cSJose E. Roman    Input Parameters:
127cab54364SBarry Smith +  sf - star forest for communication of type `PETSCSFWINDOW`
1285b0d146aSStefano Zampini -  flavor - flavor type
1295b0d146aSStefano Zampini 
1305b0d146aSStefano Zampini    Options Database Key:
131cab54364SBarry Smith .  -sf_window_flavor <flavor> - sets the flavor type CREATE, DYNAMIC, ALLOCATE or SHARED (see `PetscSFWindowFlavorType`)
1325b0d146aSStefano Zampini 
1335b0d146aSStefano Zampini    Level: advanced
1345b0d146aSStefano Zampini 
135cab54364SBarry Smith    Notes:
136cab54364SBarry Smith    Windows reuse follows these rules:
137cab54364SBarry Smith .vb
1385b0d146aSStefano Zampini      PETSCSF_WINDOW_FLAVOR_CREATE: creates a new window every time, uses MPI_Win_create
1395b0d146aSStefano Zampini 
1405b0d146aSStefano Zampini      PETSCSF_WINDOW_FLAVOR_DYNAMIC: uses MPI_Win_create_dynamic/MPI_Win_attach and tries to reuse windows by comparing the root array. Intended to be used on repeated applications of the same SF, e.g.
1415b0d146aSStefano Zampini        for i=1 to K
1425b0d146aSStefano Zampini          PetscSFOperationBegin(rootdata1,leafdata_whatever);
1435b0d146aSStefano Zampini          PetscSFOperationEnd(rootdata1,leafdata_whatever);
1445b0d146aSStefano Zampini          ...
1455b0d146aSStefano Zampini          PetscSFOperationBegin(rootdataN,leafdata_whatever);
1465b0d146aSStefano Zampini          PetscSFOperationEnd(rootdataN,leafdata_whatever);
1475b0d146aSStefano Zampini        endfor
1485b0d146aSStefano Zampini        The following pattern will instead raise an error
1495b0d146aSStefano Zampini          PetscSFOperationBegin(rootdata1,leafdata_whatever);
1505b0d146aSStefano Zampini          PetscSFOperationEnd(rootdata1,leafdata_whatever);
1515b0d146aSStefano Zampini          PetscSFOperationBegin(rank ? rootdata1 : rootdata2,leafdata_whatever);
1525b0d146aSStefano Zampini          PetscSFOperationEnd(rank ? rootdata1 : rootdata2,leafdata_whatever);
1535b0d146aSStefano Zampini 
1545b0d146aSStefano Zampini      PETSCSF_WINDOW_FLAVOR_ALLOCATE: uses MPI_Win_allocate, reuses any pre-existing window which fits the data and it is not in use
1555b0d146aSStefano Zampini 
1565b0d146aSStefano Zampini      PETSCSF_WINDOW_FLAVOR_SHARED: uses MPI_Win_allocate_shared, reusage policy as for PETSCSF_WINDOW_FLAVOR_ALLOCATE
157cab54364SBarry Smith .ve
1585b0d146aSStefano Zampini 
159cab54364SBarry Smith .seealso:  `PetscSF`, `PETSCSFWINDOW`, `PetscSFSetFromOptions()`, `PetscSFWindowGetFlavorType()`
1605b0d146aSStefano Zampini @*/
161d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowSetFlavorType(PetscSF sf, PetscSFWindowFlavorType flavor)
162d71ae5a4SJacob Faibussowitsch {
1635b0d146aSStefano Zampini   PetscFunctionBegin;
1645b0d146aSStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
1655b0d146aSStefano Zampini   PetscValidLogicalCollectiveEnum(sf, flavor, 2);
166cac4c232SBarry Smith   PetscTryMethod(sf, "PetscSFWindowSetFlavorType_C", (PetscSF, PetscSFWindowFlavorType), (sf, flavor));
1675b0d146aSStefano Zampini   PetscFunctionReturn(0);
1685b0d146aSStefano Zampini }
1695b0d146aSStefano Zampini 
170d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowSetFlavorType_Window(PetscSF sf, PetscSFWindowFlavorType flavor)
171d71ae5a4SJacob Faibussowitsch {
1725b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
1735b0d146aSStefano Zampini 
1745b0d146aSStefano Zampini   PetscFunctionBegin;
1755b0d146aSStefano Zampini   w->flavor = flavor;
1765b0d146aSStefano Zampini   PetscFunctionReturn(0);
1775b0d146aSStefano Zampini }
1785b0d146aSStefano Zampini 
1795b0d146aSStefano Zampini /*@C
180cab54364SBarry Smith    PetscSFWindowGetFlavorType - Get  `PETSCSFWINDOW` flavor type for `PetscSF` communication
1815b0d146aSStefano Zampini 
1825b0d146aSStefano Zampini    Logically Collective
1835b0d146aSStefano Zampini 
1844165533cSJose E. Roman    Input Parameter:
185cab54364SBarry Smith .  sf - star forest for communication of type `PETSCSFWINDOW`
1865b0d146aSStefano Zampini 
1874165533cSJose E. Roman    Output Parameter:
1885b0d146aSStefano Zampini .  flavor - flavor type
1895b0d146aSStefano Zampini 
1905b0d146aSStefano Zampini    Level: advanced
1915b0d146aSStefano Zampini 
192cab54364SBarry Smith .seealso:  `PetscSF`, `PETSCSFWINDOW`, `PetscSFSetFromOptions()`, `PetscSFWindowSetFlavorType()`
1935b0d146aSStefano Zampini @*/
194d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowGetFlavorType(PetscSF sf, PetscSFWindowFlavorType *flavor)
195d71ae5a4SJacob Faibussowitsch {
1965b0d146aSStefano Zampini   PetscFunctionBegin;
1975b0d146aSStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
1985b0d146aSStefano Zampini   PetscValidPointer(flavor, 2);
199cac4c232SBarry Smith   PetscUseMethod(sf, "PetscSFWindowGetFlavorType_C", (PetscSF, PetscSFWindowFlavorType *), (sf, flavor));
2005b0d146aSStefano Zampini   PetscFunctionReturn(0);
2015b0d146aSStefano Zampini }
2025b0d146aSStefano Zampini 
203d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowGetFlavorType_Window(PetscSF sf, PetscSFWindowFlavorType *flavor)
204d71ae5a4SJacob Faibussowitsch {
2055b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
2065b0d146aSStefano Zampini 
2075b0d146aSStefano Zampini   PetscFunctionBegin;
2085b0d146aSStefano Zampini   *flavor = w->flavor;
2095b0d146aSStefano Zampini   PetscFunctionReturn(0);
2105b0d146aSStefano Zampini }
2115b0d146aSStefano Zampini 
2125b0d146aSStefano Zampini /*@C
213cab54364SBarry Smith    PetscSFWindowSetSyncType - Set synchronization type for `PetscSF` communication of type  `PETSCSFWINDOW`
21495fce210SBarry Smith 
21595fce210SBarry Smith    Logically Collective
21695fce210SBarry Smith 
2174165533cSJose E. Roman    Input Parameters:
21895fce210SBarry Smith +  sf - star forest for communication
21995fce210SBarry Smith -  sync - synchronization type
22095fce210SBarry Smith 
22195fce210SBarry Smith    Options Database Key:
222cab54364SBarry Smith .  -sf_window_sync <sync> - sets the synchronization type FENCE, LOCK, or ACTIVE (see `PetscSFWindowSyncType`)
22395fce210SBarry Smith 
22495fce210SBarry Smith    Level: advanced
22595fce210SBarry Smith 
226cab54364SBarry Smith .seealso:  `PetscSF`, `PETSCSFWINDOW`, `PetscSFSetFromOptions()`, `PetscSFWindowGetSyncType()`, `PetscSFWindowSyncType`
22795fce210SBarry Smith @*/
228d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowSetSyncType(PetscSF sf, PetscSFWindowSyncType sync)
229d71ae5a4SJacob Faibussowitsch {
23095fce210SBarry Smith   PetscFunctionBegin;
23195fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
23295fce210SBarry Smith   PetscValidLogicalCollectiveEnum(sf, sync, 2);
233cac4c232SBarry Smith   PetscTryMethod(sf, "PetscSFWindowSetSyncType_C", (PetscSF, PetscSFWindowSyncType), (sf, sync));
23495fce210SBarry Smith   PetscFunctionReturn(0);
23595fce210SBarry Smith }
23695fce210SBarry Smith 
237d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowSetSyncType_Window(PetscSF sf, PetscSFWindowSyncType sync)
238d71ae5a4SJacob Faibussowitsch {
23995fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
24095fce210SBarry Smith 
24195fce210SBarry Smith   PetscFunctionBegin;
24295fce210SBarry Smith   w->sync = sync;
24395fce210SBarry Smith   PetscFunctionReturn(0);
24495fce210SBarry Smith }
24595fce210SBarry Smith 
24695fce210SBarry Smith /*@C
247cab54364SBarry Smith    PetscSFWindowGetSyncType - Get synchronization type for `PetscSF` communication of type `PETSCSFWINDOW`
24895fce210SBarry Smith 
24995fce210SBarry Smith    Logically Collective
25095fce210SBarry Smith 
2514165533cSJose E. Roman    Input Parameter:
25295fce210SBarry Smith .  sf - star forest for communication
25395fce210SBarry Smith 
2544165533cSJose E. Roman    Output Parameter:
25595fce210SBarry Smith .  sync - synchronization type
25695fce210SBarry Smith 
25795fce210SBarry Smith    Level: advanced
25895fce210SBarry Smith 
259cab54364SBarry Smith .seealso: `PetscSF`, `PETSCSFWINDOW`, `PetscSFSetFromOptions()`, `PetscSFWindowSetSyncType()`, `PetscSFWindowSyncType`
26095fce210SBarry Smith @*/
261d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowGetSyncType(PetscSF sf, PetscSFWindowSyncType *sync)
262d71ae5a4SJacob Faibussowitsch {
26395fce210SBarry Smith   PetscFunctionBegin;
26495fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
26595fce210SBarry Smith   PetscValidPointer(sync, 2);
266cac4c232SBarry Smith   PetscUseMethod(sf, "PetscSFWindowGetSyncType_C", (PetscSF, PetscSFWindowSyncType *), (sf, sync));
26795fce210SBarry Smith   PetscFunctionReturn(0);
26895fce210SBarry Smith }
26995fce210SBarry Smith 
270d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowGetSyncType_Window(PetscSF sf, PetscSFWindowSyncType *sync)
271d71ae5a4SJacob Faibussowitsch {
27295fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
27395fce210SBarry Smith 
27495fce210SBarry Smith   PetscFunctionBegin;
27595fce210SBarry Smith   *sync = w->sync;
27695fce210SBarry Smith   PetscFunctionReturn(0);
27795fce210SBarry Smith }
27895fce210SBarry Smith 
27995fce210SBarry Smith /*@C
280cab54364SBarry Smith    PetscSFWindowSetInfo - Set the `MPI_Info` handle that will be used for subsequent windows allocation
2815b0d146aSStefano Zampini 
2825b0d146aSStefano Zampini    Logically Collective
2835b0d146aSStefano Zampini 
2844165533cSJose E. Roman    Input Parameters:
2855b0d146aSStefano Zampini +  sf - star forest for communication
286cab54364SBarry Smith -  info - `MPI_Info` handle
2875b0d146aSStefano Zampini 
2885b0d146aSStefano Zampini    Level: advanced
2895b0d146aSStefano Zampini 
290cab54364SBarry Smith    Note:
291cab54364SBarry Smith    The info handle is duplicated with a call to `MPI_Info_dup()` unless info = `MPI_INFO_NULL`.
2925b0d146aSStefano Zampini 
293cab54364SBarry Smith .seealso: `PetscSF`, `PETSCSFWINDOW`, `PetscSFSetFromOptions()`, `PetscSFWindowGetInfo()`
2945b0d146aSStefano Zampini @*/
295d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowSetInfo(PetscSF sf, MPI_Info info)
296d71ae5a4SJacob Faibussowitsch {
2975b0d146aSStefano Zampini   PetscFunctionBegin;
2985b0d146aSStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
299cac4c232SBarry Smith   PetscTryMethod(sf, "PetscSFWindowSetInfo_C", (PetscSF, MPI_Info), (sf, info));
3005b0d146aSStefano Zampini   PetscFunctionReturn(0);
3015b0d146aSStefano Zampini }
3025b0d146aSStefano Zampini 
303d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowSetInfo_Window(PetscSF sf, MPI_Info info)
304d71ae5a4SJacob Faibussowitsch {
3055b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
3065b0d146aSStefano Zampini 
3075b0d146aSStefano Zampini   PetscFunctionBegin;
30848a46eb9SPierre Jolivet   if (w->info != MPI_INFO_NULL) PetscCallMPI(MPI_Info_free(&w->info));
30948a46eb9SPierre Jolivet   if (info != MPI_INFO_NULL) PetscCallMPI(MPI_Info_dup(info, &w->info));
3105b0d146aSStefano Zampini   PetscFunctionReturn(0);
3115b0d146aSStefano Zampini }
3125b0d146aSStefano Zampini 
3135b0d146aSStefano Zampini /*@C
314cab54364SBarry Smith    PetscSFWindowGetInfo - Get the `MPI_Info` handle used for windows allocation
3155b0d146aSStefano Zampini 
3165b0d146aSStefano Zampini    Logically Collective
3175b0d146aSStefano Zampini 
3184165533cSJose E. Roman    Input Parameter:
3195b0d146aSStefano Zampini .  sf - star forest for communication
3205b0d146aSStefano Zampini 
3214165533cSJose E. Roman    Output Parameter:
322cab54364SBarry Smith .  info - `MPI_Info` handle
3235b0d146aSStefano Zampini 
3245b0d146aSStefano Zampini    Level: advanced
3255b0d146aSStefano Zampini 
326cab54364SBarry Smith    Note:
327cab54364SBarry Smith    If `PetscSFWindowSetInfo()` has not be called, this returns `MPI_INFO_NULL`
3285b0d146aSStefano Zampini 
329cab54364SBarry Smith .seealso: `PetscSF`, `PETSCSFWINDOW`, `PetscSFSetFromOptions()`, `PetscSFWindowSetInfo()`
3305b0d146aSStefano Zampini @*/
331d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowGetInfo(PetscSF sf, MPI_Info *info)
332d71ae5a4SJacob Faibussowitsch {
3335b0d146aSStefano Zampini   PetscFunctionBegin;
3345b0d146aSStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3355b0d146aSStefano Zampini   PetscValidPointer(info, 2);
336cac4c232SBarry Smith   PetscUseMethod(sf, "PetscSFWindowGetInfo_C", (PetscSF, MPI_Info *), (sf, info));
3375b0d146aSStefano Zampini   PetscFunctionReturn(0);
3385b0d146aSStefano Zampini }
3395b0d146aSStefano Zampini 
340d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowGetInfo_Window(PetscSF sf, MPI_Info *info)
341d71ae5a4SJacob Faibussowitsch {
3425b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
3435b0d146aSStefano Zampini 
3445b0d146aSStefano Zampini   PetscFunctionBegin;
3455b0d146aSStefano Zampini   *info = w->info;
3465b0d146aSStefano Zampini   PetscFunctionReturn(0);
3475b0d146aSStefano Zampini }
3485b0d146aSStefano Zampini 
3495b0d146aSStefano Zampini /*
35095fce210SBarry Smith    PetscSFGetWindow - Get a window for use with a given data type
35195fce210SBarry Smith 
352c3339decSBarry Smith    Collective
35395fce210SBarry Smith 
3544165533cSJose E. Roman    Input Parameters:
35595fce210SBarry Smith +  sf - star forest
35695fce210SBarry Smith .  unit - data type
35795fce210SBarry Smith .  array - array to be sent
358cab54364SBarry Smith .  sync - type of synchronization `PetscSFWindowSyncType`
359cab54364SBarry Smith .  epoch - `PETSC_TRUE` to acquire the window and start an epoch, `PETSC_FALSE` to just acquire the window
360cab54364SBarry Smith .  fenceassert - assert parameter for call to `MPI_Win_fence()`, if sync == `PETSCSF_WINDOW_SYNC_FENCE`
361cab54364SBarry Smith .  postassert - assert parameter for call to `MPI_Win_post()`, if sync == `PETSCSF_WINDOW_SYNC_ACTIVE`
362cab54364SBarry Smith -  startassert - assert parameter for call to `MPI_Win_start()`, if sync == `PETSCSF_WINDOW_SYNC_ACTIVE`
36395fce210SBarry Smith 
3644165533cSJose E. Roman    Output Parameters:
365cab54364SBarry Smith +  target_disp - target_disp argument for RMA calls (significative for `PETSCSF_WINDOW_FLAVOR_DYNAMIC` only)
366cab54364SBarry Smith +  reqs - array of requests (significative for sync == `PETSCSF_WINDOW_SYNC_LOCK` only)
367684a874aSStefano Zampini -  win - window
36895fce210SBarry Smith 
36995fce210SBarry Smith    Level: developer
370cab54364SBarry Smith 
371cab54364SBarry Smith .seealso: `PetscSF`, `PETSCSFWINDOW`, `PetscSFGetRootRanks()`, `PetscSFWindowGetDataTypes()`
3725b0d146aSStefano Zampini */
373d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFGetWindow(PetscSF sf, MPI_Datatype unit, void *array, PetscSFWindowSyncType sync, PetscBool epoch, PetscMPIInt fenceassert, PetscMPIInt postassert, PetscMPIInt startassert, const MPI_Aint **target_disp, MPI_Request **reqs, MPI_Win *win)
374d71ae5a4SJacob Faibussowitsch {
37595fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
37695fce210SBarry Smith   MPI_Aint        lb, lb_true, bytes, bytes_true;
37795fce210SBarry Smith   PetscSFWinLink  link;
378d547623eSJunchao Zhang #if defined(PETSC_HAVE_MPI_FEATURE_DYNAMIC_WINDOW)
3795b0d146aSStefano Zampini   MPI_Aint winaddr;
3805b0d146aSStefano Zampini   PetscInt nranks;
381d547623eSJunchao Zhang #endif
3825b0d146aSStefano Zampini   PetscBool reuse = PETSC_FALSE, update = PETSC_FALSE;
3835b0d146aSStefano Zampini   PetscBool dummy[2];
3845b0d146aSStefano Zampini   MPI_Aint  wsize;
38595fce210SBarry Smith 
38695fce210SBarry Smith   PetscFunctionBegin;
3879566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_get_extent(unit, &lb, &bytes));
3889566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_get_true_extent(unit, &lb_true, &bytes_true));
389c9cc58a2SBarry Smith   PetscCheck(lb == 0 && lb_true == 0, PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "No support for unit type with nonzero lower bound, write petsc-maint@mcs.anl.gov if you want this feature");
39008401ef6SPierre Jolivet   PetscCheck(bytes == bytes_true, PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "No support for unit type with modified extent, write petsc-maint@mcs.anl.gov if you want this feature");
3915b0d146aSStefano Zampini   if (w->flavor != PETSCSF_WINDOW_FLAVOR_CREATE) reuse = PETSC_TRUE;
3925b0d146aSStefano Zampini   for (link = w->wins; reuse && link; link = link->next) {
3935b0d146aSStefano Zampini     PetscBool winok = PETSC_FALSE;
3945b0d146aSStefano Zampini     if (w->flavor != link->flavor) continue;
3955b0d146aSStefano Zampini     switch (w->flavor) {
3965b0d146aSStefano Zampini     case PETSCSF_WINDOW_FLAVOR_DYNAMIC: /* check available matching array, error if in use (we additionally check that the matching condition is the same across processes) */
3975b0d146aSStefano Zampini       if (array == link->addr) {
39876bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
3995b0d146aSStefano Zampini           dummy[0] = PETSC_TRUE;
4005b0d146aSStefano Zampini           dummy[1] = PETSC_TRUE;
4019566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, dummy, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)sf)));
4029566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, dummy + 1, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
40308401ef6SPierre Jolivet           PetscCheck(dummy[0] == dummy[1], PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "PETSCSF_WINDOW_FLAVOR_DYNAMIC requires root pointers to be consistently used across the comm. Use PETSCSF_WINDOW_FLAVOR_CREATE or PETSCSF_WINDOW_FLAVOR_ALLOCATE instead");
40476bd3646SJed Brown         }
40528b400f6SJacob Faibussowitsch         PetscCheck(!link->inuse, PetscObjectComm((PetscObject)sf), PETSC_ERR_PLIB, "Window in use");
40608401ef6SPierre Jolivet         PetscCheck(!epoch || !link->epoch, PetscObjectComm((PetscObject)sf), PETSC_ERR_PLIB, "Window epoch not finished");
4075b0d146aSStefano Zampini         winok       = PETSC_TRUE;
4085b0d146aSStefano Zampini         link->paddr = array;
40976bd3646SJed Brown       } else if (PetscDefined(USE_DEBUG)) {
4105b0d146aSStefano Zampini         dummy[0] = PETSC_FALSE;
4115b0d146aSStefano Zampini         dummy[1] = PETSC_FALSE;
4129566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, dummy, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)sf)));
4139566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, dummy + 1, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
41408401ef6SPierre Jolivet         PetscCheck(dummy[0] == dummy[1], PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "PETSCSF_WINDOW_FLAVOR_DYNAMIC requires root pointers to be consistently used across the comm. Use PETSCSF_WINDOW_FLAVOR_CREATE or PETSCSF_WINDOW_FLAVOR_ALLOCATE instead");
4155b0d146aSStefano Zampini       }
4165b0d146aSStefano Zampini       break;
4175b0d146aSStefano Zampini     case PETSCSF_WINDOW_FLAVOR_ALLOCATE: /* check available by matching size, allocate if in use */
4185b0d146aSStefano Zampini     case PETSCSF_WINDOW_FLAVOR_SHARED:
4195b0d146aSStefano Zampini       if (!link->inuse && bytes == (MPI_Aint)link->bytes) {
4205b0d146aSStefano Zampini         update      = PETSC_TRUE;
4215b0d146aSStefano Zampini         link->paddr = array;
4225b0d146aSStefano Zampini         winok       = PETSC_TRUE;
4235b0d146aSStefano Zampini       }
4245b0d146aSStefano Zampini       break;
425d71ae5a4SJacob Faibussowitsch     default:
426d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "No support for flavor %s", PetscSFWindowFlavorTypes[w->flavor]);
4275b0d146aSStefano Zampini     }
4285b0d146aSStefano Zampini     if (winok) {
4295b0d146aSStefano Zampini       *win = link->win;
430*fef353a4SJacob Faibussowitsch       PetscCall(PetscInfo(sf, "Reusing window %" PETSC_INTPTR_T_FMT " of flavor %d for comm %" PETSC_INTPTR_T_FMT "\n", (PETSC_INTPTR_T)link->win, link->flavor, (PETSC_INTPTR_T)PetscObjectComm((PetscObject)sf)));
4315b0d146aSStefano Zampini       goto found;
4325b0d146aSStefano Zampini     }
4335b0d146aSStefano Zampini   }
4345b0d146aSStefano Zampini 
4355b0d146aSStefano Zampini   wsize = (MPI_Aint)bytes * sf->nroots;
4369566063dSJacob Faibussowitsch   PetscCall(PetscNew(&link));
43795fce210SBarry Smith   link->bytes           = bytes;
43895fce210SBarry Smith   link->next            = w->wins;
4395b0d146aSStefano Zampini   link->flavor          = w->flavor;
4405b0d146aSStefano Zampini   link->dyn_target_addr = NULL;
441684a874aSStefano Zampini   link->reqs            = NULL;
44295fce210SBarry Smith   w->wins               = link;
443684a874aSStefano Zampini   if (sync == PETSCSF_WINDOW_SYNC_LOCK) {
444684a874aSStefano Zampini     PetscInt i;
445684a874aSStefano Zampini 
4469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sf->nranks, &link->reqs));
447684a874aSStefano Zampini     for (i = 0; i < sf->nranks; i++) link->reqs[i] = MPI_REQUEST_NULL;
448684a874aSStefano Zampini   }
4495b0d146aSStefano Zampini   switch (w->flavor) {
4505b0d146aSStefano Zampini   case PETSCSF_WINDOW_FLAVOR_CREATE:
4519566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_create(array, wsize, (PetscMPIInt)bytes, w->info, PetscObjectComm((PetscObject)sf), &link->win));
4525b0d146aSStefano Zampini     link->addr  = array;
4535b0d146aSStefano Zampini     link->paddr = array;
4545b0d146aSStefano Zampini     break;
455d547623eSJunchao Zhang #if defined(PETSC_HAVE_MPI_FEATURE_DYNAMIC_WINDOW)
456d71ae5a4SJacob Faibussowitsch   case PETSCSF_WINDOW_FLAVOR_DYNAMIC:
457d71ae5a4SJacob Faibussowitsch     PetscCallMPI(MPI_Win_create_dynamic(w->info, PetscObjectComm((PetscObject)sf), &link->win));
4585b0d146aSStefano Zampini   #if defined(PETSC_HAVE_OMPI_MAJOR_VERSION) /* some OpenMPI versions do not support MPI_Win_attach(win,NULL,0); */
459244dd087SJunchao Zhang     PetscCallMPI(MPI_Win_attach(link->win, wsize ? array : (void *)dummy, wsize));
4605b0d146aSStefano Zampini   #else
4619566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_attach(link->win, array, wsize));
4625b0d146aSStefano Zampini   #endif
4635b0d146aSStefano Zampini     link->addr  = array;
4645b0d146aSStefano Zampini     link->paddr = array;
46528b400f6SJacob Faibussowitsch     PetscCheck(w->dynsf, PetscObjectComm((PetscObject)sf), PETSC_ERR_ORDER, "Must call PetscSFSetUp()");
4669566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(w->dynsf));
4679566063dSJacob Faibussowitsch     PetscCall(PetscSFGetRootRanks(w->dynsf, &nranks, NULL, NULL, NULL, NULL));
4689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nranks, &link->dyn_target_addr));
4699566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Get_address(array, &winaddr));
4709566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(w->dynsf, MPI_AINT, &winaddr, link->dyn_target_addr, MPI_REPLACE));
4719566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(w->dynsf, MPI_AINT, &winaddr, link->dyn_target_addr, MPI_REPLACE));
4725b0d146aSStefano Zampini     break;
4735b0d146aSStefano Zampini   case PETSCSF_WINDOW_FLAVOR_ALLOCATE:
4749566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_allocate(wsize, (PetscMPIInt)bytes, w->info, PetscObjectComm((PetscObject)sf), &link->addr, &link->win));
4755b0d146aSStefano Zampini     update      = PETSC_TRUE;
4765b0d146aSStefano Zampini     link->paddr = array;
4775b0d146aSStefano Zampini     break;
478d547623eSJunchao Zhang #endif
4795b0d146aSStefano Zampini #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
4805b0d146aSStefano Zampini   case PETSCSF_WINDOW_FLAVOR_SHARED:
4819566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_allocate_shared(wsize, (PetscMPIInt)bytes, w->info, PetscObjectComm((PetscObject)sf), &link->addr, &link->win));
4825b0d146aSStefano Zampini     update      = PETSC_TRUE;
4835b0d146aSStefano Zampini     link->paddr = array;
4845b0d146aSStefano Zampini     break;
4855b0d146aSStefano Zampini #endif
486d71ae5a4SJacob Faibussowitsch   default:
487d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "No support for flavor %s", PetscSFWindowFlavorTypes[w->flavor]);
4885b0d146aSStefano Zampini   }
489*fef353a4SJacob Faibussowitsch   PetscCall(PetscInfo(sf, "New window %" PETSC_INTPTR_T_FMT " of flavor %d for comm %" PETSC_INTPTR_T_FMT "\n", (PETSC_INTPTR_T)link->win, link->flavor, (PETSC_INTPTR_T)PetscObjectComm((PetscObject)sf)));
49095fce210SBarry Smith   *win = link->win;
49195fce210SBarry Smith 
4925b0d146aSStefano Zampini found:
4935b0d146aSStefano Zampini 
494684a874aSStefano Zampini   if (target_disp) *target_disp = link->dyn_target_addr;
495684a874aSStefano Zampini   if (reqs) *reqs = link->reqs;
496684a874aSStefano Zampini   if (update) { /* locks are needed for the "separate" memory model only, the fence guaranties memory-synchronization */
497684a874aSStefano Zampini     PetscMPIInt rank;
498684a874aSStefano Zampini 
4999566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sf), &rank));
5009566063dSJacob Faibussowitsch     if (sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_lock(MPI_LOCK_EXCLUSIVE, rank, MPI_MODE_NOCHECK, *win));
5019566063dSJacob Faibussowitsch     PetscCall(PetscMemcpy(link->addr, array, sf->nroots * bytes));
5025b0d146aSStefano Zampini     if (sync == PETSCSF_WINDOW_SYNC_LOCK) {
5039566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Win_unlock(rank, *win));
5049566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Win_fence(0, *win));
5055b0d146aSStefano Zampini     }
5065b0d146aSStefano Zampini   }
5075b0d146aSStefano Zampini   link->inuse = PETSC_TRUE;
5085b0d146aSStefano Zampini   link->epoch = epoch;
50995fce210SBarry Smith   if (epoch) {
5105b0d146aSStefano Zampini     switch (sync) {
511d71ae5a4SJacob Faibussowitsch     case PETSCSF_WINDOW_SYNC_FENCE:
512d71ae5a4SJacob Faibussowitsch       PetscCallMPI(MPI_Win_fence(fenceassert, *win));
513d71ae5a4SJacob Faibussowitsch       break;
514d71ae5a4SJacob Faibussowitsch     case PETSCSF_WINDOW_SYNC_LOCK: /* Handled outside */
515d71ae5a4SJacob Faibussowitsch       break;
51695fce210SBarry Smith     case PETSCSF_WINDOW_SYNC_ACTIVE: {
51795fce210SBarry Smith       MPI_Group   ingroup, outgroup;
5185b0d146aSStefano Zampini       PetscMPIInt isize, osize;
5195b0d146aSStefano Zampini 
5205b0d146aSStefano Zampini       /* OpenMPI 4.0.2 with btl=vader does not like calling
5215b0d146aSStefano Zampini          - MPI_Win_complete when ogroup is empty
5225b0d146aSStefano Zampini          - MPI_Win_wait when igroup is empty
5235b0d146aSStefano Zampini          So, we do not even issue the corresponding start and post calls
5245b0d146aSStefano Zampini          The MPI standard (Sec. 11.5.2 of MPI 3.1) only requires that
5255b0d146aSStefano Zampini          start(outgroup) has a matching post(ingroup)
5265b0d146aSStefano Zampini          and this is guaranteed by PetscSF
5275b0d146aSStefano Zampini       */
5289566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGroups(sf, &ingroup, &outgroup));
5299566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_size(ingroup, &isize));
5309566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_size(outgroup, &osize));
5319566063dSJacob Faibussowitsch       if (isize) PetscCallMPI(MPI_Win_post(ingroup, postassert, *win));
5329566063dSJacob Faibussowitsch       if (osize) PetscCallMPI(MPI_Win_start(outgroup, startassert, *win));
53395fce210SBarry Smith     } break;
534d71ae5a4SJacob Faibussowitsch     default:
535d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_PLIB, "Unknown synchronization type");
53695fce210SBarry Smith     }
53795fce210SBarry Smith   }
53895fce210SBarry Smith   PetscFunctionReturn(0);
53995fce210SBarry Smith }
54095fce210SBarry Smith 
5415b0d146aSStefano Zampini /*
54295fce210SBarry Smith    PetscSFFindWindow - Finds a window that is already in use
54395fce210SBarry Smith 
54495fce210SBarry Smith    Not Collective
54595fce210SBarry Smith 
5464165533cSJose E. Roman    Input Parameters:
54795fce210SBarry Smith +  sf - star forest
54895fce210SBarry Smith .  unit - data type
54995fce210SBarry Smith -  array - array with which the window is associated
55095fce210SBarry Smith 
5514165533cSJose E. Roman    Output Parameters:
552684a874aSStefano Zampini +  win - window
553684a874aSStefano Zampini -  reqs - outstanding requests associated to the window
55495fce210SBarry Smith 
55595fce210SBarry Smith    Level: developer
55695fce210SBarry Smith 
557cab54364SBarry Smith .seealso: `PetscSF`, `PETSCSFWINDOW`, `PetscSFGetWindow()`, `PetscSFRestoreWindow()`
5585b0d146aSStefano Zampini */
559d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFFindWindow(PetscSF sf, MPI_Datatype unit, const void *array, MPI_Win *win, MPI_Request **reqs)
560d71ae5a4SJacob Faibussowitsch {
56195fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
56295fce210SBarry Smith   PetscSFWinLink  link;
56395fce210SBarry Smith 
56495fce210SBarry Smith   PetscFunctionBegin;
565c0cd0301SJed Brown   *win = MPI_WIN_NULL;
56695fce210SBarry Smith   for (link = w->wins; link; link = link->next) {
5675b0d146aSStefano Zampini     if (array == link->paddr) {
568*fef353a4SJacob Faibussowitsch       PetscCall(PetscInfo(sf, "Window %" PETSC_INTPTR_T_FMT " of flavor %d for comm %" PETSC_INTPTR_T_FMT "\n", (PETSC_INTPTR_T)link->win, link->flavor, (PETSC_INTPTR_T)PetscObjectComm((PetscObject)sf)));
56995fce210SBarry Smith       *win  = link->win;
570684a874aSStefano Zampini       *reqs = link->reqs;
57195fce210SBarry Smith       PetscFunctionReturn(0);
57295fce210SBarry Smith     }
57395fce210SBarry Smith   }
57495fce210SBarry Smith   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Requested window not in use");
57595fce210SBarry Smith }
57695fce210SBarry Smith 
5775b0d146aSStefano Zampini /*
578cab54364SBarry Smith    PetscSFRestoreWindow - Restores a window obtained with `PetscSFGetWindow()`
57995fce210SBarry Smith 
58095fce210SBarry Smith    Collective
58195fce210SBarry Smith 
5824165533cSJose E. Roman    Input Parameters:
58395fce210SBarry Smith +  sf - star forest
58495fce210SBarry Smith .  unit - data type
58595fce210SBarry Smith .  array - array associated with window
586cab54364SBarry Smith .  sync - type of synchronization `PetscSFWindowSyncType`
587cab54364SBarry Smith .  epoch - close an epoch, must match argument to `PetscSFGetWindow()`
5885b0d146aSStefano Zampini .  update - if we have to update the local window array
58995fce210SBarry Smith -  win - window
59095fce210SBarry Smith 
59195fce210SBarry Smith    Level: developer
59295fce210SBarry Smith 
593cab54364SBarry Smith .seealso: `PetscSF`, `PETSCSFWINDOW`, `PetscSFFindWindow()`
5945b0d146aSStefano Zampini */
595d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFRestoreWindow(PetscSF sf, MPI_Datatype unit, void *array, PetscSFWindowSyncType sync, PetscBool epoch, PetscMPIInt fenceassert, PetscBool update, MPI_Win *win)
596d71ae5a4SJacob Faibussowitsch {
59795fce210SBarry Smith   PetscSF_Window         *w = (PetscSF_Window *)sf->data;
59895fce210SBarry Smith   PetscSFWinLink         *p, link;
5995b0d146aSStefano Zampini   PetscBool               reuse = PETSC_FALSE;
6005b0d146aSStefano Zampini   PetscSFWindowFlavorType flavor;
6015b0d146aSStefano Zampini   void                   *laddr;
6025b0d146aSStefano Zampini   size_t                  bytes;
60395fce210SBarry Smith 
60495fce210SBarry Smith   PetscFunctionBegin;
60595fce210SBarry Smith   for (p = &w->wins; *p; p = &(*p)->next) {
60695fce210SBarry Smith     link = *p;
60795fce210SBarry Smith     if (*win == link->win) {
60808401ef6SPierre Jolivet       PetscCheck(array == link->paddr, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Matched window, but not array");
60995fce210SBarry Smith       if (epoch != link->epoch) {
61028b400f6SJacob Faibussowitsch         PetscCheck(!epoch, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "No epoch to end");
611f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Restoring window without ending epoch");
61295fce210SBarry Smith       }
6135b0d146aSStefano Zampini       laddr  = link->addr;
6145b0d146aSStefano Zampini       flavor = link->flavor;
6155b0d146aSStefano Zampini       bytes  = link->bytes;
6165b0d146aSStefano Zampini       if (flavor != PETSCSF_WINDOW_FLAVOR_CREATE) reuse = PETSC_TRUE;
6179371c9d4SSatish Balay       else {
6189371c9d4SSatish Balay         *p     = link->next;
6199371c9d4SSatish Balay         update = PETSC_FALSE;
6209371c9d4SSatish Balay       } /* remove from list */
62195fce210SBarry Smith       goto found;
62295fce210SBarry Smith     }
62395fce210SBarry Smith   }
62495fce210SBarry Smith   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Requested window not in use");
62595fce210SBarry Smith 
62695fce210SBarry Smith found:
627*fef353a4SJacob Faibussowitsch   PetscCall(PetscInfo(sf, "Window %" PETSC_INTPTR_T_FMT " of flavor %d for comm %" PETSC_INTPTR_T_FMT "\n", (PETSC_INTPTR_T)link->win, link->flavor, (PETSC_INTPTR_T)PetscObjectComm((PetscObject)sf)));
62895fce210SBarry Smith   if (epoch) {
6295b0d146aSStefano Zampini     switch (sync) {
630d71ae5a4SJacob Faibussowitsch     case PETSCSF_WINDOW_SYNC_FENCE:
631d71ae5a4SJacob Faibussowitsch       PetscCallMPI(MPI_Win_fence(fenceassert, *win));
632d71ae5a4SJacob Faibussowitsch       break;
633d71ae5a4SJacob Faibussowitsch     case PETSCSF_WINDOW_SYNC_LOCK: /* Handled outside */
634d71ae5a4SJacob Faibussowitsch       break;
63595fce210SBarry Smith     case PETSCSF_WINDOW_SYNC_ACTIVE: {
6365b0d146aSStefano Zampini       MPI_Group   ingroup, outgroup;
6375b0d146aSStefano Zampini       PetscMPIInt isize, osize;
6385b0d146aSStefano Zampini 
6395b0d146aSStefano Zampini       /* OpenMPI 4.0.2 with btl=wader does not like calling
6405b0d146aSStefano Zampini          - MPI_Win_complete when ogroup is empty
6415b0d146aSStefano Zampini          - MPI_Win_wait when igroup is empty
6425b0d146aSStefano Zampini          The MPI standard (Sec. 11.5.2 of MPI 3.1) only requires that
6435b0d146aSStefano Zampini          - each process who issues a call to MPI_Win_start issues a call to MPI_Win_Complete
6445b0d146aSStefano Zampini          - each process who issues a call to MPI_Win_post issues a call to MPI_Win_Wait
6455b0d146aSStefano Zampini       */
6469566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGroups(sf, &ingroup, &outgroup));
6479566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_size(ingroup, &isize));
6489566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_size(outgroup, &osize));
6499566063dSJacob Faibussowitsch       if (osize) PetscCallMPI(MPI_Win_complete(*win));
6509566063dSJacob Faibussowitsch       if (isize) PetscCallMPI(MPI_Win_wait(*win));
65195fce210SBarry Smith     } break;
652d71ae5a4SJacob Faibussowitsch     default:
653d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_PLIB, "Unknown synchronization type");
65495fce210SBarry Smith     }
65595fce210SBarry Smith   }
6565b0d146aSStefano Zampini   if (update) {
65748a46eb9SPierre Jolivet     if (sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_fence(MPI_MODE_NOPUT | MPI_MODE_NOSUCCEED, *win));
6589566063dSJacob Faibussowitsch     PetscCall(PetscMemcpy(array, laddr, sf->nroots * bytes));
6595b0d146aSStefano Zampini   }
6605b0d146aSStefano Zampini   link->epoch = PETSC_FALSE;
6615b0d146aSStefano Zampini   link->inuse = PETSC_FALSE;
6625b0d146aSStefano Zampini   link->paddr = NULL;
6635b0d146aSStefano Zampini   if (!reuse) {
6649566063dSJacob Faibussowitsch     PetscCall(PetscFree(link->dyn_target_addr));
6659566063dSJacob Faibussowitsch     PetscCall(PetscFree(link->reqs));
6669566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_free(&link->win));
6679566063dSJacob Faibussowitsch     PetscCall(PetscFree(link));
66895fce210SBarry Smith     *win = MPI_WIN_NULL;
6695b0d146aSStefano Zampini   }
67095fce210SBarry Smith   PetscFunctionReturn(0);
67195fce210SBarry Smith }
67295fce210SBarry Smith 
673d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFSetUp_Window(PetscSF sf)
674d71ae5a4SJacob Faibussowitsch {
67595fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
67695fce210SBarry Smith   MPI_Group       ingroup, outgroup;
67795fce210SBarry Smith 
67895fce210SBarry Smith   PetscFunctionBegin;
6799566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUpRanks(sf, MPI_GROUP_EMPTY));
6805b0d146aSStefano Zampini   if (!w->dynsf) {
6815b0d146aSStefano Zampini     PetscInt     i;
6825b0d146aSStefano Zampini     PetscSFNode *remotes;
6835b0d146aSStefano Zampini 
6849566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sf->nranks, &remotes));
6855b0d146aSStefano Zampini     for (i = 0; i < sf->nranks; i++) {
6865b0d146aSStefano Zampini       remotes[i].rank  = sf->ranks[i];
6875b0d146aSStefano Zampini       remotes[i].index = 0;
6885b0d146aSStefano Zampini     }
6899566063dSJacob Faibussowitsch     PetscCall(PetscSFDuplicate(sf, PETSCSF_DUPLICATE_RANKS, &w->dynsf));
6909566063dSJacob Faibussowitsch     PetscCall(PetscSFWindowSetFlavorType(w->dynsf, PETSCSF_WINDOW_FLAVOR_CREATE)); /* break recursion */
6919566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(w->dynsf, 1, sf->nranks, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
6925b0d146aSStefano Zampini   }
69395fce210SBarry Smith   switch (w->sync) {
694d71ae5a4SJacob Faibussowitsch   case PETSCSF_WINDOW_SYNC_ACTIVE:
695d71ae5a4SJacob Faibussowitsch     PetscCall(PetscSFGetGroups(sf, &ingroup, &outgroup));
696d71ae5a4SJacob Faibussowitsch   default:
697d71ae5a4SJacob Faibussowitsch     break;
69895fce210SBarry Smith   }
69995fce210SBarry Smith   PetscFunctionReturn(0);
70095fce210SBarry Smith }
70195fce210SBarry Smith 
702d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFSetFromOptions_Window(PetscSF sf, PetscOptionItems *PetscOptionsObject)
703d71ae5a4SJacob Faibussowitsch {
70495fce210SBarry Smith   PetscSF_Window         *w      = (PetscSF_Window *)sf->data;
7055b0d146aSStefano Zampini   PetscSFWindowFlavorType flavor = w->flavor;
70695fce210SBarry Smith 
70795fce210SBarry Smith   PetscFunctionBegin;
708d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "PetscSF Window options");
7099566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-sf_window_sync", "synchronization type to use for PetscSF Window communication", "PetscSFWindowSetSyncType", PetscSFWindowSyncTypes, (PetscEnum)w->sync, (PetscEnum *)&w->sync, NULL));
7109566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-sf_window_flavor", "flavor to use for PetscSF Window creation", "PetscSFWindowSetFlavorType", PetscSFWindowFlavorTypes, (PetscEnum)flavor, (PetscEnum *)&flavor, NULL));
7119566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowSetFlavorType(sf, flavor));
712d0609cedSBarry Smith   PetscOptionsHeadEnd();
71395fce210SBarry Smith   PetscFunctionReturn(0);
71495fce210SBarry Smith }
71595fce210SBarry Smith 
716d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFReset_Window(PetscSF sf)
717d71ae5a4SJacob Faibussowitsch {
71895fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
71995fce210SBarry Smith   PetscSFDataLink link, next;
72095fce210SBarry Smith   PetscSFWinLink  wlink, wnext;
72195fce210SBarry Smith   PetscInt        i;
72295fce210SBarry Smith 
72395fce210SBarry Smith   PetscFunctionBegin;
72495fce210SBarry Smith   for (link = w->link; link; link = next) {
72595fce210SBarry Smith     next = link->next;
7269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&link->unit));
72795fce210SBarry Smith     for (i = 0; i < sf->nranks; i++) {
7289566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&link->mine[i]));
7299566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&link->remote[i]));
73095fce210SBarry Smith     }
7319566063dSJacob Faibussowitsch     PetscCall(PetscFree2(link->mine, link->remote));
7329566063dSJacob Faibussowitsch     PetscCall(PetscFree(link));
73395fce210SBarry Smith   }
73495fce210SBarry Smith   w->link = NULL;
73595fce210SBarry Smith   for (wlink = w->wins; wlink; wlink = wnext) {
73695fce210SBarry Smith     wnext = wlink->next;
73728b400f6SJacob Faibussowitsch     PetscCheck(!wlink->inuse, PetscObjectComm((PetscObject)sf), PETSC_ERR_ARG_WRONGSTATE, "Window still in use with address %p", (void *)wlink->addr);
7389566063dSJacob Faibussowitsch     PetscCall(PetscFree(wlink->dyn_target_addr));
7399566063dSJacob Faibussowitsch     PetscCall(PetscFree(wlink->reqs));
7409566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_free(&wlink->win));
7419566063dSJacob Faibussowitsch     PetscCall(PetscFree(wlink));
74295fce210SBarry Smith   }
74395fce210SBarry Smith   w->wins = NULL;
7449566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&w->dynsf));
74548a46eb9SPierre Jolivet   if (w->info != MPI_INFO_NULL) PetscCallMPI(MPI_Info_free(&w->info));
74695fce210SBarry Smith   PetscFunctionReturn(0);
74795fce210SBarry Smith }
74895fce210SBarry Smith 
749d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFDestroy_Window(PetscSF sf)
750d71ae5a4SJacob Faibussowitsch {
75195fce210SBarry Smith   PetscFunctionBegin;
7529566063dSJacob Faibussowitsch   PetscCall(PetscSFReset_Window(sf));
7539566063dSJacob Faibussowitsch   PetscCall(PetscFree(sf->data));
7549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetSyncType_C", NULL));
7559566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetSyncType_C", NULL));
7569566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetFlavorType_C", NULL));
7579566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetFlavorType_C", NULL));
7589566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetInfo_C", NULL));
7599566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetInfo_C", NULL));
76095fce210SBarry Smith   PetscFunctionReturn(0);
76195fce210SBarry Smith }
76295fce210SBarry Smith 
763d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFView_Window(PetscSF sf, PetscViewer viewer)
764d71ae5a4SJacob Faibussowitsch {
76595fce210SBarry Smith   PetscSF_Window   *w = (PetscSF_Window *)sf->data;
76695fce210SBarry Smith   PetscBool         iascii;
7675b0d146aSStefano Zampini   PetscViewerFormat format;
76895fce210SBarry Smith 
76995fce210SBarry Smith   PetscFunctionBegin;
7709566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
7719566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
77295fce210SBarry Smith   if (iascii) {
7739566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  current flavor=%s synchronization=%s MultiSF sort=%s\n", PetscSFWindowFlavorTypes[w->flavor], PetscSFWindowSyncTypes[w->sync], sf->rankorder ? "rank-order" : "unordered"));
7745b0d146aSStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
7755b0d146aSStefano Zampini       if (w->info != MPI_INFO_NULL) {
7765b0d146aSStefano Zampini         PetscMPIInt k, nkeys;
7775b0d146aSStefano Zampini         char        key[MPI_MAX_INFO_KEY], value[MPI_MAX_INFO_VAL];
7785b0d146aSStefano Zampini 
7799566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Info_get_nkeys(w->info, &nkeys));
7809566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "    current info with %d keys. Ordered key-value pairs follow:\n", nkeys));
7815b0d146aSStefano Zampini         for (k = 0; k < nkeys; k++) {
7825b0d146aSStefano Zampini           PetscMPIInt flag;
7835b0d146aSStefano Zampini 
7849566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Info_get_nthkey(w->info, k, key));
7859566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Info_get(w->info, key, MPI_MAX_INFO_VAL, value, &flag));
78628b400f6SJacob Faibussowitsch           PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing key %s", key);
7879566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "      %s = %s\n", key, value));
7885b0d146aSStefano Zampini         }
7895b0d146aSStefano Zampini       } else {
7909566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "    current info=MPI_INFO_NULL\n"));
7915b0d146aSStefano Zampini       }
7925b0d146aSStefano Zampini     }
79395fce210SBarry Smith   }
79495fce210SBarry Smith   PetscFunctionReturn(0);
79595fce210SBarry Smith }
79695fce210SBarry Smith 
797d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFDuplicate_Window(PetscSF sf, PetscSFDuplicateOption opt, PetscSF newsf)
798d71ae5a4SJacob Faibussowitsch {
79995fce210SBarry Smith   PetscSF_Window       *w = (PetscSF_Window *)sf->data;
80095fce210SBarry Smith   PetscSFWindowSyncType synctype;
80195fce210SBarry Smith 
80295fce210SBarry Smith   PetscFunctionBegin;
80395fce210SBarry Smith   synctype = w->sync;
80495fce210SBarry Smith   /* HACK: Must use FENCE or LOCK when called from PetscSFGetGroups() because ACTIVE here would cause recursion. */
8055b0d146aSStefano Zampini   if (!sf->setupcalled) synctype = PETSCSF_WINDOW_SYNC_LOCK;
8069566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowSetSyncType(newsf, synctype));
8079566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowSetFlavorType(newsf, w->flavor));
8089566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowSetInfo(newsf, w->info));
80995fce210SBarry Smith   PetscFunctionReturn(0);
81095fce210SBarry Smith }
81195fce210SBarry Smith 
812d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFBcastBegin_Window(PetscSF sf, MPI_Datatype unit, PetscMemType rootmtype, const void *rootdata, PetscMemType leafmtype, void *leafdata, MPI_Op op)
813d71ae5a4SJacob Faibussowitsch {
81495fce210SBarry Smith   PetscSF_Window     *w = (PetscSF_Window *)sf->data;
81595fce210SBarry Smith   PetscInt            i, nranks;
81695fce210SBarry Smith   const PetscMPIInt  *ranks;
8175b0d146aSStefano Zampini   const MPI_Aint     *target_disp;
81895fce210SBarry Smith   const MPI_Datatype *mine, *remote;
819684a874aSStefano Zampini   MPI_Request        *reqs;
82095fce210SBarry Smith   MPI_Win             win;
82195fce210SBarry Smith 
82295fce210SBarry Smith   PetscFunctionBegin;
82308401ef6SPierre Jolivet   PetscCheck(op == MPI_REPLACE, PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "PetscSFBcastBegin_Window with op!=MPI_REPLACE has not been implemented");
8249566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL));
8259566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowGetDataTypes(sf, unit, &mine, &remote));
8269566063dSJacob Faibussowitsch   PetscCall(PetscSFGetWindow(sf, unit, (void *)rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOPUT | MPI_MODE_NOPRECEDE, MPI_MODE_NOPUT, 0, &target_disp, &reqs, &win));
82795fce210SBarry Smith   for (i = 0; i < nranks; i++) {
8285b0d146aSStefano Zampini     MPI_Aint tdp = target_disp ? target_disp[i] : 0;
8295b0d146aSStefano Zampini 
830684a874aSStefano Zampini     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) {
8319566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Win_lock(MPI_LOCK_SHARED, ranks[i], MPI_MODE_NOCHECK, win));
832684a874aSStefano Zampini #if defined(PETSC_HAVE_MPI_RGET)
8339566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Rget(leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], win, &reqs[i]));
834684a874aSStefano Zampini #else
8359566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Get(leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], win));
836684a874aSStefano Zampini #endif
837684a874aSStefano Zampini     } else {
8389566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Get(leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], win));
839684a874aSStefano Zampini     }
84095fce210SBarry Smith   }
84195fce210SBarry Smith   PetscFunctionReturn(0);
84295fce210SBarry Smith }
84395fce210SBarry Smith 
844d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFBcastEnd_Window(PetscSF sf, MPI_Datatype unit, const void *rootdata, void *leafdata, MPI_Op op)
845d71ae5a4SJacob Faibussowitsch {
8465b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
84795fce210SBarry Smith   MPI_Win         win;
8484b9acda6SJunchao Zhang   MPI_Request    *reqs = NULL;
84995fce210SBarry Smith 
85095fce210SBarry Smith   PetscFunctionBegin;
8519566063dSJacob Faibussowitsch   PetscCall(PetscSFFindWindow(sf, unit, rootdata, &win, &reqs));
8529566063dSJacob Faibussowitsch   if (reqs) PetscCallMPI(MPI_Waitall(sf->nranks, reqs, MPI_STATUSES_IGNORE));
853684a874aSStefano Zampini   if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) {
854684a874aSStefano Zampini     PetscInt           i, nranks;
855684a874aSStefano Zampini     const PetscMPIInt *ranks;
856684a874aSStefano Zampini 
8579566063dSJacob Faibussowitsch     PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL));
85848a46eb9SPierre Jolivet     for (i = 0; i < nranks; i++) PetscCallMPI(MPI_Win_unlock(ranks[i], win));
859684a874aSStefano Zampini   }
8609566063dSJacob Faibussowitsch   PetscCall(PetscSFRestoreWindow(sf, unit, (void *)rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOSTORE | MPI_MODE_NOSUCCEED, PETSC_FALSE, &win));
86195fce210SBarry Smith   PetscFunctionReturn(0);
86295fce210SBarry Smith }
86395fce210SBarry Smith 
864d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFReduceBegin_Window(PetscSF sf, MPI_Datatype unit, PetscMemType leafmtype, const void *leafdata, PetscMemType rootmtype, void *rootdata, MPI_Op op)
865d71ae5a4SJacob Faibussowitsch {
86695fce210SBarry Smith   PetscSF_Window     *w = (PetscSF_Window *)sf->data;
86795fce210SBarry Smith   PetscInt            i, nranks;
86895fce210SBarry Smith   const PetscMPIInt  *ranks;
8695b0d146aSStefano Zampini   const MPI_Aint     *target_disp;
87095fce210SBarry Smith   const MPI_Datatype *mine, *remote;
87195fce210SBarry Smith   MPI_Win             win;
87295fce210SBarry Smith 
87395fce210SBarry Smith   PetscFunctionBegin;
8749566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL));
8759566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowGetDataTypes(sf, unit, &mine, &remote));
8769566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowOpTranslate(&op));
8779566063dSJacob Faibussowitsch   PetscCall(PetscSFGetWindow(sf, unit, rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOPRECEDE, 0, 0, &target_disp, NULL, &win));
87895fce210SBarry Smith   for (i = 0; i < nranks; i++) {
8795b0d146aSStefano Zampini     MPI_Aint tdp = target_disp ? target_disp[i] : 0;
8805b0d146aSStefano Zampini 
8819566063dSJacob Faibussowitsch     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_lock(MPI_LOCK_SHARED, ranks[i], MPI_MODE_NOCHECK, win));
8829566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Accumulate((void *)leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], op, win));
8839566063dSJacob Faibussowitsch     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_unlock(ranks[i], win));
88495fce210SBarry Smith   }
88595fce210SBarry Smith   PetscFunctionReturn(0);
88695fce210SBarry Smith }
88795fce210SBarry Smith 
888d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFReduceEnd_Window(PetscSF sf, MPI_Datatype unit, const void *leafdata, void *rootdata, MPI_Op op)
889d71ae5a4SJacob Faibussowitsch {
89095fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
89195fce210SBarry Smith   MPI_Win         win;
8924b9acda6SJunchao Zhang   MPI_Request    *reqs = NULL;
89395fce210SBarry Smith 
89495fce210SBarry Smith   PetscFunctionBegin;
8959566063dSJacob Faibussowitsch   PetscCall(PetscSFFindWindow(sf, unit, rootdata, &win, &reqs));
8969566063dSJacob Faibussowitsch   if (reqs) PetscCallMPI(MPI_Waitall(sf->nranks, reqs, MPI_STATUSES_IGNORE));
8979566063dSJacob Faibussowitsch   PetscCall(PetscSFRestoreWindow(sf, unit, rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOSUCCEED, PETSC_TRUE, &win));
89895fce210SBarry Smith   PetscFunctionReturn(0);
89995fce210SBarry Smith }
9005b0d146aSStefano Zampini 
901d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFFetchAndOpBegin_Window(PetscSF sf, MPI_Datatype unit, PetscMemType rootmtype, void *rootdata, PetscMemType leafmtype, const void *leafdata, void *leafupdate, MPI_Op op)
902d71ae5a4SJacob Faibussowitsch {
90395fce210SBarry Smith   PetscInt            i, nranks;
90495fce210SBarry Smith   const PetscMPIInt  *ranks;
90595fce210SBarry Smith   const MPI_Datatype *mine, *remote;
9065b0d146aSStefano Zampini   const MPI_Aint     *target_disp;
90795fce210SBarry Smith   MPI_Win             win;
9085b0d146aSStefano Zampini   PetscSF_Window     *w = (PetscSF_Window *)sf->data;
9095b0d146aSStefano Zampini #if !defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9105b0d146aSStefano Zampini   PetscSFWindowFlavorType oldf;
9115b0d146aSStefano Zampini #endif
91295fce210SBarry Smith 
91395fce210SBarry Smith   PetscFunctionBegin;
9149566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL));
9159566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowGetDataTypes(sf, unit, &mine, &remote));
9169566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowOpTranslate(&op));
9175b0d146aSStefano Zampini #if !defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9185b0d146aSStefano Zampini   /* FetchAndOp without MPI_Get_Accumulate requires locking.
9195b0d146aSStefano Zampini      we create a new window every time to not interfere with user-defined MPI_Info which may have used "no_locks"="true" */
9205b0d146aSStefano Zampini   oldf      = w->flavor;
9215b0d146aSStefano Zampini   w->flavor = PETSCSF_WINDOW_FLAVOR_CREATE;
9229566063dSJacob Faibussowitsch   PetscCall(PetscSFGetWindow(sf, unit, rootdata, PETSCSF_WINDOW_SYNC_LOCK, PETSC_FALSE, 0, 0, 0, &target_disp, NULL, &win));
9235b0d146aSStefano Zampini #else
9249566063dSJacob Faibussowitsch   PetscCall(PetscSFGetWindow(sf, unit, rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOPRECEDE, 0, 0, &target_disp, NULL, &win));
9255b0d146aSStefano Zampini #endif
9265b0d146aSStefano Zampini   for (i = 0; i < nranks; i++) {
9275b0d146aSStefano Zampini     MPI_Aint tdp = target_disp ? target_disp[i] : 0;
9285b0d146aSStefano Zampini 
9295b0d146aSStefano Zampini #if !defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9309566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_lock(MPI_LOCK_EXCLUSIVE, ranks[i], 0, win));
9319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Get(leafupdate, 1, mine[i], ranks[i], tdp, 1, remote[i], win));
9329566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Accumulate((void *)leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], op, win));
9339566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_unlock(ranks[i], win));
9345b0d146aSStefano Zampini #else
9359566063dSJacob Faibussowitsch     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_lock(MPI_LOCK_SHARED, ranks[i], 0, win));
9369566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Get_accumulate((void *)leafdata, 1, mine[i], leafupdate, 1, mine[i], ranks[i], tdp, 1, remote[i], op, win));
9379566063dSJacob Faibussowitsch     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_unlock(ranks[i], win));
9385b0d146aSStefano Zampini #endif
9395b0d146aSStefano Zampini   }
9405b0d146aSStefano Zampini #if !defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9415b0d146aSStefano Zampini   w->flavor = oldf;
9425b0d146aSStefano Zampini #endif
94395fce210SBarry Smith   PetscFunctionReturn(0);
94495fce210SBarry Smith }
94595fce210SBarry Smith 
946d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFFetchAndOpEnd_Window(PetscSF sf, MPI_Datatype unit, void *rootdata, const void *leafdata, void *leafupdate, MPI_Op op)
947d71ae5a4SJacob Faibussowitsch {
94895fce210SBarry Smith   MPI_Win win;
9495b0d146aSStefano Zampini #if defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9505b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
9515b0d146aSStefano Zampini #endif
9524b9acda6SJunchao Zhang   MPI_Request *reqs = NULL;
95395fce210SBarry Smith 
95495fce210SBarry Smith   PetscFunctionBegin;
9559566063dSJacob Faibussowitsch   PetscCall(PetscSFFindWindow(sf, unit, rootdata, &win, &reqs));
9569566063dSJacob Faibussowitsch   if (reqs) PetscCallMPI(MPI_Waitall(sf->nranks, reqs, MPI_STATUSES_IGNORE));
9575b0d146aSStefano Zampini #if defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9589566063dSJacob Faibussowitsch   PetscCall(PetscSFRestoreWindow(sf, unit, rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOSUCCEED, PETSC_TRUE, &win));
9595b0d146aSStefano Zampini #else
9609566063dSJacob Faibussowitsch   PetscCall(PetscSFRestoreWindow(sf, unit, rootdata, PETSCSF_WINDOW_SYNC_LOCK, PETSC_FALSE, 0, PETSC_TRUE, &win));
9615b0d146aSStefano Zampini #endif
96295fce210SBarry Smith   PetscFunctionReturn(0);
96395fce210SBarry Smith }
96495fce210SBarry Smith 
965d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFCreate_Window(PetscSF sf)
966d71ae5a4SJacob Faibussowitsch {
96795fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
96895fce210SBarry Smith 
96995fce210SBarry Smith   PetscFunctionBegin;
97095fce210SBarry Smith   sf->ops->SetUp           = PetscSFSetUp_Window;
97195fce210SBarry Smith   sf->ops->SetFromOptions  = PetscSFSetFromOptions_Window;
97295fce210SBarry Smith   sf->ops->Reset           = PetscSFReset_Window;
97395fce210SBarry Smith   sf->ops->Destroy         = PetscSFDestroy_Window;
97495fce210SBarry Smith   sf->ops->View            = PetscSFView_Window;
97595fce210SBarry Smith   sf->ops->Duplicate       = PetscSFDuplicate_Window;
976ad227feaSJunchao Zhang   sf->ops->BcastBegin      = PetscSFBcastBegin_Window;
977ad227feaSJunchao Zhang   sf->ops->BcastEnd        = PetscSFBcastEnd_Window;
97895fce210SBarry Smith   sf->ops->ReduceBegin     = PetscSFReduceBegin_Window;
97995fce210SBarry Smith   sf->ops->ReduceEnd       = PetscSFReduceEnd_Window;
98095fce210SBarry Smith   sf->ops->FetchAndOpBegin = PetscSFFetchAndOpBegin_Window;
98195fce210SBarry Smith   sf->ops->FetchAndOpEnd   = PetscSFFetchAndOpEnd_Window;
98295fce210SBarry Smith 
9834dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&w));
98495fce210SBarry Smith   sf->data  = (void *)w;
98595fce210SBarry Smith   w->sync   = PETSCSF_WINDOW_SYNC_FENCE;
9865b0d146aSStefano Zampini   w->flavor = PETSCSF_WINDOW_FLAVOR_CREATE;
9875b0d146aSStefano Zampini   w->info   = MPI_INFO_NULL;
98895fce210SBarry Smith 
9899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetSyncType_C", PetscSFWindowSetSyncType_Window));
9909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetSyncType_C", PetscSFWindowGetSyncType_Window));
9919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetFlavorType_C", PetscSFWindowSetFlavorType_Window));
9929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetFlavorType_C", PetscSFWindowGetFlavorType_Window));
9939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetInfo_C", PetscSFWindowSetInfo_Window));
9949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetInfo_C", PetscSFWindowGetInfo_Window));
99595fce210SBarry Smith 
99695fce210SBarry Smith #if defined(OMPI_MAJOR_VERSION) && (OMPI_MAJOR_VERSION < 1 || (OMPI_MAJOR_VERSION == 1 && OMPI_MINOR_VERSION <= 6))
99795fce210SBarry Smith   {
99895fce210SBarry Smith     PetscBool ackbug = PETSC_FALSE;
9999566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, NULL, "-acknowledge_ompi_onesided_bug", &ackbug, NULL));
100095fce210SBarry Smith     if (ackbug) {
10019566063dSJacob Faibussowitsch       PetscCall(PetscInfo(sf, "Acknowledged Open MPI bug, proceeding anyway. Expect memory corruption.\n"));
100295fce210SBarry Smith     } else SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_LIB, "Open MPI is known to be buggy (https://svn.open-mpi.org/trac/ompi/ticket/1905 and 2656), use -acknowledge_ompi_onesided_bug to proceed");
100395fce210SBarry Smith   }
100495fce210SBarry Smith #endif
100595fce210SBarry Smith   PetscFunctionReturn(0);
100695fce210SBarry Smith }
1007