All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Main.py
Go to the documentation of this file.
1 import sys, os
2 from time import time
3 from Gaudi import Configuration
4 import logging
5 
6 log = logging.getLogger(__name__)
7 
8 def toOpt(value):
9  '''
10  Helper to convert values to old .opts format.
11 
12  >>> print toOpt('some "text"')
13  "some \\"text\\""
14  >>> print toOpt('first\\nsecond')
15  "first
16  second"
17  >>> print toOpt({'a': [1, 2, '3']})
18  {"a": [1, 2, "3"]}
19  '''
20  if isinstance(value, basestring):
21  return '"{0}"'.format(value.replace('"', '\\"'))
22  elif isinstance(value, dict):
23  return '{{{0}}}'.format(', '.join('{0}: {1}'.format(toOpt(k), toOpt(v))
24  for k, v in value.iteritems()))
25  elif hasattr(value, '__iter__'):
26  return '[{0}]'.format(', '.join(map(toOpt, value)))
27  else:
28  return repr(value)
29 
30 class gaudimain(object) :
31  # main loop implementation, None stands for the default
32  mainLoop = None
33 
34  def __init__(self) :
35  from Configurables import ApplicationMgr
36  appMgr = ApplicationMgr()
37  if "GAUDIAPPNAME" in os.environ:
38  appMgr.AppName = str(os.environ["GAUDIAPPNAME"])
39  if "GAUDIAPPVERSION" in os.environ:
40  appMgr.AppVersion = str(os.environ["GAUDIAPPVERSION"])
41  self.log = logging.getLogger(__name__)
42  self.printsequence = False
43 
44  def setupParallelLogging( self ) :
45  # ---------------------------------------------------
46  # set up Logging
47  # ----------------
48  # from multiprocessing import enableLogging, getLogger
49  import multiprocessing
50  # preliminaries for handlers/output files, etc.
51  from time import ctime
52  datetime = ctime()
53  datetime = datetime.replace(' ', '_')
54  outfile = open( 'gaudirun-%s.log'%(datetime), 'w' )
55  # two handlers, one for a log file, one for terminal
56  streamhandler = logging.StreamHandler(strm=outfile)
57  console = logging.StreamHandler()
58  # create formatter : the params in parentheses are variable names available via logging
59  formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s" )
60  # add formatter to Handler
61  streamhandler.setFormatter(formatter)
62  console.setFormatter(formatter)
63  # now, configure the logger
64  # enableLogging( level=0 )
65  # self.log = getLogger()
66  self.log = multiprocessing.log_to_stderr()
67  self.log.setLevel( logging.INFO )
68  self.log.name = 'Gaudi/Main.py Logger'
69  self.log.handlers = []
70  # add handlers to logger : one for output to a file, one for console output
71  self.log.addHandler(streamhandler)
72  self.log.addHandler(console)
73  self.log.removeHandler(console)
74  # set level!!
75  self.log.setLevel = logging.INFO
76  # ---------------------------------------------------
77 
78  def generatePyOutput(self, all = False):
79  from pprint import pformat
80  conf_dict = Configuration.configurationDict(all)
81  return pformat(conf_dict)
82 
83  def generateOptsOutput(self, all = False):
84  from pprint import pformat
85  conf_dict = Configuration.configurationDict(all)
86  out = []
87  names = conf_dict.keys()
88  names.sort()
89  for n in names:
90  props = conf_dict[n].keys()
91  props.sort()
92  for p in props:
93  out.append('%s.%s = %s;' % (n,p, toOpt(conf_dict[n][p])))
94  return "\n".join(out)
95 
96  def _writepickle(self, filename) :
97  #--- Lets take the first file input file as the name of the pickle file
98  import pickle
99  output = open(filename, 'wb')
100  # Dump only the the configurables that make sense to dump (not User ones)
101  from GaudiKernel.Proxy.Configurable import getNeededConfigurables
102  to_dump = {}
103  for n in getNeededConfigurables():
104  to_dump[n] = Configuration.allConfigurables[n]
105  pickle.dump(to_dump, output, -1)
106  output.close()
107 
108  def printconfig(self, old_format = False, all = False) :
109  msg = 'Dumping all configurables and properties'
110  if not all:
111  msg += ' (different from default)'
112  log.info(msg)
113  conf_dict = Configuration.configurationDict(all)
114  if old_format:
115  print self.generateOptsOutput(all)
116  else:
117  print self.generatePyOutput(all)
118 
119  def writeconfig(self, filename, all = False):
120  write = { ".pkl" : lambda filename, all: self._writepickle(filename),
121  ".py" : lambda filename, all: open(filename,"w").write(self.generatePyOutput(all) + "\n"),
122  ".opts": lambda filename, all: open(filename,"w").write(self.generateOptsOutput(all) + "\n"),
123  }
124  from os.path import splitext
125  ext = splitext(filename)[1]
126  if ext in write:
127  write[ext](filename, all)
128  else:
129  log.error("Unknown file type '%s'. Must be any of %r.", ext, write.keys())
130  sys.exit(1)
131 
132  def _printsequence(self):
133  if not self.printsequence:
134  # No printing requested
135  return
136 
137  def printAlgo( algName, appMgr, prefix = ' ') :
138  print prefix + algName
139  alg = appMgr.algorithm( algName.split( "/" )[ -1 ] )
140  prop = alg.properties()
141  if prop.has_key( "Members" ) :
142  subs = prop[ "Members" ].value()
143  for i in subs : printAlgo( i.strip( '"' ), appMgr, prefix + " " )
144  elif prop.has_key( "DetectorList" ) :
145  subs = prop[ "DetectorList" ].value()
146  for i in subs : printAlgo( algName.split( "/" )[ -1 ] + i.strip( '"' ) + "Seq", appMgr, prefix + " ")
147 
148  mp = self.g.properties()
149  print "\n ****************************** Algorithm Sequence **************************** \n"
150  for i in mp["TopAlg"].value(): printAlgo( i, self.g )
151  print "\n ****************************************************************************** \n"
152 
153  ## Instantiate and run the application.
154  # Depending on the number of CPUs (ncpus) specified, it start
155  def run(self, ncpus = None):
156  if not ncpus:
157  # Standard sequential mode
158  result = self.runSerial()
159  else:
160  # Otherwise, run with the specified number of cpus
161  result = self.runParallel(ncpus)
162  return result
163 
164 
165  def runSerial(self) :
166  #--- Instantiate the ApplicationMgr------------------------------
167  import GaudiPython
168  self.log.debug('-'*80)
169  self.log.debug('%s: running in serial mode', __name__)
170  self.log.debug('-'*80)
171  sysStart = time()
172  self.g = GaudiPython.AppMgr()
173  self._printsequence()
174  runner = self.mainLoop or (lambda app, nevt: app.run(nevt))
175  try:
176  statuscode = runner(self.g, self.g.EvtMax)
177  except SystemError:
178  # It may not be 100% correct, but usually it means a segfault in C++
179  self.g.ReturnCode = 128 + 11
180  statuscode = False
181  except:
182  # for other exceptions, just set a generic error code
183  self.g.ReturnCode = 1
184  statuscode = False
185  if hasattr(statuscode, "isSuccess"):
186  success = statuscode.isSuccess()
187  else:
188  success = statuscode
189  success = self.g.exit().isSuccess() and success
190  if not success and self.g.ReturnCode == 0:
191  # ensure that the return code is correctly set
192  self.g.ReturnCode = 1
193  sysTime = time()-sysStart
194  self.log.debug('-'*80)
195  self.log.debug('%s: serial system finished, time taken: %5.4fs', __name__, sysTime)
196  self.log.debug('-'*80)
197  return self.g.ReturnCode
198 
199  def runParallel(self, ncpus) :
200  if self.mainLoop:
201  self.log.fatal("Cannot use custom main loop in multi-process mode, check your options")
202  return 1
203  self.setupParallelLogging( )
204  from Gaudi.Configuration import Configurable
205  import GaudiMP.GMPBase as gpp
206  c = Configurable.allConfigurables
207  self.log.info('-'*80)
208  self.log.info('%s: Parallel Mode : %i '%(__name__, ncpus))
209  from commands import getstatusoutput as gso
210  metadataCommands = [ 'uname -a',
211  'echo $CMTCONFIG',
212  'echo $GAUDIAPPNAME',
213  'echo $GAUDIAPPVERSION']
214  for comm in metadataCommands :
215  s, o = gso( comm )
216  if s :
217  o = "Undetermined"
218  string = '%s: %30s : %s '%(__name__, comm, o)
219  self.log.info( string )
220  try :
221  events = str(c['ApplicationMgr'].EvtMax)
222  except :
223  events = "Undetermined"
224  self.log.info('%s: Events Specified : %s '%(__name__,events))
225  self.log.info('-'*80)
226  # Parall = gpp.Coordinator(ncpus, shared, c, self.log)
227  Parall = gpp.Coord( ncpus, c, self.log )
228  sysStart = time()
229  sc = Parall.Go()
230  self.log.info('MAIN.PY : received %s from Coordinator'%(sc))
231  if sc.isFailure() :
232  return 1
233  sysTime = time()-sysStart
234  self.log.name = 'Gaudi/Main.py Logger'
235  self.log.info('-'*80)
236  self.log.info('%s: parallel system finished, time taken: %5.4fs', __name__, sysTime)
237  self.log.info('-'*80)
238  return 0