Gaudi Framework, version v23r7

Home   Generated: Wed Mar 20 2013
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
gaudirun.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
4  """
5  Remove from the arguments the presence of the profiler and its output in
6  order to relaunch the script w/o infinite loops.
7 
8  >>> getArgsWithoutoProfilerInfo(['--profilerName', 'igprof', 'myopts.py'])
9  ['myopts.py']
10 
11  >>> getArgsWithoutoProfilerInfo(['--profilerName=igprof', 'myopts.py'])
12  ['myopts.py']
13 
14  >>> getArgsWithoutoProfilerInfo(['--profilerName', 'igprof', '--profilerExtraOptions', 'a b c', 'myopts.py'])
15  ['myopts.py']
16 
17  >>> getArgsWithoutoProfilerInfo(['--profilerName', 'igprof', '--options', 'a b c', 'myopts.py'])
18  ['--options', 'a b c', 'myopts.py']
19  """
20  newargs = []
21  args = list(args) # make a temp copy
22  while args:
23  o = args.pop(0)
24  if o.startswith('--profile'):
25  if '=' not in o:
26  args.pop(0)
27  else:
28  newargs.append(o)
29  return newargs
30 
31 
32 #---------------------------------------------------------------------
33 if __name__ == "__main__":
34  import os, sys
35  from optparse import OptionParser
36  parser = OptionParser(usage = "%prog [options] <opts_file> ...")
37  parser.add_option("-n","--dry-run", action="store_true",
38  help="do not run the application, just parse option files")
39  parser.add_option("-p","--pickle-output", action="store", type="string",
40  metavar = "FILE",
41  help="DEPRECATED: use '--output file.pkl' instead. Write "
42  "the parsed options as a pickle file (static option "
43  "file)")
44  parser.add_option("-v","--verbose", action="store_true",
45  help="print the parsed options")
46  parser.add_option("--old-opts", action="store_true",
47  help="format printed options in old option files style")
48  parser.add_option("--all-opts", action="store_true",
49  help="print all the option (even if equal to default)")
50  # GaudiPython Parallel Mode Option
51  # Argument must be an integer in range [ -1, sys_cpus ]
52  # -1 : All available cpus
53  # 0 : Serial Mode (traditional gaudirun)
54  # n>0 : parallel with n cpus (n <= sys_cpus)
55  parser.add_option("--ncpus", action="store", type="int", default=0,
56  help="start the application in parallel mode using NCPUS processes. "
57  "0 => serial mode (default), -1 => use all CPUs")
58 
59  def option_cb(option, opt, value, parser):
60  """Add the option line to a list together with its position in the
61  argument list.
62  """
63  parser.values.options.append((len(parser.largs), value))
64  parser.add_option("--option", action="callback", callback=option_cb,
65  type = "string", nargs = 1,
66  help="add a single line (Python) option to the configuration. "
67  "All options lines are executed, one after the other, in "
68  "the same context.")
69  parser.add_option("--no-conf-user-apply", action="store_true",
70  help="disable the automatic application of configurable "
71  "users (for backward compatibility)")
72  parser.add_option("-o", "--output", action = "store", type = "string",
73  help ="dump the configuration to a file. The format of "
74  "the options is determined by the extension of the "
75  "file name: .pkl = pickle, .py = python, .opts = "
76  "old style options. The python format cannot be "
77  "used to run the application and it contains the "
78  "same dictionary printed with -v")
79  parser.add_option("--post-option", action="append", type="string",
80  dest="post_options",
81  help="Python options to be executed after the ConfigurableUser "
82  "are applied. "
83  "All options lines are executed, one after the other, in "
84  "the same context.")
85  parser.add_option("--debug", action="store_true",
86  help="enable some debug print-out")
87  parser.add_option("--printsequence", action="store_true",
88  help="print the sequence")
89  if not sys.platform.startswith("win"):
90  # These options can be used only on unix platforms
91  parser.add_option("-T", "--tcmalloc", action="store_true",
92  help="Use the Google malloc replacement. The environment "
93  "variable TCMALLOCLIB can be used to specify a different "
94  "name for the library (the default is libtcmalloc.so)")
95  parser.add_option("--preload", action="append",
96  help="Allow pre-loading of special libraries (e.g. Google "
97  "profiling libraries).")
98 
99  # Option to use a profiler
100  parser.add_option("--profilerName", type="string",
101  help="Select one profiler among: igprofPerf, igprofMem and valgrind<toolname>")
102 
103  # Option to specify the filename where to collect the profiler's output
104  parser.add_option("--profilerOutput", type="string",
105  help="Specify the name of the output file for the profiler output")
106 
107  # Option to specify the filename where to collect the profiler's output
108  parser.add_option("--profilerExtraOptions", type="string",
109  help="Specify additional options for the profiler. The '--' string should be expressed as '__' (--my-opt becomes __my-opt)")
110 
111  parser.set_defaults(options = [],
112  tcmalloc = False,
113  profilerName = '',
114  profilerOutput = '',
115  profilerExtraOptions = '',
116  preload = [],
117  ncpus = None)
118 
119  opts, args = parser.parse_args()
120 
121  # Check consistency of options
122 
123  # Parallel Option ---------------------------------------------------------
124  if opts.ncpus:
125  from multiprocessing import cpu_count
126  sys_cpus = cpu_count()
127  if opts.ncpus > sys_cpus:
128  s = "Invalid value : --ncpus : only %i cpus available" % sys_cpus
129  parser.error(s)
130  elif opts.ncpus < -1 :
131  s = "Invalid value : --ncpus must be integer >= -1"
132  parser.error(s)
133  else:
134  # FIXME: is it really needed to set it to None if it is 0 or False?
135  opts.ncpus = None
136 
137  # configure the logging
138  import logging
139  from GaudiKernel.ProcessJobOptions import InstallRootLoggingHandler
140 
141  if opts.old_opts: prefix = "// "
142  else: prefix = "# "
143  level = logging.INFO
144  if opts.debug:
145  level = logging.DEBUG
146  InstallRootLoggingHandler(prefix, level = level)
147  root_logger = logging.getLogger()
148 
149  # tcmalloc support
150  if opts.tcmalloc:
151  opts.preload.insert(0, os.environ.get("TCMALLOCLIB", "libtcmalloc.so"))
152  # allow preloading of libraries
153  if opts.preload:
154  preload = os.environ.get("LD_PRELOAD", "")
155  if preload:
156  preload = preload.replace(" ", ":").split(":")
157  else:
158  preload = []
159  for libname in set(preload).intersection(opts.preload):
160  logging.warning("Ignoring preload of library %s because it is "
161  "already in LD_PRELOAD.", libname)
162  to_load = [libname
163  for libname in opts.preload
164  if libname not in set(preload)]
165  if to_load:
166  preload += to_load
167  preload = ":".join(preload)
168  os.environ["LD_PRELOAD"] = preload
169  logging.info("Restarting with LD_PRELOAD='%s'", preload)
170  # remove the --tcmalloc option from the arguments
171  # FIXME: the --preload arguments will issue a warning but it's tricky to remove them
172  args = [ a for a in sys.argv if a != '-T' and not '--tcmalloc'.startswith(a) ]
173  os.execv(sys.executable, [sys.executable] + args)
174 
175  # Profiler Support ------
176  if opts.profilerName:
177  profilerName = opts.profilerName
178  profilerExecName = ""
179  profilerOutput = opts.profilerOutput or (profilerName + ".output")
180 
181  # To restart the application removing the igprof option and prepending the string
182  args = getArgsWithoutoProfilerInfo(sys.argv)
183 
184  igprofPerfOptions = "-d -pp -z -o igprof.pp.gz".split()
185 
186  profilerOptions = ""
187  if profilerName == "igprof":
188  if not opts.profilerOutput:
189  profilerOutput += ".profile.gz"
190  profilerOptions = "-d -z -o %s" % profilerOutput
191  profilerExecName = "igprof"
192 
193  elif profilerName == "igprofPerf":
194  if not opts.profilerOutput:
195  profilerOutput += ".pp.gz"
196  profilerOptions = "-d -pp -z -o %s" % profilerOutput
197  profilerExecName = "igprof"
198 
199  elif profilerName == "igprofMem":
200  if not opts.profilerOutput:
201  profilerOutput += ".mp.gz"
202  profilerOptions = "-d -mp -z -o %s" % profilerOutput
203  profilerExecName = "igprof"
204 
205  elif "valgrind" in profilerName:
206  # extract the tool
207  if not opts.profilerOutput:
208  profilerOutput += ".log"
209  toolname = profilerName.replace('valgrind','')
210  outoption = "--log-file"
211  if toolname in ("massif", "callgrind", "cachegrind"):
212  outoption = "--%s-out-file" % toolname
213  profilerOptions = "--tool=%s %s=%s" % (toolname, outoption, profilerOutput)
214  profilerExecName = "valgrind"
215 
216  else:
217  root_logger.warning("Profiler %s not recognized!" % profilerName)
218 
219  # Add potential extra options
220  if opts.profilerExtraOptions!="":
221  profilerExtraOptions = opts.profilerExtraOptions
222  profilerExtraOptions = profilerExtraOptions.replace("__","--")
223  profilerOptions += " %s" % profilerExtraOptions
224 
225  # now we look for the full path of the profiler: is it really there?
226  import distutils.spawn
227  profilerPath = distutils.spawn.find_executable(profilerExecName)
228  if not profilerPath:
229  root_logger.error("Cannot locate profiler %s" % profilerExecName)
230  sys.exit(1)
231 
232  root_logger.info("------ Profiling options are on ------ \n"\
233  " o Profiler: %s\n"\
234  " o Options: '%s'.\n"\
235  " o Output: %s" % (profilerExecName, profilerOptions, profilerOutput))
236 
237  # We profile python
238  profilerOptions += " python"
239 
240  # now we have all the ingredients to prepare our command
241  arglist = [profilerPath] + profilerOptions.split() + args
242  arglist = [ a for a in arglist if a!='' ]
243  #print profilerPath
244  #for arg in arglist:
245  #print arg
246  os.execv(profilerPath, arglist)
247 
248  # End Profiler Support ------
249 
250  if opts.pickle_output:
251  if opts.output:
252  root_logger.error("Conflicting options: use only --pickle-output or --output")
253  sys.exit(1)
254  else:
255  root_logger.warning("--pickle-output is deprecated, use --output instead")
256  opts.output = opts.pickle_output
257 
258  from Gaudi.Main import gaudimain
259  c = gaudimain()
260 
261  # Prepare the "configuration script" to parse (like this it is easier than
262  # having a list with files and python commands, with an if statements that
263  # decides to do importOptions or exec)
264  options = [ "importOptions(%r)" % f for f in args ]
265  # The option lines are inserted into the list of commands using their
266  # position on the command line
267  optlines = list(opts.options)
268  optlines.reverse() # this allows to avoid to have to care about corrections of the positions
269  for pos, l in optlines:
270  options.insert(pos,l)
271 
272  # prevent the usage of GaudiPython
273  class FakeModule(object):
274  def __init__(self, exception):
275  self.exception = exception
276  def __getattr__(self, *args, **kwargs):
277  raise self.exception
278  sys.modules["GaudiPython"] = FakeModule(RuntimeError("GaudiPython cannot be used in option files"))
279 
280  # "execute" the configuration script generated (if any)
281  if options:
282  g = {}
283  l = {}
284  exec "from Gaudi.Configuration import *" in g, l
285  for o in options:
286  logging.debug(o)
287  exec o in g, l
288 
289  import GaudiKernel.Proxy.Configurable
290  if opts.no_conf_user_apply:
291  logging.info("Disabling automatic apply of ConfigurableUser")
292  # pretend that they have been already applied
293  GaudiKernel.Proxy.Configurable._appliedConfigurableUsers_ = True
294 
295  # This need to be done before dumping
296  from GaudiKernel.Proxy.Configurable import applyConfigurableUsers
298 
299  # Options to be processed after applyConfigurableUsers
300  if opts.post_options:
301  g = {}
302  l = {}
303  exec "from Gaudi.Configuration import *" in g, l
304  for o in opts.post_options:
305  logging.debug(o)
306  exec o in g, l
307 
308  if opts.verbose:
309  c.printconfig(opts.old_opts, opts.all_opts)
310  if opts.output:
311  c.writeconfig(opts.output, opts.all_opts)
312 
313  c.printsequence = opts.printsequence
314  if opts.printsequence:
315  if opts.ncpus:
316  logging.warning("--printsequence not supported with --ncpus: ignored")
317  elif opts.dry_run:
318  logging.warning("--printsequence not supported with --dry-run: ignored")
319 
320  # re-enable the GaudiPython module
321  del sys.modules["GaudiPython"]
322 
323  if not opts.dry_run:
324  # Do the real processing
325  sys.exit(c.run(opts.ncpus))

Generated at Wed Mar 20 2013 17:59:36 for Gaudi Framework, version v23r7 by Doxygen version 1.8.2 written by Dimitri van Heesch, © 1997-2004