1  """Automated backend choosing.""" 
  2   
  3  __copyright__ = "Copyright (C) 2007 Andreas Kloeckner" 
  4   
  5  __license__ = """ 
  6  This program is free software: you can redistribute it and/or modify 
  7  it under the terms of the GNU General Public License as published by 
  8  the Free Software Foundation, either version 3 of the License, or 
  9  (at your option) any later version. 
 10   
 11  This program is distributed in the hope that it will be useful, 
 12  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  GNU General Public License for more details. 
 15   
 16  You should have received a copy of the GNU General Public License 
 17  along with this program.  If not, see U{http://www.gnu.org/licenses/}. 
 18  """ 
 19   
 20   
 21   
 22   
 23  import hedge.discretization 
 24  import hedge.mesh 
 25   
 26   
 27   
 28   
 29 -class RunContext(object): 
  30      @property 
 32          raise NotImplementedError 
  33   
 34      @property 
 36          raise NotImplementedError 
  37   
 38      @property 
 39 -    def head_rank(self): 
  40          raise NotImplementedError 
  41   
 42      @property 
 43 -    def is_head_rank(self): 
  44          return self.rank == self.head_rank 
  45   
 46 -    def distribute_mesh(self, mesh, partition=None): 
  47          """Take the Mesh instance `mesh' and distribute it according to `partition'. 
 48   
 49          If partition is an integer, invoke PyMetis to partition the mesh into this 
 50          many parts, distributing over the first `partition' ranks. 
 51   
 52          If partition is None, act as if partition was the integer corresponding 
 53          to the current number of ranks on the job. 
 54   
 55          If partition is not an integer, it must be a mapping from element number to 
 56          rank. (A list or tuple of rank numbers will do, for example, or so will 
 57          a full-blown dict.) 
 58   
 59          Returns a mesh chunk. 
 60   
 61          We deliberately do not define the term `mesh chunk'. The return value 
 62          of this function is to be treated as opaque by the user, only to be 
 63          used as an argument to L{make_discretization}(). 
 64   
 65          This routine may only be invoked on the head rank. 
 66          """ 
 67          raise NotImplementedError 
  68   
 69 -    def receive_mesh(self): 
  70          """Wait for a mesh chunk to be sent by the head rank. 
 71   
 72          We deliberately do not define the term `mesh chunk'. The return value 
 73          of this function is to be treated as opaque by the user, only to be 
 74          used as an argument to L{make_discretization}(). 
 75   
 76          This routine should only be invoked on non-head ranks. 
 77          """ 
 78   
 79          raise NotImplementedError 
  80   
 81 -    def make_discretization(self, mesh_data, *args, **kwargs): 
  82          """Construct a Discretization instance. 
 83   
 84          `mesh_data' is whatever gets returned from distribute_mesh and 
 85          receive_mesh(). Any extra arguments are directly forwarded to 
 86          the respective Discretization constructor. 
 87          """ 
 88          raise NotImplementedError 
   89   
 90   
 91   
 92   
 93   
 94 -class SerialRunContext(RunContext): 
  95      communicator = None 
 96   
 97 -    def __init__(self, discr_class): 
  98          self.discr_class = discr_class 
  99   
100      @property 
103   
104      @property 
107   
108      @property 
109 -    def head_rank(self): 
 111   
112 -    def distribute_mesh(self, mesh, partition=None): 
 114   
115 -    def make_discretization(self, mesh_data, *args, **kwargs): 
 116          return self.discr_class(mesh_data, *args, **kwargs) 
  117   
118   
119   
120   
121  FEAT_MPI = "mpi" 
122  FEAT_CUDA = "cuda" 
127      if FEAT_MPI in allowed_features: 
128          import pytools.prefork 
129          pytools.prefork.enable_prefork() 
130   
131          try: 
132              import boostmpi.autoinit 
133          except ImportError: 
134              pass 
135          else: 
136              import boostmpi as mpi 
137              if mpi.size > 1: 
138                  yield FEAT_MPI 
139   
140      if FEAT_CUDA in allowed_features: 
141          try: 
142              import pycuda 
143          except ImportError: 
144              have_cuda = False 
145          else: 
146              import pycuda.driver 
147              try: 
148                  if pycuda.driver.Device.count(): 
149                      yield FEAT_CUDA 
150              except pycuda.driver.LogicError: 
151                   
152                  yield FEAT_CUDA 
 153   
154   
155   
156   
157 -def guess_run_context(allow=None): 
 158      if allow is None: 
159          import sys 
160   
161          i = 1 
162          while i < len(sys.argv): 
163              arg = sys.argv[i] 
164              if arg.startswith("--features="): 
165                  allow = arg[arg.index("=")+1:].split(",") 
166                  i += 1 
167              elif arg == "-f" and i+1 < len(sys.argv): 
168                  allow = sys.argv[i+1].split(",") 
169                  i += 2 
170              else: 
171                  i += 1 
172   
173          if allow is None: 
174              allow = [] 
175   
176      feat = list(generate_features(allow)) 
177   
178      if FEAT_CUDA in feat: 
179          from hedge.backends.cuda import Discretization as discr_class 
180      else: 
181          from hedge.backends.jit import Discretization as discr_class 
182   
183      if FEAT_MPI in feat: 
184          from hedge.backends.mpi import MPIRunContext 
185          import boostmpi as mpi 
186          return MPIRunContext(mpi.world, discr_class) 
187      else: 
188          return SerialRunContext(discr_class) 
 189