Day 100: PMI. Interesting observation #1In this example I will be testing if PMI passes objects from Serial into Parallel by reference or by value. First I will give the output of my little test script, and then the source code.
############ TEST 1: PASSING FROM SERIAL INTO PARALLEL ############
Testing PMI pass by reference: an array is created in Serial and then passed into Parallel
array before mpi.invoke: [1 2 3]
If the array was passed by _value_ then after modifying it in Parallel it should remain
unchanged in Serial
array after mpi.invoke: [1000 2 3]
As you can see, the array has been changed in serial as well, which proves that objects
are passed by reference in pmi.
############ TEST 2: PASSING FROM PARALLEL INTO SERIAL ############
Now we'll check if modifying the same array in Serial will make it change in Parallel
The array: [1000 2 3]
Changed the first element to be 999: [999 2 3]
Now calling pmi.invoke that will make Parallel print out the array (it has been stored
as a class atribute during the previous experiment)
Node 0 array: [999 2 3]
Node 1 array: [1000 2 3]
Oops! It seems like objects are passed by reference only between Serial and node 0 of parallel.
Let's verify that: the next pmi.invoke will call a method in Parallel that will attempt to set
the second array element to be 1000 on node 0 (and only on node 0) and the third element to be
1000 on node 1 (and node 1 only)
############ TEST 3: CHANGING DIFFERENT ELEMENTS ON DIFFERENT NODES ############
Once again, array before pmi.invoke: [999 2 3]
Array after pmi.invoke: [ 999 1000 3]
Ok, that proves the case that objects are indeed passed by reference in pmi between Serial
and Parallel,but only for the first node. For all other nodes they are passed by reference.
This is a bit tricky, but might be useful.
and the source code:
if __name__ != 'pmi':
##################################################
## Serial code
##################################################
import pmi
from time import time
from numpy import array
pmi.setup()
pmi.execfile_(__file__)
# create a frontend class
class Hello(object):
def __init__(self, name):
self.pmiobj = pmi.create('HelloLocal', name)
def __call__(self):
return pmi.invoke(self.pmiobj, '__call__')
def check_pass_by_ref1(self,arr):
pmi.invoke(self.pmiobj,"modify_array",arr)
def check_pass_by_ref2(self):
pmi.invoke(self.pmiobj,"print_array")
def check_pass_by_ref3(self):
pmi.invoke(self.pmiobj,"modify_array2")
# use the class
hello = Hello('Konstantin')
a = array([1,2,3])
print "############ TEST 1: PASSING FROM SERIAL INTO PARALLEL ############"
print "Testing PMI pass by reference: an array is created in Serial and then passed into Parallel"
print "array before mpi.invoke:",a
hello.check_pass_by_ref1(a)
print "If the array was passed by _value_ then after modifying it in Parallel it should remain"
print "unchanged in Serial"
print "array after mpi.invoke:",a
print "As you can see, the array has been changed in serial as well, which proves that objects"
print "are passed by reference in pmi."
# test 2
print ""
print "############ TEST 2: PASSING FROM PARALLEL INTO SERIAL ############"
print "Now we'll check if modifying the same array in Serial will make it change in Parallel"
print "The array:", a
a[0] = 999
print "Changed the first element to be 999:", a
print "Now calling pmi.invoke that will make Parallel print out the array (it has been stored"
print "as a class atribute during the previous experiment)"
hello.check_pass_by_ref2()
print "Oops! It seems like objects are passed by reference only between Serial and node 0 of parallel."
print "Let's verify that: the next pmi.invoke will call a method in Parallel that will attempt to set"
print "the second array element to be 1000 on node 0 (and only on node 0) and the third element to be"
print " 1000 on node 1 (and node 1 only)"
print ""
print "############ TEST 3: CHANGING DIFFERENT ELEMENTS ON DIFFERENT NODES ############"
print "Once again, array before pmi.invoke:",a
hello.check_pass_by_ref3()
print "Array after pmi.invoke:",a
print ""
print "Ok, that proves the case that objects are indeed passed by reference in pmi between Serial"
print "and Parallel,but only for the first node. For all other nodes they are passed by reference."
print " This is a bit tricky, but might be useful."
else:
##################################################
## Parallel code
##################################################
from mpi4py import MPI
from numpy.random import beta
y = beta(a=1,b=1000,size=(210,210))
class HelloLocal(object):
def __init__(self, name):
self.name = name
self.rank = MPI.COMM_WORLD.Get_rank()
def __call__(self):
return 'Hello %s, this is MPI task %d!' % (self.name, MPI.COMM_WORLD.rank)
def modify_array(self,arr):
self.arr = arr
self.arr[0] = 1000
def modify_array2(self):
if self.rank== 0:
self.arr[1] = 1000
if self.rank== 1:
self.arr[2] = 1000
def print_array(self):
print "Node",self.rank,"array:",self.arr
I think, the reason for this is very simple: PMI seems to be broadcasting the data to all nodes, when pmi.invoke is issued, (perhaps, using MPI bcast()) from node 0 and keep the broadcast data on node 0 as it is, i.e. reference to the object passed into pmi.invoke, and not the copy of this object.