xref: /petsc/src/vec/is/sf/impls/window/sfwindow.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
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) */
39*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowOpTranslate(MPI_Op *op)
40*d71ae5a4SJacob 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:
5495fce210SBarry Smith +  sf - star forest
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 
63db781477SPatrick Sanan .seealso: `PetscSFSetGraph()`, `PetscSFView()`
6495fce210SBarry Smith @*/
65*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowGetDataTypes(PetscSF sf, MPI_Datatype unit, const MPI_Datatype **localtypes, const MPI_Datatype **remotetypes)
66*d71ae5a4SJacob 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
1225b0d146aSStefano Zampini    PetscSFWindowSetFlavorType - Set flavor type for MPI_Win creation
1235b0d146aSStefano Zampini 
1245b0d146aSStefano Zampini    Logically Collective
1255b0d146aSStefano Zampini 
1264165533cSJose E. Roman    Input Parameters:
1275b0d146aSStefano Zampini +  sf - star forest for communication
1285b0d146aSStefano Zampini -  flavor - flavor type
1295b0d146aSStefano Zampini 
1305b0d146aSStefano Zampini    Options Database Key:
1315b0d146aSStefano Zampini .  -sf_window_flavor <flavor> - sets the flavor type CREATE, DYNAMIC, ALLOCATE or SHARED (see PetscSFWindowFlavorType)
1325b0d146aSStefano Zampini 
1335b0d146aSStefano Zampini    Level: advanced
1345b0d146aSStefano Zampini 
1355b0d146aSStefano Zampini    Notes: Windows reusage follow this rules:
1365b0d146aSStefano Zampini 
1375b0d146aSStefano Zampini      PETSCSF_WINDOW_FLAVOR_CREATE: creates a new window every time, uses MPI_Win_create
1385b0d146aSStefano Zampini 
1395b0d146aSStefano 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.
1405b0d146aSStefano Zampini        for i=1 to K
1415b0d146aSStefano Zampini          PetscSFOperationBegin(rootdata1,leafdata_whatever);
1425b0d146aSStefano Zampini          PetscSFOperationEnd(rootdata1,leafdata_whatever);
1435b0d146aSStefano Zampini          ...
1445b0d146aSStefano Zampini          PetscSFOperationBegin(rootdataN,leafdata_whatever);
1455b0d146aSStefano Zampini          PetscSFOperationEnd(rootdataN,leafdata_whatever);
1465b0d146aSStefano Zampini        endfor
1475b0d146aSStefano Zampini        The following pattern will instead raise an error
1485b0d146aSStefano Zampini          PetscSFOperationBegin(rootdata1,leafdata_whatever);
1495b0d146aSStefano Zampini          PetscSFOperationEnd(rootdata1,leafdata_whatever);
1505b0d146aSStefano Zampini          PetscSFOperationBegin(rank ? rootdata1 : rootdata2,leafdata_whatever);
1515b0d146aSStefano Zampini          PetscSFOperationEnd(rank ? rootdata1 : rootdata2,leafdata_whatever);
1525b0d146aSStefano Zampini 
1535b0d146aSStefano Zampini      PETSCSF_WINDOW_FLAVOR_ALLOCATE: uses MPI_Win_allocate, reuses any pre-existing window which fits the data and it is not in use
1545b0d146aSStefano Zampini 
1555b0d146aSStefano Zampini      PETSCSF_WINDOW_FLAVOR_SHARED: uses MPI_Win_allocate_shared, reusage policy as for PETSCSF_WINDOW_FLAVOR_ALLOCATE
1565b0d146aSStefano Zampini 
157db781477SPatrick Sanan .seealso: `PetscSFSetFromOptions()`, `PetscSFWindowGetFlavorType()`
1585b0d146aSStefano Zampini @*/
159*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowSetFlavorType(PetscSF sf, PetscSFWindowFlavorType flavor)
160*d71ae5a4SJacob Faibussowitsch {
1615b0d146aSStefano Zampini   PetscFunctionBegin;
1625b0d146aSStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
1635b0d146aSStefano Zampini   PetscValidLogicalCollectiveEnum(sf, flavor, 2);
164cac4c232SBarry Smith   PetscTryMethod(sf, "PetscSFWindowSetFlavorType_C", (PetscSF, PetscSFWindowFlavorType), (sf, flavor));
1655b0d146aSStefano Zampini   PetscFunctionReturn(0);
1665b0d146aSStefano Zampini }
1675b0d146aSStefano Zampini 
168*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowSetFlavorType_Window(PetscSF sf, PetscSFWindowFlavorType flavor)
169*d71ae5a4SJacob Faibussowitsch {
1705b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
1715b0d146aSStefano Zampini 
1725b0d146aSStefano Zampini   PetscFunctionBegin;
1735b0d146aSStefano Zampini   w->flavor = flavor;
1745b0d146aSStefano Zampini   PetscFunctionReturn(0);
1755b0d146aSStefano Zampini }
1765b0d146aSStefano Zampini 
1775b0d146aSStefano Zampini /*@C
1785b0d146aSStefano Zampini    PetscSFWindowGetFlavorType - Get flavor type for PetscSF communication
1795b0d146aSStefano Zampini 
1805b0d146aSStefano Zampini    Logically Collective
1815b0d146aSStefano Zampini 
1824165533cSJose E. Roman    Input Parameter:
1835b0d146aSStefano Zampini .  sf - star forest for communication
1845b0d146aSStefano Zampini 
1854165533cSJose E. Roman    Output Parameter:
1865b0d146aSStefano Zampini .  flavor - flavor type
1875b0d146aSStefano Zampini 
1885b0d146aSStefano Zampini    Level: advanced
1895b0d146aSStefano Zampini 
190db781477SPatrick Sanan .seealso: `PetscSFSetFromOptions()`, `PetscSFWindowSetFlavorType()`
1915b0d146aSStefano Zampini @*/
192*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowGetFlavorType(PetscSF sf, PetscSFWindowFlavorType *flavor)
193*d71ae5a4SJacob Faibussowitsch {
1945b0d146aSStefano Zampini   PetscFunctionBegin;
1955b0d146aSStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
1965b0d146aSStefano Zampini   PetscValidPointer(flavor, 2);
197cac4c232SBarry Smith   PetscUseMethod(sf, "PetscSFWindowGetFlavorType_C", (PetscSF, PetscSFWindowFlavorType *), (sf, flavor));
1985b0d146aSStefano Zampini   PetscFunctionReturn(0);
1995b0d146aSStefano Zampini }
2005b0d146aSStefano Zampini 
201*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowGetFlavorType_Window(PetscSF sf, PetscSFWindowFlavorType *flavor)
202*d71ae5a4SJacob Faibussowitsch {
2035b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
2045b0d146aSStefano Zampini 
2055b0d146aSStefano Zampini   PetscFunctionBegin;
2065b0d146aSStefano Zampini   *flavor = w->flavor;
2075b0d146aSStefano Zampini   PetscFunctionReturn(0);
2085b0d146aSStefano Zampini }
2095b0d146aSStefano Zampini 
2105b0d146aSStefano Zampini /*@C
2115b0d146aSStefano Zampini    PetscSFWindowSetSyncType - Set synchronization type for PetscSF communication
21295fce210SBarry Smith 
21395fce210SBarry Smith    Logically Collective
21495fce210SBarry Smith 
2154165533cSJose E. Roman    Input Parameters:
21695fce210SBarry Smith +  sf - star forest for communication
21795fce210SBarry Smith -  sync - synchronization type
21895fce210SBarry Smith 
21995fce210SBarry Smith    Options Database Key:
22060263706SJed Brown .  -sf_window_sync <sync> - sets the synchronization type FENCE, LOCK, or ACTIVE (see PetscSFWindowSyncType)
22195fce210SBarry Smith 
22295fce210SBarry Smith    Level: advanced
22395fce210SBarry Smith 
224db781477SPatrick Sanan .seealso: `PetscSFSetFromOptions()`, `PetscSFWindowGetSyncType()`
22595fce210SBarry Smith @*/
226*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowSetSyncType(PetscSF sf, PetscSFWindowSyncType sync)
227*d71ae5a4SJacob Faibussowitsch {
22895fce210SBarry Smith   PetscFunctionBegin;
22995fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
23095fce210SBarry Smith   PetscValidLogicalCollectiveEnum(sf, sync, 2);
231cac4c232SBarry Smith   PetscTryMethod(sf, "PetscSFWindowSetSyncType_C", (PetscSF, PetscSFWindowSyncType), (sf, sync));
23295fce210SBarry Smith   PetscFunctionReturn(0);
23395fce210SBarry Smith }
23495fce210SBarry Smith 
235*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowSetSyncType_Window(PetscSF sf, PetscSFWindowSyncType sync)
236*d71ae5a4SJacob Faibussowitsch {
23795fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
23895fce210SBarry Smith 
23995fce210SBarry Smith   PetscFunctionBegin;
24095fce210SBarry Smith   w->sync = sync;
24195fce210SBarry Smith   PetscFunctionReturn(0);
24295fce210SBarry Smith }
24395fce210SBarry Smith 
24495fce210SBarry Smith /*@C
2455b0d146aSStefano Zampini    PetscSFWindowGetSyncType - Get synchronization type for PetscSF communication
24695fce210SBarry Smith 
24795fce210SBarry Smith    Logically Collective
24895fce210SBarry Smith 
2494165533cSJose E. Roman    Input Parameter:
25095fce210SBarry Smith .  sf - star forest for communication
25195fce210SBarry Smith 
2524165533cSJose E. Roman    Output Parameter:
25395fce210SBarry Smith .  sync - synchronization type
25495fce210SBarry Smith 
25595fce210SBarry Smith    Level: advanced
25695fce210SBarry Smith 
257db781477SPatrick Sanan .seealso: `PetscSFSetFromOptions()`, `PetscSFWindowSetSyncType()`
25895fce210SBarry Smith @*/
259*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowGetSyncType(PetscSF sf, PetscSFWindowSyncType *sync)
260*d71ae5a4SJacob Faibussowitsch {
26195fce210SBarry Smith   PetscFunctionBegin;
26295fce210SBarry Smith   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
26395fce210SBarry Smith   PetscValidPointer(sync, 2);
264cac4c232SBarry Smith   PetscUseMethod(sf, "PetscSFWindowGetSyncType_C", (PetscSF, PetscSFWindowSyncType *), (sf, sync));
26595fce210SBarry Smith   PetscFunctionReturn(0);
26695fce210SBarry Smith }
26795fce210SBarry Smith 
268*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowGetSyncType_Window(PetscSF sf, PetscSFWindowSyncType *sync)
269*d71ae5a4SJacob Faibussowitsch {
27095fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
27195fce210SBarry Smith 
27295fce210SBarry Smith   PetscFunctionBegin;
27395fce210SBarry Smith   *sync = w->sync;
27495fce210SBarry Smith   PetscFunctionReturn(0);
27595fce210SBarry Smith }
27695fce210SBarry Smith 
27795fce210SBarry Smith /*@C
2785b0d146aSStefano Zampini    PetscSFWindowSetInfo - Set the MPI_Info handle that will be used for subsequent windows allocation
2795b0d146aSStefano Zampini 
2805b0d146aSStefano Zampini    Logically Collective
2815b0d146aSStefano Zampini 
2824165533cSJose E. Roman    Input Parameters:
2835b0d146aSStefano Zampini +  sf - star forest for communication
2845b0d146aSStefano Zampini -  info - MPI_Info handle
2855b0d146aSStefano Zampini 
2865b0d146aSStefano Zampini    Level: advanced
2875b0d146aSStefano Zampini 
2885b0d146aSStefano Zampini    Notes: the info handle is duplicated with a call to MPI_Info_dup unless info = MPI_INFO_NULL.
2895b0d146aSStefano Zampini 
290db781477SPatrick Sanan .seealso: `PetscSFSetFromOptions()`, `PetscSFWindowGetInfo()`
2915b0d146aSStefano Zampini @*/
292*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowSetInfo(PetscSF sf, MPI_Info info)
293*d71ae5a4SJacob Faibussowitsch {
2945b0d146aSStefano Zampini   PetscFunctionBegin;
2955b0d146aSStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
296cac4c232SBarry Smith   PetscTryMethod(sf, "PetscSFWindowSetInfo_C", (PetscSF, MPI_Info), (sf, info));
2975b0d146aSStefano Zampini   PetscFunctionReturn(0);
2985b0d146aSStefano Zampini }
2995b0d146aSStefano Zampini 
300*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowSetInfo_Window(PetscSF sf, MPI_Info info)
301*d71ae5a4SJacob Faibussowitsch {
3025b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
3035b0d146aSStefano Zampini 
3045b0d146aSStefano Zampini   PetscFunctionBegin;
30548a46eb9SPierre Jolivet   if (w->info != MPI_INFO_NULL) PetscCallMPI(MPI_Info_free(&w->info));
30648a46eb9SPierre Jolivet   if (info != MPI_INFO_NULL) PetscCallMPI(MPI_Info_dup(info, &w->info));
3075b0d146aSStefano Zampini   PetscFunctionReturn(0);
3085b0d146aSStefano Zampini }
3095b0d146aSStefano Zampini 
3105b0d146aSStefano Zampini /*@C
3115b0d146aSStefano Zampini    PetscSFWindowGetInfo - Get the MPI_Info handle used for windows allocation
3125b0d146aSStefano Zampini 
3135b0d146aSStefano Zampini    Logically Collective
3145b0d146aSStefano Zampini 
3154165533cSJose E. Roman    Input Parameter:
3165b0d146aSStefano Zampini .  sf - star forest for communication
3175b0d146aSStefano Zampini 
3184165533cSJose E. Roman    Output Parameter:
3195b0d146aSStefano Zampini .  info - MPI_Info handle
3205b0d146aSStefano Zampini 
3215b0d146aSStefano Zampini    Level: advanced
3225b0d146aSStefano Zampini 
3235b0d146aSStefano Zampini    Notes: if PetscSFWindowSetInfo() has not be called, this returns MPI_INFO_NULL
3245b0d146aSStefano Zampini 
325db781477SPatrick Sanan .seealso: `PetscSFSetFromOptions()`, `PetscSFWindowSetInfo()`
3265b0d146aSStefano Zampini @*/
327*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFWindowGetInfo(PetscSF sf, MPI_Info *info)
328*d71ae5a4SJacob Faibussowitsch {
3295b0d146aSStefano Zampini   PetscFunctionBegin;
3305b0d146aSStefano Zampini   PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 1);
3315b0d146aSStefano Zampini   PetscValidPointer(info, 2);
332cac4c232SBarry Smith   PetscUseMethod(sf, "PetscSFWindowGetInfo_C", (PetscSF, MPI_Info *), (sf, info));
3335b0d146aSStefano Zampini   PetscFunctionReturn(0);
3345b0d146aSStefano Zampini }
3355b0d146aSStefano Zampini 
336*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFWindowGetInfo_Window(PetscSF sf, MPI_Info *info)
337*d71ae5a4SJacob Faibussowitsch {
3385b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
3395b0d146aSStefano Zampini 
3405b0d146aSStefano Zampini   PetscFunctionBegin;
3415b0d146aSStefano Zampini   *info = w->info;
3425b0d146aSStefano Zampini   PetscFunctionReturn(0);
3435b0d146aSStefano Zampini }
3445b0d146aSStefano Zampini 
3455b0d146aSStefano Zampini /*
34695fce210SBarry Smith    PetscSFGetWindow - Get a window for use with a given data type
34795fce210SBarry Smith 
34895fce210SBarry Smith    Collective on PetscSF
34995fce210SBarry Smith 
3504165533cSJose E. Roman    Input Parameters:
35195fce210SBarry Smith +  sf - star forest
35295fce210SBarry Smith .  unit - data type
35395fce210SBarry Smith .  array - array to be sent
3545b0d146aSStefano Zampini .  sync - type of synchronization PetscSFWindowSyncType
35595fce210SBarry Smith .  epoch - PETSC_TRUE to acquire the window and start an epoch, PETSC_FALSE to just acquire the window
3565b0d146aSStefano Zampini .  fenceassert - assert parameter for call to MPI_Win_fence(), if sync == PETSCSF_WINDOW_SYNC_FENCE
3575b0d146aSStefano Zampini .  postassert - assert parameter for call to MPI_Win_post(), if sync == PETSCSF_WINDOW_SYNC_ACTIVE
358684a874aSStefano Zampini -  startassert - assert parameter for call to MPI_Win_start(), if sync == PETSCSF_WINDOW_SYNC_ACTIVE
35995fce210SBarry Smith 
3604165533cSJose E. Roman    Output Parameters:
361684a874aSStefano Zampini +  target_disp - target_disp argument for RMA calls (significative for PETSCSF_WINDOW_FLAVOR_DYNAMIC only)
362684a874aSStefano Zampini +  reqs - array of requests (significative for sync == PETSCSF_WINDOW_SYNC_LOCK only)
363684a874aSStefano Zampini -  win - window
36495fce210SBarry Smith 
36595fce210SBarry Smith    Level: developer
366db781477SPatrick Sanan .seealso: `PetscSFGetRootRanks()`, `PetscSFWindowGetDataTypes()`
3675b0d146aSStefano Zampini */
368*d71ae5a4SJacob 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)
369*d71ae5a4SJacob Faibussowitsch {
37095fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
37195fce210SBarry Smith   MPI_Aint        lb, lb_true, bytes, bytes_true;
37295fce210SBarry Smith   PetscSFWinLink  link;
373d547623eSJunchao Zhang #if defined(PETSC_HAVE_MPI_FEATURE_DYNAMIC_WINDOW)
3745b0d146aSStefano Zampini   MPI_Aint winaddr;
3755b0d146aSStefano Zampini   PetscInt nranks;
376d547623eSJunchao Zhang #endif
3775b0d146aSStefano Zampini   PetscBool reuse = PETSC_FALSE, update = PETSC_FALSE;
3785b0d146aSStefano Zampini   PetscBool dummy[2];
3795b0d146aSStefano Zampini   MPI_Aint  wsize;
38095fce210SBarry Smith 
38195fce210SBarry Smith   PetscFunctionBegin;
3829566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_get_extent(unit, &lb, &bytes));
3839566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_get_true_extent(unit, &lb_true, &bytes_true));
384c9cc58a2SBarry 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");
38508401ef6SPierre 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");
3865b0d146aSStefano Zampini   if (w->flavor != PETSCSF_WINDOW_FLAVOR_CREATE) reuse = PETSC_TRUE;
3875b0d146aSStefano Zampini   for (link = w->wins; reuse && link; link = link->next) {
3885b0d146aSStefano Zampini     PetscBool winok = PETSC_FALSE;
3895b0d146aSStefano Zampini     if (w->flavor != link->flavor) continue;
3905b0d146aSStefano Zampini     switch (w->flavor) {
3915b0d146aSStefano 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) */
3925b0d146aSStefano Zampini       if (array == link->addr) {
39376bd3646SJed Brown         if (PetscDefined(USE_DEBUG)) {
3945b0d146aSStefano Zampini           dummy[0] = PETSC_TRUE;
3955b0d146aSStefano Zampini           dummy[1] = PETSC_TRUE;
3969566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, dummy, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)sf)));
3979566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, dummy + 1, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
39808401ef6SPierre 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");
39976bd3646SJed Brown         }
40028b400f6SJacob Faibussowitsch         PetscCheck(!link->inuse, PetscObjectComm((PetscObject)sf), PETSC_ERR_PLIB, "Window in use");
40108401ef6SPierre Jolivet         PetscCheck(!epoch || !link->epoch, PetscObjectComm((PetscObject)sf), PETSC_ERR_PLIB, "Window epoch not finished");
4025b0d146aSStefano Zampini         winok       = PETSC_TRUE;
4035b0d146aSStefano Zampini         link->paddr = array;
40476bd3646SJed Brown       } else if (PetscDefined(USE_DEBUG)) {
4055b0d146aSStefano Zampini         dummy[0] = PETSC_FALSE;
4065b0d146aSStefano Zampini         dummy[1] = PETSC_FALSE;
4079566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, dummy, 1, MPIU_BOOL, MPI_LAND, PetscObjectComm((PetscObject)sf)));
4089566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Allreduce(MPI_IN_PLACE, dummy + 1, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)sf)));
40908401ef6SPierre 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");
4105b0d146aSStefano Zampini       }
4115b0d146aSStefano Zampini       break;
4125b0d146aSStefano Zampini     case PETSCSF_WINDOW_FLAVOR_ALLOCATE: /* check available by matching size, allocate if in use */
4135b0d146aSStefano Zampini     case PETSCSF_WINDOW_FLAVOR_SHARED:
4145b0d146aSStefano Zampini       if (!link->inuse && bytes == (MPI_Aint)link->bytes) {
4155b0d146aSStefano Zampini         update      = PETSC_TRUE;
4165b0d146aSStefano Zampini         link->paddr = array;
4175b0d146aSStefano Zampini         winok       = PETSC_TRUE;
4185b0d146aSStefano Zampini       }
4195b0d146aSStefano Zampini       break;
420*d71ae5a4SJacob Faibussowitsch     default:
421*d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "No support for flavor %s", PetscSFWindowFlavorTypes[w->flavor]);
4225b0d146aSStefano Zampini     }
4235b0d146aSStefano Zampini     if (winok) {
4245b0d146aSStefano Zampini       *win = link->win;
4259566063dSJacob Faibussowitsch       PetscCall(PetscInfo(sf, "Reusing window %" PETSC_MPI_WIN_FMT " of flavor %d for comm %" PETSC_MPI_COMM_FMT "\n", link->win, link->flavor, PetscObjectComm((PetscObject)sf)));
4265b0d146aSStefano Zampini       goto found;
4275b0d146aSStefano Zampini     }
4285b0d146aSStefano Zampini   }
4295b0d146aSStefano Zampini 
4305b0d146aSStefano Zampini   wsize = (MPI_Aint)bytes * sf->nroots;
4319566063dSJacob Faibussowitsch   PetscCall(PetscNew(&link));
43295fce210SBarry Smith   link->bytes           = bytes;
43395fce210SBarry Smith   link->next            = w->wins;
4345b0d146aSStefano Zampini   link->flavor          = w->flavor;
4355b0d146aSStefano Zampini   link->dyn_target_addr = NULL;
436684a874aSStefano Zampini   link->reqs            = NULL;
43795fce210SBarry Smith   w->wins               = link;
438684a874aSStefano Zampini   if (sync == PETSCSF_WINDOW_SYNC_LOCK) {
439684a874aSStefano Zampini     PetscInt i;
440684a874aSStefano Zampini 
4419566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sf->nranks, &link->reqs));
442684a874aSStefano Zampini     for (i = 0; i < sf->nranks; i++) link->reqs[i] = MPI_REQUEST_NULL;
443684a874aSStefano Zampini   }
4445b0d146aSStefano Zampini   switch (w->flavor) {
4455b0d146aSStefano Zampini   case PETSCSF_WINDOW_FLAVOR_CREATE:
4469566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_create(array, wsize, (PetscMPIInt)bytes, w->info, PetscObjectComm((PetscObject)sf), &link->win));
4475b0d146aSStefano Zampini     link->addr  = array;
4485b0d146aSStefano Zampini     link->paddr = array;
4495b0d146aSStefano Zampini     break;
450d547623eSJunchao Zhang #if defined(PETSC_HAVE_MPI_FEATURE_DYNAMIC_WINDOW)
451*d71ae5a4SJacob Faibussowitsch   case PETSCSF_WINDOW_FLAVOR_DYNAMIC:
452*d71ae5a4SJacob Faibussowitsch     PetscCallMPI(MPI_Win_create_dynamic(w->info, PetscObjectComm((PetscObject)sf), &link->win));
4535b0d146aSStefano Zampini   #if defined(PETSC_HAVE_OMPI_MAJOR_VERSION) /* some OpenMPI versions do not support MPI_Win_attach(win,NULL,0); */
454244dd087SJunchao Zhang     PetscCallMPI(MPI_Win_attach(link->win, wsize ? array : (void *)dummy, wsize));
4555b0d146aSStefano Zampini   #else
4569566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_attach(link->win, array, wsize));
4575b0d146aSStefano Zampini   #endif
4585b0d146aSStefano Zampini     link->addr  = array;
4595b0d146aSStefano Zampini     link->paddr = array;
46028b400f6SJacob Faibussowitsch     PetscCheck(w->dynsf, PetscObjectComm((PetscObject)sf), PETSC_ERR_ORDER, "Must call PetscSFSetUp()");
4619566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(w->dynsf));
4629566063dSJacob Faibussowitsch     PetscCall(PetscSFGetRootRanks(w->dynsf, &nranks, NULL, NULL, NULL, NULL));
4639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nranks, &link->dyn_target_addr));
4649566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Get_address(array, &winaddr));
4659566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(w->dynsf, MPI_AINT, &winaddr, link->dyn_target_addr, MPI_REPLACE));
4669566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(w->dynsf, MPI_AINT, &winaddr, link->dyn_target_addr, MPI_REPLACE));
4675b0d146aSStefano Zampini     break;
4685b0d146aSStefano Zampini   case PETSCSF_WINDOW_FLAVOR_ALLOCATE:
4699566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_allocate(wsize, (PetscMPIInt)bytes, w->info, PetscObjectComm((PetscObject)sf), &link->addr, &link->win));
4705b0d146aSStefano Zampini     update      = PETSC_TRUE;
4715b0d146aSStefano Zampini     link->paddr = array;
4725b0d146aSStefano Zampini     break;
473d547623eSJunchao Zhang #endif
4745b0d146aSStefano Zampini #if defined(PETSC_HAVE_MPI_PROCESS_SHARED_MEMORY)
4755b0d146aSStefano Zampini   case PETSCSF_WINDOW_FLAVOR_SHARED:
4769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_allocate_shared(wsize, (PetscMPIInt)bytes, w->info, PetscObjectComm((PetscObject)sf), &link->addr, &link->win));
4775b0d146aSStefano Zampini     update      = PETSC_TRUE;
4785b0d146aSStefano Zampini     link->paddr = array;
4795b0d146aSStefano Zampini     break;
4805b0d146aSStefano Zampini #endif
481*d71ae5a4SJacob Faibussowitsch   default:
482*d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "No support for flavor %s", PetscSFWindowFlavorTypes[w->flavor]);
4835b0d146aSStefano Zampini   }
4849566063dSJacob Faibussowitsch   PetscCall(PetscInfo(sf, "New window %" PETSC_MPI_WIN_FMT " of flavor %d for comm %" PETSC_MPI_COMM_FMT "\n", link->win, link->flavor, PetscObjectComm((PetscObject)sf)));
48595fce210SBarry Smith   *win = link->win;
48695fce210SBarry Smith 
4875b0d146aSStefano Zampini found:
4885b0d146aSStefano Zampini 
489684a874aSStefano Zampini   if (target_disp) *target_disp = link->dyn_target_addr;
490684a874aSStefano Zampini   if (reqs) *reqs = link->reqs;
491684a874aSStefano Zampini   if (update) { /* locks are needed for the "separate" memory model only, the fence guaranties memory-synchronization */
492684a874aSStefano Zampini     PetscMPIInt rank;
493684a874aSStefano Zampini 
4949566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)sf), &rank));
4959566063dSJacob Faibussowitsch     if (sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_lock(MPI_LOCK_EXCLUSIVE, rank, MPI_MODE_NOCHECK, *win));
4969566063dSJacob Faibussowitsch     PetscCall(PetscMemcpy(link->addr, array, sf->nroots * bytes));
4975b0d146aSStefano Zampini     if (sync == PETSCSF_WINDOW_SYNC_LOCK) {
4989566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Win_unlock(rank, *win));
4999566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Win_fence(0, *win));
5005b0d146aSStefano Zampini     }
5015b0d146aSStefano Zampini   }
5025b0d146aSStefano Zampini   link->inuse = PETSC_TRUE;
5035b0d146aSStefano Zampini   link->epoch = epoch;
50495fce210SBarry Smith   if (epoch) {
5055b0d146aSStefano Zampini     switch (sync) {
506*d71ae5a4SJacob Faibussowitsch     case PETSCSF_WINDOW_SYNC_FENCE:
507*d71ae5a4SJacob Faibussowitsch       PetscCallMPI(MPI_Win_fence(fenceassert, *win));
508*d71ae5a4SJacob Faibussowitsch       break;
509*d71ae5a4SJacob Faibussowitsch     case PETSCSF_WINDOW_SYNC_LOCK: /* Handled outside */
510*d71ae5a4SJacob Faibussowitsch       break;
51195fce210SBarry Smith     case PETSCSF_WINDOW_SYNC_ACTIVE: {
51295fce210SBarry Smith       MPI_Group   ingroup, outgroup;
5135b0d146aSStefano Zampini       PetscMPIInt isize, osize;
5145b0d146aSStefano Zampini 
5155b0d146aSStefano Zampini       /* OpenMPI 4.0.2 with btl=vader does not like calling
5165b0d146aSStefano Zampini          - MPI_Win_complete when ogroup is empty
5175b0d146aSStefano Zampini          - MPI_Win_wait when igroup is empty
5185b0d146aSStefano Zampini          So, we do not even issue the corresponding start and post calls
5195b0d146aSStefano Zampini          The MPI standard (Sec. 11.5.2 of MPI 3.1) only requires that
5205b0d146aSStefano Zampini          start(outgroup) has a matching post(ingroup)
5215b0d146aSStefano Zampini          and this is guaranteed by PetscSF
5225b0d146aSStefano Zampini       */
5239566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGroups(sf, &ingroup, &outgroup));
5249566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_size(ingroup, &isize));
5259566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_size(outgroup, &osize));
5269566063dSJacob Faibussowitsch       if (isize) PetscCallMPI(MPI_Win_post(ingroup, postassert, *win));
5279566063dSJacob Faibussowitsch       if (osize) PetscCallMPI(MPI_Win_start(outgroup, startassert, *win));
52895fce210SBarry Smith     } break;
529*d71ae5a4SJacob Faibussowitsch     default:
530*d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_PLIB, "Unknown synchronization type");
53195fce210SBarry Smith     }
53295fce210SBarry Smith   }
53395fce210SBarry Smith   PetscFunctionReturn(0);
53495fce210SBarry Smith }
53595fce210SBarry Smith 
5365b0d146aSStefano Zampini /*
53795fce210SBarry Smith    PetscSFFindWindow - Finds a window that is already in use
53895fce210SBarry Smith 
53995fce210SBarry Smith    Not Collective
54095fce210SBarry Smith 
5414165533cSJose E. Roman    Input Parameters:
54295fce210SBarry Smith +  sf - star forest
54395fce210SBarry Smith .  unit - data type
54495fce210SBarry Smith -  array - array with which the window is associated
54595fce210SBarry Smith 
5464165533cSJose E. Roman    Output Parameters:
547684a874aSStefano Zampini +  win - window
548684a874aSStefano Zampini -  reqs - outstanding requests associated to the window
54995fce210SBarry Smith 
55095fce210SBarry Smith    Level: developer
55195fce210SBarry Smith 
552db781477SPatrick Sanan .seealso: `PetscSFGetWindow()`, `PetscSFRestoreWindow()`
5535b0d146aSStefano Zampini */
554*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFFindWindow(PetscSF sf, MPI_Datatype unit, const void *array, MPI_Win *win, MPI_Request **reqs)
555*d71ae5a4SJacob Faibussowitsch {
55695fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
55795fce210SBarry Smith   PetscSFWinLink  link;
55895fce210SBarry Smith 
55995fce210SBarry Smith   PetscFunctionBegin;
560c0cd0301SJed Brown   *win = MPI_WIN_NULL;
56195fce210SBarry Smith   for (link = w->wins; link; link = link->next) {
5625b0d146aSStefano Zampini     if (array == link->paddr) {
5639566063dSJacob Faibussowitsch       PetscCall(PetscInfo(sf, "Window %" PETSC_MPI_WIN_FMT " of flavor %d for comm %" PETSC_MPI_COMM_FMT "\n", link->win, link->flavor, PetscObjectComm((PetscObject)sf)));
56495fce210SBarry Smith       *win  = link->win;
565684a874aSStefano Zampini       *reqs = link->reqs;
56695fce210SBarry Smith       PetscFunctionReturn(0);
56795fce210SBarry Smith     }
56895fce210SBarry Smith   }
56995fce210SBarry Smith   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Requested window not in use");
57095fce210SBarry Smith }
57195fce210SBarry Smith 
5725b0d146aSStefano Zampini /*
57395fce210SBarry Smith    PetscSFRestoreWindow - Restores a window obtained with PetscSFGetWindow()
57495fce210SBarry Smith 
57595fce210SBarry Smith    Collective
57695fce210SBarry Smith 
5774165533cSJose E. Roman    Input Parameters:
57895fce210SBarry Smith +  sf - star forest
57995fce210SBarry Smith .  unit - data type
58095fce210SBarry Smith .  array - array associated with window
5815b0d146aSStefano Zampini .  sync - type of synchronization PetscSFWindowSyncType
58295fce210SBarry Smith .  epoch - close an epoch, must match argument to PetscSFGetWindow()
5835b0d146aSStefano Zampini .  update - if we have to update the local window array
58495fce210SBarry Smith -  win - window
58595fce210SBarry Smith 
58695fce210SBarry Smith    Level: developer
58795fce210SBarry Smith 
588db781477SPatrick Sanan .seealso: `PetscSFFindWindow()`
5895b0d146aSStefano Zampini */
590*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFRestoreWindow(PetscSF sf, MPI_Datatype unit, void *array, PetscSFWindowSyncType sync, PetscBool epoch, PetscMPIInt fenceassert, PetscBool update, MPI_Win *win)
591*d71ae5a4SJacob Faibussowitsch {
59295fce210SBarry Smith   PetscSF_Window         *w = (PetscSF_Window *)sf->data;
59395fce210SBarry Smith   PetscSFWinLink         *p, link;
5945b0d146aSStefano Zampini   PetscBool               reuse = PETSC_FALSE;
5955b0d146aSStefano Zampini   PetscSFWindowFlavorType flavor;
5965b0d146aSStefano Zampini   void                   *laddr;
5975b0d146aSStefano Zampini   size_t                  bytes;
59895fce210SBarry Smith 
59995fce210SBarry Smith   PetscFunctionBegin;
60095fce210SBarry Smith   for (p = &w->wins; *p; p = &(*p)->next) {
60195fce210SBarry Smith     link = *p;
60295fce210SBarry Smith     if (*win == link->win) {
60308401ef6SPierre Jolivet       PetscCheck(array == link->paddr, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Matched window, but not array");
60495fce210SBarry Smith       if (epoch != link->epoch) {
60528b400f6SJacob Faibussowitsch         PetscCheck(!epoch, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "No epoch to end");
606f7d195e4SLawrence Mitchell         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Restoring window without ending epoch");
60795fce210SBarry Smith       }
6085b0d146aSStefano Zampini       laddr  = link->addr;
6095b0d146aSStefano Zampini       flavor = link->flavor;
6105b0d146aSStefano Zampini       bytes  = link->bytes;
6115b0d146aSStefano Zampini       if (flavor != PETSCSF_WINDOW_FLAVOR_CREATE) reuse = PETSC_TRUE;
6129371c9d4SSatish Balay       else {
6139371c9d4SSatish Balay         *p     = link->next;
6149371c9d4SSatish Balay         update = PETSC_FALSE;
6159371c9d4SSatish Balay       } /* remove from list */
61695fce210SBarry Smith       goto found;
61795fce210SBarry Smith     }
61895fce210SBarry Smith   }
61995fce210SBarry Smith   SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Requested window not in use");
62095fce210SBarry Smith 
62195fce210SBarry Smith found:
6229566063dSJacob Faibussowitsch   PetscCall(PetscInfo(sf, "Window %" PETSC_MPI_WIN_FMT " of flavor %d for comm %" PETSC_MPI_COMM_FMT "\n", link->win, link->flavor, PetscObjectComm((PetscObject)sf)));
62395fce210SBarry Smith   if (epoch) {
6245b0d146aSStefano Zampini     switch (sync) {
625*d71ae5a4SJacob Faibussowitsch     case PETSCSF_WINDOW_SYNC_FENCE:
626*d71ae5a4SJacob Faibussowitsch       PetscCallMPI(MPI_Win_fence(fenceassert, *win));
627*d71ae5a4SJacob Faibussowitsch       break;
628*d71ae5a4SJacob Faibussowitsch     case PETSCSF_WINDOW_SYNC_LOCK: /* Handled outside */
629*d71ae5a4SJacob Faibussowitsch       break;
63095fce210SBarry Smith     case PETSCSF_WINDOW_SYNC_ACTIVE: {
6315b0d146aSStefano Zampini       MPI_Group   ingroup, outgroup;
6325b0d146aSStefano Zampini       PetscMPIInt isize, osize;
6335b0d146aSStefano Zampini 
6345b0d146aSStefano Zampini       /* OpenMPI 4.0.2 with btl=wader does not like calling
6355b0d146aSStefano Zampini          - MPI_Win_complete when ogroup is empty
6365b0d146aSStefano Zampini          - MPI_Win_wait when igroup is empty
6375b0d146aSStefano Zampini          The MPI standard (Sec. 11.5.2 of MPI 3.1) only requires that
6385b0d146aSStefano Zampini          - each process who issues a call to MPI_Win_start issues a call to MPI_Win_Complete
6395b0d146aSStefano Zampini          - each process who issues a call to MPI_Win_post issues a call to MPI_Win_Wait
6405b0d146aSStefano Zampini       */
6419566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGroups(sf, &ingroup, &outgroup));
6429566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_size(ingroup, &isize));
6439566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Group_size(outgroup, &osize));
6449566063dSJacob Faibussowitsch       if (osize) PetscCallMPI(MPI_Win_complete(*win));
6459566063dSJacob Faibussowitsch       if (isize) PetscCallMPI(MPI_Win_wait(*win));
64695fce210SBarry Smith     } break;
647*d71ae5a4SJacob Faibussowitsch     default:
648*d71ae5a4SJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)sf), PETSC_ERR_PLIB, "Unknown synchronization type");
64995fce210SBarry Smith     }
65095fce210SBarry Smith   }
6515b0d146aSStefano Zampini   if (update) {
65248a46eb9SPierre Jolivet     if (sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_fence(MPI_MODE_NOPUT | MPI_MODE_NOSUCCEED, *win));
6539566063dSJacob Faibussowitsch     PetscCall(PetscMemcpy(array, laddr, sf->nroots * bytes));
6545b0d146aSStefano Zampini   }
6555b0d146aSStefano Zampini   link->epoch = PETSC_FALSE;
6565b0d146aSStefano Zampini   link->inuse = PETSC_FALSE;
6575b0d146aSStefano Zampini   link->paddr = NULL;
6585b0d146aSStefano Zampini   if (!reuse) {
6599566063dSJacob Faibussowitsch     PetscCall(PetscFree(link->dyn_target_addr));
6609566063dSJacob Faibussowitsch     PetscCall(PetscFree(link->reqs));
6619566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_free(&link->win));
6629566063dSJacob Faibussowitsch     PetscCall(PetscFree(link));
66395fce210SBarry Smith     *win = MPI_WIN_NULL;
6645b0d146aSStefano Zampini   }
66595fce210SBarry Smith   PetscFunctionReturn(0);
66695fce210SBarry Smith }
66795fce210SBarry Smith 
668*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFSetUp_Window(PetscSF sf)
669*d71ae5a4SJacob Faibussowitsch {
67095fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
67195fce210SBarry Smith   MPI_Group       ingroup, outgroup;
67295fce210SBarry Smith 
67395fce210SBarry Smith   PetscFunctionBegin;
6749566063dSJacob Faibussowitsch   PetscCall(PetscSFSetUpRanks(sf, MPI_GROUP_EMPTY));
6755b0d146aSStefano Zampini   if (!w->dynsf) {
6765b0d146aSStefano Zampini     PetscInt     i;
6775b0d146aSStefano Zampini     PetscSFNode *remotes;
6785b0d146aSStefano Zampini 
6799566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(sf->nranks, &remotes));
6805b0d146aSStefano Zampini     for (i = 0; i < sf->nranks; i++) {
6815b0d146aSStefano Zampini       remotes[i].rank  = sf->ranks[i];
6825b0d146aSStefano Zampini       remotes[i].index = 0;
6835b0d146aSStefano Zampini     }
6849566063dSJacob Faibussowitsch     PetscCall(PetscSFDuplicate(sf, PETSCSF_DUPLICATE_RANKS, &w->dynsf));
6859566063dSJacob Faibussowitsch     PetscCall(PetscSFWindowSetFlavorType(w->dynsf, PETSCSF_WINDOW_FLAVOR_CREATE)); /* break recursion */
6869566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(w->dynsf, 1, sf->nranks, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
6875b0d146aSStefano Zampini   }
68895fce210SBarry Smith   switch (w->sync) {
689*d71ae5a4SJacob Faibussowitsch   case PETSCSF_WINDOW_SYNC_ACTIVE:
690*d71ae5a4SJacob Faibussowitsch     PetscCall(PetscSFGetGroups(sf, &ingroup, &outgroup));
691*d71ae5a4SJacob Faibussowitsch   default:
692*d71ae5a4SJacob Faibussowitsch     break;
69395fce210SBarry Smith   }
69495fce210SBarry Smith   PetscFunctionReturn(0);
69595fce210SBarry Smith }
69695fce210SBarry Smith 
697*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFSetFromOptions_Window(PetscSF sf, PetscOptionItems *PetscOptionsObject)
698*d71ae5a4SJacob Faibussowitsch {
69995fce210SBarry Smith   PetscSF_Window         *w      = (PetscSF_Window *)sf->data;
7005b0d146aSStefano Zampini   PetscSFWindowFlavorType flavor = w->flavor;
70195fce210SBarry Smith 
70295fce210SBarry Smith   PetscFunctionBegin;
703d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "PetscSF Window options");
7049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-sf_window_sync", "synchronization type to use for PetscSF Window communication", "PetscSFWindowSetSyncType", PetscSFWindowSyncTypes, (PetscEnum)w->sync, (PetscEnum *)&w->sync, NULL));
7059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-sf_window_flavor", "flavor to use for PetscSF Window creation", "PetscSFWindowSetFlavorType", PetscSFWindowFlavorTypes, (PetscEnum)flavor, (PetscEnum *)&flavor, NULL));
7069566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowSetFlavorType(sf, flavor));
707d0609cedSBarry Smith   PetscOptionsHeadEnd();
70895fce210SBarry Smith   PetscFunctionReturn(0);
70995fce210SBarry Smith }
71095fce210SBarry Smith 
711*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFReset_Window(PetscSF sf)
712*d71ae5a4SJacob Faibussowitsch {
71395fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
71495fce210SBarry Smith   PetscSFDataLink link, next;
71595fce210SBarry Smith   PetscSFWinLink  wlink, wnext;
71695fce210SBarry Smith   PetscInt        i;
71795fce210SBarry Smith 
71895fce210SBarry Smith   PetscFunctionBegin;
71995fce210SBarry Smith   for (link = w->link; link; link = next) {
72095fce210SBarry Smith     next = link->next;
7219566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Type_free(&link->unit));
72295fce210SBarry Smith     for (i = 0; i < sf->nranks; i++) {
7239566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&link->mine[i]));
7249566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&link->remote[i]));
72595fce210SBarry Smith     }
7269566063dSJacob Faibussowitsch     PetscCall(PetscFree2(link->mine, link->remote));
7279566063dSJacob Faibussowitsch     PetscCall(PetscFree(link));
72895fce210SBarry Smith   }
72995fce210SBarry Smith   w->link = NULL;
73095fce210SBarry Smith   for (wlink = w->wins; wlink; wlink = wnext) {
73195fce210SBarry Smith     wnext = wlink->next;
73228b400f6SJacob Faibussowitsch     PetscCheck(!wlink->inuse, PetscObjectComm((PetscObject)sf), PETSC_ERR_ARG_WRONGSTATE, "Window still in use with address %p", (void *)wlink->addr);
7339566063dSJacob Faibussowitsch     PetscCall(PetscFree(wlink->dyn_target_addr));
7349566063dSJacob Faibussowitsch     PetscCall(PetscFree(wlink->reqs));
7359566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_free(&wlink->win));
7369566063dSJacob Faibussowitsch     PetscCall(PetscFree(wlink));
73795fce210SBarry Smith   }
73895fce210SBarry Smith   w->wins = NULL;
7399566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&w->dynsf));
74048a46eb9SPierre Jolivet   if (w->info != MPI_INFO_NULL) PetscCallMPI(MPI_Info_free(&w->info));
74195fce210SBarry Smith   PetscFunctionReturn(0);
74295fce210SBarry Smith }
74395fce210SBarry Smith 
744*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFDestroy_Window(PetscSF sf)
745*d71ae5a4SJacob Faibussowitsch {
74695fce210SBarry Smith   PetscFunctionBegin;
7479566063dSJacob Faibussowitsch   PetscCall(PetscSFReset_Window(sf));
7489566063dSJacob Faibussowitsch   PetscCall(PetscFree(sf->data));
7499566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetSyncType_C", NULL));
7509566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetSyncType_C", NULL));
7519566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetFlavorType_C", NULL));
7529566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetFlavorType_C", NULL));
7539566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetInfo_C", NULL));
7549566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetInfo_C", NULL));
75595fce210SBarry Smith   PetscFunctionReturn(0);
75695fce210SBarry Smith }
75795fce210SBarry Smith 
758*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFView_Window(PetscSF sf, PetscViewer viewer)
759*d71ae5a4SJacob Faibussowitsch {
76095fce210SBarry Smith   PetscSF_Window   *w = (PetscSF_Window *)sf->data;
76195fce210SBarry Smith   PetscBool         iascii;
7625b0d146aSStefano Zampini   PetscViewerFormat format;
76395fce210SBarry Smith 
76495fce210SBarry Smith   PetscFunctionBegin;
7659566063dSJacob Faibussowitsch   PetscCall(PetscViewerGetFormat(viewer, &format));
7669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));
76795fce210SBarry Smith   if (iascii) {
7689566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  current flavor=%s synchronization=%s MultiSF sort=%s\n", PetscSFWindowFlavorTypes[w->flavor], PetscSFWindowSyncTypes[w->sync], sf->rankorder ? "rank-order" : "unordered"));
7695b0d146aSStefano Zampini     if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
7705b0d146aSStefano Zampini       if (w->info != MPI_INFO_NULL) {
7715b0d146aSStefano Zampini         PetscMPIInt k, nkeys;
7725b0d146aSStefano Zampini         char        key[MPI_MAX_INFO_KEY], value[MPI_MAX_INFO_VAL];
7735b0d146aSStefano Zampini 
7749566063dSJacob Faibussowitsch         PetscCallMPI(MPI_Info_get_nkeys(w->info, &nkeys));
7759566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "    current info with %d keys. Ordered key-value pairs follow:\n", nkeys));
7765b0d146aSStefano Zampini         for (k = 0; k < nkeys; k++) {
7775b0d146aSStefano Zampini           PetscMPIInt flag;
7785b0d146aSStefano Zampini 
7799566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Info_get_nthkey(w->info, k, key));
7809566063dSJacob Faibussowitsch           PetscCallMPI(MPI_Info_get(w->info, key, MPI_MAX_INFO_VAL, value, &flag));
78128b400f6SJacob Faibussowitsch           PetscCheck(flag, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing key %s", key);
7829566063dSJacob Faibussowitsch           PetscCall(PetscViewerASCIIPrintf(viewer, "      %s = %s\n", key, value));
7835b0d146aSStefano Zampini         }
7845b0d146aSStefano Zampini       } else {
7859566063dSJacob Faibussowitsch         PetscCall(PetscViewerASCIIPrintf(viewer, "    current info=MPI_INFO_NULL\n"));
7865b0d146aSStefano Zampini       }
7875b0d146aSStefano Zampini     }
78895fce210SBarry Smith   }
78995fce210SBarry Smith   PetscFunctionReturn(0);
79095fce210SBarry Smith }
79195fce210SBarry Smith 
792*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFDuplicate_Window(PetscSF sf, PetscSFDuplicateOption opt, PetscSF newsf)
793*d71ae5a4SJacob Faibussowitsch {
79495fce210SBarry Smith   PetscSF_Window       *w = (PetscSF_Window *)sf->data;
79595fce210SBarry Smith   PetscSFWindowSyncType synctype;
79695fce210SBarry Smith 
79795fce210SBarry Smith   PetscFunctionBegin;
79895fce210SBarry Smith   synctype = w->sync;
79995fce210SBarry Smith   /* HACK: Must use FENCE or LOCK when called from PetscSFGetGroups() because ACTIVE here would cause recursion. */
8005b0d146aSStefano Zampini   if (!sf->setupcalled) synctype = PETSCSF_WINDOW_SYNC_LOCK;
8019566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowSetSyncType(newsf, synctype));
8029566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowSetFlavorType(newsf, w->flavor));
8039566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowSetInfo(newsf, w->info));
80495fce210SBarry Smith   PetscFunctionReturn(0);
80595fce210SBarry Smith }
80695fce210SBarry Smith 
807*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFBcastBegin_Window(PetscSF sf, MPI_Datatype unit, PetscMemType rootmtype, const void *rootdata, PetscMemType leafmtype, void *leafdata, MPI_Op op)
808*d71ae5a4SJacob Faibussowitsch {
80995fce210SBarry Smith   PetscSF_Window     *w = (PetscSF_Window *)sf->data;
81095fce210SBarry Smith   PetscInt            i, nranks;
81195fce210SBarry Smith   const PetscMPIInt  *ranks;
8125b0d146aSStefano Zampini   const MPI_Aint     *target_disp;
81395fce210SBarry Smith   const MPI_Datatype *mine, *remote;
814684a874aSStefano Zampini   MPI_Request        *reqs;
81595fce210SBarry Smith   MPI_Win             win;
81695fce210SBarry Smith 
81795fce210SBarry Smith   PetscFunctionBegin;
81808401ef6SPierre Jolivet   PetscCheck(op == MPI_REPLACE, PetscObjectComm((PetscObject)sf), PETSC_ERR_SUP, "PetscSFBcastBegin_Window with op!=MPI_REPLACE has not been implemented");
8199566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL));
8209566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowGetDataTypes(sf, unit, &mine, &remote));
8219566063dSJacob 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));
82295fce210SBarry Smith   for (i = 0; i < nranks; i++) {
8235b0d146aSStefano Zampini     MPI_Aint tdp = target_disp ? target_disp[i] : 0;
8245b0d146aSStefano Zampini 
825684a874aSStefano Zampini     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) {
8269566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Win_lock(MPI_LOCK_SHARED, ranks[i], MPI_MODE_NOCHECK, win));
827684a874aSStefano Zampini #if defined(PETSC_HAVE_MPI_RGET)
8289566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Rget(leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], win, &reqs[i]));
829684a874aSStefano Zampini #else
8309566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Get(leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], win));
831684a874aSStefano Zampini #endif
832684a874aSStefano Zampini     } else {
8339566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Get(leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], win));
834684a874aSStefano Zampini     }
83595fce210SBarry Smith   }
83695fce210SBarry Smith   PetscFunctionReturn(0);
83795fce210SBarry Smith }
83895fce210SBarry Smith 
839*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFBcastEnd_Window(PetscSF sf, MPI_Datatype unit, const void *rootdata, void *leafdata, MPI_Op op)
840*d71ae5a4SJacob Faibussowitsch {
8415b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
84295fce210SBarry Smith   MPI_Win         win;
8434b9acda6SJunchao Zhang   MPI_Request    *reqs = NULL;
84495fce210SBarry Smith 
84595fce210SBarry Smith   PetscFunctionBegin;
8469566063dSJacob Faibussowitsch   PetscCall(PetscSFFindWindow(sf, unit, rootdata, &win, &reqs));
8479566063dSJacob Faibussowitsch   if (reqs) PetscCallMPI(MPI_Waitall(sf->nranks, reqs, MPI_STATUSES_IGNORE));
848684a874aSStefano Zampini   if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) {
849684a874aSStefano Zampini     PetscInt           i, nranks;
850684a874aSStefano Zampini     const PetscMPIInt *ranks;
851684a874aSStefano Zampini 
8529566063dSJacob Faibussowitsch     PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL));
85348a46eb9SPierre Jolivet     for (i = 0; i < nranks; i++) PetscCallMPI(MPI_Win_unlock(ranks[i], win));
854684a874aSStefano Zampini   }
8559566063dSJacob Faibussowitsch   PetscCall(PetscSFRestoreWindow(sf, unit, (void *)rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOSTORE | MPI_MODE_NOSUCCEED, PETSC_FALSE, &win));
85695fce210SBarry Smith   PetscFunctionReturn(0);
85795fce210SBarry Smith }
85895fce210SBarry Smith 
859*d71ae5a4SJacob Faibussowitsch PetscErrorCode PetscSFReduceBegin_Window(PetscSF sf, MPI_Datatype unit, PetscMemType leafmtype, const void *leafdata, PetscMemType rootmtype, void *rootdata, MPI_Op op)
860*d71ae5a4SJacob Faibussowitsch {
86195fce210SBarry Smith   PetscSF_Window     *w = (PetscSF_Window *)sf->data;
86295fce210SBarry Smith   PetscInt            i, nranks;
86395fce210SBarry Smith   const PetscMPIInt  *ranks;
8645b0d146aSStefano Zampini   const MPI_Aint     *target_disp;
86595fce210SBarry Smith   const MPI_Datatype *mine, *remote;
86695fce210SBarry Smith   MPI_Win             win;
86795fce210SBarry Smith 
86895fce210SBarry Smith   PetscFunctionBegin;
8699566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL));
8709566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowGetDataTypes(sf, unit, &mine, &remote));
8719566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowOpTranslate(&op));
8729566063dSJacob Faibussowitsch   PetscCall(PetscSFGetWindow(sf, unit, rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOPRECEDE, 0, 0, &target_disp, NULL, &win));
87395fce210SBarry Smith   for (i = 0; i < nranks; i++) {
8745b0d146aSStefano Zampini     MPI_Aint tdp = target_disp ? target_disp[i] : 0;
8755b0d146aSStefano Zampini 
8769566063dSJacob Faibussowitsch     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_lock(MPI_LOCK_SHARED, ranks[i], MPI_MODE_NOCHECK, win));
8779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Accumulate((void *)leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], op, win));
8789566063dSJacob Faibussowitsch     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_unlock(ranks[i], win));
87995fce210SBarry Smith   }
88095fce210SBarry Smith   PetscFunctionReturn(0);
88195fce210SBarry Smith }
88295fce210SBarry Smith 
883*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFReduceEnd_Window(PetscSF sf, MPI_Datatype unit, const void *leafdata, void *rootdata, MPI_Op op)
884*d71ae5a4SJacob Faibussowitsch {
88595fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
88695fce210SBarry Smith   MPI_Win         win;
8874b9acda6SJunchao Zhang   MPI_Request    *reqs = NULL;
88895fce210SBarry Smith 
88995fce210SBarry Smith   PetscFunctionBegin;
8909566063dSJacob Faibussowitsch   PetscCall(PetscSFFindWindow(sf, unit, rootdata, &win, &reqs));
8919566063dSJacob Faibussowitsch   if (reqs) PetscCallMPI(MPI_Waitall(sf->nranks, reqs, MPI_STATUSES_IGNORE));
8929566063dSJacob Faibussowitsch   PetscCall(PetscSFRestoreWindow(sf, unit, rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOSUCCEED, PETSC_TRUE, &win));
89395fce210SBarry Smith   PetscFunctionReturn(0);
89495fce210SBarry Smith }
8955b0d146aSStefano Zampini 
896*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFFetchAndOpBegin_Window(PetscSF sf, MPI_Datatype unit, PetscMemType rootmtype, void *rootdata, PetscMemType leafmtype, const void *leafdata, void *leafupdate, MPI_Op op)
897*d71ae5a4SJacob Faibussowitsch {
89895fce210SBarry Smith   PetscInt            i, nranks;
89995fce210SBarry Smith   const PetscMPIInt  *ranks;
90095fce210SBarry Smith   const MPI_Datatype *mine, *remote;
9015b0d146aSStefano Zampini   const MPI_Aint     *target_disp;
90295fce210SBarry Smith   MPI_Win             win;
9035b0d146aSStefano Zampini   PetscSF_Window     *w = (PetscSF_Window *)sf->data;
9045b0d146aSStefano Zampini #if !defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9055b0d146aSStefano Zampini   PetscSFWindowFlavorType oldf;
9065b0d146aSStefano Zampini #endif
90795fce210SBarry Smith 
90895fce210SBarry Smith   PetscFunctionBegin;
9099566063dSJacob Faibussowitsch   PetscCall(PetscSFGetRootRanks(sf, &nranks, &ranks, NULL, NULL, NULL));
9109566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowGetDataTypes(sf, unit, &mine, &remote));
9119566063dSJacob Faibussowitsch   PetscCall(PetscSFWindowOpTranslate(&op));
9125b0d146aSStefano Zampini #if !defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9135b0d146aSStefano Zampini   /* FetchAndOp without MPI_Get_Accumulate requires locking.
9145b0d146aSStefano Zampini      we create a new window every time to not interfere with user-defined MPI_Info which may have used "no_locks"="true" */
9155b0d146aSStefano Zampini   oldf      = w->flavor;
9165b0d146aSStefano Zampini   w->flavor = PETSCSF_WINDOW_FLAVOR_CREATE;
9179566063dSJacob Faibussowitsch   PetscCall(PetscSFGetWindow(sf, unit, rootdata, PETSCSF_WINDOW_SYNC_LOCK, PETSC_FALSE, 0, 0, 0, &target_disp, NULL, &win));
9185b0d146aSStefano Zampini #else
9199566063dSJacob Faibussowitsch   PetscCall(PetscSFGetWindow(sf, unit, rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOPRECEDE, 0, 0, &target_disp, NULL, &win));
9205b0d146aSStefano Zampini #endif
9215b0d146aSStefano Zampini   for (i = 0; i < nranks; i++) {
9225b0d146aSStefano Zampini     MPI_Aint tdp = target_disp ? target_disp[i] : 0;
9235b0d146aSStefano Zampini 
9245b0d146aSStefano Zampini #if !defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9259566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_lock(MPI_LOCK_EXCLUSIVE, ranks[i], 0, win));
9269566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Get(leafupdate, 1, mine[i], ranks[i], tdp, 1, remote[i], win));
9279566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Accumulate((void *)leafdata, 1, mine[i], ranks[i], tdp, 1, remote[i], op, win));
9289566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Win_unlock(ranks[i], win));
9295b0d146aSStefano Zampini #else
9309566063dSJacob Faibussowitsch     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_lock(MPI_LOCK_SHARED, ranks[i], 0, win));
9319566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Get_accumulate((void *)leafdata, 1, mine[i], leafupdate, 1, mine[i], ranks[i], tdp, 1, remote[i], op, win));
9329566063dSJacob Faibussowitsch     if (w->sync == PETSCSF_WINDOW_SYNC_LOCK) PetscCallMPI(MPI_Win_unlock(ranks[i], win));
9335b0d146aSStefano Zampini #endif
9345b0d146aSStefano Zampini   }
9355b0d146aSStefano Zampini #if !defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9365b0d146aSStefano Zampini   w->flavor = oldf;
9375b0d146aSStefano Zampini #endif
93895fce210SBarry Smith   PetscFunctionReturn(0);
93995fce210SBarry Smith }
94095fce210SBarry Smith 
941*d71ae5a4SJacob Faibussowitsch static PetscErrorCode PetscSFFetchAndOpEnd_Window(PetscSF sf, MPI_Datatype unit, void *rootdata, const void *leafdata, void *leafupdate, MPI_Op op)
942*d71ae5a4SJacob Faibussowitsch {
94395fce210SBarry Smith   MPI_Win win;
9445b0d146aSStefano Zampini #if defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9455b0d146aSStefano Zampini   PetscSF_Window *w = (PetscSF_Window *)sf->data;
9465b0d146aSStefano Zampini #endif
9474b9acda6SJunchao Zhang   MPI_Request *reqs = NULL;
94895fce210SBarry Smith 
94995fce210SBarry Smith   PetscFunctionBegin;
9509566063dSJacob Faibussowitsch   PetscCall(PetscSFFindWindow(sf, unit, rootdata, &win, &reqs));
9519566063dSJacob Faibussowitsch   if (reqs) PetscCallMPI(MPI_Waitall(sf->nranks, reqs, MPI_STATUSES_IGNORE));
9525b0d146aSStefano Zampini #if defined(PETSC_HAVE_MPI_GET_ACCUMULATE)
9539566063dSJacob Faibussowitsch   PetscCall(PetscSFRestoreWindow(sf, unit, rootdata, w->sync, PETSC_TRUE, MPI_MODE_NOSUCCEED, PETSC_TRUE, &win));
9545b0d146aSStefano Zampini #else
9559566063dSJacob Faibussowitsch   PetscCall(PetscSFRestoreWindow(sf, unit, rootdata, PETSCSF_WINDOW_SYNC_LOCK, PETSC_FALSE, 0, PETSC_TRUE, &win));
9565b0d146aSStefano Zampini #endif
95795fce210SBarry Smith   PetscFunctionReturn(0);
95895fce210SBarry Smith }
95995fce210SBarry Smith 
960*d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode PetscSFCreate_Window(PetscSF sf)
961*d71ae5a4SJacob Faibussowitsch {
96295fce210SBarry Smith   PetscSF_Window *w = (PetscSF_Window *)sf->data;
96395fce210SBarry Smith 
96495fce210SBarry Smith   PetscFunctionBegin;
96595fce210SBarry Smith   sf->ops->SetUp           = PetscSFSetUp_Window;
96695fce210SBarry Smith   sf->ops->SetFromOptions  = PetscSFSetFromOptions_Window;
96795fce210SBarry Smith   sf->ops->Reset           = PetscSFReset_Window;
96895fce210SBarry Smith   sf->ops->Destroy         = PetscSFDestroy_Window;
96995fce210SBarry Smith   sf->ops->View            = PetscSFView_Window;
97095fce210SBarry Smith   sf->ops->Duplicate       = PetscSFDuplicate_Window;
971ad227feaSJunchao Zhang   sf->ops->BcastBegin      = PetscSFBcastBegin_Window;
972ad227feaSJunchao Zhang   sf->ops->BcastEnd        = PetscSFBcastEnd_Window;
97395fce210SBarry Smith   sf->ops->ReduceBegin     = PetscSFReduceBegin_Window;
97495fce210SBarry Smith   sf->ops->ReduceEnd       = PetscSFReduceEnd_Window;
97595fce210SBarry Smith   sf->ops->FetchAndOpBegin = PetscSFFetchAndOpBegin_Window;
97695fce210SBarry Smith   sf->ops->FetchAndOpEnd   = PetscSFFetchAndOpEnd_Window;
97795fce210SBarry Smith 
9784dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&w));
97995fce210SBarry Smith   sf->data  = (void *)w;
98095fce210SBarry Smith   w->sync   = PETSCSF_WINDOW_SYNC_FENCE;
9815b0d146aSStefano Zampini   w->flavor = PETSCSF_WINDOW_FLAVOR_CREATE;
9825b0d146aSStefano Zampini   w->info   = MPI_INFO_NULL;
98395fce210SBarry Smith 
9849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetSyncType_C", PetscSFWindowSetSyncType_Window));
9859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetSyncType_C", PetscSFWindowGetSyncType_Window));
9869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetFlavorType_C", PetscSFWindowSetFlavorType_Window));
9879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetFlavorType_C", PetscSFWindowGetFlavorType_Window));
9889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowSetInfo_C", PetscSFWindowSetInfo_Window));
9899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)sf, "PetscSFWindowGetInfo_C", PetscSFWindowGetInfo_Window));
99095fce210SBarry Smith 
99195fce210SBarry Smith #if defined(OMPI_MAJOR_VERSION) && (OMPI_MAJOR_VERSION < 1 || (OMPI_MAJOR_VERSION == 1 && OMPI_MINOR_VERSION <= 6))
99295fce210SBarry Smith   {
99395fce210SBarry Smith     PetscBool ackbug = PETSC_FALSE;
9949566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, NULL, "-acknowledge_ompi_onesided_bug", &ackbug, NULL));
99595fce210SBarry Smith     if (ackbug) {
9969566063dSJacob Faibussowitsch       PetscCall(PetscInfo(sf, "Acknowledged Open MPI bug, proceeding anyway. Expect memory corruption.\n"));
99795fce210SBarry 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");
99895fce210SBarry Smith   }
99995fce210SBarry Smith #endif
100095fce210SBarry Smith   PetscFunctionReturn(0);
100195fce210SBarry Smith }
1002