HWRF  trunk@4391
impi.py
1 ##@namespace produtil.mpi_impl.impi
2 # Adds Intel MPI support to produtil.run
3 #
4 # This module is part of the produtil.mpi_impl package -- see
5 # __init__.py for details. This implements the Intel MPI, but may
6 # work for other MPI implementations that use the "mpirun" command and
7 # OpenMP implementations that use the KMP_NUM_THREADS or
8 # OMP_NUM_THREADS environment variables.
9 #
10 # @warning This module assumes the TOTAL_TASKS environment variable is
11 # set to the maximum number of MPI ranks the program has available to
12 # it. That is used when the mpirunner is called with the
13 # allranks=True option.
14 
15 import os, sys, logging
17 
18 from .mpi_impl_base import MPIMixed,CMDFGen
19 
20 ##@var mpirun_path
21 # Path to the mpirun program, or None if it could not be found.
22 mpirun_path=produtil.fileop.find_exe('mpirun',raise_missing=False)
23 
24 module_logger=logging.getLogger('lsf_cray_intel')
25 
26 def runsync(logger=None):
27  """!Runs the "sync" command as an exe()."""
28  if logger is None: logger=module_logger
29  sync=produtil.prog.Runner(['/bin/sync'])
30  p=produtil.pipeline.Pipeline(sync,capture=True,logger=logger)
31  version=p.to_string()
32  status=p.poll()
33 
34 def openmp(arg,threads):
35  """!Adds OpenMP support to the provided object
36 
37  @param arg An produtil.prog.Runner or
38  produtil.mpiprog.MPIRanksBase object tree
39  @param threads the number of threads, or threads per rank, an
40  integer"""
41  if threads is not None:
42  arg.threads=threads
43  return arg.env(OMP_NUM_THREADS=threads,KMP_NUM_THREADS=threads,
44  KMP_AFFINITY='scatter')
45  else:
46  del arg.threads
47  return arg
48 
49 def detect():
50  """!Detects whether Intel MPI is available."""
51  logger=logging.getLogger('produtil.mpi_impl.impi')
52  if mpirun_path is None: return False
53  try:
54  mpirun=produtil.prog.Runner([mpirun_path])
55  p=produtil.pipeline.Pipeline(mpirun,capture=True,logger=logger)
56  version=p.to_string()
57  status=p.poll()
58  return version.find('Intel(R) MPI')>=0
59  except Exception as e:
60  logger.error('ERROR in mpirun --version: %s\n'%(str(e),),
61  exc_info=True)
62  raise
63 
65  """!Does this module represent an MPI implementation? Returns True."""
66  return True
67 
68 def make_bigexe(exe,**kwargs):
69  """!Returns an ImmutableRunner that will run the specified program.
70  @returns an empty list
71  @param exe The executable to run on compute nodes.
72  @param kwargs Ignored."""
73  return produtil.prog.ImmutableRunner([str(exe)],**kwargs)
74 
75 def mpirunner(arg,allranks=False,**kwargs):
76  """!Turns a produtil.mpiprog.MPIRanksBase tree into a produtil.prog.Runner
77  @param arg a tree of produtil.mpiprog.MPIRanksBase objects
78  @param allranks if True, and only one rank is requested by arg, then
79  all MPI ranks will be used
80  @param kwargs passed to produtil.mpi_impl.mpi_impl_base.CMDFGen
81  when mpiserial is in use.
82  @returns a produtil.prog.Runner that will run the selected MPI program"""
83  assert(isinstance(arg,produtil.mpiprog.MPIRanksBase))
84  (serial,parallel)=arg.check_serial()
85  if serial and parallel:
86  raise MPIMixed('Cannot mix serial and parallel MPI ranks in the '
87  'same MPI program.')
88  if arg.nranks()==1 and allranks:
89  arglist=[ a for a in arg.to_arglist(
90  pre=[mpirun_path],
91  before=['-np',os.environ['TOTAL_TASKS']],
92  between=[':'])]
93  return produtil.prog.Runner(arglist)
94  elif allranks:
95  raise MPIAllRanksError(
96  "When using allranks=True, you must provide an mpi program "
97  "specification with only one MPI rank (to be duplicated across "
98  "all ranks).")
99  elif serial:
100  lines=[a for a in arg.to_arglist(to_shell=True,expand=True)]
101  if produtil.fileop.find_exe('mpiserial') is None:
102  raise MPISerialMissing(
103  'Attempting to run a serial program via mpirun but the '
104  'mpiserial program is not in your $PATH.')
105  return produtil.prog.Runner(
106  [mpirun_path,'-np','%s'%(arg.nranks()),'mpiserial'],
107  prerun=CMDFGen('serialcmdf',lines,**kwargs))
108  else:
109  arglist=[ a for a in arg.to_arglist(
110  pre=[mpirun_path], # command is mpirun
111  before=['-np','%(n)d'], # pass env, number of procs is kw['n']
112  between=[':']) ] # separate commands with ':'
113  return produtil.prog.Runner(arglist)
114 
def can_run_mpi()
Does this module represent an MPI implementation? Returns True.
Definition: impi.py:64
This module provides a set of utility functions to do filesystem operations.
Definition: fileop.py:1
def mpirunner(arg, allranks=False, kwargs)
Turns a produtil.mpiprog.MPIRanksBase tree into a produtil.prog.Runner.
Definition: impi.py:75
def detect()
Detects whether Intel MPI is available.
Definition: impi.py:49
This class is a wrapper around launch and manage.
Definition: pipeline.py:564
Implements the produtil.run: provides the object tree for representing shell commands.
Definition: prog.py:1
def runsync
Runs the "sync" command as an exe().
Definition: impi.py:26
def make_bigexe(exe, kwargs)
Returns an ImmutableRunner that will run the specified program.
Definition: impi.py:68
Object structure for describing MPI programs.
Definition: mpiprog.py:1
This is the abstract superclass of all classes that represent one or more MPI ranks, including MPI ranks that are actually serial programs.
Definition: mpiprog.py:68
def openmp(arg, threads)
Adds OpenMP support to the provided object.
Definition: impi.py:34
Represents a single stage of a pipeline to execute.
Definition: prog.py:299
def find_exe
Searches the $PATH or a specified iterable of directory names to find an executable file with the giv...
Definition: fileop.py:573
Internal module that launches and monitors processes.
Definition: pipeline.py:1
An copy-on-write version of Runner.
Definition: prog.py:884