The static variable apg is accessed by most of the collective operations in the library. Its value should reflect the currently effective active progress group. Its declaration is
extern Group apg ;
When an Adlib program starts the value of apg represents the initial process group. If collective operations are to function properly there is an onus on the programmer to maintain the value of apg consistently. In this section three common idiomatic ways of modifying the active process group are discussed.
The first idiom involves a conditional construct which restricts the set of processes performing a block of code to some group, p. Membership of the local process in this group is determined by calling p.member(), as follows:
if(p.member()) { ... }
If it is necessary to invoke collective library operations inside the construct, apg must be reset appropriately. Assuming the construct appears at the point where p is a subset of the active process group, the logical active process group inside the construct will be the whole of p. Appropriate manipulations of apg are
Group apgSave = apg ; if(p.member()) { apg = p ; ... } apg = apgSave ;
The only subtlety is the need to save the old value of apg so that it can be restored on completion of the construct. With these manipulations of the apg variable we can safely invoke collective operations before, during and after the conditional construct. This idiom will sometimes be called an on construct. In the ad++ interface to Adlib macros ON/NO are defined to allow the whole of the fragment above to be written as
ON(p) { ... } NO(p) ;
A second common idiom for modifiying apg occurs when the logical active process group is partitioned by breaking up one of its process dimensions. Suppose the current active process group is a multi-dimensional array of processes. One of its process dimensions is d. Suppose we need to perform operations collectively across dimensions orthogonal to d, but independently for each value of the d coordinate. In this case the value of apg should be temporarily changed as follows
Group apgSave = apg ; apg.restrict(d) ; ... apg = apgSave ;
In the ad++ interface, for example, this kind of manipulation of apg occurs in the AT/TA construct and OVERALL/ ALLOVER distributed loop.
The preceding idiom allows for regular partitioning
of the active process group across one of its dimensions.
A different technique can be used to achieve arbitrary partitioning.
Suppose each of is a set of processes,
and together they partition the current active process group, A.
For each i in
,
is a vector of
ids (relative to A) for the processes in
, and
and
define a rank and
a shape for a grid of size
.
Now, if the local process is a member of
, the following constructor call
Procs p(
,
,
)
creates n logically distinct collective objects representing non-overlapping process arrays. An on construct using p will now partition the active process group as required. For example, suppose the current active process group has 5 processes. We can partition these temporarily into groups of 2 and 3 as follows
int shp [1], *ids ; if(apg.id() < 2) { shp [0] = 2 ; ids = {0, 1} ; } else { shp [0] = 3 ; ids = {2, 3, 4} ; } Procs p(1, shp, ids) ; Group apgSave = apg ; if(p.member()) { apg = p ; ... } apg = apgSave ;
This use of the Procs constructor departs slightly from usual rules for collective operations, because when the constructor is called the value of apg is the original active process group, but its arguments take different values in sectors of that group which will later be in separate partitions.
Notice that the idioms we have introduced in this section can be nested freely. As usual, the only subtlety is in ensuring that old values of the active process group are restored properly when the constructs complete. This can be achieved either by using a suitable series of automatic variables (like apgSave), or by using an explicit stack of group objects.