15from tempfile
import mkstemp
20 Remove from the arguments the presence of the profiler and its output in
21 order to relaunch the script w/o infinite loops.
23 >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', 'myopts.py'])
26 >>> getArgsWithoutProfilerInfo(['--profilerName=igprof', 'myopts.py'])
29 >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', '--profilerExtraOptions', 'a b c', 'myopts.py'])
32 >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', '--options', 'a b c', 'myopts.py'])
33 ['--options', 'a b c', 'myopts.py']
39 if o.startswith(
"--profile"):
48 """Adds a list of libraries to LD_PRELOAD"""
49 preload = os.environ.get(
"LD_PRELOAD",
"")
51 preload = preload.replace(
" ",
":").split(
":")
55 for libname
in set(preload).intersection(newpreload):
57 "Ignoring preload of library %s because it is " "already in LD_PRELOAD.",
61 to_load = [libname
for libname
in newpreload
if libname
not in set(preload)]
65 preload =
":".join(preload)
66 os.environ[
"LD_PRELOAD"] = preload
67 logging.info(
"Setting LD_PRELOAD='%s'", preload)
74 Convert the given path to a real path if the pointed file exists, otherwise
77 path = os.path.normpath(os.path.expandvars(path))
78 if os.path.exists(path):
79 path = os.path.realpath(path)
85_qmt_tmp_opt_files = []
90 Given a .qmt file, return the command line arguments of the corresponding
93 from xml.etree
import ElementTree
as ET
95 global _qmt_tmp_opt_files
97 qmt = ET.parse(qmtfile)
98 args = [a.text
for a
in qmt.findall(
"argument[@name='args']//text")]
99 options = qmt.find(
"argument[@name='options']/text")
102 options
is not None and options.text
is not None
105 from tempfile
import NamedTemporaryFile
108 r"from\s+Gaudi.Configuration\s+import\s+\*"
109 r"|from\s+Configurables\s+import",
112 tmp_opts = NamedTemporaryFile(suffix=
".py")
114 tmp_opts = NamedTemporaryFile(suffix=
".opts")
115 tmp_opts.write(options.text.encode(
"ascii"))
117 args.append(tmp_opts.name)
118 _qmt_tmp_opt_files.append(tmp_opts)
122 qmtfile = os.path.abspath(qmtfile)
123 if "qmtest" in qmtfile.split(os.path.sep):
126 while os.path.basename(testdir) !=
"qmtest":
127 testdir = os.path.dirname(testdir)
131 old_cwd = os.getcwd()
140if __name__ ==
"__main__":
142 if os.environ.get(
"LC_ALL") !=
"C":
143 print(
'# setting LC_ALL to "C"')
145 os.environ[
"LC_ALL"] =
"C"
147 from optparse
import OptionParser
149 parser = OptionParser(usage=
"%prog [options] <opts_file|function_id> ...")
154 help=
"do not run the application, just parse option files",
162 help=
"DEPRECATED: use '--output file.pkl' instead. Write "
163 "the parsed options as a pickle file (static option "
167 "-v",
"--verbose", action=
"store_true", help=
"print the parsed options"
172 help=
"format printed options in old option files style",
177 help=
"print all the option (even if equal to default)",
189 help=
"start the application in parallel mode using NCPUS processes. "
190 "0 => serial mode (default), -1 => use all CPUs",
194 """Add the option line to a list together with its position in the
197 parser.values.options.append((len(parser.largs), value))
205 help=
"add a single line (Python) option to the configuration. "
206 "All options lines are executed, one after the other, in "
210 "--no-conf-user-apply",
212 help=
"disable the automatic application of configurable "
213 "users (for backward compatibility)",
216 "--old-conf-user-apply",
218 help=
"use the old logic when applying ConfigurableUsers "
219 "(with bug #103803) [default]",
222 "--new-conf-user-apply",
223 action=
"store_false",
224 dest=
"old_conf_user_apply",
225 help=
"use the new (correct) logic when applying "
226 "ConfigurableUsers (fixed bug #103803), can be "
227 "turned on also with the environment variable "
228 "GAUDI_FIXED_APPLY_CONF",
235 help=
"dump the configuration to a file. The format of "
236 "the options is determined by the extension of the "
237 "file name: .pkl = pickle, .py = python, .opts = "
238 "old style options. The python format cannot be "
239 "used to run the application and it contains the "
240 "same dictionary printed with -v",
247 help=
"Python options to be executed after the ConfigurableUser "
249 "All options lines are executed, one after the other, in "
253 "--debug", action=
"store_true", help=
"enable some debug print-out"
255 parser.add_option(
"--gdb", action=
"store_true", help=
"attach gdb")
256 parser.add_option(
"--printsequence", action=
"store_true", help=
"print the sequence")
257 if not sys.platform.startswith(
"win"):
263 help=
"Use the Google malloc replacement. The environment "
264 "variable TCMALLOCLIB can be used to specify a different "
265 "name for the library (the default is libtcmalloc.so)",
270 help=
"Allow pre-loading of special libraries (e.g. Google "
271 "profiling libraries).",
277 help=
"Select one profiler among: igprofPerf, igprofMem and valgrind<toolname>",
284 help=
"Specify the name of the output file for the profiler output",
289 "--profilerExtraOptions",
291 help=
"Specify additional options for the profiler. The '--' string should be expressed as '__' (--my-opt becomes __my-opt)",
297 help=
"when this option is enabled, the options are parsed"
298 " and stored in a temporary file, then the job is "
299 "restarted using that file as input (to save "
305 help=
"Save gaudi process information to the file specified (in JSON format)",
309 help=
"name of the Gaudi::Application to use [default: %default]",
317 profilerExtraOptions=
"",
321 old_conf_user_apply=
"GAUDI_FIXED_APPLY_CONF" not in os.environ,
323 application=
"Gaudi::Application",
328 for a
in sys.argv[1:]:
329 if a.endswith(
".qmt")
and os.path.exists(a):
333 if argv != sys.argv[1:]:
334 print(
"# Running", sys.argv[0],
"with arguments", argv)
336 opts, args = parser.parse_args(args=argv)
342 from multiprocessing
import cpu_count
344 sys_cpus = cpu_count()
345 if opts.ncpus > sys_cpus:
346 s = f
"Invalid value : --ncpus : only {sys_cpus} cpus available"
348 elif opts.ncpus < -1:
349 s =
"Invalid value : --ncpus must be integer >= -1"
366 level = logging.DEBUG
367 InstallRootLoggingHandler(prefix, level=level, with_time=opts.debug)
368 root_logger = logging.getLogger()
371 sanitizers = os.environ.get(
"PRELOAD_SANITIZER_LIB",
"")
372 preload = os.environ.get(
"LD_PRELOAD",
"")
374 os.environ[
"PRELOAD_SANITIZER_LIB"] =
""
375 sanitizer_list = sanitizers.split(
":")
384 if preload
and not all(s
in preload
for s
in sanitizer_list):
386 f
"Ignoring PRELOAD_SANITIZER_LIB (={sanitizers}) as LD_PRELOAD (={preload}) is "
387 "different and takes precedence."
390 for sanitizer
in reversed(sanitizer_list):
391 if sanitizer
not in preload:
392 opts.preload.insert(0, sanitizer)
393 if opts.profilerName ==
"jemalloc":
394 logging.warning(
"jemalloc disabled when using a sanitizer")
395 opts.profilerName =
None
401 logging.warning(
"tcmalloc preload disabled when using a sanitizer")
403 opts.preload.insert(0, os.environ.get(
"TCMALLOCLIB",
"libtcmalloc.so"))
407 preload = os.environ.get(
"LD_PRELOAD",
"")
409 preload = preload.replace(
" ",
":").split(
":")
412 for libname
in set(preload).intersection(opts.preload):
414 "Ignoring preload of library %s because it is "
415 "already in LD_PRELOAD.",
418 to_load = [libname
for libname
in opts.preload
if libname
not in set(preload)]
421 preload =
":".join(preload)
422 os.environ[
"LD_PRELOAD"] = preload
423 logging.info(
"Restarting with LD_PRELOAD='%s'", preload)
426 args = [a
for a
in sys.argv
if a !=
"-T" and not "--tcmalloc".startswith(a)]
427 os.execv(sys.executable, [sys.executable] + args)
430 if opts.profilerName:
431 profilerName = opts.profilerName
432 profilerExecName =
""
433 profilerOutput = opts.profilerOutput
or (profilerName +
".output")
438 igprofPerfOptions =
"-d -pp -z -o igprof.pp.gz".split()
441 if profilerName ==
"igprof":
442 if not opts.profilerOutput:
443 profilerOutput +=
".profile.gz"
444 profilerOptions = f
"-d -z -o {profilerOutput}"
445 profilerExecName =
"igprof"
447 elif profilerName ==
"igprofPerf":
448 if not opts.profilerOutput:
449 profilerOutput +=
".pp.gz"
450 profilerOptions = f
"-d -pp -z -o {profilerOutput}"
451 profilerExecName =
"igprof"
453 elif profilerName ==
"igprofMem":
454 if not opts.profilerOutput:
455 profilerOutput +=
".mp.gz"
456 profilerOptions = f
"-d -mp -z -o {profilerOutput}"
457 profilerExecName =
"igprof"
459 elif "valgrind" in profilerName:
461 if not opts.profilerOutput:
462 profilerOutput +=
".log"
463 toolname = profilerName.replace(
"valgrind",
"")
464 outoption =
"--log-file"
465 if toolname
in (
"massif",
"callgrind",
"cachegrind"):
466 outoption = f
"--{toolname}-out-file"
467 profilerOptions = f
"--tool={toolname} {outoption}={profilerOutput}"
468 profilerExecName =
"valgrind"
470 elif profilerName ==
"jemalloc":
471 opts.preload.insert(0, os.environ.get(
"JEMALLOCLIB",
"libjemalloc.so"))
472 os.environ[
"MALLOC_CONF"] =
"prof:true,prof_leak:true"
474 root_logger.warning(f
"Profiler {profilerName} not recognized!")
477 if opts.profilerExtraOptions !=
"":
478 profilerExtraOptions = opts.profilerExtraOptions
479 profilerExtraOptions = profilerExtraOptions.replace(
"__",
"--")
480 profilerOptions += f
" {profilerExtraOptions}"
484 import distutils.spawn
486 profilerPath = distutils.spawn.find_executable(profilerExecName)
488 root_logger.error(f
"Cannot locate profiler {profilerExecName}")
492 "------ Profiling options are on ------ \n"
493 f
" o Profiler: {profilerExecName or profilerName}\n"
494 f
" o Options: '{profilerOptions}'.\n"
495 f
" o Output: {profilerOutput}"
506 profilerOptions +=
" python"
509 arglist = [profilerPath] + profilerOptions.split() + args
510 arglist = [a
for a
in arglist
if a !=
""]
514 os.execv(profilerPath, arglist)
516 arglist = [a
for a
in sys.argv
if not a.startswith(
"--profiler")]
517 os.execv(sys.executable, [sys.executable] + arglist)
521 if opts.pickle_output:
524 "Conflicting options: use only --pickle-output or --output"
528 root_logger.warning(
"--pickle-output is deprecated, use --output instead")
529 opts.output = opts.pickle_output
537 Helper class to be able to process option files or options
538 callables as they come along in the arguments.
542 self.
config = {}
if initial_config
is None else initial_config
545 from GaudiConfig2
import CALLABLE_FORMAT, invokeConfig, mergeConfigs
549 arg = os.path.expandvars(arg)
551 if CALLABLE_FORMAT.match(arg):
552 self.
config = mergeConfigs(self.
config, invokeConfig(arg))
561 options = [f
"process({arg!r})" for arg
in args]
564 optlines = list(opts.options)
567 for pos, l
in optlines:
568 options.insert(pos, l)
579 RuntimeError(
"GaudiPython cannot be used in option files")
584 if "GAUDI_TEMP_OPTS_FILE" in os.environ:
585 options = [
"process({!r})".
format(os.environ[
"GAUDI_TEMP_OPTS_FILE"])]
590 g = {
"process": process}
592 exec(
"from Gaudi.Configuration import *", g, l)
597 import GaudiKernel.Proxy.Configurable
599 if opts.no_conf_user_apply:
600 logging.info(
"Disabling automatic apply of ConfigurableUser")
602 GaudiKernel.Proxy.Configurable._appliedConfigurableUsers_ =
True
605 if opts.old_conf_user_apply:
606 from GaudiKernel.Proxy.Configurable
import (
607 applyConfigurableUsers_old
as applyConfigurableUsers,
610 from GaudiKernel.Proxy.Configurable
import applyConfigurableUsers
611 applyConfigurableUsers()
614 if opts.post_options:
615 g = {
"process": process}
617 exec(
"from Gaudi.Configuration import *", g, l)
618 for o
in opts.post_options:
622 if "GAUDI_TEMP_OPTS_FILE" in os.environ:
623 os.remove(os.environ[
"GAUDI_TEMP_OPTS_FILE"])
624 opts.use_temp_opts =
False
628 from GaudiConfig2
import Configurable, mergeConfigs
630 Configurable.instances = mergeConfigs(Configurable.instances, process.config)
632 if opts.verbose
and not opts.use_temp_opts:
633 c.printconfig(opts.old_opts, opts.all_opts)
635 c.writeconfig(opts.output, opts.all_opts)
637 if opts.use_temp_opts:
638 fd, tmpfile = mkstemp(
".opts")
640 c.writeconfig(tmpfile, opts.all_opts)
641 os.environ[
"GAUDI_TEMP_OPTS_FILE"] = tmpfile
642 logging.info(
"Restarting from pre-parsed options")
643 os.execv(sys.executable, [sys.executable] + sys.argv)
645 c.printsequence = opts.printsequence
646 if opts.printsequence:
648 logging.warning(
"--printsequence not supported with --ncpus: ignored")
650 logging.warning(
"--printsequence not supported with --dry-run: ignored")
652 c.application = opts.application
655 del sys.modules[
"GaudiPython"]
659 retcode = c.run(opts.gdb, opts.ncpus)
663 if opts.run_info_file:
668 run_info[
"pid"] = os.getpid()
669 run_info[
"retcode"] = retcode
670 if os.path.exists(
"/proc/self/exe"):
672 run_info[
"exe"] = os.readlink(
"/proc/self/exe")
674 logging.info(f
"Saving run info to: {opts.run_info_file}")
675 with open(opts.run_info_file,
"w")
as f:
676 json.dump(run_info, f)
GAUDI_API std::string format(const char *,...)
MsgStream format utility "a la sprintf(...)".
__init__(self, initial_config=None)
__getattr__(self, *args, **kwargs)
__init__(self, exception)
option_cb(option, opt, value, parser)
getArgsWithoutProfilerInfo(args)
setLibraryPreload(newpreload)