Reductions¶
A reduction is a distributed and scalable operation that reduces data
distributed across chares into a smaller set of data.
A reduction involves the chares in a collection (Group, Array or Section). They are
started by the elements calling their Chare.reduce()
or Chare.allreduce()
methods (see Chare).
Important
Reduction calls are asynchronous and return immediately. Chares can start multiple reduction operations at the same time, but every chare in the same collection must contribute to reductions in the same order.
Reducers¶
charm4py.Reducer
contains the reducer functions that have been registered with
the runtime. Reducer functions are used in reductions, to aggregate data across the members
of a chare collection.
Reducer
has the following built-in attributes (reducers) for use in reductions:
max
: max function. When contributions are vectors (lists or arrays) of numbers, the reduction result will be the pairwise or “parallel” maxima of the vectors.min
: min function. Pairwise minima in the case of vector contributions.sum
: sum function. Pairwise sum in the case of vector contributions.product
: product function. Pairwise product in the case of vector contributions.logical_and
: logical and. Requires bool values or arrays of bools.logical_or
: logical or. Requires bool values or arrays of bools.logical_xor
: logical xor. Requires bool values or arrays of bools.gather
: Adds contributions to a Python list, and sorts the list based on the index of the contributors in their collection.
Registering custom reducers¶
To register a custom reducer function:
Reducer.addReducer(func, pre=None, post=None):
Where func is a Python function with one parameter (list of contributions), and must return the result of reducing the given contributions. pre is optional and is a function intended to pre-process data passed in reduce calls. It must take two parameters
(data, contributor)
, wheredata
is the data passed in a reduce call andcontributor
is the chare object. post is optional and is a function intended to post-process the data after the whole reduction operation has completed. It takes only one parameter, which is the reduced data.
To refer to a custom reducer:
Reducer.name
, where name
is the name of the function that was passed to addReducer
.
Example¶
from charm4py import charm, Chare, Group, Reducer
import numpy as np
DATA_SIZE = 100
NUM_ITER = 20
class A(Chare):
def __init__(self):
self.data = np.zeros(DATA_SIZE)
self.iteration = 0
def work(self):
# ... do some computation, modifying self.data ...
# do reduction and send result to element 0
self.reduce(self.thisProxy[0].collectResult, self.data, Reducer.sum)
def collectResult(self, result):
# ... do something with result ...
self.iteration += 1
if self.iteration == NUM_ITER:
exit()
else:
# continue doing work
self.thisProxy.work()
def main(args):
g = Group(A)
g.work()
charm.start(main)