mailr15460 - /1.3/multi/test_implementation.py


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by edward on March 08, 2012 - 11:26:
Author: bugman
Date: Thu Mar  8 11:26:19 2012
New Revision: 15460

URL: http://svn.gna.org/viewcvs/relax?rev=15460&view=rev
Log:
Documentation improvements to the multi-processor test implementation.

This should make it very easy to see what is happening at all stages.


Modified:
    1.3/multi/test_implementation.py

Modified: 1.3/multi/test_implementation.py
URL: 
http://svn.gna.org/viewcvs/relax/1.3/multi/test_implementation.py?rev=15460&r1=15459&r2=15460&view=diff
==============================================================================
--- 1.3/multi/test_implementation.py (original)
+++ 1.3/multi/test_implementation.py Thu Mar  8 11:26:19 2012
@@ -1,17 +1,27 @@
-"""
-To run in uni-processor mode on a dual core system, change the MULTI 
variable to False and type:
-
-$ python parallel_test.py
-
-
-To run in mpi4py multi-processor mode with one master and two slave 
processors on minimally a dual core system, change the MULTI variable to True 
and type:
-
-$ mpiexec -n 3 python parallel_test.py
+"""A reference implementation of the multi-processor package.
+
+Description
+===========
+
+This is a basic but full implementation of the multi-processor package to 
demonstrate how it is used.
+
+
+Testing
+=======
+
+To run in uni-processor mode on a dual core system, change the MULTI 
variable to False and type::
+
+$ python test_implementation.py
+
+
+To run in mpi4py multi-processor mode with one master and two slave 
processors on minimally a dual core system, change the MULTI variable to True 
and type::
+
+$ mpiexec -n 3 python test_implementation.py
 
 For a single dual core CPU (Intel Core 2 Duo E8400 at 3.00GHz), the total 
times averaged over 5 runs are:
-    - Uni-processor:        31.293 seconds 
(30.724+30.413+31.197+31.866+32.266)
-    - Mpi4py-processor:     23.772 seconds 
(24.854+21.756+22.514+26.899+22.836)
-    - Scaling efficiency:   1.316
+    - Uni-processor:        51.548 seconds 
(51.054+52.224+51.257+51.112+52.093)
+    - Mpi4py-processor:     43.185 seconds 
(43.867+41.478+46.209+39.941+44.429)
+    - Scaling efficiency:   1.194
 """
 
 # Python module imports.
@@ -22,15 +32,18 @@
     import profile
 import pstats
 from random import uniform
+import sys
+
+# Modify the module path.
+sys.path.append('..')
 
 # relax module imports.
 from multi import Application_callback, load_multiprocessor, Memo, 
Processor_box, Result_command, Slave_command
-from maths_fns.rotation_matrix import R_random_hypersphere
 
 
 # Module variables.
 PROFILE = True
-MULTI = True
+MULTI = False
 if MULTI:
     FABRIC = 'mpi4py'
     PROCESSOR_NUM = 2
@@ -40,56 +53,100 @@
 
 
 def print_stats(stats, status=0):
-    """Profiling print out function."""
-
+    """Profiling print out function, sorting first by total time then by 
name."""
+
+    # Sorted print out.
     pstats.Stats(stats).sort_stats('time', 'name').print_stats()
 
 
 
 class Main:
+    """The program."""
+
     def __init__(self):
         """Set up some initial variables."""
 
-        self.N = 10000000
+        # The total number of calculations to perform by all slave 
processors.
+        self.N = 2000000
+
+        # Variable for counting the completed calculations (to demonstrate 
slave->master communication).
         self.num = 0
 
 
     def run(self):
+        """This required method executes the entire program."""
+
         # Initialise the Processor box singleton.
         processor_box = Processor_box()
 
         # Loop over the slaves.
         num = processor_box.processor.processor_size()
         for i in range(num):
-            # Queue the slave command and memo.
-            
processor_box.processor.add_to_queue(Test_slave_command(N=self.N/num), 
Test_memo(name="Memo_"+repr(i), sum_fn=self.sum_fn))
-
-        # Execute the calculations.
+            # Partition out the calculations to one slave.
+            slave = Test_slave_command(N=self.N/num)
+
+            # Initialise the memo object.
+            memo = Test_memo(name="Memo_"+repr(i), sum_fn=self.sum_fn)
+
+            # Queue the slave command and its memo.
+            processor_box.processor.add_to_queue(slave, memo)
+
+        # Execute the calculations, waiting for completion.
         processor_box.processor.run_queue()
 
-        # Print out.
+        # Final program print out.
         print("\n\nTotal number of calculations: %s" % self.num)
 
 
     def sum_fn(self, num):
+        """Method for slave->master communication.
+
+        This is stored in the memo object and used by the result_command on 
the master (itself invoked by the slave command on the slave processors) to 
pass the slave data to the master.
+
+        @param num:     The number of calculations performed by a given 
slave processor.
+        @type num:      int
+        """
+
+        # Sum the total number of calculations performed on the slaves.
         self.num += num
 
 
+
 class Test_memo(Memo):
+    """The memo object containing data and functions for the 
results_command."""
+
     def __init__(self, name, sum_fn):
-        """Store some data for the result_command."""
-
-        # Store the args.
+        """Store some data for the result command.
+
+        @param name:    A name for the memo.
+        @type name:     str
+        @param sum_fn:  A method for summing the number calculations 
performed by all slaves.
+        @type sum_fn:   method
+        """
+
+        # Store the arguments for later use by the result_command.
         self.name = name
         self.sum_fn = sum_fn
 
 
 
 class Test_result_command(Result_command):
+    """The result command for processing the results from the slaves on the 
master."""
+
     def __init__(self, processor, memo_id=None, num=None, completed=True):
-        """Store all the slave results for processing on the master."""
-
-        # Execute the base class __init__() method.
+        """Store all the slave results for processing on the master.
+
+        @param processor:   The slave processor object.
+        @type processor:    Processor instance
+        @keyword memo_id:   The ID of the corresponding memo object 
(currently serves no purpose).
+        @type memo_id:      int
+        @keyword num:       The number of calculations performed by the 
slave.  This is an example of data transfer from the slave to master 
processor.
+        @type num:          int
+        @keyword completed: A flag saying if the calculation on the slave 
processor completed correctly.
+        @type completed:    bool
+        """
+
+        # Execute the base class __init__() method (essential).
         super(Test_result_command, self).__init__(processor=processor, 
completed=completed)
 
         # Store the arguments.
@@ -98,25 +155,48 @@
 
 
     def run(self, processor, memo):
-
-        # Print out.
+        """Essential method for doing something with the results from the 
slave processors.
+
+        @param processor:   The slave processor object.
+        @type processor:    Processor instance
+        @param memo:        The slave's corresponding memo object.
+        @type memo:         Memo instance
+        """
+
+        # Random print out.
         print("%s, %s calculations completed." % (memo.name, self.num))
 
-        # Calling a function on the master.
+        # Calling a method on the master.
         memo.sum_fn(self.num)
 
 
 
 class Test_slave_command(Slave_command):
-    def __init__(self, N=None):
+    """The slave command for use by the slave processor."""
+
+    def __init__(self, N=0):
+        """Set up the slave command object for the slave processor.
+
+        @keyword N:     The number of calculations for the slave to perform.
+        @type N:        int
+        """
+
+        # Store the argument.
         self.N = N
 
-        # Initialise the matrices.
+        # Initialise some matrices.
         self.A = zeros((3, 3), float64)
         self.B = zeros((3, 3), float64)
 
 
-    def run(self, processor, completed):
+    def run(self, processor, completed=False):
+        """Essential method for performing calculations on the slave 
processors.
+
+        @param processor:   The slave processor object.
+        @type processor:    Processor instance
+        @keyword completed: A flag specifying if the slave calculation is 
completed.  This is currently meaningless, but will be passed to this run() 
method anyway so it needs to be present.
+        @type completed:    bool
+        """
 
         # Perform some random useless time-consuming stuff.
         num_calcs = 0
@@ -139,7 +219,6 @@
 
 
 # Set up the processor.
-main = Main()
 processor = load_multiprocessor(FABRIC, Application_callback(master=Main()), 
processor_size=PROCESSOR_NUM, verbosity=1)
 
 # Run in multi-processor mode.
@@ -148,6 +227,8 @@
 
 # Run in multi-processor mode with profiling.
 else:
+    # Replace the default profiling print out function.
     profile.Profile.print_stats = print_stats
+
+    # Execute with profiling.
     profile.runctx('processor.run()', globals(), locals())
-




Related Messages


Powered by MHonArc, Updated Thu Mar 08 12:20:02 2012