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:
1067 if ((
'multiprocess' in self.
conf._argdict
and self.
conf._argdict[
'multiprocess'].value)
and
1068 (
'ATHENA_CORE_NUMBER' not in os.environ)):
1069 raise ValueError(
'--multiprocess argument used but ATHENA_CORE_NUMBER environment variable not set. Please check your configuration!')
1075 if (
'multithreaded' in self.
conf._argdict
and self.
conf._argdict[
'multithreaded'].value)
and (
'ATHENA_CORE_NUMBER' not in os.environ):
1076 msg.warning(
'--multithreaded argument used but ATHENA_CORE_NUMBER environment variable not set. Athena will continue in MT mode with 1 thread')
1088 msg.info(
"This configuration does not support MT, falling back to MP")
1096 msg.info(
"This configuration does not support MP, using MT")
1105 msg.info(
"Disabling AthenaMP as number of input events to process is too low ({0} events for {1} workers)".format(expectedEvents, self.
_athenaMP))
1110 if self.
conf.totalExecutorSteps > 1:
1111 for dataType
in output:
1112 if self.
conf._dataDictionary[dataType].originalName:
1113 self.
conf._dataDictionary[dataType].value[0] = self.
conf._dataDictionary[dataType].originalName
1115 self.
conf._dataDictionary[dataType].originalName = self.
conf._dataDictionary[dataType].value[0]
1116 self.
conf._dataDictionary[dataType].value[0] +=
"_{0}{1}".format(executorStepSuffix, self.
conf.executorStep)
1117 msg.info(
"Updated athena output filename for {0} to {1}".format(dataType, self.
conf._dataDictionary[dataType].value[0]))
1124 if 'athenaMPUseEventOrders' in self.
conf.argdict
and self.
conf._argdict[
'athenaMPUseEventOrders'].value
is True:
1129 if (
'athenaMPStrategy' in self.
conf.argdict
and
1130 (self.
conf.argdict[
'athenaMPStrategy'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
is not None)):
1136 if 'athenaMPMergeTargetSize' in self.
conf.argdict:
1137 for dataType
in output:
1138 if dataType
in self.
conf.argdict[
'athenaMPMergeTargetSize'].value:
1139 self.
conf._dataDictionary[dataType].mergeTargetSize = self.
conf.argdict[
'athenaMPMergeTargetSize'].value[dataType] * 1000000
1140 msg.info(
'Set target merge size for {0} to {1}'.format(dataType, self.
conf._dataDictionary[dataType].mergeTargetSize))
1143 matchedViaGlob =
False
1144 for mtsType, mtsSize
in self.
conf.argdict[
'athenaMPMergeTargetSize'].value.items():
1145 if fnmatch(dataType, mtsType):
1146 self.
conf._dataDictionary[dataType].mergeTargetSize = mtsSize * 1000000
1147 msg.info(
'Set target merge size for {0} to {1} from "{2}" glob'.format(dataType, self.
conf._dataDictionary[dataType].mergeTargetSize, mtsType))
1148 matchedViaGlob =
True
1150 if not matchedViaGlob
and "ALL" in self.
conf.argdict[
'athenaMPMergeTargetSize'].value:
1151 self.
conf._dataDictionary[dataType].mergeTargetSize = self.
conf.argdict[
'athenaMPMergeTargetSize'].value[
"ALL"] * 1000000
1152 msg.info(
'Set target merge size for {0} to {1} from "ALL" value'.format(dataType, self.
conf._dataDictionary[dataType].mergeTargetSize))
1157 for dataType
in output:
1158 if self.
conf.totalExecutorSteps <= 1:
1159 self.
conf._dataDictionary[dataType].originalName = self.
conf._dataDictionary[dataType].value[0]
1160 if 'eventService' not in self.
conf.argdict
or 'eventService' in self.
conf.argdict
and self.
conf.argdict[
'eventService'].value
is False:
1161 if 'sharedWriter' in self.
conf.argdict
and self.
conf.argdict[
'sharedWriter'].value:
1162 msg.info(
"SharedWriter: not updating athena output filename for {0}".format(dataType))
1164 self.
conf._dataDictionary[dataType].value[0] +=
"_000"
1165 msg.info(
"Updated athena output filename for {0} to {1}".format(dataType, self.
conf._dataDictionary[dataType].value[0]))
1170 if 'mpi' in self.
conf.argdict
and self.
conf.argdict[
'mpi'].value:
1171 msg.info(
"Running in MPI mode")
1172 mpi.setupMPIConfig(output, self.
conf.dataDictionary)
1177 for dataType
in input:
1178 inputFiles[dataType] = self.
conf.dataDictionary[dataType]
1179 outputFiles = dict()
1180 for dataType
in output:
1181 outputFiles[dataType] = self.
conf.dataDictionary[dataType]
1184 nameForFiles = commonExecutorStepName(self.
_name)
1185 for dataType, dataArg
in self.
conf.dataDictionary.items():
1186 if isinstance(dataArg, list)
and dataArg:
1187 if self.
conf.totalExecutorSteps <= 1:
1188 raise ValueError(
'Multiple input arguments provided but only running one substep')
1189 if self.
conf.totalExecutorSteps != len(dataArg):
1190 raise ValueError(f
'{len(dataArg)} input arguments provided but running {self.conf.totalExecutorSteps} substeps')
1192 if dataArg[self.
conf.executorStep].io ==
'input' and nameForFiles
in dataArg[self.
conf.executorStep].executor:
1193 inputFiles[dataArg[self.
conf.executorStep].subtype] = dataArg
1195 if dataArg.io ==
'input' and nameForFiles
in dataArg.executor:
1196 inputFiles[dataArg.subtype] = dataArg
1198 msg.debug(
'Input Files: {0}; Output Files: {1}'.format(inputFiles, outputFiles))
1202 output = outputFiles)
1212 dbrelease = dbsetup =
None
1213 if 'DBRelease' in self.
conf.argdict:
1214 dbrelease = self.
conf.argdict[
'DBRelease'].returnMyValue(name=self.
_name, substep=self.
_substep, first=self.
conf.firstExecutor)
1215 if path.islink(dbrelease):
1216 dbrelease = path.realpath(dbrelease)
1219 dbdMatch = re.match(
r'DBRelease-([\d\.]+)\.tar\.gz', path.basename(dbrelease))
1221 msg.debug(
'DBRelease setting {0} matches classic tarball file'.format(dbrelease))
1222 if not os.access(dbrelease, os.R_OK):
1223 msg.warning(
'Transform was given tarball DBRelease file {0}, but this is not there'.format(dbrelease))
1224 msg.warning(
'I will now try to find DBRelease {0} in cvmfs'.format(dbdMatch.group(1)))
1225 dbrelease = dbdMatch.group(1)
1226 dbsetup = cvmfsDBReleaseCheck(dbrelease)
1229 msg.debug(
'Setting up {0} from {1}'.format(dbdMatch.group(1), dbrelease))
1230 unpacked, dbsetup = unpackDBRelease(tarball=dbrelease, dbversion=dbdMatch.group(1))
1233 setupDBRelease(dbsetup)
1236 dbsetup = cvmfsDBReleaseCheck(dbrelease)
1244 super(athenaExecutor, self).
preExecute(input, output)
1249 msg.info(
'Now writing wrapper for substep executor {0}'.format(self.
_name))
1251 msg.info(
'Athena will be executed in a subshell via {0}'.format(self.
_cmd))
1257 if 'mpi' in self.
conf.argdict
and self.
conf.argdict[
'mpi'].value:
1261 if self.
conf.totalExecutorSteps > 1:
1263 outputDataDictionary = dict([ (dataType, self.
conf.dataDictionary[dataType])
for dataType
in self.
_output ])
1265 if self.
conf.executorStep == self.
conf.totalExecutorSteps - 1:
1271 for i
in range(self.
conf.totalExecutorSteps):
1272 for v
in self.
conf.dataDictionary[dataType].value:
1273 newValue.append(v.replace(
'_{0}{1}_'.format(executorStepSuffix, self.
conf.executorStep),
1274 '_{0}{1}_'.format(executorStepSuffix, i)))
1276 self.
conf.dataDictionary[dataType].multipleOK =
True
1278 for i
in range(self.
conf.totalExecutorSteps):
1279 newValue.append(self.
conf.dataDictionary[dataType].originalName +
'_{0}{1}'.format(executorStepSuffix, i))
1280 self.
conf.dataDictionary[dataType].value = newValue
1283 if self.
conf.dataDictionary[dataType].io ==
"output" and len(self.
conf.dataDictionary[dataType].value) > 1:
1288 outputDataDictionary = dict([ (dataType, self.
conf.dataDictionary[dataType])
for dataType
in self.
_output ])
1290 skipFileChecks=
False
1291 if 'eventService' in self.
conf.argdict
and self.
conf.argdict[
'eventService'].value:
1295 if self.
conf.dataDictionary[dataType].io ==
"output" and len(self.
conf.dataDictionary[dataType].value) > 1:
1298 if 'TXT_JIVEXMLTGZ' in self.
conf.dataDictionary:
1309 msg.info(
'scanning {0} for reporting events passed the filter ISF_SimEventFilter'.format(self.
_logFileName))
1317 if (
'deleteIntermediateOutputfiles' in self.
conf._argdict
and self.
conf._argdict[
'deleteIntermediateOutputfiles'].value):
1318 inputDataDictionary = dict([ (dataType, self.
conf.dataDictionary[dataType])
for dataType
in self.
_input ])
1320 for k, v
in inputDataDictionary.items():
1321 if not v.io ==
'temporary':
1323 for filename
in v.value:
1324 if os.access(filename, os.R_OK)
and not filename.startswith(
"/cvmfs"):
1325 msg.info(
"Removing intermediate {0} input file {1}".format(k, filename))
1327 if (os.path.realpath(filename) != filename):
1328 targetpath = os.path.realpath(filename)
1330 if (targetpath)
and os.access(targetpath, os.R_OK):
1331 os.unlink(targetpath)
1337 deferredException =
None
1338 memLeakThreshold = 5000
1343 super(athenaExecutor, self).
validate()
1346 msg.error(
'Validation of return code failed: {0!s}'.format(e))
1347 deferredException = e
1357 msg.info(
'Analysing memory monitor output file {0} for possible memory leak'.format(self.
_memFullFile))
1362 msg.warning(
'Possible memory leak; abnormally high values in memory monitor parameters (ignore this message if the job has finished successfully)')
1364 msg.warning(
'Failed to analyse the memory monitor file {0}'.format(self.
_memFullFile))
1366 msg.info(
'No memory monitor file to be analysed')
1372 if 'ignorePatterns' in self.
conf.argdict:
1373 igPat = self.
conf.argdict[
'ignorePatterns'].value
1376 if 'ignoreFiles' in self.
conf.argdict:
1384 msg.info(
'Scanning logfile {0} for errors in substep {1}'.format(self.
_logFileName, self.
_substep))
1386 ignoreList=ignorePatterns)
1387 worstError = self.
_logScan.worstError()
1388 eventLoopWarnings = self.
_logScan.eventLoopWarnings()
1394 if worstError[
'firstError']:
1395 if len(worstError[
'firstError'][
'message']) > athenaExecutor._exitMessageLimit:
1396 if 'CoreDumpSvc' in worstError[
'firstError'][
'message']:
1397 exitErrorMessage =
"Core dump at line {0} (see jobReport for further details)".format(worstError[
'firstError'][
'firstLine'])
1398 elif 'G4Exception' in worstError[
'firstError'][
'message']:
1399 exitErrorMessage =
"G4 exception at line {0} (see jobReport for further details)".format(worstError[
'firstError'][
'firstLine'])
1401 exitErrorMessage =
"Long {0} message at line {1} (see jobReport for further details)".format(worstError[
'level'], worstError[
'firstError'][
'firstLine'])
1403 exitErrorMessage =
"Logfile error in {0}: \"{1}\"".format(self.
_logFileName, worstError[
'firstError'][
'message'])
1405 exitErrorMessage =
"Error level {0} found (see athena logfile for details)".format(worstError[
'level'])
1408 if deferredException
is not None:
1410 if worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
1411 deferredException.errMsg = deferredException.errMsg +
"; {0}".format(exitErrorMessage)
1414 deferredException.errMsg = deferredException.errMsg +
"; Possible memory leak: 'pss' slope: {0} KB/s".format(self.
_memLeakResult[
'slope'])
1415 raise deferredException
1419 if worstError[
'nLevel'] == stdLogLevels[
'ERROR']
and (
'ignoreErrors' in self.
conf.argdict
and self.
conf.argdict[
'ignoreErrors'].value
is True):
1420 msg.warning(
'Found ERRORs in the logfile, but ignoring this as ignoreErrors=True (see jobReport for details)')
1422 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']
and (
not mpi.mpiShouldValidate()):
1423 msg.warning(f
'Found {worstError["level"]} in the logfile in MPI rank {mpi.getMPIRank()} but moving on to be failure-tolerant')
1424 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
1426 msg.error(
'Fatal error in athena logfile (level {0})'.format(worstError[
'level']))
1429 exitErrorMessage = exitErrorMessage +
"; Possible memory leak: 'pss' slope: {0} KB/s".format(self.
_memLeakResult[
'slope'])
1431 'Fatal error in athena logfile: "{0}"'.format(exitErrorMessage))
1434 if (len(eventLoopWarnings) > 0):
1435 msg.warning(
'Found WARNINGS in the event loop, as follows:')
1436 for element
in eventLoopWarnings:
1437 msg.warning(
'{0} {1} ({2} instances)'.format(element[
'item'][
'service'],element[
'item'][
'message'],element[
'count']))
1440 msg.info(
'Executor {0} has validated successfully'.format(self.
name))
1444 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
1449 if self.
_name !=
'generate' and self.
_name !=
'afterburn':
1450 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):
1457 if 'CA' not in self.
conf.argdict:
1465 if self.
conf.argdict[
'CA']
is None:
1469 if self.
conf.argdict[
'CA'].returnMyValue(name=self.
name, substep=self.
substep)
is True:
1479 if 'athena' in self.
conf.argdict:
1484 currentSubstep =
None
1485 if 'athenaopts' in self.
conf.argdict:
1486 currentName = commonExecutorStepName(self.
name)
1487 if currentName
in self.
conf.argdict[
'athenaopts'].value:
1488 currentSubstep = currentName
1489 if self.
substep in self.
conf.argdict[
'athenaopts'].value:
1490 msg.info(
'Athenaopts found for {0} and {1}, joining options. '
1491 'Consider changing your configuration to use just the name or the alias of the substep.'
1493 self.
conf.argdict[
'athenaopts'].value[currentSubstep].extend(self.
conf.argdict[
'athenaopts'].value[self.
substep])
1494 del self.
conf.argdict[
'athenaopts'].value[self.
substep]
1495 msg.debug(
'Athenaopts: {0}'.format(self.
conf.argdict[
'athenaopts'].value))
1496 elif self.
substep in self.
conf.argdict[
'athenaopts'].value:
1498 elif 'all' in self.
conf.argdict[
'athenaopts'].value:
1499 currentSubstep =
'all'
1502 preLoadUpdated = dict()
1504 preLoadUpdated[currentSubstep] =
False
1505 if 'athenaopts' in self.
conf.argdict:
1506 if currentSubstep
is not None:
1507 for athArg
in self.
conf.argdict[
'athenaopts'].value[currentSubstep]:
1510 if athArg.startswith(
'--preloadlib'):
1512 i = self.
conf.argdict[
'athenaopts'].value[currentSubstep].
index(athArg)
1513 v = athArg.split(
'=', 1)[1]
1514 msg.info(
'Updating athena --preloadlib option for substep {1} with: {0}'.format(self.
_envUpdate.value(
'LD_PRELOAD'), self.
name))
1516 self.
conf.argdict[
'athenaopts']._value[currentSubstep][i] =
'--preloadlib={0}'.format(newPreloads)
1517 except Exception
as e:
1518 msg.warning(
'Failed to interpret athena option: {0} ({1})'.format(athArg, e))
1519 preLoadUpdated[currentSubstep] =
True
1521 if not preLoadUpdated[currentSubstep]:
1522 msg.info(
'Setting athena preloadlibs for substep {1} to: {0}'.format(self.
_envUpdate.value(
'LD_PRELOAD'), self.
name))
1523 if 'athenaopts' in self.
conf.argdict:
1524 if currentSubstep
is not None:
1525 self.
conf.argdict[
'athenaopts'].value[currentSubstep].append(
"--preloadlib={0}".format(self.
_envUpdate.value(
'LD_PRELOAD')))
1527 self.
conf.argdict[
'athenaopts'].value[
'all'] = [
"--preloadlib={0}".format(self.
_envUpdate.value(
'LD_PRELOAD'))]
1532 if 'athenaopts' in self.
conf.argdict:
1533 if currentSubstep
is None and "all" in self.
conf.argdict[
'athenaopts'].value:
1534 self.
_cmd.extend(self.
conf.argdict[
'athenaopts'].value[
'all'])
1535 elif currentSubstep
in self.
conf.argdict[
'athenaopts'].value:
1536 self.
_cmd.extend(self.
conf.argdict[
'athenaopts'].value[currentSubstep])
1538 if currentSubstep
is None:
1539 currentSubstep =
'all'
1543 msg.info(
'ignoring "--drop-and-reload" for CA-based transforms, config cleaned up anyway')
1544 elif 'valgrind' in self.
conf._argdict
and self.
conf._argdict[
'valgrind'].value
is True:
1545 msg.info(
'Disabling "--drop-and-reload" because the job is configured to use Valgrind')
1546 elif 'athenaopts' in self.
conf.argdict:
1547 athenaConfigRelatedOpts = [
'--config-only',
'--drop-and-reload']
1549 if currentSubstep
in self.
conf.argdict[
'athenaopts'].value:
1550 conflictOpts =
set(athenaConfigRelatedOpts).
intersection(
set([opt.split(
'=')[0]
for opt
in self.
conf.argdict[
'athenaopts'].value[currentSubstep]]))
1551 if len(conflictOpts) > 0:
1552 msg.info(
'Not appending "--drop-and-reload" to athena command line because these options conflict: {0}'.format(list(conflictOpts)))
1554 msg.info(
'Appending "--drop-and-reload" to athena options')
1555 self.
_cmd.append(
'--drop-and-reload')
1557 msg.info(
'No Athenaopts for substep {0}, appending "--drop-and-reload" to athena options'.format(self.
name))
1558 self.
_cmd.append(
'--drop-and-reload')
1561 msg.info(
'Appending "--drop-and-reload" to athena options')
1562 self.
_cmd.append(
'--drop-and-reload')
1564 msg.info(
'Skipping test for "--drop-and-reload" in this executor')
1569 if not (
'athenaopts' in self.
conf.argdict
and
1570 any(
'--threads' in opt
for opt
in self.
conf.argdict[
'athenaopts'].value[currentSubstep])):
1575 if not (
'athenaopts' in self.
conf.argdict
and
1576 any(
'--nprocs' in opt
for opt
in self.
conf.argdict[
'athenaopts'].value[currentSubstep])):
1583 msg.info(
'Updated script arguments with topoptions: %s', self.
_cmd)
1603 setupATLAS =
'my_setupATLAS.sh'
1604 with open(setupATLAS,
'w')
as f:
1605 print(
"#!/bin/bash", file=f)
1607if [ -z $ATLAS_LOCAL_ROOT_BASE ]; then
1608 export ATLAS_LOCAL_ROOT_BASE=/cvmfs/atlas.cern.ch/repo/ATLASLocalRootBase
1610source ${ATLAS_LOCAL_ROOT_BASE}/user/atlasLocalSetup.sh"""
1612 os.chmod(setupATLAS, 0o755)
1615 'Preparing wrapper file {wrapperFileName} with '
1616 'asetup={asetupStatus} and dbsetup={dbsetupStatus}'.format(
1623 container_cmd =
None
1626 print(
'#!/bin/sh', file=wrapper)
1628 container_cmd = [ os.path.abspath(setupATLAS),
1636 print(
'echo "This wrapper is executed within a container! For a local re-run, do:"', file=wrapper)
1637 print(
'echo " '+
" ".join([
'setupATLAS'] + container_cmd[1:] + [path.join(
'.', self.
_wrapperFile)]) +
'"', file=wrapper)
1638 print(
'echo "N.B.: if launching a nested container, navigate to /srv before running the above command"',
1640 print(
'echo " and use --pwd workdir, where workdir is the transform running directory within /srv"',
1642 print(
'echo', file=wrapper)
1652 print(f
'source ./{setupATLAS} -q', file=wfile)
1653 print(f
'asetup {asetup}', file=wfile)
1654 print(
'if [ ${?} != "0" ]; then exit 255; fi', file=wfile)
1656 dbroot = path.dirname(dbsetup)
1657 dbversion = path.basename(dbroot)
1658 print(
"# DBRelease setup", file=wrapper)
1659 print(
'echo Setting up DBRelease {dbroot} environment'.format(dbroot = dbroot), file=wrapper)
1660 print(
'export DBRELEASE={dbversion}'.format(dbversion = dbversion), file=wrapper)
1661 print(
'export CORAL_AUTH_PATH={directory}'.format(directory = path.join(dbroot,
'XMLConfig')), file=wrapper)
1662 print(
'export CORAL_DBLOOKUP_PATH={directory}'.format(directory = path.join(dbroot,
'XMLConfig')), file=wrapper)
1663 print(
'export TNS_ADMIN={directory}'.format(directory = path.join(dbroot,
'oracle-admin')), file=wrapper)
1664 print(
'DATAPATH={dbroot}:$DATAPATH'.format(dbroot = dbroot), file=wrapper)
1666 print(
"# AthenaMT explicitly disabled for this executor", file=wrapper)
1668 print(
"# AthenaMP explicitly disabled for this executor", file=wrapper)
1671 if not envSetting.startswith(
'LD_PRELOAD'):
1672 print(
"export", envSetting, file=wrapper)
1676 if 'valgrind' in self.
conf._argdict
and self.
conf._argdict[
'valgrind'].value
is True:
1677 msg.info(
'Valgrind engaged')
1680 AthenaSerialisedConfigurationFile =
"{name}Conf.pkl".format(
1684 print(
' '.join(self.
_cmd),
"--config-only={0}".format(AthenaSerialisedConfigurationFile), file=wrapper)
1685 print(
'if [ $? != "0" ]; then exit 255; fi', file=wrapper)
1688 if 'valgrindDefaultOpts' in self.
conf._argdict:
1689 defaultOptions = self.
conf._argdict[
'valgrindDefaultOpts'].value
1691 defaultOptions =
True
1692 if 'valgrindExtraOpts' in self.
conf._argdict:
1693 extraOptionsList = self.
conf._argdict[
'valgrindExtraOpts'].value
1695 extraOptionsList =
None
1696 msg.debug(
"requested Valgrind command basic options: {options}".format(options = defaultOptions))
1697 msg.debug(
"requested Valgrind command extra options: {options}".format(options = extraOptionsList))
1698 command = ValgrindCommand(
1699 defaultOptions = defaultOptions,
1700 extraOptionsList = extraOptionsList,
1701 AthenaSerialisedConfigurationFile = \
1702 AthenaSerialisedConfigurationFile
1704 msg.debug(
"Valgrind command: {command}".format(command = command))
1705 print(command, file=wrapper)
1709 elif 'vtune' in self.
conf._argdict
and self.
conf._argdict[
'vtune'].value
is True:
1710 msg.info(
'VTune engaged')
1713 AthenaSerialisedConfigurationFile =
"{name}Conf.pkl".format(
1717 print(
' '.join(self.
_cmd),
"--config-only={0}".format(AthenaSerialisedConfigurationFile), file=wrapper)
1718 print(
'if [ $? != "0" ]; then exit 255; fi', file=wrapper)
1721 if 'vtuneDefaultOpts' in self.
conf._argdict:
1722 defaultOptions = self.
conf._argdict[
'vtuneDefaultOpts'].value
1724 defaultOptions =
True
1725 if 'vtuneExtraOpts' in self.
conf._argdict:
1726 extraOptionsList = self.
conf._argdict[
'vtuneExtraOpts'].value
1728 extraOptionsList =
None
1734 AthenaCommand = self.
_cmd
1735 AthenaCommand.append(AthenaSerialisedConfigurationFile)
1737 msg.debug(
"requested VTune command basic options: {options}".format(options = defaultOptions))
1738 msg.debug(
"requested VTune command extra options: {options}".format(options = extraOptionsList))
1739 command = VTuneCommand(
1740 defaultOptions = defaultOptions,
1741 extraOptionsList = extraOptionsList,
1742 AthenaCommand = AthenaCommand
1744 msg.debug(
"VTune command: {command}".format(command = command))
1745 print(command, file=wrapper)
1747 msg.info(
'Valgrind/VTune not engaged')
1749 print(
' '.join(self.
_cmd), file=wrapper)
1751 except OSError
as e:
1752 errMsg =
'error writing athena wrapper {fileName}: {error}'.format(
1758 trfExit.nameToCode(
'TRF_EXEC_SETUP_WRAPPER'),
1764 self.
_cmd = container_cmd + self.
_cmd
1771 if 'selfMerge' not in dir(fileArg):
1772 msg.info(
'Files in {0} cannot merged (no selfMerge() method is implemented)'.format(fileArg.name))
1775 if fileArg.mergeTargetSize == 0:
1776 msg.info(
'Files in {0} will not be merged as target size is set to 0'.format(fileArg.name))
1780 mergeCandidates = [list()]
1781 currentMergeSize = 0
1782 for fname
in fileArg.value:
1783 size = fileArg.getSingleMetadata(fname,
'file_size')
1784 if not isinstance(size, int):
1785 msg.warning(
'File size metadata for {0} was not correct, found type {1}. Aborting merge attempts.'.format(fileArg,
type(size)))
1788 if len(mergeCandidates[-1]) == 0:
1789 msg.debug(
'Adding file {0} to current empty merge list'.format(fname))
1790 mergeCandidates[-1].append(fname)
1791 currentMergeSize += size
1794 if fileArg.mergeTargetSize < 0
or math.fabs(currentMergeSize + size - fileArg.mergeTargetSize) < math.fabs(currentMergeSize - fileArg.mergeTargetSize):
1795 msg.debug(
'Adding file {0} to merge list {1} as it gets closer to the target size'.format(fname, mergeCandidates[-1]))
1796 mergeCandidates[-1].append(fname)
1797 currentMergeSize += size
1800 msg.debug(
'Starting a new merge list with file {0}'.format(fname))
1801 mergeCandidates.append([fname])
1802 currentMergeSize = size
1804 msg.debug(
'First pass splitting will merge files in this way: {0}'.format(mergeCandidates))
1806 if len(mergeCandidates) == 1:
1809 mergeNames = [fileArg.originalName]
1814 for mergeGroup
in mergeCandidates:
1817 mergeName = fileArg.originalName +
'_{0}'.format(counter)
1818 while path.exists(mergeName):
1820 mergeName = fileArg.originalName +
'_{0}'.format(counter)
1821 mergeNames.append(mergeName)
1824 for targetName, mergeGroup, counter
in zip(mergeNames, mergeCandidates, list(range(len(mergeNames)))):
1825 msg.info(
'Want to merge files {0} to {1}'.format(mergeGroup, targetName))
1826 if len(mergeGroup) <= 1:
1827 msg.info(
'Skip merging for single file')
1830 self.
_myMerger.append(fileArg.selfMerge(output=targetName, inputs=mergeGroup, counter=counter, argdict=self.
conf.argdict))
1835 targetTGZName = self.
conf.dataDictionary[
'TXT_JIVEXMLTGZ'].value[0]
1836 if os.path.exists(targetTGZName):
1837 os.remove(targetTGZName)
1840 fNameRE = re.compile(
r"JiveXML\_\d+\_\d+.xml")
1843 tar = tarfile.open(targetTGZName,
"w:gz")
1844 for fName
in os.listdir(
'.'):
1845 matches = fNameRE.findall(fName)
1846 if len(matches) > 0:
1847 if fNameRE.findall(fName)[0] == fName:
1848 msg.info(
'adding %s to %s', fName, targetTGZName)
1852 msg.info(
'JiveXML compression: %s has been written and closed.', targetTGZName)
1862 super(optionalAthenaExecutor, self).
validate()
1865 msg.warning(
'Validation failed for {0}: {1}'.format(self.
_name, e))
1870 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
1885 def __init__(self, name = 'hybridPOOLMerge', trf = None, conf = None, skeletonFile=None, skeletonCA='RecJobTransforms.MergePool_Skeleton',
1886 inData = set(), outData =
set(), exe =
'athena.py', exeArgs = [
'athenaopts'], substep =
None, inputEventTest =
True,
1887 perfMonFile =
None, tryDropAndReload =
True, extraRunargs = {},
1888 manualDataDictionary =
None, memMonitor =
True):
1890 super(POOLMergeExecutor, self).
__init__(name, trf=trf, conf=conf, skeletonFile=skeletonFile, skeletonCA=skeletonCA,
1891 inData=inData, outData=outData, exe=exe, exeArgs=exeArgs, substep=substep,
1892 inputEventTest=inputEventTest, perfMonFile=perfMonFile,
1893 tryDropAndReload=tryDropAndReload, extraRunargs=extraRunargs,
1894 manualDataDictionary=manualDataDictionary, memMonitor=memMonitor)
1898 super(POOLMergeExecutor, self).
preExecute(input=input, output=output)
1903 super(POOLMergeExecutor, self).
execute()
1913 msg.debug(
'Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
1914 if 'NTUP_PILEUP' not in output:
1916 if 'formats' not in self.
conf.argdict:
1918 'No derivation configuration specified')
1920 if (
'DAOD' not in output)
and (
'D2AOD' not in output):
1922 'No base name for DAOD output')
1925 if 'formats' in self.
conf.argdict: formatList = self.
conf.argdict[
'formats'].value
1926 for reduction
in formatList:
1927 if (
'DAOD' in output):
1928 dataType =
'DAOD_' + reduction
1929 if 'augmentations' not in self.
conf.argdict:
1930 outputName =
'DAOD_' + reduction +
'.' + self.
conf.argdict[
'outputDAODFile'].value[0]
1932 for val
in self.
conf.argdict[
'augmentations'].value:
1933 if reduction
in val.split(
':')[0]:
1934 outputName =
'DAOD_' + val.split(
':')[1] +
'.' + self.
conf.argdict[
'outputDAODFile'].value[0]
1937 outputName =
'DAOD_' + reduction +
'.' + self.
conf.argdict[
'outputDAODFile'].value[0]
1939 if (
'D2AOD' in output):
1940 dataType =
'D2AOD_' + reduction
1941 outputName =
'D2AOD_' + reduction +
'.' + self.
conf.argdict[
'outputD2AODFile'].value[0]
1943 msg.info(
'Adding reduction output type {0}'.format(dataType))
1944 output.add(dataType)
1948 self.
conf.dataDictionary[dataType] = newReduction
1952 if (
'DAOD' in output):
1953 output.remove(
'DAOD')
1954 del self.
conf.dataDictionary[
'DAOD']
1955 del self.
conf.argdict[
'outputDAODFile']
1956 if (
'D2AOD' in output):
1957 output.remove(
'D2AOD')
1958 del self.
conf.dataDictionary[
'D2AOD']
1959 del self.
conf.argdict[
'outputD2AODFile']
1961 msg.info(
'Data dictionary is now: {0}'.format(self.
conf.dataDictionary))
1962 msg.info(
'Input/Output: {0}/{1}'.format(input, output))
1964 msg.info(
'Data dictionary is now: {0}'.format(self.
conf.dataDictionary))
1965 msg.info(
'Input/Output: {0}/{1}'.format(input, output))
1966 super(reductionFrameworkExecutor, self).
preExecute(input, output)
1971 def __init__(self, name='DQHistMerge', trf=None, conf=None, inData=set([
'HIST_AOD',
'HIST_ESD']), outData=
set([
'HIST']),
1972 exe=
'DQHistogramMerge.py', exeArgs = [], memMonitor =
True):
1976 super(DQMergeExecutor, self).
__init__(name=name, trf=trf, conf=conf, inData=inData, outData=outData, exe=exe,
1977 exeArgs=exeArgs, memMonitor=memMonitor)
1982 msg.debug(
'Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
1984 super(DQMergeExecutor, self).
preExecute(input=input, output=output)
1988 for dataType
in input:
1989 for fname
in self.
conf.dataDictionary[dataType].value:
1990 self.
conf.dataDictionary[dataType]._getNumberOfEvents([fname])
1991 print(fname, file=DQMergeFile)
1996 if len(output) != 1:
1998 'One (and only one) output file must be given to {0} (got {1})'.format(self.
name, len(output)))
1999 outDataType = list(output)[0]
2000 self.
_cmd.append(self.
conf.dataDictionary[outDataType].value[0])
2003 if (self.
conf._argdict.get(
"run_post_processing",
False)):
2004 self.
_cmd.append(
'True')
2006 self.
_cmd.append(
'False')
2008 if (self.
conf._argdict.get(
"is_incremental_merge",
False)):
2009 self.
_cmd.append(
'True')
2011 self.
_cmd.append(
'False')
2013 for k
in (
"excludeHist",
"excludeDir"):
2014 if k
in self.
conf._argdict:
2015 self.
_cmd.append(
"--{0}={1}".format(k,self.
conf._argdict[k]))
2020 super(DQMergeExecutor, self).
validate()
2022 exitErrorMessage =
''
2026 worstError = logScan.worstError()
2030 if worstError[
'firstError']:
2031 if len(worstError[
'firstError'][
'message']) > logScan._msgLimit:
2032 exitErrorMessage =
"Long {0} message at line {1}" \
2033 " (see jobReport for further details)".format(worstError[
'level'],
2034 worstError[
'firstError'][
'firstLine'])
2036 exitErrorMessage =
"Logfile error in {0}: \"{1}\"".format(self.
_logFileName,
2037 worstError[
'firstError'][
'message'])
2038 except OSError
as e:
2039 exitCode = trfExit.nameToCode(
'TRF_EXEC_LOGERROR')
2041 'Exception raised while attempting to scan logfile {0}: {1}'.format(self.
_logFileName, e))
2043 if worstError[
'nLevel'] == stdLogLevels[
'ERROR']
and (
2044 'ignoreErrors' in self.
conf.argdict
and self.
conf.argdict[
'ignoreErrors'].value
is True):
2045 msg.warning(
'Found ERRORs in the logfile, but ignoring this as ignoreErrors=True (see jobReport for details)')
2047 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
2049 msg.error(
'Fatal error in script logfile (level {0})'.format(worstError[
'level']))
2050 exitCode = trfExit.nameToCode(
'TRF_EXEC_LOGERROR')
2054 msg.info(
'Executor {0} has validated successfully'.format(self.
name))
2058 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
2062 def __init__(self, name='DQMPostProcess', trf=None, conf=None, inData=set([
'HIST']), outData=
set([
'HIST']),
2063 exe=
'DQM_Tier0Wrapper_tf.py', exeArgs = [], memMonitor =
True):
2067 super(DQMPostProcessExecutor, self).
__init__(name=name, trf=trf, conf=conf, inData=inData, outData=outData, exe=exe,
2068 exeArgs=exeArgs, memMonitor=memMonitor)
2073 msg.debug(
'Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
2075 super(DQMPostProcessExecutor, self).
preExecute(input=input, output=output)
2078 dsName=self.
conf.argdict[
"inputHISTFile"].dataset
2080 for dataType
in input:
2081 for fname
in self.
conf.dataDictionary[dataType].value:
2083 if not dsName: dsName=
".".join(fname.split(
'.')[0:4])
2084 inputList.append(
"#".join([dsName,fname]))
2087 if len(output) != 1:
2089 'One (and only one) output file must be given to {0} (got {1})'.format(self.
name, len(output)))
2090 outDataType = list(output)[0]
2094 wrapperParams={
"inputHistFiles" : inputList,
2095 "outputHistFile" : dsName+
"#"+self.
conf.dataDictionary[outDataType].value[0],
2096 "incrementalMode":
"True" if self.
conf._argdict.get(
"is_incremental_merge",
False)
else "False",
2097 "postProcessing" :
"True" if self.
conf._argdict.get(
"run_post_processing",
False)
else "False",
2098 "doWebDisplay" :
"True" if self.
conf._argdict.get(
"doWebDisplay",
False)
else "False",
2099 "allowCOOLUpload":
"True" if self.
conf._argdict.get(
"allowCOOLUpload",
False)
else "False",
2103 if "servers" in self.
conf._argdict:
2104 wrapperParams[
"server"]=self.
conf._argdict[
"servers"]
2106 for k
in (
"excludeHist",
"excludeDir"):
2107 if k
in self.
conf._argdict:
2108 wrapperParams[
"mergeParams"]+=(
" --{0}={1}".format(k,self.
conf._argdict[k]))
2111 with open(
"args.json",
"w")
as f:
2112 json.dump(wrapperParams, f)
2114 self.
_cmd.append(
"--argJSON=args.json")
2120 super(DQMPostProcessExecutor, self).
validate()
2122 exitErrorMessage =
''
2126 worstError = logScan.worstError()
2130 if worstError[
'firstError']:
2131 if len(worstError[
'firstError'][
'message']) > logScan._msgLimit:
2132 exitErrorMessage =
"Long {0} message at line {1}" \
2133 " (see jobReport for further details)".format(worstError[
'level'],
2134 worstError[
'firstError'][
'firstLine'])
2136 exitErrorMessage =
"Logfile error in {0}: \"{1}\"".format(self.
_logFileName,
2137 worstError[
'firstError'][
'message'])
2138 except OSError
as e:
2139 exitCode = trfExit.nameToCode(
'TRF_EXEC_LOGERROR')
2141 'Exception raised while attempting to scan logfile {0}: {1}'.format(self.
_logFileName, e))
2143 if worstError[
'nLevel'] == stdLogLevels[
'ERROR']
and (
2144 'ignoreErrors' in self.
conf.argdict
and self.
conf.argdict[
'ignoreErrors'].value
is True):
2145 msg.warning(
'Found ERRORs in the logfile, but ignoring this as ignoreErrors=True (see jobReport for details)')
2147 elif worstError[
'nLevel'] >= stdLogLevels[
'ERROR']:
2149 msg.error(
'Fatal error in script logfile (level {0})'.format(worstError[
'level']))
2150 exitCode = trfExit.nameToCode(
'TRF_EXEC_LOGERROR')
2154 msg.info(
'Executor {0} has validated successfully'.format(self.
name))
2158 msg.debug(
'valStop time is {0}'.format(self.
_valStop))
2164 msg.debug(
'[NTUP] Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
2167 if self.
_exe is None:
2173 if len(output) != 1:
2175 'One (and only one) output file must be given to {0} (got {1})'.format(self.
name, len(output)))
2176 outDataType = list(output)[0]
2177 self.
_cmd.append(self.
conf.dataDictionary[outDataType].value[0])
2179 for dataType
in input:
2180 self.
_cmd.extend(self.
conf.dataDictionary[dataType].value)
2182 super(NTUPMergeExecutor, self).
preExecute(input=input, output=output)
2186 """Executor for running physvalPostProcessing.py with <input> <output> args"""
2190 msg.debug(
'[NTUP] Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.
name, input, output))
2194 if len(input) != 1
or len(output) != 1:
2196 f
'Exactly one input and one output must be specified (got inputs={len(input)}, outputs={len(output)})')
2198 self.
_cmd.append(self.
conf.dataDictionary[list(input)[0]].value[0])
2199 self.
_cmd.append(self.
conf.dataDictionary[list(output)[0]].value[0])
2202 super(NtupPhysValPostProcessingExecutor, self).
preExecute(input=input, output=output)
2213 if 'maskEmptyInputs' in self.
conf.argdict
and self.
conf.argdict[
'maskEmptyInputs'].value
is True:
2215 for fname
in self.
conf.dataDictionary[self.
_inputBS].value:
2216 nEvents = self.
conf.dataDictionary[self.
_inputBS].getSingleMetadata(fname,
'nentries')
2217 msg.debug(
'Found {0} events in file {1}'.format(nEvents, fname))
2218 if isinstance(nEvents, int)
and nEvents > 0:
2219 eventfullFiles.append(fname)
2222 msg.info(
'The following input files are masked because they have 0 events: {0}'.format(
' '.join(self.
_maskedFiles)))
2223 if len(eventfullFiles) == 0:
2224 if 'emptyStubFile' in self.
conf.argdict
and path.exists(self.
conf.argdict[
'emptyStubFile'].value):
2226 msg.info(
"All input files are empty - will use stub file {0} as output".format(self.
conf.argdict[
'emptyStubFile'].value))
2229 'All input files had zero events - aborting BS merge')
2236 for fname
in self.
conf.dataDictionary[self.
_inputBS].value:
2238 print(fname, file=BSFileList)
2239 except OSError
as e:
2240 errMsg =
'Got an error when writing list of BS files to {0}: {1}'.format(self.
_mergeBSFileList, e)
2249 elif self.
conf.argdict[
'allowRename'].value
is True:
2251 msg.info(
'Output filename does not end in "._0001.data" will proceed, but be aware that the internal filename metadata will be wrong')
2255 errmsg =
'Output filename for outputBS_MRGFile must end in "._0001.data" or infile metadata will be wrong'
2261 super(bsMergeExecutor, self).
preExecute(input=input, output=output)
2267 msg.debug(
'exeStart time is {0}'.format(self.
_exeStart))
2268 msg.info(
"Using stub file for empty BS output - execution is fake")
2275 msg.debug(
'exeStop time is {0}'.format(self.
_exeStop))
2277 super(bsMergeExecutor, self).
execute()
2287 except OSError
as e:
2302 if 'outputArchFile' not in self.
conf.argdict:
2307 with open(
'zip_wrapper.py',
'w')
as zip_wrapper:
2308 print(
"import zipfile, os, shutil", file=zip_wrapper)
2309 if os.path.exists(self.
conf.argdict[
'outputArchFile'].value[0]):
2311 print(
"zf = zipfile.ZipFile('{}', mode='a', allowZip64=True)".format(self.
conf.argdict[
'outputArchFile'].value[0]), file=zip_wrapper)
2314 print(
"zf = zipfile.ZipFile('{}', mode='w', allowZip64=True)".format(self.
conf.argdict[
'outputArchFile'].value[0]), file=zip_wrapper)
2315 print(
"for f in {}:".format(self.
conf.argdict[
'inputDataFile'].value), file=zip_wrapper)
2318 print(
" if zipfile.is_zipfile(f) and '.zip' in f:", file=zip_wrapper)
2319 print(
" archive = zipfile.ZipFile(f, mode='r')", file=zip_wrapper)
2320 print(
" print 'Extracting input zip file {0} to temporary directory {1}'.format(f,'tmp')", file=zip_wrapper)
2321 print(
" archive.extractall('tmp')", file=zip_wrapper)
2322 print(
" archive.close()", file=zip_wrapper)
2324 print(
" if os.access(f, os.F_OK):", file=zip_wrapper)
2325 print(
" print 'Removing input zip file {}'.format(f)", file=zip_wrapper)
2326 print(
" os.unlink(f)", file=zip_wrapper)
2327 print(
" if os.path.isdir('tmp'):", file=zip_wrapper)
2328 print(
" for root, dirs, files in os.walk('tmp'):", file=zip_wrapper)
2329 print(
" for name in files:", file=zip_wrapper)
2330 print(
" print 'Zipping {}'.format(name)", file=zip_wrapper)
2331 print(
" zf.write(os.path.join(root, name), name, compress_type=zipfile.ZIP_STORED)", file=zip_wrapper)
2332 print(
" shutil.rmtree('tmp')", file=zip_wrapper)
2333 print(
" else:", file=zip_wrapper)
2334 print(
" print 'Zipping {}'.format(os.path.basename(f))", file=zip_wrapper)
2335 print(
" zf.write(f, arcname=os.path.basename(f), compress_type=zipfile.ZIP_STORED)", file=zip_wrapper)
2336 print(
" if os.access(f, os.F_OK):", file=zip_wrapper)
2337 print(
" print 'Removing input file {}'.format(f)", file=zip_wrapper)
2338 print(
" os.unlink(f)", file=zip_wrapper)
2339 print(
"zf.close()", file=zip_wrapper)
2340 os.chmod(
'zip_wrapper.py', 0o755)
2341 except OSError
as e:
2342 errMsg =
'error writing zip wrapper {fileName}: {error}'.format(fileName =
'zip_wrapper.py',
2349 self.
_cmd.append(
'zip_wrapper.py')
2352 elif self.
_exe ==
'unarchive':
2354 for infile
in self.
conf.argdict[
'inputArchFile'].value:
2355 if not zipfile.is_zipfile(infile):
2357 'An input file is not a zip archive - aborting unpacking')
2358 self.
_cmd = [
'python']
2360 with open(
'unarchive_wrapper.py',
'w')
as unarchive_wrapper:
2361 print(
"import zipfile", file=unarchive_wrapper)
2362 print(
"for f in {}:".format(self.
conf.argdict[
'inputArchFile'].value), file=unarchive_wrapper)
2363 print(
" archive = zipfile.ZipFile(f, mode='r')", file=unarchive_wrapper)
2364 print(
" path = '{}'".format(self.
conf.argdict[
'path']), file=unarchive_wrapper)
2365 print(
" print 'Extracting archive {0} to {1}'.format(f,path)", file=unarchive_wrapper)
2366 print(
" archive.extractall(path)", file=unarchive_wrapper)
2367 print(
" archive.close()", file=unarchive_wrapper)
2368 os.chmod(
'unarchive_wrapper.py', 0o755)
2369 except OSError
as e:
2370 errMsg =
'error writing unarchive wrapper {fileName}: {error}'.format(fileName =
'unarchive_wrapper.py',
2377 self.
_cmd.append(
'unarchive_wrapper.py')
2378 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=":")