979 def preExecute(self, input = set(), output =
set()):
980 self.setPreExeStart()
981 msg.debug('Preparing for execution of {0} with inputs {1} and outputs {2}'.format(self.name, input, output))
982
983
984 inputEvents = 0
985 dt = ""
986 if self._inputDataTypeCountCheck is None:
987 self._inputDataTypeCountCheck = input
988 for dataType in self._inputDataTypeCountCheck:
989 if self.conf.dataDictionary[dataType].nentries == 'UNDEFINED':
990 continue
991
992 thisInputEvents = self.conf.dataDictionary[dataType].nentries
993 if thisInputEvents > inputEvents:
994 inputEvents = thisInputEvents
995 dt = dataType
996
997
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)
1001 else:
1002 mySkipEvents = 0
1003
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)
1007 else:
1008 myMaxEvents = -1
1009
1010
1011 if (self._inputEventTest and mySkipEvents > 0 and mySkipEvents >= inputEvents):
1012 raise trfExceptions.TransformExecutionException(trfExit.nameToCode('TRF_NOEVENTS'),
1013 'No events to process: {0} (skipEvents) >= {1} (inputEvents of {2}'.format(mySkipEvents, inputEvents, dt))
1014
1015 try:
1016
1017 if (myMaxEvents != -1):
1018 if (self.inData and next(iter(self.inData)) == 'inNULL'):
1019 expectedEvents = myMaxEvents
1020 else:
1021 expectedEvents =
min(inputEvents-mySkipEvents, myMaxEvents)
1022 else:
1023 expectedEvents = inputEvents-mySkipEvents
1024 except TypeError:
1025
1026 msg.info('input event count is UNDEFINED, setting expectedEvents to 0')
1027 expectedEvents = 0
1028
1029
1032 OSSetupString = None
1033
1034
1035 asetupString = 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)
1040 else:
1041 msg.info('Asetup report: {0}'.format(asetupReport()))
1042
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))
1049
1050
1051
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:
1056 raise trfExceptions.TransformExecutionException(trfExit.nameToCode('TRF_EXEC_SETUP_FAIL'),
1057 '--asetup must be used for the substep which requires --runInContainer')
1058
1059
1060 if self._onlyMPWithRunargs:
1061 for k in self._onlyMPWithRunargs:
1062 if k in self.conf._argdict:
1063 self._onlyMP = True
1064
1065
1066
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!')
1070
1071
1072 else:
1073
1074 if not self._disableMT:
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')
1077 self._athenaMT = 1
1078 self._athenaConcurrentEvents = 1
1079 else:
1080 self._athenaMT, self._athenaConcurrentEvents = detectAthenaMTThreads(self.conf.argdict, self.name, legacyThreadingRelease)
1081
1082
1083 if not self._disableMP:
1084 self._athenaMP = detectAthenaMPProcs(self.conf.argdict, self.name, legacyThreadingRelease)
1085
1086
1087 if self._onlyMP and self._athenaMT > 0:
1088 msg.info("This configuration does not support MT, falling back to MP")
1089 if self._athenaMP == 0:
1090 self._athenaMP = self._athenaMT
1091 self._athenaMT = 0
1092 self._athenaConcurrentEvents = 0
1093
1094
1095 if self._onlyMT and self._athenaMP > 0:
1096 msg.info("This configuration does not support MP, using MT")
1097 if self._athenaMT == 0:
1098 self._athenaMT = self._athenaMP
1099 self._athenaConcurrentEvents = self._athenaMP
1100 self._athenaMP = 0
1101
1102
1103
1104 if not self._disableMP and expectedEvents < self._athenaMP and not self._inData=={'inNULL'}:
1105 msg.info("Disabling AthenaMP as number of input events to process is too low ({0} events for {1} workers)".format(expectedEvents, self._athenaMP))
1106 self._disableMP = True
1107 self._athenaMP = 0
1108
1109
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
1114 else:
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]))
1118
1119
1120 if self._athenaMP > 0:
1121 self._athenaMPWorkerTopDir = 'athenaMP-workers-{0}-{1}'.format(self._name, self._substep)
1122 self._athenaMPFileReport = 'athenaMP-outputs-{0}-{1}'.format(self._name, self._substep)
1123 self._athenaMPEventOrdersFile = 'athenamp_eventorders.txt.{0}'.format(self._name)
1124 if 'athenaMPUseEventOrders' in self.conf.argdict and self.conf._argdict['athenaMPUseEventOrders'].value is True:
1125 self._athenaMPReadEventOrders = True
1126 else:
1127 self._athenaMPReadEventOrders = False
1128
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)):
1131 self._athenaMPStrategy = self.conf.argdict['athenaMPStrategy'].returnMyValue(name=self._name, substep=self._substep, first=self.conf.firstExecutor)
1132 else:
1133 self._athenaMPStrategy = 'SharedQueue'
1134
1135
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))
1141 else:
1142
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
1149 break
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))
1153
1154
1155
1156
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))
1163 else:
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]))
1166 else:
1167 self._athenaMPWorkerTopDir = self._athenaMPFileReport = None
1168
1169
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)
1173
1174
1175 if self._skeleton or self._skeletonCA:
1176 inputFiles = dict()
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]
1182
1183
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')
1191
1192 if dataArg[self.conf.executorStep].io == 'input' and nameForFiles in dataArg[self.conf.executorStep].executor:
1193 inputFiles[dataArg[self.conf.executorStep].subtype] = dataArg
1194 else:
1195 if dataArg.io == 'input' and nameForFiles in dataArg.executor:
1196 inputFiles[dataArg.subtype] = dataArg
1197
1198 msg.debug('Input Files: {0}; Output Files: {1}'.format(inputFiles, outputFiles))
1199
1200
1201 self._topOptionsFiles = self._jobOptionsTemplate.getTopOptions(input = inputFiles,
1202 output = outputFiles)
1203
1204
1206 if len(input) > 0:
1207 self._extraMetadata['inputs'] = list(input)
1208 if len(output) > 0:
1209 self._extraMetadata['outputs'] = list(output)
1210
1211
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)
1217 if dbrelease:
1218
1219 dbdMatch = re.match(r'DBRelease-([\d\.]+)\.tar\.gz', path.basename(dbrelease))
1220 if dbdMatch:
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)
1227 else:
1228
1229 msg.debug('Setting up {0} from {1}'.format(dbdMatch.group(1), dbrelease))
1230 unpacked, dbsetup = unpackDBRelease(tarball=dbrelease, dbversion=dbdMatch.group(1))
1231 if unpacked:
1232
1233 setupDBRelease(dbsetup)
1234
1235 else:
1236 dbsetup = cvmfsDBReleaseCheck(dbrelease)
1237
1238
1239 self._envUpdate = trfEnv.environmentUpdate()
1240 self._envUpdate.setStandardEnvironment(self.conf.argdict, name=self.name, substep=self.substep)
1241 self._prepAthenaCommandLine()
1242
1243
1244 super(athenaExecutor, self).preExecute(input, output)
1245
1246
1247
1248
1249 msg.info('Now writing wrapper for substep executor {0}'.format(self._name))
1250 self._writeAthenaWrapper(asetup=asetupString, dbsetup=dbsetup, ossetup=OSSetupString)
1251 msg.info('Athena will be executed in a subshell via {0}'.format(self._cmd))
1252
1253