20from fnmatch
import fnmatch
21msg = logging.getLogger(__name__)
25 cvmfsDBReleaseCheck, forceToAlphaNum, \
26 ValgrindCommand, VTuneCommand, isInteractiveEnv, calcCpuTime, calcWallTime, analytic, reportEventsPassedSimFilter
27from PyJobTransforms.trfExeStepTools
import commonExecutorStepName, executorStepSuffix
33import PyJobTransforms.trfExceptions
as trfExceptions
36import PyJobTransforms.trfEnv
as trfEnv
46 enc = s.encoding.lower()
47 if enc.find(
'ascii') >= 0
or enc.find(
'ansi') >= 0:
48 return open (s.fileno(),
'w', encoding=
'utf-8')
63 def __init__(self, argdict={}, dataDictionary={}, firstExecutor=False):
82 @dataDictionary.setter
106 @totalExecutorSteps.setter
138 def __init__(self, name = 'Dummy', trf = None, conf = None, inData = set(), outData =
set()):
155 if len(dataOverlap) > 0:
157 'Executor definition error, executor {0} is not allowed to produce and consume the same datatypes. Duplicated input/output types {1}'.format(self.
_name,
' '.join(dataOverlap)))
167 self.
conf.setFromTransform(trf)
220 if '_substep' in dir(self):
226 if '_trf' in dir(self):
237 if '_inData' in dir(self):
247 if '_inData' in dir(self):
257 if '_outData' in dir(self):
267 if '_outData' in dir(self):
278 if '_input' in dir(self):
287 if '_output' in dir(self):
326 if hasattr(self,
'_first'):
464 msg.debug(
'preExeStart time is {0}'.format(self.
_preExeStart))
469 msg.debug(
'valStart time is {0}'.format(self.
_valStart))
473 msg.info(
'Preexecute for %s', self.
_name)
477 msg.debug(
'exeStart time is {0}'.format(self.
_exeStart))
478 msg.info(
'Starting execution of %s', self.
_name)
482 msg.info(
'%s executor returns %d', self.
_name, self.
_rc)
484 msg.debug(
'preExeStop time is {0}'.format(self.
_exeStop))
487 msg.info(
'Postexecute for %s', self.
_name)
492 msg.info(
'Executor %s has no validation function - assuming all ok', self.
_name)
496 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
508 super(logscanExecutor, self).
__init__(name=name)
514 msg.info(
'Preexecute for %s', self.
_name)
515 if 'logfile' in self.
conf.argdict:
520 msg.info(
"Starting validation for {0}".format(self.
_name))
524 if 'ignorePatterns' in self.
conf.argdict:
525 igPat = self.
conf.argdict[
'ignorePatterns'].value
528 if 'ignoreFiles' in self.
conf.argdict:
536 msg.info(
'Scanning logfile {0} for errors'.format(self.
_logFileName))
538 worstError = self.
_logScan.worstError()
542 if worstError[
'firstError']:
543 if len(worstError[
'firstError'][
'message']) > athenaExecutor._exitMessageLimit:
544 if 'CoreDumpSvc' in worstError[
'firstError'][
'message']:
545 exitErrorMessage =
"Core dump at line {0} (see jobReport for further details)".format(worstError[
'firstError'][
'firstLine'])
546 elif 'G4Exception' in worstError[
'firstError'][
'message']:
547 exitErrorMessage =
"G4 exception at line {0} (see jobReport for further details)".format(worstError[
'firstError'][
'firstLine'])
549 exitErrorMessage =
"Long {0} message at line {1} (see jobReport for further details)".format(worstError[
'level'], worstError[
'firstError'][
'firstLine'])
551 exitErrorMessage =
"Logfile error in {0}: \"{1}\"".format(self.
_logFileName, worstError[
'firstError'][
'message'])
553 exitErrorMessage =
"Error level {0} found (see athena logfile for details)".format(worstError[
'level'])
556 if worstError[
'nLevel'] == stdLogLevels[
'ERROR']
and (
'ignoreErrors' in self.
conf.argdict
and self.
conf.argdict[
'ignoreErrors'].value
is True):
557 msg.warning(
'Found ERRORs in the logfile, but ignoring this as ignoreErrors=True (see jobReport for details)')
558 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
560 msg.error(
'Fatal error in athena logfile (level {0})'.format(worstError[
'level']))
562 'Fatal error in athena logfile: "{0}"'.format(exitErrorMessage))
565 msg.info(
'Executor {0} has validated successfully'.format(self.
name))
570 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
577 super(echoExecutor, self).
__init__(name=name, trf=trf)
582 msg.debug(
'exeStart time is {0}'.format(self.
_exeStart))
583 msg.info(
'Starting execution of %s', self.
_name)
584 msg.info(
'Transform argument dictionary now follows:')
585 for k, v
in self.
conf.argdict.items():
586 print(
"%s = %s" % (k, v))
590 msg.info(
'%s executor returns %d', self.
_name, self.
_rc)
592 msg.debug(
'exeStop time is {0}'.format(self.
_exeStop))
596 def __init__(self, name = 'Dummy', trf = None, conf = None, inData = set(), outData =
set()):
599 super(dummyExecutor, self).
__init__(name=name, trf=trf, conf=conf, inData=inData, outData=outData)
604 msg.debug(
'exeStart time is {0}'.format(self.
_exeStart))
605 msg.info(
'Starting execution of %s', self.
_name)
607 for k, v
in self.
conf.argdict.items():
609 msg.info(
'Creating dummy output file: {0}'.format(self.
conf.argdict[k].value[0]))
610 open(self.
conf.argdict[k].value[0],
'a').close()
614 msg.info(
'%s executor returns %d', self.
_name, self.
_rc)
616 msg.debug(
'exeStop time is {0}'.format(self.
_exeStop))
620 def __init__(self, name = 'Script', trf = None, conf = None, inData = set(), outData =
set(),
621 exe =
None, exeArgs =
None, memMonitor =
True):
628 super(scriptExecutor, self).
__init__(name=name, trf=trf, conf=conf, inData=inData, outData=outData)
660 msg.debug(
'scriptExecutor: Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
666 if self.
_cmd is None:
668 msg.info(
'Will execute script as %s', self.
_cmd)
675 if 'TRF_ECHO' in os.environ:
676 msg.info(
'TRF_ECHO envvar is set - enabling command echoing to stdout')
678 elif 'TRF_NOECHO' in os.environ:
679 msg.info(
'TRF_NOECHO envvar is set - disabling command echoing to stdout')
682 elif isInteractiveEnv():
683 msg.info(
'Interactive environment detected (stdio or stdout is a tty) - enabling command echoing to stdout')
685 elif 'TZHOME' in os.environ:
686 msg.info(
'Tier-0 environment detected - enabling command echoing to stdout')
689 msg.info(
'Batch/grid running - command outputs will not be echoed. Logs for {0} are in {1}'.format(self.
_name, self.
_logFileName))
696 encargs = {
'encoding' :
'utf-8'}
698 self.
_exeLogFile.setFormatter(logging.Formatter(
'%(asctime)s %(message)s', datefmt=
'%H:%M:%S'))
703 self.
_echostream.setFormatter(logging.Formatter(
'%(name)s %(asctime)s %(message)s', datefmt=
'%H:%M:%S'))
711 'No executor set in {0}'.format(self.__class__.__name__))
713 if arg
in self.
conf.argdict:
717 if isinstance(self.
conf.argdict[arg].value, list):
718 self.
_cmd.extend([ str(v)
for v
in self.
conf.argdict[arg].value])
720 self.
_cmd.append(str(self.
conf.argdict[arg].value))
725 msg.info(
'Starting execution of {0} ({1})'.format(self.
_name, self.
_cmd))
728 msg.debug(
'exeStart time is {0}'.format(self.
_exeStart))
729 if (
'execOnly' in self.
conf.argdict
and self.
conf.argdict[
'execOnly']
is True):
730 msg.info(
'execOnly flag is set - execution will now switch, replacing the transform')
733 encargs = {
'encoding' :
'utf8'}
739 msg.info(
"chdir /srv to launch a nested container for the substep")
741 p = subprocess.Popen(self.
_cmd, shell =
False, stdout = subprocess.PIPE, stderr = subprocess.STDOUT, bufsize = 1, **encargs)
744 msg.info(
"chdir {} after launching the nested container".format(self.
_workdir))
751 memMonitorCommand = [
'prmon',
'--pid', str(p.pid),
'--filename',
'prmon.full.' + self.
_name,
754 mem_proc = subprocess.Popen(memMonitorCommand, shell =
False, close_fds=
True, **encargs)
756 except Exception
as e:
757 msg.warning(
'Failed to spawn memory monitor for {0}: {1}'.format(self.
_name, e))
760 while p.poll()
is None:
762 line = p.stdout.readline()
765 except UnicodeDecodeError
as e:
766 msg.warning(
'Exception raised processing athena log: {0}'.format(e))
768 for line
in p.stdout:
772 msg.info(
'%s executor returns %d', self.
_name, self.
_rc)
774 msg.debug(
'exeStop time is {0}'.format(self.
_exeStop))
776 errMsg =
'Execution of {0} failed and raised OSError: {1}'.format(self.
_cmd[0], e)
782 mem_proc.send_signal(signal.SIGUSR1)
784 while (
not mem_proc.poll())
and countWait < 10:
798 except Exception
as e:
799 msg.warning(
'Failed to load JSON memory summmary file {0}: {1}'.format(self.
_memSummaryFile, e))
807 msg.debug(
'valStart time is {0}'.format(self.
_valStart))
812 msg.info(
'Executor {0} validated successfully (return code {1})'.format(self.
_name, self.
_rc))
823 if trfExit.codeToSignalname(self.
_rc) !=
"":
824 self.
_errMsg =
'{0} got a {1} signal (exit code {2})'.format(self.
_name, trfExit.codeToSignalname(self.
_rc), self.
_rc)
826 self.
_errMsg =
'Non-zero return code from %s (%d)' % (self.
_name, self.
_rc)
831 if 'checkEventCount' in self.
conf.argdict
and self.
conf.argdict[
'checkEventCount'].returnMyValue(exe=self)
is False:
832 msg.info(
'Event counting for substep {0} is skipped'.format(self.
name))
834 if 'mpi' in self.
conf.argdict
and self.
conf.argdict[
'mpi'].value
and not mpi.mpiShouldValidate():
835 msg.info(
'MPI mode -- skipping output event count check')
840 msg.info(
'Event counting for substep {0} passed'.format(self.
name))
843 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
848 _exitMessageLimit = 200
849 _defaultIgnorePatternFile = [
'atlas_error_mask.db']
888 def __init__(self, name = 'athena', trf = None, conf = None, skeletonFile=None, skeletonCA=None,
889 inData = set(), outData =
set(), inputDataTypeCountCheck =
None, exe =
'athena.py', exeArgs = [
'athenaopts'],
890 substep =
None, inputEventTest =
True, perfMonFile =
None, tryDropAndReload =
True, extraRunargs = {}, runtimeRunargs = {},
891 literalRunargs = [], dataArgs = [], checkEventCount =
False, errorMaskFiles =
None,
892 manualDataDictionary =
None, memMonitor =
True, disableMT =
False, disableMP =
False, onlyMP =
False, onlyMT =
False, onlyMPWithRunargs =
None):
912 msg.debug(
"Resource monitoring from PerfMon is now deprecated")
915 if isinstance(skeletonFile, str):
920 super(athenaExecutor, self).
__init__(name=name, trf=trf, conf=conf, inData=inData, outData=outData, exe=exe,
921 exeArgs=exeArgs, memMonitor=memMonitor)
928 self.
_jobOptionsTemplate = JobOptionsTemplate(exe = self, version =
'$Id: trfExe.py 792052 2017-01-13 13:36:51Z mavogel $')
936 @inputDataTypeCountCheck.setter
981 msg.debug(
'Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
989 if self.
conf.dataDictionary[dataType].nentries ==
'UNDEFINED':
992 thisInputEvents = self.
conf.dataDictionary[dataType].nentries
993 if thisInputEvents > inputEvents:
994 inputEvents = thisInputEvents
998 if (
'skipEvents' in self.
conf.argdict
and
999 self.
conf.argdict[
'skipEvents'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
is not None):
1000 mySkipEvents = self.
conf.argdict[
'skipEvents'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
1004 if (
'maxEvents' in self.
conf.argdict
and
1005 self.
conf.argdict[
'maxEvents'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
is not None):
1006 myMaxEvents = self.
conf.argdict[
'maxEvents'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
1011 if (self.
_inputEventTest and mySkipEvents > 0
and mySkipEvents >= inputEvents):
1013 'No events to process: {0} (skipEvents) >= {1} (inputEvents of {2}'.format(mySkipEvents, inputEvents, dt))
1017 if (myMaxEvents != -1):
1019 expectedEvents = myMaxEvents
1021 expectedEvents =
min(inputEvents-mySkipEvents, myMaxEvents)
1023 expectedEvents = inputEvents-mySkipEvents
1026 msg.info(
'input event count is UNDEFINED, setting expectedEvents to 0')
1032 OSSetupString =
None
1036 legacyThreadingRelease =
False
1037 if 'asetup' in self.
conf.argdict:
1038 asetupString = self.
conf.argdict[
'asetup'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
1039 legacyThreadingRelease = asetupReleaseIsOlderThan(asetupString, 22)
1041 msg.info(
'Asetup report: {0}'.format(asetupReport()))
1043 if asetupString
is not None:
1044 legacyOSRelease = asetupReleaseIsOlderThan(asetupString, 24)
1045 currentOS = os.environ[
'ALRB_USER_PLATFORM']
1046 if legacyOSRelease
and "centos7" not in currentOS:
1047 OSSetupString =
"centos7"
1048 msg.info(
'Legacy release required for the substep {}, will setup a container running {}'.format(self.
_substep, OSSetupString))
1052 if 'runInContainer' in self.
conf.argdict:
1053 OSSetupString = self.
conf.argdict[
'runInContainer'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
1054 msg.info(
'The step {} will be performed in a container running {}, as explicitly requested'.format(self.
_substep, OSSetupString))
1055 if OSSetupString
is not None and asetupString
is None:
1057 '--asetup must be used for the substep which requires --runInContainer')
1062 if k
in self.
conf._argdict:
1066 if (((
'multithreaded' in self.
conf._argdict
and self.
conf._argdict[
'multithreaded'].value)
or (
'multiprocess' in self.
conf._argdict
and self.
conf._argdict[
'multiprocess'].value))
and
1067 (
'ATHENA_CORE_NUMBER' not in os.environ)):
1069 msg.warning(
'either --multithreaded or --multiprocess argument used but ATHENA_CORE_NUMBER environment not set. Athena will continue in Serial mode')
1081 msg.info(
"This configuration does not support MT, falling back to MP")
1089 msg.info(
"This configuration does not support MP, using MT")
1098 msg.info(
"Disabling AthenaMP as number of input events to process is too low ({0} events for {1} workers)".format(expectedEvents, self.
_athenaMP))
1103 if self.
conf.totalExecutorSteps > 1:
1104 for dataType
in output:
1105 if self.
conf._dataDictionary[dataType].originalName:
1106 self.
conf._dataDictionary[dataType].value[0] = self.
conf._dataDictionary[dataType].originalName
1108 self.
conf._dataDictionary[dataType].originalName = self.
conf._dataDictionary[dataType].value[0]
1109 self.
conf._dataDictionary[dataType].value[0] +=
"_{0}{1}".format(executorStepSuffix, self.
conf.executorStep)
1110 msg.info(
"Updated athena output filename for {0} to {1}".format(dataType, self.
conf._dataDictionary[dataType].value[0]))
1117 if 'athenaMPUseEventOrders' in self.
conf.argdict
and self.
conf._argdict[
'athenaMPUseEventOrders'].value
is True:
1122 if (
'athenaMPStrategy' in self.
conf.argdict
and
1123 (self.
conf.argdict[
'athenaMPStrategy'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
is not None)):
1129 if 'athenaMPMergeTargetSize' in self.
conf.argdict:
1130 for dataType
in output:
1131 if dataType
in self.
conf.argdict[
'athenaMPMergeTargetSize'].value:
1132 self.
conf._dataDictionary[dataType].mergeTargetSize = self.
conf.argdict[
'athenaMPMergeTargetSize'].value[dataType] * 1000000
1133 msg.info(
'Set target merge size for {0} to {1}'.format(dataType, self.
conf._dataDictionary[dataType].mergeTargetSize))
1136 matchedViaGlob =
False
1137 for mtsType, mtsSize
in self.
conf.argdict[
'athenaMPMergeTargetSize'].value.items():
1138 if fnmatch(dataType, mtsType):
1139 self.
conf._dataDictionary[dataType].mergeTargetSize = mtsSize * 1000000
1140 msg.info(
'Set target merge size for {0} to {1} from "{2}" glob'.format(dataType, self.
conf._dataDictionary[dataType].mergeTargetSize, mtsType))
1141 matchedViaGlob =
True
1143 if not matchedViaGlob
and "ALL" in self.
conf.argdict[
'athenaMPMergeTargetSize'].value:
1144 self.
conf._dataDictionary[dataType].mergeTargetSize = self.
conf.argdict[
'athenaMPMergeTargetSize'].value[
"ALL"] * 1000000
1145 msg.info(
'Set target merge size for {0} to {1} from "ALL" value'.format(dataType, self.
conf._dataDictionary[dataType].mergeTargetSize))
1150 for dataType
in output:
1151 if self.
conf.totalExecutorSteps <= 1:
1152 self.
conf._dataDictionary[dataType].originalName = self.
conf._dataDictionary[dataType].value[0]
1153 if 'eventService' not in self.
conf.argdict
or 'eventService' in self.
conf.argdict
and self.
conf.argdict[
'eventService'].value
is False:
1154 if 'sharedWriter' in self.
conf.argdict
and self.
conf.argdict[
'sharedWriter'].value:
1155 msg.info(
"SharedWriter: not updating athena output filename for {0}".format(dataType))
1157 self.
conf._dataDictionary[dataType].value[0] +=
"_000"
1158 msg.info(
"Updated athena output filename for {0} to {1}".format(dataType, self.
conf._dataDictionary[dataType].value[0]))
1163 if 'mpi' in self.
conf.argdict
and self.
conf.argdict[
'mpi'].value:
1164 msg.info(
"Running in MPI mode")
1165 mpi.setupMPIConfig(output, self.
conf.dataDictionary)
1170 for dataType
in input:
1171 inputFiles[dataType] = self.
conf.dataDictionary[dataType]
1172 outputFiles = dict()
1173 for dataType
in output:
1174 outputFiles[dataType] = self.
conf.dataDictionary[dataType]
1177 nameForFiles = commonExecutorStepName(self.
_name)
1178 for dataType, dataArg
in self.
conf.dataDictionary.items():
1179 if isinstance(dataArg, list)
and dataArg:
1180 if self.
conf.totalExecutorSteps <= 1:
1181 raise ValueError(
'Multiple input arguments provided but only running one substep')
1182 if self.
conf.totalExecutorSteps != len(dataArg):
1183 raise ValueError(f
'{len(dataArg)} input arguments provided but running {self.conf.totalExecutorSteps} substeps')
1185 if dataArg[self.
conf.executorStep].io ==
'input' and nameForFiles
in dataArg[self.
conf.executorStep].executor:
1186 inputFiles[dataArg[self.
conf.executorStep].subtype] = dataArg
1188 if dataArg.io ==
'input' and nameForFiles
in dataArg.executor:
1189 inputFiles[dataArg.subtype] = dataArg
1191 msg.debug(
'Input Files: {0}; Output Files: {1}'.format(inputFiles, outputFiles))
1195 output = outputFiles)
1205 dbrelease = dbsetup =
None
1206 if 'DBRelease' in self.
conf.argdict:
1207 dbrelease = self.
conf.argdict[
'DBRelease'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
1208 if path.islink(dbrelease):
1209 dbrelease = path.realpath(dbrelease)
1212 dbdMatch = re.match(
r'DBRelease-([\d\.]+)\.tar\.gz', path.basename(dbrelease))
1214 msg.debug(
'DBRelease setting {0} matches classic tarball file'.format(dbrelease))
1215 if not os.access(dbrelease, os.R_OK):
1216 msg.warning(
'Transform was given tarball DBRelease file {0}, but this is not there'.format(dbrelease))
1217 msg.warning(
'I will now try to find DBRelease {0} in cvmfs'.format(dbdMatch.group(1)))
1218 dbrelease = dbdMatch.group(1)
1219 dbsetup = cvmfsDBReleaseCheck(dbrelease)
1222 msg.debug(
'Setting up {0} from {1}'.format(dbdMatch.group(1), dbrelease))
1223 unpacked, dbsetup = unpackDBRelease(tarball=dbrelease, dbversion=dbdMatch.group(1))
1226 setupDBRelease(dbsetup)
1229 dbsetup = cvmfsDBReleaseCheck(dbrelease)
1237 super(athenaExecutor, self).
preExecute(input, output)
1242 msg.info(
'Now writing wrapper for substep executor {0}'.format(self.
_name))
1244 msg.info(
'Athena will be executed in a subshell via {0}'.format(self.
_cmd))
1250 if 'mpi' in self.
conf.argdict
and self.
conf.argdict[
'mpi'].value:
1254 if self.
conf.totalExecutorSteps > 1:
1256 outputDataDictionary = dict([ (dataType, self.
conf.dataDictionary[dataType])
for dataType
in self.
_output ])
1258 if self.
conf.executorStep == self.
conf.totalExecutorSteps - 1:
1264 for i
in range(self.
conf.totalExecutorSteps):
1265 for v
in self.
conf.dataDictionary[dataType].value:
1266 newValue.append(v.replace(
'_{0}{1}_'.format(executorStepSuffix, self.
conf.executorStep),
1267 '_{0}{1}_'.format(executorStepSuffix, i)))
1269 self.
conf.dataDictionary[dataType].multipleOK =
True
1271 for i
in range(self.
conf.totalExecutorSteps):
1272 newValue.append(self.
conf.dataDictionary[dataType].originalName +
'_{0}{1}'.format(executorStepSuffix, i))
1273 self.
conf.dataDictionary[dataType].value = newValue
1276 if self.
conf.dataDictionary[dataType].io ==
"output" and len(self.
conf.dataDictionary[dataType].value) > 1:
1281 outputDataDictionary = dict([ (dataType, self.
conf.dataDictionary[dataType])
for dataType
in self.
_output ])
1283 skipFileChecks=
False
1284 if 'eventService' in self.
conf.argdict
and self.
conf.argdict[
'eventService'].value:
1288 if self.
conf.dataDictionary[dataType].io ==
"output" and len(self.
conf.dataDictionary[dataType].value) > 1:
1291 if 'TXT_JIVEXMLTGZ' in self.
conf.dataDictionary:
1302 msg.info(
'scanning {0} for reporting events passed the filter ISF_SimEventFilter'.format(self.
_logFileName))
1310 if (
'deleteIntermediateOutputfiles' in self.
conf._argdict
and self.
conf._argdict[
'deleteIntermediateOutputfiles'].value):
1311 inputDataDictionary = dict([ (dataType, self.
conf.dataDictionary[dataType])
for dataType
in self.
_input ])
1313 for k, v
in inputDataDictionary.items():
1314 if not v.io ==
'temporary':
1316 for filename
in v.value:
1317 if os.access(filename, os.R_OK)
and not filename.startswith(
"/cvmfs"):
1318 msg.info(
"Removing intermediate {0} input file {1}".format(k, filename))
1320 if (os.path.realpath(filename) != filename):
1321 targetpath = os.path.realpath(filename)
1323 if (targetpath)
and os.access(targetpath, os.R_OK):
1324 os.unlink(targetpath)
1330 deferredException =
None
1331 memLeakThreshold = 5000
1336 super(athenaExecutor, self).
validate()
1339 msg.error(
'Validation of return code failed: {0!s}'.format(e))
1340 deferredException = e
1350 msg.info(
'Analysing memory monitor output file {0} for possible memory leak'.format(self.
_memFullFile))
1355 msg.warning(
'Possible memory leak; abnormally high values in memory monitor parameters (ignore this message if the job has finished successfully)')
1357 msg.warning(
'Failed to analyse the memory monitor file {0}'.format(self.
_memFullFile))
1359 msg.info(
'No memory monitor file to be analysed')
1365 if 'ignorePatterns' in self.
conf.argdict:
1366 igPat = self.
conf.argdict[
'ignorePatterns'].value
1369 if 'ignoreFiles' in self.
conf.argdict:
1377 msg.info(
'Scanning logfile {0} for errors in substep {1}'.format(self.
_logFileName, self.
_substep))
1379 ignoreList=ignorePatterns)
1380 worstError = self.
_logScan.worstError()
1381 eventLoopWarnings = self.
_logScan.eventLoopWarnings()
1387 if worstError[
'firstError']:
1388 if len(worstError[
'firstError'][
'message']) > athenaExecutor._exitMessageLimit:
1389 if 'CoreDumpSvc' in worstError[
'firstError'][
'message']:
1390 exitErrorMessage =
"Core dump at line {0} (see jobReport for further details)".format(worstError[
'firstError'][
'firstLine'])
1391 elif 'G4Exception' in worstError[
'firstError'][
'message']:
1392 exitErrorMessage =
"G4 exception at line {0} (see jobReport for further details)".format(worstError[
'firstError'][
'firstLine'])
1394 exitErrorMessage =
"Long {0} message at line {1} (see jobReport for further details)".format(worstError[
'level'], worstError[
'firstError'][
'firstLine'])
1396 exitErrorMessage =
"Logfile error in {0}: \"{1}\"".format(self.
_logFileName, worstError[
'firstError'][
'message'])
1398 exitErrorMessage =
"Error level {0} found (see athena logfile for details)".format(worstError[
'level'])
1401 if deferredException
is not None:
1403 if worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
1404 deferredException.errMsg = deferredException.errMsg +
"; {0}".format(exitErrorMessage)
1407 deferredException.errMsg = deferredException.errMsg +
"; Possible memory leak: 'pss' slope: {0} KB/s".format(self.
_memLeakResult[
'slope'])
1408 raise deferredException
1412 if worstError[
'nLevel'] == stdLogLevels[
'ERROR']
and (
'ignoreErrors' in self.
conf.argdict
and self.
conf.argdict[
'ignoreErrors'].value
is True):
1413 msg.warning(
'Found ERRORs in the logfile, but ignoring this as ignoreErrors=True (see jobReport for details)')
1415 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']
and (
not mpi.mpiShouldValidate()):
1416 msg.warning(f
'Found {worstError["level"]} in the logfile in MPI rank {mpi.getMPIRank()} but moving on to be failure-tolerant')
1417 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
1419 msg.error(
'Fatal error in athena logfile (level {0})'.format(worstError[
'level']))
1422 exitErrorMessage = exitErrorMessage +
"; Possible memory leak: 'pss' slope: {0} KB/s".format(self.
_memLeakResult[
'slope'])
1424 'Fatal error in athena logfile: "{0}"'.format(exitErrorMessage))
1427 if (len(eventLoopWarnings) > 0):
1428 msg.warning(
'Found WARNINGS in the event loop, as follows:')
1429 for element
in eventLoopWarnings:
1430 msg.warning(
'{0} {1} ({2} instances)'.format(element[
'item'][
'service'],element[
'item'][
'message'],element[
'count']))
1433 msg.info(
'Executor {0} has validated successfully'.format(self.
name))
1437 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
1442 if self.
_name !=
'generate' and self.
_name !=
'afterburn':
1443 if 'CA' in self.
conf.argdict
and (self.
conf.argdict[
'CA']
is False or self.
conf.argdict[
'CA'].returnMyValue(name=self.
name, substep=self.
substep)
is False):
1450 if 'CA' not in self.
conf.argdict:
1458 if self.
conf.argdict[
'CA']
is None:
1462 if self.
conf.argdict[
'CA'].returnMyValue(name=self.
name, substep=self.
substep)
is True:
1472 if 'athena' in self.
conf.argdict:
1477 currentSubstep =
None
1478 if 'athenaopts' in self.
conf.argdict:
1479 currentName = commonExecutorStepName(self.
name)
1480 if currentName
in self.
conf.argdict[
'athenaopts'].value:
1481 currentSubstep = currentName
1482 if self.
substep in self.
conf.argdict[
'athenaopts'].value:
1483 msg.info(
'Athenaopts found for {0} and {1}, joining options. '
1484 'Consider changing your configuration to use just the name or the alias of the substep.'
1486 self.
conf.argdict[
'athenaopts'].value[currentSubstep].extend(self.
conf.argdict[
'athenaopts'].value[self.
substep])
1487 del self.
conf.argdict[
'athenaopts'].value[self.
substep]
1488 msg.debug(
'Athenaopts: {0}'.format(self.
conf.argdict[
'athenaopts'].value))
1489 elif self.
substep in self.
conf.argdict[
'athenaopts'].value:
1491 elif 'all' in self.
conf.argdict[
'athenaopts'].value:
1492 currentSubstep =
'all'
1495 preLoadUpdated = dict()
1497 preLoadUpdated[currentSubstep] =
False
1498 if 'athenaopts' in self.
conf.argdict:
1499 if currentSubstep
is not None:
1500 for athArg
in self.
conf.argdict[
'athenaopts'].value[currentSubstep]:
1503 if athArg.startswith(
'--preloadlib'):
1505 i = self.
conf.argdict[
'athenaopts'].value[currentSubstep].
index(athArg)
1506 v = athArg.split(
'=', 1)[1]
1507 msg.info(
'Updating athena --preloadlib option for substep {1} with: {0}'.format(self.
_envUpdate.value(
'LD_PRELOAD'), self.
name))
1509 self.
conf.argdict[
'athenaopts']._value[currentSubstep][i] =
'--preloadlib={0}'.format(newPreloads)
1510 except Exception
as e:
1511 msg.warning(
'Failed to interpret athena option: {0} ({1})'.format(athArg, e))
1512 preLoadUpdated[currentSubstep] =
True
1514 if not preLoadUpdated[currentSubstep]:
1515 msg.info(
'Setting athena preloadlibs for substep {1} to: {0}'.format(self.
_envUpdate.value(
'LD_PRELOAD'), self.
name))
1516 if 'athenaopts' in self.
conf.argdict:
1517 if currentSubstep
is not None:
1518 self.
conf.argdict[
'athenaopts'].value[currentSubstep].append(
"--preloadlib={0}".format(self.
_envUpdate.value(
'LD_PRELOAD')))
1520 self.
conf.argdict[
'athenaopts'].value[
'all'] = [
"--preloadlib={0}".format(self.
_envUpdate.value(
'LD_PRELOAD'))]
1525 if 'athenaopts' in self.
conf.argdict:
1526 if currentSubstep
is None and "all" in self.
conf.argdict[
'athenaopts'].value:
1527 self.
_cmd.extend(self.
conf.argdict[
'athenaopts'].value[
'all'])
1528 elif currentSubstep
in self.
conf.argdict[
'athenaopts'].value:
1529 self.
_cmd.extend(self.
conf.argdict[
'athenaopts'].value[currentSubstep])
1531 if currentSubstep
is None:
1532 currentSubstep =
'all'
1536 msg.info(
'ignoring "--drop-and-reload" for CA-based transforms, config cleaned up anyway')
1537 elif 'valgrind' in self.
conf._argdict
and self.
conf._argdict[
'valgrind'].value
is True:
1538 msg.info(
'Disabling "--drop-and-reload" because the job is configured to use Valgrind')
1539 elif 'athenaopts' in self.
conf.argdict:
1540 athenaConfigRelatedOpts = [
'--config-only',
'--drop-and-reload']
1542 if currentSubstep
in self.
conf.argdict[
'athenaopts'].value:
1543 conflictOpts =
set(athenaConfigRelatedOpts).
intersection(
set([opt.split(
'=')[0]
for opt
in self.
conf.argdict[
'athenaopts'].value[currentSubstep]]))
1544 if len(conflictOpts) > 0:
1545 msg.info(
'Not appending "--drop-and-reload" to athena command line because these options conflict: {0}'.format(list(conflictOpts)))
1547 msg.info(
'Appending "--drop-and-reload" to athena options')
1548 self.
_cmd.append(
'--drop-and-reload')
1550 msg.info(
'No Athenaopts for substep {0}, appending "--drop-and-reload" to athena options'.format(self.
name))
1551 self.
_cmd.append(
'--drop-and-reload')
1554 msg.info(
'Appending "--drop-and-reload" to athena options')
1555 self.
_cmd.append(
'--drop-and-reload')
1557 msg.info(
'Skipping test for "--drop-and-reload" in this executor')
1562 if not (
'athenaopts' in self.
conf.argdict
and
1563 any(
'--threads' in opt
for opt
in self.
conf.argdict[
'athenaopts'].value[currentSubstep])):
1568 if not (
'athenaopts' in self.
conf.argdict
and
1569 any(
'--nprocs' in opt
for opt
in self.
conf.argdict[
'athenaopts'].value[currentSubstep])):
1576 msg.info(
'Updated script arguments with topoptions: %s', self.
_cmd)
1596 setupATLAS =
'my_setupATLAS.sh'
1597 with open(setupATLAS,
'w')
as f:
1598 print(
"#!/bin/bash", file=f)
1600if [ -z $ATLAS_LOCAL_ROOT_BASE ]; then
1601 export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase
1603source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh"""
1605 os.chmod(setupATLAS, 0o755)
1608 'Preparing wrapper file {wrapperFileName} with '
1609 'asetup={asetupStatus} and dbsetup={dbsetupStatus}'.format(
1616 container_cmd =
None
1619 print(
'#!/bin/sh', file=wrapper)
1621 container_cmd = [ os.path.abspath(setupATLAS),
1629 print(
'echo "This wrapper is executed within a container! For a local re-run, do:"', file=wrapper)
1630 print(
'echo " '+
" ".join([
'setupATLAS'] + container_cmd[1:] + [path.join(
'.', self.
_wrapperFile)]) +
'"', file=wrapper)
1631 print(
'echo "N.B.: if launching a nested container, navigate to /srv before running the above command"',
1633 print(
'echo " and use --pwd workdir, where workdir is the transform running directory within /srv"',
1635 print(
'echo', file=wrapper)
1645 print(f
'source ./{setupATLAS} -q', file=wfile)
1646 print(f
'asetup {asetup}', file=wfile)
1647 print(
'if [ ${?} != "0" ]; then exit 255; fi', file=wfile)
1649 dbroot = path.dirname(dbsetup)
1650 dbversion = path.basename(dbroot)
1651 print(
"# DBRelease setup", file=wrapper)
1652 print(
'echo Setting up DBRelease {dbroot} environment'.format(dbroot = dbroot), file=wrapper)
1653 print(
'export DBRELEASE={dbversion}'.format(dbversion = dbversion), file=wrapper)
1654 print(
'export CORAL_AUTH_PATH={directory}'.format(directory = path.join(dbroot,
'XMLConfig')), file=wrapper)
1655 print(
'export CORAL_DBLOOKUP_PATH={directory}'.format(directory = path.join(dbroot,
'XMLConfig')), file=wrapper)
1656 print(
'export TNS_ADMIN={directory}'.format(directory = path.join(dbroot,
'oracle-admin')), file=wrapper)
1657 print(
'DATAPATH={dbroot}:$DATAPATH'.format(dbroot = dbroot), file=wrapper)
1659 print(
"# AthenaMT explicitly disabled for this executor", file=wrapper)
1661 print(
"# AthenaMP explicitly disabled for this executor", file=wrapper)
1664 if not envSetting.startswith(
'LD_PRELOAD'):
1665 print(
"export", envSetting, file=wrapper)
1669 if 'valgrind' in self.
conf._argdict
and self.
conf._argdict[
'valgrind'].value
is True:
1670 msg.info(
'Valgrind engaged')
1673 AthenaSerialisedConfigurationFile =
"{name}Conf.pkl".format(
1677 print(
' '.join(self.
_cmd),
"--config-only={0}".format(AthenaSerialisedConfigurationFile), file=wrapper)
1678 print(
'if [ $? != "0" ]; then exit 255; fi', file=wrapper)
1681 if 'valgrindDefaultOpts' in self.
conf._argdict:
1682 defaultOptions = self.
conf._argdict[
'valgrindDefaultOpts'].value
1684 defaultOptions =
True
1685 if 'valgrindExtraOpts' in self.
conf._argdict:
1686 extraOptionsList = self.
conf._argdict[
'valgrindExtraOpts'].value
1688 extraOptionsList =
None
1689 msg.debug(
"requested Valgrind command basic options: {options}".format(options = defaultOptions))
1690 msg.debug(
"requested Valgrind command extra options: {options}".format(options = extraOptionsList))
1691 command = ValgrindCommand(
1692 defaultOptions = defaultOptions,
1693 extraOptionsList = extraOptionsList,
1694 AthenaSerialisedConfigurationFile = \
1695 AthenaSerialisedConfigurationFile
1697 msg.debug(
"Valgrind command: {command}".format(command = command))
1698 print(command, file=wrapper)
1702 elif 'vtune' in self.
conf._argdict
and self.
conf._argdict[
'vtune'].value
is True:
1703 msg.info(
'VTune engaged')
1706 AthenaSerialisedConfigurationFile =
"{name}Conf.pkl".format(
1710 print(
' '.join(self.
_cmd),
"--config-only={0}".format(AthenaSerialisedConfigurationFile), file=wrapper)
1711 print(
'if [ $? != "0" ]; then exit 255; fi', file=wrapper)
1714 if 'vtuneDefaultOpts' in self.
conf._argdict:
1715 defaultOptions = self.
conf._argdict[
'vtuneDefaultOpts'].value
1717 defaultOptions =
True
1718 if 'vtuneExtraOpts' in self.
conf._argdict:
1719 extraOptionsList = self.
conf._argdict[
'vtuneExtraOpts'].value
1721 extraOptionsList =
None
1727 AthenaCommand = self.
_cmd
1728 AthenaCommand.append(AthenaSerialisedConfigurationFile)
1730 msg.debug(
"requested VTune command basic options: {options}".format(options = defaultOptions))
1731 msg.debug(
"requested VTune command extra options: {options}".format(options = extraOptionsList))
1732 command = VTuneCommand(
1733 defaultOptions = defaultOptions,
1734 extraOptionsList = extraOptionsList,
1735 AthenaCommand = AthenaCommand
1737 msg.debug(
"VTune command: {command}".format(command = command))
1738 print(command, file=wrapper)
1740 msg.info(
'Valgrind/VTune not engaged')
1742 print(
' '.join(self.
_cmd), file=wrapper)
1744 except OSError
as e:
1745 errMsg =
'error writing athena wrapper {fileName}: {error}'.format(
1751 trfExit.nameToCode(
'TRF_EXEC_SETUP_WRAPPER'),
1757 self.
_cmd = container_cmd + self.
_cmd
1764 if 'selfMerge' not in dir(fileArg):
1765 msg.info(
'Files in {0} cannot merged (no selfMerge() method is implemented)'.format(fileArg.name))
1768 if fileArg.mergeTargetSize == 0:
1769 msg.info(
'Files in {0} will not be merged as target size is set to 0'.format(fileArg.name))
1773 mergeCandidates = [list()]
1774 currentMergeSize = 0
1775 for fname
in fileArg.value:
1776 size = fileArg.getSingleMetadata(fname,
'file_size')
1777 if not isinstance(size, int):
1778 msg.warning(
'File size metadata for {0} was not correct, found type {1}. Aborting merge attempts.'.format(fileArg,
type(size)))
1781 if len(mergeCandidates[-1]) == 0:
1782 msg.debug(
'Adding file {0} to current empty merge list'.format(fname))
1783 mergeCandidates[-1].append(fname)
1784 currentMergeSize += size
1787 if fileArg.mergeTargetSize < 0
or math.fabs(currentMergeSize + size - fileArg.mergeTargetSize) < math.fabs(currentMergeSize - fileArg.mergeTargetSize):
1788 msg.debug(
'Adding file {0} to merge list {1} as it gets closer to the target size'.format(fname, mergeCandidates[-1]))
1789 mergeCandidates[-1].append(fname)
1790 currentMergeSize += size
1793 msg.debug(
'Starting a new merge list with file {0}'.format(fname))
1794 mergeCandidates.append([fname])
1795 currentMergeSize = size
1797 msg.debug(
'First pass splitting will merge files in this way: {0}'.format(mergeCandidates))
1799 if len(mergeCandidates) == 1:
1802 mergeNames = [fileArg.originalName]
1807 for mergeGroup
in mergeCandidates:
1810 mergeName = fileArg.originalName +
'_{0}'.format(counter)
1811 while path.exists(mergeName):
1813 mergeName = fileArg.originalName +
'_{0}'.format(counter)
1814 mergeNames.append(mergeName)
1817 for targetName, mergeGroup, counter
in zip(mergeNames, mergeCandidates, list(range(len(mergeNames)))):
1818 msg.info(
'Want to merge files {0} to {1}'.format(mergeGroup, targetName))
1819 if len(mergeGroup) <= 1:
1820 msg.info(
'Skip merging for single file')
1823 self.
_myMerger.append(fileArg.selfMerge(output=targetName, inputs=mergeGroup, counter=counter, argdict=self.
conf.argdict))
1828 targetTGZName = self.
conf.dataDictionary[
'TXT_JIVEXMLTGZ'].value[0]
1829 if os.path.exists(targetTGZName):
1830 os.remove(targetTGZName)
1833 fNameRE = re.compile(
r"JiveXML\_\d+\_\d+.xml")
1836 tar = tarfile.open(targetTGZName,
"w:gz")
1837 for fName
in os.listdir(
'.'):
1838 matches = fNameRE.findall(fName)
1839 if len(matches) > 0:
1840 if fNameRE.findall(fName)[0] == fName:
1841 msg.info(
'adding %s to %s', fName, targetTGZName)
1845 msg.info(
'JiveXML compression: %s has been written and closed.', targetTGZName)
1855 super(optionalAthenaExecutor, self).
validate()
1858 msg.warning(
'Validation failed for {0}: {1}'.format(self.
_name, e))
1863 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
1878 def __init__(self, name = 'hybridPOOLMerge', trf = None, conf = None, skeletonFile=None, skeletonCA='RecJobTransforms.MergePool_Skeleton',
1879 inData = set(), outData =
set(), exe =
'athena.py', exeArgs = [
'athenaopts'], substep =
None, inputEventTest =
True,
1880 perfMonFile =
None, tryDropAndReload =
True, extraRunargs = {},
1881 manualDataDictionary =
None, memMonitor =
True):
1883 super(POOLMergeExecutor, self).
__init__(name, trf=trf, conf=conf, skeletonFile=skeletonFile, skeletonCA=skeletonCA,
1884 inData=inData, outData=outData, exe=exe, exeArgs=exeArgs, substep=substep,
1885 inputEventTest=inputEventTest, perfMonFile=perfMonFile,
1886 tryDropAndReload=tryDropAndReload, extraRunargs=extraRunargs,
1887 manualDataDictionary=manualDataDictionary, memMonitor=memMonitor)
1891 super(POOLMergeExecutor, self).
preExecute(input=input, output=output)
1896 super(POOLMergeExecutor, self).
execute()
1906 msg.debug(
'Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
1907 if 'NTUP_PILEUP' not in output:
1909 if 'formats' not in self.
conf.argdict:
1911 'No derivation configuration specified')
1913 if (
'DAOD' not in output)
and (
'D2AOD' not in output):
1915 'No base name for DAOD output')
1918 if 'formats' in self.
conf.argdict: formatList = self.
conf.argdict[
'formats'].value
1919 for reduction
in formatList:
1920 if (
'DAOD' in output):
1921 dataType =
'DAOD_' + reduction
1922 if 'augmentations' not in self.
conf.argdict:
1923 outputName =
'DAOD_' + reduction +
'.' + self.
conf.argdict[
'outputDAODFile'].value[0]
1925 for val
in self.
conf.argdict[
'augmentations'].value:
1926 if reduction
in val.split(
':')[0]:
1927 outputName =
'DAOD_' + val.split(
':')[1] +
'.' + self.
conf.argdict[
'outputDAODFile'].value[0]
1930 outputName =
'DAOD_' + reduction +
'.' + self.
conf.argdict[
'outputDAODFile'].value[0]
1932 if (
'D2AOD' in output):
1933 dataType =
'D2AOD_' + reduction
1934 outputName =
'D2AOD_' + reduction +
'.' + self.
conf.argdict[
'outputD2AODFile'].value[0]
1936 msg.info(
'Adding reduction output type {0}'.format(dataType))
1937 output.add(dataType)
1941 self.
conf.dataDictionary[dataType] = newReduction
1945 if (
'DAOD' in output):
1946 output.remove(
'DAOD')
1947 del self.
conf.dataDictionary[
'DAOD']
1948 del self.
conf.argdict[
'outputDAODFile']
1949 if (
'D2AOD' in output):
1950 output.remove(
'D2AOD')
1951 del self.
conf.dataDictionary[
'D2AOD']
1952 del self.
conf.argdict[
'outputD2AODFile']
1954 msg.info(
'Data dictionary is now: {0}'.format(self.
conf.dataDictionary))
1955 msg.info(
'Input/Output: {0}/{1}'.format(input, output))
1957 msg.info(
'Data dictionary is now: {0}'.format(self.
conf.dataDictionary))
1958 msg.info(
'Input/Output: {0}/{1}'.format(input, output))
1959 super(reductionFrameworkExecutor, self).
preExecute(input, output)
1964 def __init__(self, name='DQHistMerge', trf=None, conf=None, inData=set([
'HIST_AOD',
'HIST_ESD']), outData=
set([
'HIST']),
1965 exe=
'DQHistogramMerge.py', exeArgs = [], memMonitor =
True):
1969 super(DQMergeExecutor, self).
__init__(name=name, trf=trf, conf=conf, inData=inData, outData=outData, exe=exe,
1970 exeArgs=exeArgs, memMonitor=memMonitor)
1975 msg.debug(
'Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
1977 super(DQMergeExecutor, self).
preExecute(input=input, output=output)
1981 for dataType
in input:
1982 for fname
in self.
conf.dataDictionary[dataType].value:
1983 self.
conf.dataDictionary[dataType]._getNumberOfEvents([fname])
1984 print(fname, file=DQMergeFile)
1989 if len(output) != 1:
1991 'One (and only one) output file must be given to {0} (got {1})'.format(self.
name, len(output)))
1992 outDataType = list(output)[0]
1993 self.
_cmd.append(self.
conf.dataDictionary[outDataType].value[0])
1996 if (self.
conf._argdict.get(
"run_post_processing",
False)):
1997 self.
_cmd.append(
'True')
1999 self.
_cmd.append(
'False')
2001 if (self.
conf._argdict.get(
"is_incremental_merge",
False)):
2002 self.
_cmd.append(
'True')
2004 self.
_cmd.append(
'False')
2006 for k
in (
"excludeHist",
"excludeDir"):
2007 if k
in self.
conf._argdict:
2008 self.
_cmd.append(
"--{0}={1}".format(k,self.
conf._argdict[k]))
2013 super(DQMergeExecutor, self).
validate()
2015 exitErrorMessage =
''
2019 worstError = logScan.worstError()
2023 if worstError[
'firstError']:
2024 if len(worstError[
'firstError'][
'message']) > logScan._msgLimit:
2025 exitErrorMessage =
"Long {0} message at line {1}" \
2026 " (see jobReport for further details)".format(worstError[
'level'],
2027 worstError[
'firstError'][
'firstLine'])
2029 exitErrorMessage =
"Logfile error in {0}: \"{1}\"".format(self.
_logFileName,
2030 worstError[
'firstError'][
'message'])
2031 except OSError
as e:
2032 exitCode = trfExit.nameToCode(
'TRF_EXEC_LOGERROR')
2034 'Exception raised while attempting to scan logfile {0}: {1}'.format(self.
_logFileName, e))
2036 if worstError[
'nLevel'] == stdLogLevels[
'ERROR']
and (
2037 'ignoreErrors' in self.
conf.argdict
and self.
conf.argdict[
'ignoreErrors'].value
is True):
2038 msg.warning(
'Found ERRORs in the logfile, but ignoring this as ignoreErrors=True (see jobReport for details)')
2040 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
2042 msg.error(
'Fatal error in script logfile (level {0})'.format(worstError[
'level']))
2043 exitCode = trfExit.nameToCode(
'TRF_EXEC_LOGERROR')
2047 msg.info(
'Executor {0} has validated successfully'.format(self.
name))
2051 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
2055 def __init__(self, name='DQMPostProcess', trf=None, conf=None, inData=set([
'HIST']), outData=
set([
'HIST']),
2056 exe=
'DQM_Tier0Wrapper_tf.py', exeArgs = [], memMonitor =
True):
2060 super(DQMPostProcessExecutor, self).
__init__(name=name, trf=trf, conf=conf, inData=inData, outData=outData, exe=exe,
2061 exeArgs=exeArgs, memMonitor=memMonitor)
2066 msg.debug(
'Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
2068 super(DQMPostProcessExecutor, self).
preExecute(input=input, output=output)
2071 dsName=self.
conf.argdict[
"inputHISTFile"].dataset
2073 for dataType
in input:
2074 for fname
in self.
conf.dataDictionary[dataType].value:
2076 if not dsName: dsName=
".".join(fname.split(
'.')[0:4])
2077 inputList.append(
"#".join([dsName,fname]))
2080 if len(output) != 1:
2082 'One (and only one) output file must be given to {0} (got {1})'.format(self.
name, len(output)))
2083 outDataType = list(output)[0]
2087 wrapperParams={
"inputHistFiles" : inputList,
2088 "outputHistFile" : dsName+
"#"+self.
conf.dataDictionary[outDataType].value[0],
2089 "incrementalMode":
"True" if self.
conf._argdict.get(
"is_incremental_merge",
False)
else "False",
2090 "postProcessing" :
"True" if self.
conf._argdict.get(
"run_post_processing",
False)
else "False",
2091 "doWebDisplay" :
"True" if self.
conf._argdict.get(
"doWebDisplay",
False)
else "False",
2092 "allowCOOLUpload":
"True" if self.
conf._argdict.get(
"allowCOOLUpload",
False)
else "False",
2096 if "servers" in self.
conf._argdict:
2097 wrapperParams[
"server"]=self.
conf._argdict[
"servers"]
2099 for k
in (
"excludeHist",
"excludeDir"):
2100 if k
in self.
conf._argdict:
2101 wrapperParams[
"mergeParams"]+=(
" --{0}={1}".format(k,self.
conf._argdict[k]))
2104 with open(
"args.json",
"w")
as f:
2105 json.dump(wrapperParams, f)
2107 self.
_cmd.append(
"--argJSON=args.json")
2113 super(DQMPostProcessExecutor, self).
validate()
2115 exitErrorMessage =
''
2119 worstError = logScan.worstError()
2123 if worstError[
'firstError']:
2124 if len(worstError[
'firstError'][
'message']) > logScan._msgLimit:
2125 exitErrorMessage =
"Long {0} message at line {1}" \
2126 " (see jobReport for further details)".format(worstError[
'level'],
2127 worstError[
'firstError'][
'firstLine'])
2129 exitErrorMessage =
"Logfile error in {0}: \"{1}\"".format(self.
_logFileName,
2130 worstError[
'firstError'][
'message'])
2131 except OSError
as e:
2132 exitCode = trfExit.nameToCode(
'TRF_EXEC_LOGERROR')
2134 'Exception raised while attempting to scan logfile {0}: {1}'.format(self.
_logFileName, e))
2136 if worstError[
'nLevel'] == stdLogLevels[
'ERROR']
and (
2137 'ignoreErrors' in self.
conf.argdict
and self.
conf.argdict[
'ignoreErrors'].value
is True):
2138 msg.warning(
'Found ERRORs in the logfile, but ignoring this as ignoreErrors=True (see jobReport for details)')
2140 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
2142 msg.error(
'Fatal error in script logfile (level {0})'.format(worstError[
'level']))
2143 exitCode = trfExit.nameToCode(
'TRF_EXEC_LOGERROR')
2147 msg.info(
'Executor {0} has validated successfully'.format(self.
name))
2151 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
2157 msg.debug(
'[NTUP] Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
2160 if self.
_exe is None:
2166 if len(output) != 1:
2168 'One (and only one) output file must be given to {0} (got {1})'.format(self.
name, len(output)))
2169 outDataType = list(output)[0]
2170 self.
_cmd.append(self.
conf.dataDictionary[outDataType].value[0])
2172 for dataType
in input:
2173 self.
_cmd.extend(self.
conf.dataDictionary[dataType].value)
2175 super(NTUPMergeExecutor, self).
preExecute(input=input, output=output)
2179 """Executor for running physvalPostProcessing.py with <input> <output> args"""
2183 msg.debug(
'[NTUP] Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
2187 if len(input) != 1
or len(output) != 1:
2189 f
'Exactly one input and one output must be specified (got inputs={len(input)}, outputs={len(output)})')
2191 self.
_cmd.append(self.
conf.dataDictionary[list(input)[0]].value[0])
2192 self.
_cmd.append(self.
conf.dataDictionary[list(output)[0]].value[0])
2195 super(NtupPhysValPostProcessingExecutor, self).
preExecute(input=input, output=output)
2206 if 'maskEmptyInputs' in self.
conf.argdict
and self.
conf.argdict[
'maskEmptyInputs'].value
is True:
2208 for fname
in self.
conf.dataDictionary[self.
_inputBS].value:
2209 nEvents = self.
conf.dataDictionary[self.
_inputBS].getSingleMetadata(fname,
'nentries')
2210 msg.debug(
'Found {0} events in file {1}'.format(nEvents, fname))
2211 if isinstance(nEvents, int)
and nEvents > 0:
2212 eventfullFiles.append(fname)
2215 msg.info(
'The following input files are masked because they have 0 events: {0}'.format(
' '.join(self.
_maskedFiles)))
2216 if len(eventfullFiles) == 0:
2217 if 'emptyStubFile' in self.
conf.argdict
and path.exists(self.
conf.argdict[
'emptyStubFile'].value):
2219 msg.info(
"All input files are empty - will use stub file {0} as output".format(self.
conf.argdict[
'emptyStubFile'].value))
2222 'All input files had zero events - aborting BS merge')
2229 for fname
in self.
conf.dataDictionary[self.
_inputBS].value:
2231 print(fname, file=BSFileList)
2232 except OSError
as e:
2233 errMsg =
'Got an error when writing list of BS files to {0}: {1}'.format(self.
_mergeBSFileList, e)
2242 elif self.
conf.argdict[
'allowRename'].value
is True:
2244 msg.info(
'Output filename does not end in "._0001.data" will proceed, but be aware that the internal filename metadata will be wrong')
2248 errmsg =
'Output filename for outputBS_MRGFile must end in "._0001.data" or infile metadata will be wrong'
2254 super(bsMergeExecutor, self).
preExecute(input=input, output=output)
2260 msg.debug(
'exeStart time is {0}'.format(self.
_exeStart))
2261 msg.info(
"Using stub file for empty BS output - execution is fake")
2268 msg.debug(
'exeStop time is {0}'.format(self.
_exeStop))
2270 super(bsMergeExecutor, self).
execute()
2280 except OSError
as e:
2295 if 'outputArchFile' not in self.
conf.argdict:
2300 with open(
'zip_wrapper.py',
'w')
as zip_wrapper:
2301 print(
"import zipfile, os, shutil", file=zip_wrapper)
2302 if os.path.exists(self.
conf.argdict[
'outputArchFile'].value[0]):
2304 print(
"zf = zipfile.ZipFile('{}', mode='a', allowZip64=True)".format(self.
conf.argdict[
'outputArchFile'].value[0]), file=zip_wrapper)
2307 print(
"zf = zipfile.ZipFile('{}', mode='w', allowZip64=True)".format(self.
conf.argdict[
'outputArchFile'].value[0]), file=zip_wrapper)
2308 print(
"for f in {}:".format(self.
conf.argdict[
'inputDataFile'].value), file=zip_wrapper)
2311 print(
" if zipfile.is_zipfile(f) and '.zip' in f:", file=zip_wrapper)
2312 print(
" archive = zipfile.ZipFile(f, mode='r')", file=zip_wrapper)
2313 print(
" print 'Extracting input zip file {0} to temporary directory {1}'.format(f,'tmp')", file=zip_wrapper)
2314 print(
" archive.extractall('tmp')", file=zip_wrapper)
2315 print(
" archive.close()", file=zip_wrapper)
2317 print(
" if os.access(f, os.F_OK):", file=zip_wrapper)
2318 print(
" print 'Removing input zip file {}'.format(f)", file=zip_wrapper)
2319 print(
" os.unlink(f)", file=zip_wrapper)
2320 print(
" if os.path.isdir('tmp'):", file=zip_wrapper)
2321 print(
" for root, dirs, files in os.walk('tmp'):", file=zip_wrapper)
2322 print(
" for name in files:", file=zip_wrapper)
2323 print(
" print 'Zipping {}'.format(name)", file=zip_wrapper)
2324 print(
" zf.write(os.path.join(root, name), name, compress_type=zipfile.ZIP_STORED)", file=zip_wrapper)
2325 print(
" shutil.rmtree('tmp')", file=zip_wrapper)
2326 print(
" else:", file=zip_wrapper)
2327 print(
" print 'Zipping {}'.format(os.path.basename(f))", file=zip_wrapper)
2328 print(
" zf.write(f, arcname=os.path.basename(f), compress_type=zipfile.ZIP_STORED)", file=zip_wrapper)
2329 print(
" if os.access(f, os.F_OK):", file=zip_wrapper)
2330 print(
" print 'Removing input file {}'.format(f)", file=zip_wrapper)
2331 print(
" os.unlink(f)", file=zip_wrapper)
2332 print(
"zf.close()", file=zip_wrapper)
2333 os.chmod(
'zip_wrapper.py', 0o755)
2334 except OSError
as e:
2335 errMsg =
'error writing zip wrapper {fileName}: {error}'.format(fileName =
'zip_wrapper.py',
2342 self.
_cmd.append(
'zip_wrapper.py')
2345 elif self.
_exe ==
'unarchive':
2347 for infile
in self.
conf.argdict[
'inputArchFile'].value:
2348 if not zipfile.is_zipfile(infile):
2350 'An input file is not a zip archive - aborting unpacking')
2351 self.
_cmd = [
'python']
2353 with open(
'unarchive_wrapper.py',
'w')
as unarchive_wrapper:
2354 print(
"import zipfile", file=unarchive_wrapper)
2355 print(
"for f in {}:".format(self.
conf.argdict[
'inputArchFile'].value), file=unarchive_wrapper)
2356 print(
" archive = zipfile.ZipFile(f, mode='r')", file=unarchive_wrapper)
2357 print(
" path = '{}'".format(self.
conf.argdict[
'path']), file=unarchive_wrapper)
2358 print(
" print 'Extracting archive {0} to {1}'.format(f,path)", file=unarchive_wrapper)
2359 print(
" archive.extractall(path)", file=unarchive_wrapper)
2360 print(
" archive.close()", file=unarchive_wrapper)
2361 os.chmod(
'unarchive_wrapper.py', 0o755)
2362 except OSError
as e:
2363 errMsg =
'error writing unarchive wrapper {fileName}: {error}'.format(fileName =
'unarchive_wrapper.py',
2370 self.
_cmd.append(
'unarchive_wrapper.py')
2371 super(archiveExecutor, self).
preExecute(input=input, output=output)
void print(char *figname, TCanvas *c1)
Argument class for substep lists, suitable for preExec/postExec.
Class holding the update to an environment that will be passed on to an executor.
Specialist execution class for DQM post-processing of histograms.
__init__(self, name='DQMPostProcess', trf=None, conf=None, inData=set(['HIST']), outData=set(['HIST']), exe='DQM_Tier0Wrapper_tf.py', exeArgs=[], memMonitor=True)
preExecute(self, input=set(), output=set())
Specialist execution class for merging DQ histograms.
__init__(self, name='DQHistMerge', trf=None, conf=None, inData=set(['HIST_AOD', 'HIST_ESD']), outData=set(['HIST']), exe='DQHistogramMerge.py', exeArgs=[], memMonitor=True)
preExecute(self, input=set(), output=set())
Specialist execution class for merging NTUPLE files.
preExecute(self, input=set(), output=set())
Specialist execution class for running post processing on merged PHYVAL NTUPLE file.
preExecute(self, input=set(), output=set())
preExecute(self, input=set(), output=set())
__init__(self, name='hybridPOOLMerge', trf=None, conf=None, skeletonFile=None, skeletonCA='RecJobTransforms.MergePool_Skeleton', inData=set(), outData=set(), exe='athena.py', exeArgs=['athenaopts'], substep=None, inputEventTest=True, perfMonFile=None, tryDropAndReload=True, extraRunargs={}, manualDataDictionary=None, memMonitor=True)
Initialise hybrid POOL merger athena executor.
preExecute(self, input=set(), output=set())
str _athenaMPEventOrdersFile
_writeAthenaWrapper(self, asetup=None, dbsetup=None, ossetup=None)
Write a wrapper script which runs asetup and then Athena.
_smartMerge(self, fileArg)
Manage smart merging of output files.
preExecute(self, input=set(), output=set())
__init__(self, name='athena', trf=None, conf=None, skeletonFile=None, skeletonCA=None, inData=set(), outData=set(), inputDataTypeCountCheck=None, exe='athena.py', exeArgs=['athenaopts'], substep=None, inputEventTest=True, perfMonFile=None, tryDropAndReload=True, extraRunargs={}, runtimeRunargs={}, literalRunargs=[], dataArgs=[], checkEventCount=False, errorMaskFiles=None, manualDataDictionary=None, memMonitor=True, disableMT=False, disableMP=False, onlyMP=False, onlyMT=False, onlyMPWithRunargs=None)
Initialise athena executor.
bool _athenaMPReadEventOrders
inputDataTypeCountCheck(self)
_prepAthenaCommandLine(self)
Prepare the correct command line to be used to invoke athena.
str _athenaMPWorkerTopDir
_isCAEnabled(self)
Check if running with CA.
_skeletonCA
Handle MPI setup.
_tryDropAndReload
Add –drop-and-reload if possible (and allowed!).
_envUpdate
Look for environment updates and perpare the athena command line.
Specalise the script executor to deal with the BS merge oddity of excluding empty DRAWs.
preExecute(self, input=set(), output=set())
__init__(self, name='Dummy', trf=None, conf=None, inData=set(), outData=set())
__init__(self, name='Echo', trf=None)
setFromTransform(self, trf)
Set configuration properties from the parent transform.
addToArgdict(self, key, value)
Add a new object to the argdict.
addToDataDictionary(self, key, value)
Add a new object to the dataDictionary.
__init__(self, argdict={}, dataDictionary={}, firstExecutor=False)
Configuration for an executor.
Special executor that will enable a logfile scan as part of its validation.
__init__(self, name='Logscan')
preExecute(self, input=set(), output=set())
Athena executor where failure is not consisered fatal.
Specialist executor to manage the handling of multiple implicit input and output files within the der...
preExecute(self, input=set(), output=set())
Take inputDAODFile and setup the actual outputs needed in this job.
_buildStandardCommand(self)
preExecute(self, input=set(), output=set())
__init__(self, name='Script', trf=None, conf=None, inData=set(), outData=set(), exe=None, exeArgs=None, memMonitor=True)
Logfile suitable for scanning logfiles with an athena flavour, i.e., lines of the form "SERVICE LOGL...
Small class used for vailiadating event counts between input and output files.
Class of patterns that can be ignored from athena logfiles.
std::vector< std::string > intersection(std::vector< std::string > &v1, std::vector< std::string > &v2)
bool add(const std::string &hname, TKey *tobj)
std::vector< std::string > split(const std::string &s, const std::string &t=":")