Skip to content
Snippets Groups Projects
Commit d3f61316 authored by Kenny Sharma's avatar Kenny Sharma
Browse files

[NRRPLT-5486] Support multi-process RNG seed.

This patch adds support for setting a global RNG seed to be used
across all processes - the CLE and brain processes.

Change-Id: I8f4554e0684fa69bb801083e5f9dbecaa275f8f8
parent 86686d41
No related branches found
No related tags found
No related merge requests found
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
""" """
A distributed brain process that can be launched standalone on remote hosts. A distributed brain process that can be launched standalone on remote hosts.
""" """
from hbp_nrp_cle.brainsim import config
from hbp_nrp_cle.brainsim.pynn import simulator as sim from hbp_nrp_cle.brainsim.pynn import simulator as sim
from hbp_nrp_cle.brainsim.pynn.PyNNControlAdapter import PyNNControlAdapter from hbp_nrp_cle.brainsim.pynn.PyNNControlAdapter import PyNNControlAdapter
import hbp_nrp_cle.tf_framework.config as tf_config import hbp_nrp_cle.tf_framework.config as tf_config
...@@ -51,7 +52,7 @@ class MUSICBrainProcess(object): ...@@ -51,7 +52,7 @@ class MUSICBrainProcess(object):
# tag to listen for MPI configuration/command messages # tag to listen for MPI configuration/command messages
MPI_MSG_TAG = 100 MPI_MSG_TAG = 100
def __init__(self, bibi_file): def __init__(self, bibi_file, rng_seed):
""" """
Load the distributed brain and construct MUSIC proxies for communication Load the distributed brain and construct MUSIC proxies for communication
to/from the CLE. Nest will automatically allocate the brain in a round-robin to/from the CLE. Nest will automatically allocate the brain in a round-robin
...@@ -74,6 +75,9 @@ class MUSICBrainProcess(object): ...@@ -74,6 +75,9 @@ class MUSICBrainProcess(object):
"defined on target node!") "defined on target node!")
brain_file = os.path.join(models_path, self._bibi.brainModel.file) brain_file = os.path.join(models_path, self._bibi.brainModel.file)
# set the RNG seed before initializing any PyNN interfaces in the brain controller
config.rng_seed = int(rng_seed)
# spawn CLE components that will handle loading the brain file and interfaces # spawn CLE components that will handle loading the brain file and interfaces
self._brain_controller = PyNNControlAdapter() self._brain_controller = PyNNControlAdapter()
self._brain_controller.initialize() self._brain_controller.initialize()
...@@ -192,10 +196,12 @@ if __name__ == '__main__': # pragma: no cover ...@@ -192,10 +196,12 @@ if __name__ == '__main__': # pragma: no cover
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--bibi-file', dest='bibi_file', parser.add_argument('--bibi-file', dest='bibi_file',
help='the bibi file path to load', required=True) help='the bibi file path to load', required=True)
parser.add_argument('--rng-seed', dest='rng_seed',
help='the global experiment RNG seed', required=True)
args = parser.parse_args() args = parser.parse_args()
# construct brain and proxies (expand environment variables in paths) # construct brain and proxies (expand environment variables in paths)
brain = MUSICBrainProcess(os.path.expandvars(args.bibi_file)) brain = MUSICBrainProcess(os.path.expandvars(args.bibi_file), args.rng_seed)
# run the brain until terminated, this is a blocking call # run the brain until terminated, this is a blocking call
brain.run() brain.run()
......
...@@ -31,6 +31,8 @@ from hbp_nrp_music_interface.launch.host.LocalLauncher import LocalLauncher ...@@ -31,6 +31,8 @@ from hbp_nrp_music_interface.launch.host.LocalLauncher import LocalLauncher
from hbp_nrp_music_interface.launch.host.LuganoLauncher import LuganoLauncher from hbp_nrp_music_interface.launch.host.LuganoLauncher import LuganoLauncher
import os import os
import random
import sys
class MUSICLauncher(object): class MUSICLauncher(object):
...@@ -78,20 +80,22 @@ class MUSICLauncher(object): ...@@ -78,20 +80,22 @@ class MUSICLauncher(object):
# the MPI process launcher for the CLE and brain processes # the MPI process launcher for the CLE and brain processes
self.cle_server = None self.cle_server = None
def init(self, bibi, brain_processes): def init(self, bibi, exd):
""" """
Construct the MUSIC launch configuration that will spawn CLE + brain processes Construct the MUSIC launch configuration that will spawn CLE + brain processes
on distributed hosts. on distributed hosts.
:param bibi The BIBI configuration to launch brain processes with. :param bibi The BIBI configuration to launch brain processes with.
:param brain_processes The number of brain processses (does not include CLE process). :param exd The parsed ExDConf configuration to launch brain processes with.
""" """
# create a host specific launcher # create a host specific launcher
if self._server_host == 'local': if self._server_host == 'local':
self._launcher = LocalLauncher() self._launcher = LocalLauncher()
elif self._server_host == 'lugano': elif self._server_host == 'lugano':
self._launcher = LuganoLauncher(brain_processes + 1, self._timeout, self._reservation) self._launcher = LuganoLauncher(exd.bibiConf.processes + 1,
self._timeout,
self._reservation)
else: else:
raise Exception('Unknown server host {}, cannot configure and launch MUSIC!' raise Exception('Unknown server host {}, cannot configure and launch MUSIC!'
.format(self._server_host)) .format(self._server_host))
...@@ -104,6 +108,9 @@ class MUSICLauncher(object): ...@@ -104,6 +108,9 @@ class MUSICLauncher(object):
reservation_str = self._reservation if self._reservation else '' reservation_str = self._reservation if self._reservation else ''
timeout_str = str(self._timeout).replace(' ', '_') timeout_str = str(self._timeout).replace(' ', '_')
# extract the multiprocess RNG seed to use or generate one if needed
rng_seed = exd.rngSeed if exd.rngSeed is not None else random.randint(1, sys.maxint)
# build a MUSIC configuration script with correct brain ports, launchers and arugments # build a MUSIC configuration script with correct brain ports, launchers and arugments
# save it to the host launcher temp directory, this is the same for every host # save it to the host launcher temp directory, this is the same for every host
music_conf = bibi_music_config.MUSICConfiguration(bibi) music_conf = bibi_music_config.MUSICConfiguration(bibi)
...@@ -116,12 +123,14 @@ class MUSICLauncher(object): ...@@ -116,12 +123,14 @@ class MUSICLauncher(object):
'--reservation={}'.format(reservation_str), '--reservation={}'.format(reservation_str),
'--sim-id={}'.format(self._sim_id), '--sim-id={}'.format(self._sim_id),
'--timeout={}'.format(timeout_str), '--timeout={}'.format(timeout_str),
'--rng-seed={}'.format(rng_seed),
'--music'], '--music'],
1) 1)
music_conf.add_application('BRAIN', music_conf.add_application('BRAIN',
brain_launcher, brain_launcher,
['--bibi-file={}'.format(self._bibi_file)], ['--bibi-file={}'.format(self._bibi_file),
brain_processes) '--rng-seed={}'.format(rng_seed)],
exd.bibiConf.processes)
music_conf.save(self._launcher.local_tmpdir) music_conf.save(self._launcher.local_tmpdir)
# deploy the generated configuration files / launch scripts to the target host # deploy the generated configuration files / launch scripts to the target host
...@@ -132,7 +141,7 @@ class MUSICLauncher(object): ...@@ -132,7 +141,7 @@ class MUSICLauncher(object):
self.cle_server = MUSICMPILauncher() self.cle_server = MUSICMPILauncher()
self.cle_server.add_host(self._launcher.hostname, self.cle_server.add_host(self._launcher.hostname,
self._launcher.host_tmpdir, self._launcher.host_tmpdir,
brain_processes + 1) exd.bibiConf.processes + 1)
# construct the mpi command line with the above host/launch information # construct the mpi command line with the above host/launch information
self.cle_server.build() self.cle_server.build()
......
...@@ -59,8 +59,13 @@ class TestMUSICLauncher(unittest.TestCase): ...@@ -59,8 +59,13 @@ class TestMUSICLauncher(unittest.TestCase):
@patch('hbp_nrp_music_interface.launch.MUSICLauncher.MUSICMPILauncher') @patch('hbp_nrp_music_interface.launch.MUSICLauncher.MUSICMPILauncher')
def test_init(self, mock_mpi, mock_conf): def test_init(self, mock_mpi, mock_conf):
# mock the ExDConf and parameters
exd = Mock()
exd.rngSeed = 123456
exd.bibiConf.processes = 10
# mock all of the local launcher functionality # mock all of the local launcher functionality
self.__launcher.init('bibi', 10) self.__launcher.init('bibi', exd)
# call to generate launch scripts # call to generate launch scripts
self.__launcher._launcher.deploy.assert_called_once() self.__launcher._launcher.deploy.assert_called_once()
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment