13 from __future__
import print_function
16 from tempfile
import mkstemp
21 Remove from the arguments the presence of the profiler and its output in
22 order to relaunch the script w/o infinite loops.
24 >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', 'myopts.py'])
27 >>> getArgsWithoutProfilerInfo(['--profilerName=igprof', 'myopts.py'])
30 >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', '--profilerExtraOptions', 'a b c', 'myopts.py'])
33 >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', '--options', 'a b c', 'myopts.py'])
34 ['--options', 'a b c', 'myopts.py']
40 if o.startswith(
'--profile'):
49 ''' Adds a list of libraries to LD_PRELOAD '''
50 preload = os.environ.get(
"LD_PRELOAD",
"")
52 preload = preload.replace(
" ",
":").split(
":")
56 for libname
in set(preload).intersection(newpreload):
58 "Ignoring preload of library %s because it is "
59 "already in LD_PRELOAD.", libname)
62 libname
for libname
in newpreload
if libname
not in set(preload)
67 preload =
":".join(preload)
68 os.environ[
"LD_PRELOAD"] = preload
69 logging.info(
"Setting LD_PRELOAD='%s'", preload)
76 Convert the given path to a real path if the pointed file exists, otherwise
79 path = os.path.normpath(os.path.expandvars(path))
80 if os.path.exists(path):
81 path = os.path.realpath(path)
87 _qmt_tmp_opt_files = []
92 Given a .qmt file, return the command line arguments of the corresponding
95 from xml.etree
import ElementTree
as ET
96 global _qmt_tmp_opt_files
98 qmt = ET.parse(qmtfile)
99 args = [a.text
for a
in qmt.findall(
"argument[@name='args']//text")]
100 options = qmt.find(
"argument[@name='options']/text")
102 if options
is not None:
103 from tempfile
import NamedTemporaryFile
106 r"from\s+Gaudi.Configuration\s+import\s+\*"
107 r"|from\s+Configurables\s+import", options.text):
108 tmp_opts = NamedTemporaryFile(suffix=
'.py')
110 tmp_opts = NamedTemporaryFile(suffix=
'.opts')
111 tmp_opts.write(options.text.encode(
'ascii'))
113 args.append(tmp_opts.name)
114 _qmt_tmp_opt_files.append(tmp_opts)
118 qmtfile = os.path.abspath(qmtfile)
119 if 'qmtest' in qmtfile.split(os.path.sep):
122 while os.path.basename(testdir) !=
'qmtest':
123 testdir = os.path.dirname(testdir)
127 old_cwd = os.getcwd()
136 if __name__ ==
"__main__":
138 if os.environ.get(
'LC_ALL') !=
'C':
139 print(
'# setting LC_ALL to "C"')
141 os.environ[
'LC_ALL'] =
'C'
143 from optparse
import OptionParser
144 parser = OptionParser(usage=
"%prog [options] <opts_file|function_id> ...")
149 help=
"do not run the application, just parse option files")
156 help=
"DEPRECATED: use '--output file.pkl' instead. Write "
157 "the parsed options as a pickle file (static option "
163 help=
"print the parsed options")
167 help=
"format printed options in old option files style")
171 help=
"print all the option (even if equal to default)")
182 help=
"start the application in parallel mode using NCPUS processes. "
183 "0 => serial mode (default), -1 => use all CPUs")
186 """Add the option line to a list together with its position in the
189 parser.values.options.append((len(parser.largs), value))
197 help=
"add a single line (Python) option to the configuration. "
198 "All options lines are executed, one after the other, in "
201 "--no-conf-user-apply",
203 help=
"disable the automatic application of configurable "
204 "users (for backward compatibility)")
206 "--old-conf-user-apply",
208 help=
"use the old logic when applying ConfigurableUsers "
209 "(with bug #103803) [default]")
211 "--new-conf-user-apply",
212 action=
"store_false",
213 dest=
"old_conf_user_apply",
214 help=
"use the new (correct) logic when applying "
215 "ConfigurableUsers (fixed bug #103803), can be "
216 "turned on also with the environment variable "
217 "GAUDI_FIXED_APPLY_CONF")
223 help=
"dump the configuration to a file. The format of "
224 "the options is determined by the extension of the "
225 "file name: .pkl = pickle, .py = python, .opts = "
226 "old style options. The python format cannot be "
227 "used to run the application and it contains the "
228 "same dictionary printed with -v")
234 help=
"Python options to be executed after the ConfigurableUser "
236 "All options lines are executed, one after the other, in "
239 "--debug", action=
"store_true", help=
"enable some debug print-out")
240 parser.add_option(
"--gdb", action=
"store_true", help=
"attach gdb")
242 "--printsequence", action=
"store_true", help=
"print the sequence")
243 if not sys.platform.startswith(
"win"):
249 help=
"Use the Google malloc replacement. The environment "
250 "variable TCMALLOCLIB can be used to specify a different "
251 "name for the library (the default is libtcmalloc.so)")
255 help=
"Allow pre-loading of special libraries (e.g. Google "
256 "profiling libraries).")
262 "Select one profiler among: igprofPerf, igprofMem and valgrind<toolname>"
269 help=
"Specify the name of the output file for the profiler output")
273 "--profilerExtraOptions",
276 "Specify additional options for the profiler. The '--' string should be expressed as '__' (--my-opt becomes __my-opt)"
282 help=
'when this option is enabled, the options are parsed'
283 ' and stored in a temporary file, then the job is '
284 'restarted using that file as input (to save '
290 "Save gaudi process information to the file specified (in JSON format)"
294 help=
'name of the Gaudi::Application to use [default: %default]')
301 profilerExtraOptions=
'',
305 old_conf_user_apply=
'GAUDI_FIXED_APPLY_CONF' not in os.environ,
307 application=
'Gaudi::Application')
311 for a
in sys.argv[1:]:
312 if a.endswith(
'.qmt')
and os.path.exists(a):
316 if argv != sys.argv[1:]:
317 print(
'# Running', sys.argv[0],
'with arguments', argv)
319 opts, args = parser.parse_args(args=argv)
325 from multiprocessing
import cpu_count
326 sys_cpus = cpu_count()
327 if opts.ncpus > sys_cpus:
328 s =
"Invalid value : --ncpus : only %i cpus available" % sys_cpus
330 elif opts.ncpus < -1:
331 s =
"Invalid value : --ncpus must be integer >= -1"
348 level = logging.DEBUG
350 root_logger = logging.getLogger()
353 sanitizers = os.environ.get(
"PRELOAD_SANITIZER_LIB",
"")
354 preload = os.environ.get(
"LD_PRELOAD",
"")
356 os.environ[
"PRELOAD_SANITIZER_LIB"] =
""
357 if preload
and sanitizers != preload:
359 "Ignoring PRELOAD_SANITIZER_LIB (={}) as LD_PRELOAD (={}) is "
360 "different and takes precedence.".
format(sanitizers, preload))
362 for sanitizer
in reversed(sanitizers.split(
":")):
363 if sanitizer
not in preload:
364 opts.preload.insert(0, sanitizer)
365 if opts.profilerName ==
'jemalloc':
366 logging.warning(
"jemalloc disabled when using a sanitizer")
367 opts.profilerName =
None
373 logging.warning(
"tcmalloc preload disabled when using a sanitizer")
376 0, os.environ.get(
"TCMALLOCLIB",
"libtcmalloc.so"))
380 preload = os.environ.get(
"LD_PRELOAD",
"")
382 preload = preload.replace(
" ",
":").split(
":")
385 for libname
in set(preload).intersection(opts.preload):
387 "Ignoring preload of library %s because it is "
388 "already in LD_PRELOAD.", libname)
390 libname
for libname
in opts.preload
if libname
not in set(preload)
394 preload =
":".join(preload)
395 os.environ[
"LD_PRELOAD"] = preload
396 logging.info(
"Restarting with LD_PRELOAD='%s'", preload)
401 if a !=
'-T' and not '--tcmalloc'.startswith(a)
403 os.execv(sys.executable, [sys.executable] + args)
406 if opts.profilerName:
407 profilerName = opts.profilerName
408 profilerExecName =
""
409 profilerOutput = opts.profilerOutput
or (profilerName +
".output")
414 igprofPerfOptions =
"-d -pp -z -o igprof.pp.gz".split()
417 if profilerName ==
"igprof":
418 if not opts.profilerOutput:
419 profilerOutput +=
".profile.gz"
420 profilerOptions =
"-d -z -o %s" % profilerOutput
421 profilerExecName =
"igprof"
423 elif profilerName ==
"igprofPerf":
424 if not opts.profilerOutput:
425 profilerOutput +=
".pp.gz"
426 profilerOptions =
"-d -pp -z -o %s" % profilerOutput
427 profilerExecName =
"igprof"
429 elif profilerName ==
"igprofMem":
430 if not opts.profilerOutput:
431 profilerOutput +=
".mp.gz"
432 profilerOptions =
"-d -mp -z -o %s" % profilerOutput
433 profilerExecName =
"igprof"
435 elif "valgrind" in profilerName:
437 if not opts.profilerOutput:
438 profilerOutput +=
".log"
439 toolname = profilerName.replace(
'valgrind',
'')
440 outoption =
"--log-file"
441 if toolname
in (
"massif",
"callgrind",
"cachegrind"):
442 outoption =
"--%s-out-file" % toolname
443 profilerOptions =
"--tool=%s %s=%s" % (toolname, outoption,
445 profilerExecName =
"valgrind"
447 elif profilerName ==
"jemalloc":
449 0, os.environ.get(
"JEMALLOCLIB",
"libjemalloc.so"))
450 os.environ[
'MALLOC_CONF'] =
"prof:true,prof_leak:true"
452 root_logger.warning(
"Profiler %s not recognized!" % profilerName)
455 if opts.profilerExtraOptions !=
"":
456 profilerExtraOptions = opts.profilerExtraOptions
457 profilerExtraOptions = profilerExtraOptions.replace(
"__",
"--")
458 profilerOptions +=
" %s" % profilerExtraOptions
462 import distutils.spawn
463 profilerPath = distutils.spawn.find_executable(profilerExecName)
466 "Cannot locate profiler %s" % profilerExecName)
469 root_logger.info(
"------ Profiling options are on ------ \n"
471 " o Options: '%s'.\n"
472 " o Output: %s" % (profilerExecName
or profilerName,
473 profilerOptions, profilerOutput))
483 profilerOptions +=
" python"
486 arglist = [profilerPath] + profilerOptions.split() + args
487 arglist = [a
for a
in arglist
if a !=
'']
491 os.execv(profilerPath, arglist)
493 arglist = [a
for a
in sys.argv
if not a.startswith(
"--profiler")]
494 os.execv(sys.executable, [sys.executable] + arglist)
498 if opts.pickle_output:
501 "Conflicting options: use only --pickle-output or --output")
505 "--pickle-output is deprecated, use --output instead")
506 opts.output = opts.pickle_output
511 from GaudiConfig2
import CALLABLE_FORMAT, mergeConfigs, invokeConfig, Configurable
516 if CALLABLE_FORMAT.match(arg):
517 callables.append(arg)
519 opt_files.append(arg)
524 options = [
"importOptions(%r)" % f
for f
in opt_files]
527 optlines = list(opts.options)
530 for pos, l
in optlines:
531 options.insert(pos, l)
542 RuntimeError(
"GaudiPython cannot be used in option files"))
546 if 'GAUDI_TEMP_OPTS_FILE' in os.environ:
547 options = [
'importOptions(%r)' % os.environ[
'GAUDI_TEMP_OPTS_FILE']]
554 exec(
"from Gaudi.Configuration import *", g, l)
559 import GaudiKernel.Proxy.Configurable
560 if opts.no_conf_user_apply:
561 logging.info(
"Disabling automatic apply of ConfigurableUser")
563 GaudiKernel.Proxy.Configurable._appliedConfigurableUsers_ =
True
566 if opts.old_conf_user_apply:
567 from GaudiKernel.Proxy.Configurable
import applyConfigurableUsers_old
as applyConfigurableUsers
569 from GaudiKernel.Proxy.Configurable
import applyConfigurableUsers
573 if opts.post_options:
576 exec(
"from Gaudi.Configuration import *", g, l)
577 for o
in opts.post_options:
581 if 'GAUDI_TEMP_OPTS_FILE' in os.environ:
582 os.remove(os.environ[
'GAUDI_TEMP_OPTS_FILE'])
583 opts.use_temp_opts =
False
591 if opts.verbose
and not opts.use_temp_opts:
592 c.printconfig(opts.old_opts, opts.all_opts)
594 c.writeconfig(opts.output, opts.all_opts)
596 if opts.use_temp_opts:
597 fd, tmpfile = mkstemp(
'.opts')
599 c.writeconfig(tmpfile, opts.all_opts)
600 os.environ[
'GAUDI_TEMP_OPTS_FILE'] = tmpfile
601 logging.info(
'Restarting from pre-parsed options')
602 os.execv(sys.executable, [sys.executable] + sys.argv)
604 c.printsequence = opts.printsequence
605 if opts.printsequence:
608 "--printsequence not supported with --ncpus: ignored")
611 "--printsequence not supported with --dry-run: ignored")
613 c.application = opts.application
616 del sys.modules[
"GaudiPython"]
620 retcode = c.run(opts.gdb, opts.ncpus)
624 if opts.run_info_file:
628 run_info[
"pid"] = os.getpid()
629 run_info[
"retcode"] = retcode
630 if os.path.exists(
'/proc/self/exe'):
632 run_info[
"exe"] = os.readlink(
'/proc/self/exe')
634 logging.info(
"Saving run info to: %s" % opts.run_info_file)
635 with open(opts.run_info_file,
"w")
as f:
636 json.dump(run_info, f)