[pyfr] 48/88: Cleanup the rank allocation code.

Ghislain Vaillant ghisvail-guest at moszumanska.debian.org
Wed Nov 16 12:05:29 UTC 2016


This is an automated email from the git hooks/post-receive script.

ghisvail-guest pushed a commit to branch master
in repository pyfr.

commit 909c31978cd0f97f66b4f3ee9feb25141d8a43a9
Author: Freddie Witherden <freddie at witherden.org>
Date:   Mon Jun 6 11:58:50 2016 -0700

    Cleanup the rank allocation code.
    
    We now save the rank allocation inside of the stats file as a
    comma separated list of partition numbers.  Hence, the first
    item is the partition assigned to the first MPI rank.
    
    A random rank allocation strategy has also been added.  This is
    useful for assessing the impact of the cluster topoplogy on a
    simulation.
---
 doc/src/user_guide.rst   |  2 +-
 pyfr/integrators/base.py |  5 +++++
 pyfr/rank_allocator.py   | 51 +++++++++++++++++++++++++++---------------------
 3 files changed, 35 insertions(+), 23 deletions(-)

diff --git a/doc/src/user_guide.rst b/doc/src/user_guide.rst
index cae9d0a..4bf225a 100644
--- a/doc/src/user_guide.rst
+++ b/doc/src/user_guide.rst
@@ -173,7 +173,7 @@ Parameterises the backend with
 
 2. ``rank-allocator`` --- MPI rank allocator:
 
-    ``linear``
+    ``linear`` | ``random``
 
 Example::
 
diff --git a/pyfr/integrators/base.py b/pyfr/integrators/base.py
index a227201..6be56f1 100644
--- a/pyfr/integrators/base.py
+++ b/pyfr/integrators/base.py
@@ -201,6 +201,11 @@ class BaseIntegrator(object, metaclass=ABCMeta):
     def collect_stats(self, stats):
         wtime = time.time() - self._wstart
 
+        # Rank allocation
+        stats.set('backend', 'rank-allocation',
+                  ','.join(str(r) for r in self.rallocs.mprankmap))
+
+        # Simulation and wall clock times
         stats.set('solver-time-integrator', 'tcurr', self.tcurr)
         stats.set('solver-time-integrator', 'wall-time', wtime)
 
diff --git a/pyfr/rank_allocator.py b/pyfr/rank_allocator.py
index 2c77cf3..aff8293 100644
--- a/pyfr/rank_allocator.py
+++ b/pyfr/rank_allocator.py
@@ -2,6 +2,7 @@
 
 from abc import ABCMeta, abstractmethod
 from collections import defaultdict
+import random
 import re
 
 from pyfr.mpiutil import get_comm_rank_root
@@ -22,36 +23,35 @@ class BaseRankAllocator(object, metaclass=ABCMeta):
 
         comm, rank, root = get_comm_rank_root()
 
+        # Have the root rank determine the connectivity of the mesh
         if rank == root:
-            # Determine the (physical) connectivity of the mesh
             prankconn = self._get_mesh_connectivity(mesh)
-            nparts = len(prankconn) or 1
+            nparts = len(prankconn)
 
             if nparts != comm.size:
-                raise RuntimeError('Mesh has %d partitions but running with '
-                                   '%d MPI ranks' % (nparts, comm.size))
+                raise RuntimeError('Mesh has {0} partitions but running with '
+                                   '{1} MPI ranks'.format(nparts, comm.size))
         else:
             prankconn = None
 
-        # Get subclass dependant info about each rank (e.g, hostname)
+        # Get subclass dependant info about each rank (e.g., hostname)
         rinfo = comm.gather(self._get_rank_info(), root=root)
 
+        # If we are the root rank then perform the rank allocation
         if rank == root:
-            # Use this info to construct a mapping from MPI ranks to
-            # physical mesh ranks
             mprankmap = self._get_mprankmap(prankconn, rinfo)
         else:
             mprankmap = None
 
-        # Broadcast the connectivity and physical to each MPI rank
-        self.prankconn = comm.bcast(prankconn, root=root)
-        self.mprankmap = comm.bcast(mprankmap, root=root)
+        # Broadcast the connectivity and rank mappings to all other ranks
+        self.prankconn = prankconn = comm.bcast(prankconn, root=root)
+        self.mprankmap = mprankmap = comm.bcast(mprankmap, root=root)
 
-        # Invert this mapping
-        self.pmrankmap = {v: k for k, v in self.mprankmap.items()}
+        # Invert the mapping to obtain the physical-to-MPI rank mapping
+        self.pmrankmap = sorted(range(comm.size), key=mprankmap.__getitem__)
 
-        # Compute the physical rank of ourself
-        self.prank = self.mprankmap[rank]
+        # Compute our physical rank
+        self.prank = mprankmap[rank]
 
     def _get_mesh_connectivity(self, mesh):
         conn = defaultdict(list)
@@ -61,14 +61,11 @@ class BaseRankAllocator(object, metaclass=ABCMeta):
                 lhs, rhs = int(m.group(1)), int(m.group(2))
                 conn[lhs].append(rhs)
 
-                if 'con_p%dp%d' % (rhs, lhs) not in mesh:
-                    raise ValueError('MPI interface (%d, %d) is not symmetric'
-                                     % (lhs, rhs))
+                if 'con_p{0}p{1}'.format(rhs, lhs) not in mesh:
+                    raise ValueError('MPI interface ({0}, {1}) is not '
+                                     'symmetric'.format(lhs, rhs))
 
-        if sorted(conn) != list(range(len(conn))):
-            raise ValueError('Mesh has invalid partition numbers')
-
-        return conn
+        return [conn[i] for i in range(len(conn) or 1)]
 
     @abstractmethod
     def _get_rank_info(self):
@@ -86,4 +83,14 @@ class LinearRankAllocator(BaseRankAllocator):
         return None
 
     def _get_mprankmap(self, prankconn, rinfo):
-        return {i: i for i in range(len(rinfo))}
+        return list(range(len(rinfo)))
+
+
+class RandomRankAllocator(BaseRankAllocator):
+    name = 'random'
+
+    def _get_rank_info(self):
+        return None
+
+    def _get_mprankmap(self, prankconn, rinfo):
+        return random.sample(range(len(rinfo)), len(rinfo))

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/pyfr.git



More information about the debian-science-commits mailing list