HWRF  trunk@4391
mpirun_lsf.py
1 ##@namespace produtil.mpi_impl.mpirun_lsf
2 # Adds LSF+IBMPE support to produtil.run
3 #
4 # This module is part of the produtil.mpi_impl package. It underlies
5 # the produtil.run.openmp, produtil.run.mpirun , and
6 # produtil.run.mpiserial functions, providing the implementation
7 # needed to run with LSF combined with the IBMPE MPI implementation.
8 # It may work with other MPI implementations connected to LSF, as long
9 # as they use mpirun.lsf to launch MPI programs.
10 #
11 # @note Unlike other MPI implementations, LSF does not allow changing of the
12 # number of MPI ranks used when running an MPI program. You can only run
13 # on all provided ranks, or one rank. Hence the TOTAL_TASKS variable used
14 # elsewhere in produtil, is ignored here.
15 import os, socket, logging
17 
18 from .mpi_impl_base import MPIMixed,CMDFGen
19 
20 ##@var mpirun_lsf_path
21 # Path to the mpirun.lsf program, or None if it isn't found.
22 mpirun_lsf_path=produtil.fileop.find_exe('mpirun.lsf',raise_missing=False)
23 module_logger=logging.getLogger('lsf_cray_intel')
24 
25 def runsync(logger=None):
26  """!Runs the "sync" command as an exe()."""
27  if logger is None: logger=module_logger
28  sync=produtil.prog.Runner(['/bin/sync'])
29  p=produtil.pipeline.Pipeline(sync,capture=True,logger=logger)
30  version=p.to_string()
31  status=p.poll()
32 
33 def openmp(arg,threads):
34  """!Adds OpenMP support to the provided object
35 
36  @param arg An produtil.prog.Runner or
37  produtil.mpiprog.MPIRanksBase object tree
38  @param threads the number of threads, or threads per rank, an
39  integer"""
40  if threads is not None:
41  arg.threads=threads
42  return arg.env(OMP_NUM_THREADS=threads)
43  else:
44  del arg.threads
45  return arg
46 
47 def detect():
48  """!Determines if LSF+IBMPE should be used to run MPI programs by
49  looking for the mpirun.lsf program in $PATH"""
50  return mpirun_lsf_path is not None
51 
53  """!Does this module represent an MPI implementation? Returns True."""
54  return True
55 
56 def make_bigexe(exe,**kwargs):
57  """!Returns an ImmutableRunner that will run the specified program.
58  @returns an empty list
59  @param exe The executable to run on compute nodes.
60  @param kwargs Ignored."""
61  return prog.ImmutableRunner([str(exe)],**kwargs)
62 
63 def mpirunner(arg,allranks=False,logger=None,**kwargs):
64  """!Turns a produtil.mpiprog.MPIRanksBase tree into a produtil.prog.Runner
65  @param arg a tree of produtil.mpiprog.MPIRanksBase objects
66  @param allranks if True, and only one rank is requested by arg, then
67  all MPI ranks will be used
68  @param logger a logging.Logger for log messages
69  @param kwargs passed to produtil.mpi_impl.mpi_impl_base.CMDFGen
70  when mpiserial is in use.
71  @returns a produtil.prog.Runner that will run the selected MPI program
72  @note LSF does not support modifying the number of MPI ranks
73  to use when running a program. You can only use all provided
74  ranks, or one rank."""
75  if logger is None:
76  logger=logging.getLogger('mpirun_lsf')
77  assert(isinstance(arg,produtil.mpiprog.MPIRanksBase))
78  (serial,parallel)=arg.check_serial()
79  if serial and parallel:
80  raise MPIMixed(
81  'Cannot mix serial and parallel MPI ranks in the same '
82  'MPI program.')
83  if arg.nranks()==1 and allranks:
84  arglist=[ a for a in arg.to_arglist(
85  pre=[mpirun_lsf_path],
86  before=[],
87  between=[])]
88  return produtil.prog.Runner(arglist)
89  elif arg.nranks()==1:
90  # Hack to get LSF to run only one MPI rank. Tested on NCEP
91  # WCOSS supercomputer and approved by its IBM support staff.
92  host=socket.gethostname()
93  runner=produtil.prog.Runner(
94  [ a for a in arg.to_arglist(
95  pre=[mpirun_lsf_path],
96  before=[], between=[]) ])
97  runner=runner.env(
98  LSB_PJL_TASK_GEOMETRY="{(0)}",LSB_HOSTS=host,
99  LSB_MCPU_HOSTS=host+" 1", LSB_DJOB_NUMPROC='1',
100  LSB_MAX_NUM_PROCESSORS='1',MP_TASK_AFFINITY='core')
101  if logger is not None:
102  logger.info(
103  'Using a hack to work around an LSF bug and run a one core '
104  'program: '+repr(runner))
105  return runner
106  elif allranks:
107  raise MPIAllRanksError(
108  "When using allranks=True, you must provide an mpi program "
109  "specification with only one MPI rank (to be duplicated "
110  "across all ranks).")
111  elif serial:
112  lines=[a for a in arg.to_arglist(to_shell=True,expand=True)]
113  if produtil.fileop.find_exe('mpiserial') is None:
114  raise MPISerialMissing(
115  'Attempting to run a serial program via mpirun.lsf but '
116  'the mpiserial program is not in your $PATH.')
117  return produtil.prog.Runner([mpirun_lsf_path,'mpiserial'],
118  prerun=CMDFGen('serialcmdf',lines,
119  cmd_envar='MP_CMDFILE',
120  model_envar='MP_PGMMODEL',
121  **kwargs))
122  else:
123  lines=[a for a in arg.to_arglist(to_shell=True,expand=True)]
124  return produtil.prog.Runner([mpirun_lsf_path],
125  prerun=CMDFGen('mpirun_lsf_cmdf',lines,
126  cmd_envar='MP_CMDFILE',
127  model_envar='MP_PGMMODEL',
128  **kwargs))
129 
This module provides a set of utility functions to do filesystem operations.
Definition: fileop.py:1
def mpirunner(arg, allranks=False, logger=None, kwargs)
Turns a produtil.mpiprog.MPIRanksBase tree into a produtil.prog.Runner.
Definition: mpirun_lsf.py:63
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 detect()
Determines if LSF+IBMPE should be used to run MPI programs by looking for the mpirun.lsf program in $PATH.
Definition: mpirun_lsf.py:47
def runsync
Runs the "sync" command as an exe().
Definition: mpirun_lsf.py:25
def openmp(arg, threads)
Adds OpenMP support to the provided object.
Definition: mpirun_lsf.py:33
Object structure for describing MPI programs.
Definition: mpiprog.py:1
def can_run_mpi()
Does this module represent an MPI implementation? Returns True.
Definition: mpirun_lsf.py:52
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 make_bigexe(exe, kwargs)
Returns an ImmutableRunner that will run the specified program.
Definition: mpirun_lsf.py:56
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