Author: bugman Date: Thu Oct 16 16:38:23 2008 New Revision: 7752 URL: http://svn.gna.org/viewcvs/relax?rev=7752&view=rev Log: Sorted all class methods alphabetically. This will really help with code navigation and debugging. Modified: branches/multi_processor_merge/multi/processor.py Modified: branches/multi_processor_merge/multi/processor.py URL: http://svn.gna.org/viewcvs/relax/branches/multi_processor_merge/multi/processor.py?rev=7752&r1=7751&r2=7752&view=diff ============================================================================== --- branches/multi_processor_merge/multi/processor.py (original) +++ branches/multi_processor_merge/multi/processor.py Thu Oct 16 16:38:23 2008 @@ -412,6 +412,11 @@ @todo: The processor can't currently harvest the required command line arguments from the current command line. ''' + + # register load multi_processor as a ststic function of the class + # FIXME: cleanup move function into class + load_multiprocessor = staticmethod(load_multiprocessor) + def __init__(self, processor_size, callback, stdio_capture=None): '''Initialise the processor. @@ -471,9 +476,25 @@ # global_stdio_capture self.setup_stdio_capture(stdio_capture) - # register load multi_processor as a ststic function of the class - # FIXME: cleanup move function into class - load_multiprocessor = staticmethod(load_multiprocessor) + 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() + + @see: multi.processor.Application_callback. + @see: multi.mpi4py_processor.Mpi4py_processor.abort(). + @see: mpi4py.MPI.COMM_WORLD.Abort(). + ''' + + sys.exit() def add_to_queue(self, command, memo=None): @@ -494,40 +515,45 @@ raise_unimplimented(self.add_to_queue) - def run_queue(self): - '''Run the processor queue - an abstract method. - - All commands queued with add_to_queue will be executed, this function causes the current - thread to block until the command has completed. - ''' - - raise_unimplimented(self.run_queue) - - - def run(self): - '''Run the processor - an abstract method. - - This function runs the processor main loop and is called after all processor setup has been - completed. It does remote execution setup and teardown round either side of a call to - Application_callback.init_master. - - @see: multi.processor.Application_callback. - ''' - - raise_unimplimented(self.run) - - - def return_object(self, result): - '''Return a result to the master processor from a slave - an abstract method. - - @param result: A result to be returned to the master processor. - @type result: Result_string, Result_command or Exception instance - - @see: multi.processor.Result_string. - @see: multi.processor.Resulf_command. - ''' - - raise_unimplimented(self.return_object) + def capture_stdio(self, stdio_capture=None): + '''Enable capture of the STDOUT and STDERR by self.stdio_capture or user supplied streams. + + @note: On slave processors the replacement STDOUT and STDERR streams should be file like + objects which implement the methods truncate and getvalue (see PrependStringIO). + @note: Both or neither stream has to be replaced you can't just replace one! + + @keyword stdio_capture: A pair of file like objects used to replace sys.stdout and + sys.stderr respectively. + @type stdio_capture: list of two file-like objects + ''' + + if stdio_capture == None: + stdio_capture = self.stdio_capture + + sys.stdout = self.stdio_capture[0] + sys.stderr = self.stdio_capture[1] + + + # FIXME is this used? +# def exit(self): +# raise_unimplimented(self.exit) + + + def get_intro_string(self): + '''Get a string describing the multi processor - designed for overriding. + + The string should be suitable for display at application startup and should be less than 100 + characters wide. A good example is the string returned by mpi4py_processor: + + >>> MPI running via mpi4py with <n> slave processors & 1 master, mpi version = <x>.<y> + + @see: multi.processor.mpi4py_processor.Mpi4py_processor.get_intro_string. + + @return: A string describing the multi processor. + @rtype: str + ''' + + raise_unimplimented(self.get_intro_string) def get_name(self): @@ -545,99 +571,43 @@ raise_unimplimented(self.get_name) - 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() - - @see: multi.processor.Application_callback. - @see: multi.mpi4py_processor.Mpi4py_processor.abort(). - @see: mpi4py.MPI.COMM_WORLD.Abort(). - ''' - - sys.exit() - - - # FIXME is this used? -# def exit(self): -# raise_unimplimented(self.exit) - - - def rank(self): - '''Get the rank of this processor - an abstract method. - - The rank of the processor should be a number between 0 and n where n is the number of slave - processors, the rank of 0 is reserved for the master processor. - - @return: The rank of the processor. - @rtype: int - ''' - - raise_unimplimented(self.rank) - - - def processor_size(self): - '''Get the number of slave processors - designed for overriding. - - @return: The number of slave processors. - @rtype: int - ''' - - return self._processor_size - - - def get_intro_string(self): - '''Get a string describing the multi processor - designed for overriding. - - The string should be suitable for display at application startup and should be less than 100 - characters wide. A good example is the string returned by mpi4py_processor: - - >>> MPI running via mpi4py with <n> slave processors & 1 master, mpi version = <x>.<y> - - @see: multi.processor.mpi4py_processor.Mpi4py_processor.get_intro_string. - - @return: A string describing the multi processor. - @rtype: str - ''' - - raise_unimplimented(self.get_intro_string) - - -# def restore_stdio(self): -# sys.stderr = self.save_stderr -# sys.stdout = self.save_stdout - - - def run_command_globally(self, command): - '''Run the same command on all slave processors. - - @see: multi.processor.processor.Slave_command. - - @param command: A slave command. - @type command: Slave_command instance - ''' - - queue = [command for i in range(self.processor_size())] - self.run_command_queue(queue) - - - def pre_run(self): - '''Method called before starting the application main loop - designed for overriding. - - The default implementation just saves the start time for application timing. All subclasses - should call the base method via super(). Only called on the master. - ''' - - if self.rank() == 0: - self.start_time = time.time() + def get_stdio_capture(self): + '''Get the file like objects currently replacing sys.stdout and sys.stderr. + + @return: The file like objects currently replacing sys.stdout and sys.stderr. + @rtype: tuple of two file-like objects + ''' + + return self.stdio_capture + + + def get_stdio_pre_strings(self): + '''Get the strings used prepend STDOUT and STDERR dependant on the current rank. + + For processors with only one slave the result should be ('', '') - designed for overriding. + + @note: The defaults are ('MM X]', 'MM E]') and ('NN S]' , 'NN E]') for masters and slaves + respectively with NN replaced by the rank of the processor. + + @return: A list of two strings for STDOUT and STDERR respectively. + @rtype: list of 2 str + ''' + + pre_string = '' + stdout_string = '' + stderr_string = '' + rank = self.rank() + + if self.processor_size() > 1 and rank > 0: + pre_string = self.rank_format_string() % rank + elif self.processor_size() > 1 and rank == 0: + pre_string = 'M'*self.rank_format_string_width() + + if self.processor_size() > 1: + stderr_string = pre_string + ' E> ' + stdout_string = pre_string + ' S> ' + + return stdout_string, stderr_string def get_time_delta(self, start_time, end_time): @@ -674,16 +644,38 @@ print 'overall runtime: ' + time_delta_str + '\n' - def rank_format_string_width(self): - '''Get the width of the string designating the rank of a slave process. - - Typically this will be the number of digits in the slaves rank. - - @return: The number of digits in the biggest slave processor's rank. + def pre_run(self): + '''Method called before starting the application main loop - designed for overriding. + + The default implementation just saves the start time for application timing. All subclasses + should call the base method via super(). Only called on the master. + ''' + + if self.rank() == 0: + self.start_time = time.time() + + + def processor_size(self): + '''Get the number of slave processors - designed for overriding. + + @return: The number of slave processors. @rtype: int ''' - return int(math.ceil(math.log10(self.processor_size()))) + return self._processor_size + + + def rank(self): + '''Get the rank of this processor - an abstract method. + + The rank of the processor should be a number between 0 and n where n is the number of slave + processors, the rank of 0 is reserved for the master processor. + + @return: The rank of the processor. + @rtype: int + ''' + + raise_unimplimented(self.rank) def rank_format_string(self): @@ -698,6 +690,77 @@ digits = self.rank_format_string_width() format = '%%%di' % digits return format + + + def rank_format_string_width(self): + '''Get the width of the string designating the rank of a slave process. + + Typically this will be the number of digits in the slaves rank. + + @return: The number of digits in the biggest slave processor's rank. + @rtype: int + ''' + + return int(math.ceil(math.log10(self.processor_size()))) + + + def restore_stdio(self): + '''Restore sys.stdout and sys.stderr to the system defaults. + + @note: sys.stdout and sys.stderr are replaced with sys.__stdout__ ans sys.__stderr__. + ''' + + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ + + + def return_object(self, result): + '''Return a result to the master processor from a slave - an abstract method. + + @param result: A result to be returned to the master processor. + @type result: Result_string, Result_command or Exception instance + + @see: multi.processor.Result_string. + @see: multi.processor.Resulf_command. + ''' + + raise_unimplimented(self.return_object) + + + def run(self): + '''Run the processor - an abstract method. + + This function runs the processor main loop and is called after all processor setup has been + completed. It does remote execution setup and teardown round either side of a call to + Application_callback.init_master. + + @see: multi.processor.Application_callback. + ''' + + raise_unimplimented(self.run) + + + def run_command_globally(self, command): + '''Run the same command on all slave processors. + + @see: multi.processor.processor.Slave_command. + + @param command: A slave command. + @type command: Slave_command instance + ''' + + queue = [command for i in range(self.processor_size())] + self.run_command_queue(queue) + + + def run_queue(self): + '''Run the processor queue - an abstract method. + + All commands queued with add_to_queue will be executed, this function causes the current + thread to block until the command has completed. + ''' + + raise_unimplimented(self.run_queue) # fixme: is an argument of the form stio_capture needed @@ -763,74 +826,6 @@ return (stdout_capture, stderr_capture) - def capture_stdio(self, stdio_capture=None): - '''Enable capture of the STDOUT and STDERR by self.stdio_capture or user supplied streams. - - @note: On slave processors the replacement STDOUT and STDERR streams should be file like - objects which implement the methods truncate and getvalue (see PrependStringIO). - @note: Both or neither stream has to be replaced you can't just replace one! - - @keyword stdio_capture: A pair of file like objects used to replace sys.stdout and - sys.stderr respectively. - @type stdio_capture: list of two file-like objects - ''' - - if stdio_capture == None: - stdio_capture = self.stdio_capture - - sys.stdout = self.stdio_capture[0] - sys.stderr = self.stdio_capture[1] - - - def get_stdio_capture(self): - '''Get the file like objects currently replacing sys.stdout and sys.stderr. - - @return: The file like objects currently replacing sys.stdout and sys.stderr. - @rtype: tuple of two file-like objects - ''' - - return self.stdio_capture - - - def restore_stdio(self): - '''Restore sys.stdout and sys.stderr to the system defaults. - - @note: sys.stdout and sys.stderr are replaced with sys.__stdout__ ans sys.__stderr__. - ''' - - sys.stdout = sys.__stdout__ - sys.stderr = sys.__stderr__ - - - def get_stdio_pre_strings(self): - '''Get the strings used prepend STDOUT and STDERR dependant on the current rank. - - For processors with only one slave the result should be ('', '') - designed for overriding. - - @note: The defaults are ('MM X]', 'MM E]') and ('NN S]' , 'NN E]') for masters and slaves - respectively with NN replaced by the rank of the processor. - - @return: A list of two strings for STDOUT and STDERR respectively. - @rtype: list of 2 str - ''' - - pre_string = '' - stdout_string = '' - stderr_string = '' - rank = self.rank() - - if self.processor_size() > 1 and rank > 0: - pre_string = self.rank_format_string() % rank - elif self.processor_size() > 1 and rank == 0: - pre_string = 'M'*self.rank_format_string_width() - - if self.processor_size() > 1: - stderr_string = pre_string + ' E> ' - stdout_string = pre_string + ' S> ' - - return stdout_string, stderr_string - - # TODO currently uni_processor doesn't have a process_result should this be integrated class Result(object): '''A basic result object returned from a slave processor via return_object. @@ -997,19 +992,6 @@ def __init__(self): self.memo_id = None - - - def set_memo_id(self, memo): - '''Called by the master processor to remember this Slave_commands memo. - - @param memo: The memo to remember, memos are remembered by getting the memo_id of the - memo. - ''' - - if memo != None: - self.memo_id = memo.memo_id() - else: - self.memo_id = None def run(self, processor, completed): @@ -1034,3 +1016,16 @@ ''' pass + + + def set_memo_id(self, memo): + '''Called by the master processor to remember this Slave_commands memo. + + @param memo: The memo to remember, memos are remembered by getting the memo_id of the + memo. + ''' + + if memo != None: + self.memo_id = memo.memo_id() + else: + self.memo_id = None