charmplusplus / charm4py

Parallel Programming with Python and Charm++
https://charm4py.readthedocs.io
Apache License 2.0
289 stars 21 forks source link

Section reductions do not always work as expected #180

Closed ZwFink closed 3 years ago

ZwFink commented 3 years ago

Most reduction types do not work when chares in a section contribute to a reduction where each chare contributes a list of values. Some reduction types do not work when the chares are contributing to a section at all.

An example program using Reducer.sum:

from charm4py import *

class A( Chare ):
    def contr( self, future, proxy, doTuple ):
        if doTuple:
            contrib = [1,1]
        else:
            contrib = 1
        if proxy:
            self.contribute( contrib, Reducer.sum, future, proxy )
        else:
            self.reduce( future, contrib, Reducer.sum )

def main( args ):
    arr = Array( A, 10 )

    # Split the odd and even-numbered chares into sections
    sec1 = arr[ 0:10:2 ]
    sec2 = arr[ 1:10:2 ]

    oneFut = Future()
    twoFut = Future()
    redFut = Future()
    blueFut = Future()

    sec1.contr( oneFut, sec1, True )
    sec2.contr( twoFut, sec2, True )
    arr.contr( redFut, None, True )
    arr.contr( blueFut, None, False )

    print( oneFut.get() ) # Expected: [5, 5]
    print( twoFut.get() ) # Expected: [5, 5]
    print( redFut.get() ) # Expected: [10, 10]
    print( blueFut.get() ) # Expected: 10
    exit()

charm.start( main )

When the chares attempt to contribute to their respective sections, the program crashes with the following:

Fatal error on PE 1> TypeError: unsupported operand type(s) for +: 'int' and 'list'

It seems that a function equivalent to Python's built-in sum is called when the chares contribute to a section, while a different function is used when no section is specified. Running sum([list(),list()]) produces the same error.

If the chares contribute single values to the reduction, the program behaves as expected. Changing the contr calls to the following runs as expected:

    sec1.contr( oneFut, sec1, False )
    sec2.contr( twoFut, sec2, False )
    arr.contr( redFut, None, True )
    arr.contr( blueFut, None, False )

Reducer.sum is used as an illustrative example, but many of the default reducer types have similar issues. The built-in reduction types that do not work and the incorrect behavior they exhibit are as follows:

The default reduction types that work as expected are Reducer.min and Reducer.max.