Author: bugman Date: Thu Mar 22 10:13:53 2012 New Revision: 15600 URL: http://svn.gna.org/viewcvs/relax?rev=15600&view=rev Log: Redesigned how the multi-processor package terminates program execution. The Processor.exit() method has been introduced to perform this action. By default (used by the uni-processor fabric), the method does nothing. The mpi4py_processor.py module functions exit() and exit_mpi() have been merged into the Mpi4py_processor.exit() method. Modified: 1.3/multi/mpi4py_processor.py 1.3/multi/processor.py 1.3/multi/uni_processor.py Modified: 1.3/multi/mpi4py_processor.py URL: http://svn.gna.org/viewcvs/relax/1.3/multi/mpi4py_processor.py?rev=15600&r1=15599&r2=15600&view=diff ============================================================================== --- 1.3/multi/mpi4py_processor.py (original) +++ 1.3/multi/mpi4py_processor.py Thu Mar 22 10:13:53 2012 @@ -42,11 +42,6 @@ from multi.multi_processor_base import Multi_processor, Too_few_slaves_exception -# save original sys.exit to call after wrapper -_sys_exit = sys.exit - -in_main_loop = False - def broadcast_command(command): for i in range(1, MPI.COMM_WORLD.size): @@ -63,38 +58,6 @@ break -def exit(status=None): - """Wrapper for the sys.exit function.""" - - # CHECKME is status ok - - # Execution on the slave. - if MPI.COMM_WORLD.rank != 0: - if in_main_loop: - raise Exception('sys.exit unexpectedley called on slave!') - else: - sys.stderr.write('\n') - sys.stderr.write('***********************************************\n') - sys.stderr.write('\n') - sys.stderr.write('warning sys.exit called before mpi4py main loop\n') - sys.stderr.write('\n') - sys.stderr.write('***********************************************\n') - sys.stderr.write('\n') - MPI.COMM_WORLD.Abort() - - # Execution on the master. - else: - exit_mpi() - _sys_exit(status) - - -def exit_mpi(): - if MPI.Is_initialized() and not MPI.Is_finalized() and MPI.COMM_WORLD.rank == 0: - broadcast_command(Exit_command()) - ditch_all_results() - - - class Mpi4py_processor(Multi_processor): """The mpi4py multi-processor class.""" @@ -116,8 +79,8 @@ super(Mpi4py_processor, self).__init__(processor_size=mpi_processor_size, callback=callback) - # wrap sys.exit to close down mpi before exiting - sys.exit = exit + # Initialise a flag for determining if we are in the run() method or not. + self.in_main_loop = False def abort(self): @@ -148,6 +111,44 @@ MPI.COMM_WORLD.send([name, value], dest=i, tag=10) + def exit(self, status=0): + """Exit the mpi4py processor with the given status. + + @keyword status: The program exit status. + @type status: int + """ + + # Execution on the slave. + if MPI.COMM_WORLD.rank != 0: + # Catch sys.exit being called on an executing slave. + if self.in_main_loop: + raise Exception('sys.exit unexpectedly called on slave!') + + # Catch sys.exit + else: + sys.stderr.write('\n') + sys.stderr.write('***********************************************\n') + sys.stderr.write('\n') + sys.stderr.write('warning sys.exit called before mpi4py main loop\n') + sys.stderr.write('\n') + sys.stderr.write('***********************************************\n') + sys.stderr.write('\n') + MPI.COMM_WORLD.Abort() + + # Execution on the master. + else: + # Slave clean up. + if MPI.Is_initialized() and not MPI.Is_finalized() and MPI.COMM_WORLD.rank == 0: + # Send the exit command to all slaves. + broadcast_command(Exit_command()) + + # Dump all results. + ditch_all_results() + + # Exit the program with the given status. + sys.exit(status) + + def get_intro_string(self): """Return the string to append to the end of the relax introduction string. @@ -190,10 +191,9 @@ def run(self): - global in_main_loop - in_main_loop = True + self.in_main_loop = True super(Mpi4py_processor, self).run() - in_main_loop = False + self.in_main_loop = False def slave_receive_commands(self): Modified: 1.3/multi/processor.py URL: http://svn.gna.org/viewcvs/relax/1.3/multi/processor.py?rev=15600&r1=15599&r2=15600&view=diff ============================================================================== --- 1.3/multi/processor.py (original) +++ 1.3/multi/processor.py Thu Mar 22 10:13:53 2012 @@ -180,22 +180,18 @@ def abort(self): """Shutdown the multi processor in exceptional conditions - designed for overriding. - This method is called after an exception from the master or slave has been raised and - processed and is responsible for the shutdown of the multi processor fabric and terminating - the application. The functions should be called as the last thing that - Application_callback.handle_exception does. - - As an example of the methods use see Mpi4py_processor.abort which calls - MPI.COMM_WORLD.Abort() to cleanly shutdown the mpi framework and remove dangling processes. - - The default action is to call sys.exit() + This method is called after an exception from the master or slave has been raised and processed and is responsible for the shutdown of the multi processor fabric and terminating the application. The functions should be called as the last thing that Application_callback.handle_exception does. + + As an example of the methods use see Mpi4py_processor.abort which calls MPI.COMM_WORLD.Abort() to cleanly shutdown the mpi framework and remove dangling processes. + + The default action is to call the special self.exit() method. @see: multi.processor.Application_callback. @see: multi.mpi4py_processor.Mpi4py_processor.abort(). @see: mpi4py.MPI.COMM_WORLD.Abort(). """ - sys.exit() + self.exit() def add_to_queue(self, command, memo=None): @@ -216,9 +212,14 @@ raise_unimplemented(self.add_to_queue) - # FIXME is this used? -# def exit(self): -# raise_unimplemented(self.exit) + def exit(self, status=0): + """Exit the processor with the given status. + + This default method allows the program to drop off the end and terminate as it normally would - i.e. this method does nothing. + + @keyword status: The program exit status. + @type status: int + """ def data_upload(self, name=None, value=None, rank=None): @@ -489,10 +490,9 @@ # Execute any tear down code needed for the specific processor fabrics. self.post_run() - # End of execution on the master, so kill the slaves. + # End of execution, so perform any exiting actions needed by the specific processor fabrics. if self.on_master(): - # note this a modified exit that kills all MPI processors - sys.exit() + self.exit() def run_command_globally(self, command): Modified: 1.3/multi/uni_processor.py URL: http://svn.gna.org/viewcvs/relax/1.3/multi/uni_processor.py?rev=15600&r1=15599&r2=15600&view=diff ============================================================================== --- 1.3/multi/uni_processor.py (original) +++ 1.3/multi/uni_processor.py Thu Mar 22 10:13:53 2012 @@ -59,10 +59,6 @@ if memo != None: command.set_memo_id(memo) self.memo_map[memo.memo_id()] = memo - - - def exit(self): - sys.exit() def get_intro_string(self):