13 from __future__ 
import print_function
 
   17 from tempfile 
import mkstemp
 
   22     Remove from the arguments the presence of the profiler and its output in 
   23     order to relaunch the script w/o infinite loops. 
   25     >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', 'myopts.py']) 
   28     >>> getArgsWithoutProfilerInfo(['--profilerName=igprof', 'myopts.py']) 
   31     >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', '--profilerExtraOptions', 'a b c', 'myopts.py']) 
   34     >>> getArgsWithoutProfilerInfo(['--profilerName', 'igprof', '--options', 'a b c', 'myopts.py']) 
   35     ['--options', 'a b c', 'myopts.py'] 
   41         if o.startswith(
"--profile"):
 
   50     """Adds  a list of libraries to LD_PRELOAD""" 
   51     preload = os.environ.get(
"LD_PRELOAD", 
"")
 
   53         preload = preload.replace(
" ", 
":").split(
":")
 
   57     for libname 
in set(preload).intersection(newpreload):
 
   59             "Ignoring preload of library %s because it is " "already in LD_PRELOAD.",
 
   63     to_load = [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
 
   97     global _qmt_tmp_opt_files
 
   99     qmt = ET.parse(qmtfile)
 
  100     args = [a.text 
for a 
in qmt.findall(
"argument[@name='args']//text")]
 
  101     options = qmt.find(
"argument[@name='options']/text")
 
  103     if options 
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()
 
  140 if __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 = 
"Invalid value : --ncpus : only %i cpus available" % sys_cpus
 
  348         elif opts.ncpus < -1:
 
  349             s = 
"Invalid value : --ncpus must be integer >= -1" 
  366         level = logging.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         if preload 
and sanitizers != preload:
 
  377                 "Ignoring PRELOAD_SANITIZER_LIB (={}) as LD_PRELOAD (={}) is " 
  378                 "different and takes precedence.".
format(sanitizers, preload)
 
  381             for sanitizer 
in reversed(sanitizers.split(
":")):
 
  382                 if sanitizer 
not in preload:
 
  383                     opts.preload.insert(0, sanitizer)
 
  384             if opts.profilerName == 
"jemalloc":
 
  385                 logging.warning(
"jemalloc disabled when using a sanitizer")
 
  386                 opts.profilerName = 
None 
  392             logging.warning(
"tcmalloc preload disabled when using a sanitizer")
 
  394             opts.preload.insert(0, os.environ.get(
"TCMALLOCLIB", 
"libtcmalloc.so"))
 
  398         preload = os.environ.get(
"LD_PRELOAD", 
"")
 
  400             preload = preload.replace(
" ", 
":").split(
":")
 
  403         for libname 
in set(preload).intersection(opts.preload):
 
  405                 "Ignoring preload of library %s because it is " 
  406                 "already in LD_PRELOAD.",
 
  409         to_load = [libname 
for libname 
in opts.preload 
if libname 
not in set(preload)]
 
  412             preload = 
":".join(preload)
 
  413             os.environ[
"LD_PRELOAD"] = preload
 
  414             logging.info(
"Restarting with LD_PRELOAD='%s'", preload)
 
  417             args = [a 
for a 
in sys.argv 
if a != 
"-T" and not "--tcmalloc".startswith(a)]
 
  418             os.execv(sys.executable, [sys.executable] + args)
 
  421     if opts.profilerName:
 
  422         profilerName = opts.profilerName
 
  423         profilerExecName = 
"" 
  424         profilerOutput = opts.profilerOutput 
or (profilerName + 
".output")
 
  429         igprofPerfOptions = 
"-d -pp -z -o igprof.pp.gz".split()
 
  432         if profilerName == 
"igprof":
 
  433             if not opts.profilerOutput:
 
  434                 profilerOutput += 
".profile.gz" 
  435             profilerOptions = 
"-d -z -o %s" % profilerOutput
 
  436             profilerExecName = 
"igprof" 
  438         elif profilerName == 
"igprofPerf":
 
  439             if not opts.profilerOutput:
 
  440                 profilerOutput += 
".pp.gz" 
  441             profilerOptions = 
"-d -pp -z -o %s" % profilerOutput
 
  442             profilerExecName = 
"igprof" 
  444         elif profilerName == 
"igprofMem":
 
  445             if not opts.profilerOutput:
 
  446                 profilerOutput += 
".mp.gz" 
  447             profilerOptions = 
"-d -mp -z -o %s" % profilerOutput
 
  448             profilerExecName = 
"igprof" 
  450         elif "valgrind" in profilerName:
 
  452             if not opts.profilerOutput:
 
  453                 profilerOutput += 
".log" 
  454             toolname = profilerName.replace(
"valgrind", 
"")
 
  455             outoption = 
"--log-file" 
  456             if toolname 
in (
"massif", 
"callgrind", 
"cachegrind"):
 
  457                 outoption = 
"--%s-out-file" % toolname
 
  458             profilerOptions = 
"--tool=%s %s=%s" % (toolname, outoption, profilerOutput)
 
  459             profilerExecName = 
"valgrind" 
  461         elif profilerName == 
"jemalloc":
 
  462             opts.preload.insert(0, os.environ.get(
"JEMALLOCLIB", 
"libjemalloc.so"))
 
  463             os.environ[
"MALLOC_CONF"] = 
"prof:true,prof_leak:true" 
  465             root_logger.warning(
"Profiler %s not recognized!" % profilerName)
 
  468         if opts.profilerExtraOptions != 
"":
 
  469             profilerExtraOptions = opts.profilerExtraOptions
 
  470             profilerExtraOptions = profilerExtraOptions.replace(
"__", 
"--")
 
  471             profilerOptions += 
" %s" % profilerExtraOptions
 
  475             import distutils.spawn
 
  477             profilerPath = distutils.spawn.find_executable(profilerExecName)
 
  479                 root_logger.error(
"Cannot locate profiler %s" % profilerExecName)
 
  483             "------ Profiling options are on ------ \n" 
  485             " o Options: '%s'.\n" 
  487             % (profilerExecName 
or profilerName, profilerOptions, profilerOutput)
 
  498             profilerOptions += 
" python" 
  501             arglist = [profilerPath] + profilerOptions.split() + args
 
  502             arglist = [a 
for a 
in arglist 
if a != 
""]
 
  506             os.execv(profilerPath, arglist)
 
  508             arglist = [a 
for a 
in sys.argv 
if not a.startswith(
"--profiler")]
 
  509             os.execv(sys.executable, [sys.executable] + arglist)
 
  513     if opts.pickle_output:
 
  516                 "Conflicting options: use only --pickle-output or --output" 
  520             root_logger.warning(
"--pickle-output is deprecated, use --output instead")
 
  521             opts.output = opts.pickle_output
 
  529         Helper class to be able to process option files or options 
  530         callables as they come along in the arguments. 
  534             self.
config = {} 
if initial_config 
is None else initial_config
 
  538             from GaudiConfig2 
import CALLABLE_FORMAT, invokeConfig, mergeConfigs
 
  540             if CALLABLE_FORMAT.match(arg):
 
  550     options = [
"process({!r})".
format(arg) 
for arg 
in args]
 
  553     optlines = list(opts.options)
 
  556     for pos, l 
in optlines:
 
  557         options.insert(pos, l)
 
  568         RuntimeError(
"GaudiPython cannot be used in option files")
 
  573     if "GAUDI_TEMP_OPTS_FILE" in os.environ:
 
  574         options = [
"process({!r})".
format(os.environ[
"GAUDI_TEMP_OPTS_FILE"])]
 
  579         g = {
"process": process}
 
  581         exec(
"from Gaudi.Configuration import *", g, l)
 
  586     import GaudiKernel.Proxy.Configurable
 
  588     if opts.no_conf_user_apply:
 
  589         logging.info(
"Disabling automatic apply of ConfigurableUser")
 
  591         GaudiKernel.Proxy.Configurable._appliedConfigurableUsers_ = 
True 
  594     if opts.old_conf_user_apply:
 
  595         from GaudiKernel.Proxy.Configurable 
import (
 
  596             applyConfigurableUsers_old 
as applyConfigurableUsers,
 
  599         from GaudiKernel.Proxy.Configurable 
import applyConfigurableUsers
 
  603     if opts.post_options:
 
  604         g = {
"process": process}
 
  606         exec(
"from Gaudi.Configuration import *", g, l)
 
  607         for o 
in opts.post_options:
 
  611     if "GAUDI_TEMP_OPTS_FILE" in os.environ:
 
  612         os.remove(os.environ[
"GAUDI_TEMP_OPTS_FILE"])
 
  613         opts.use_temp_opts = 
False 
  617     from GaudiConfig2 
import Configurable, mergeConfigs
 
  619     Configurable.instances = 
mergeConfigs(Configurable.instances, process.config)
 
  621     if opts.verbose 
and not opts.use_temp_opts:
 
  622         c.printconfig(opts.old_opts, opts.all_opts)
 
  624         c.writeconfig(opts.output, opts.all_opts)
 
  626     if opts.use_temp_opts:
 
  627         fd, tmpfile = mkstemp(
".opts")
 
  629         c.writeconfig(tmpfile, opts.all_opts)
 
  630         os.environ[
"GAUDI_TEMP_OPTS_FILE"] = tmpfile
 
  631         logging.info(
"Restarting from pre-parsed options")
 
  632         os.execv(sys.executable, [sys.executable] + sys.argv)
 
  634     c.printsequence = opts.printsequence
 
  635     if opts.printsequence:
 
  637             logging.warning(
"--printsequence not supported with --ncpus: ignored")
 
  639             logging.warning(
"--printsequence not supported with --dry-run: ignored")
 
  641     c.application = opts.application
 
  644     del sys.modules[
"GaudiPython"]
 
  648         retcode = c.run(opts.gdb, opts.ncpus)
 
  652         if opts.run_info_file:
 
  657             run_info[
"pid"] = os.getpid()
 
  658             run_info[
"retcode"] = retcode
 
  659             if os.path.exists(
"/proc/self/exe"):
 
  661                 run_info[
"exe"] = os.readlink(
"/proc/self/exe")
 
  663             logging.info(
"Saving run info to: %s" % opts.run_info_file)
 
  664             with open(opts.run_info_file, 
"w") 
as f:
 
  665                 json.dump(run_info, f)