diff --git a/Tools/PyJobTransforms/python/transform.py b/Tools/PyJobTransforms/python/transform.py index aa6ad5fab78a0193ba994af272412a693589db71..9819293afb213553ae6e62ceccaa26193c665d72 100644 --- a/Tools/PyJobTransforms/python/transform.py +++ b/Tools/PyJobTransforms/python/transform.py @@ -28,7 +28,8 @@ from PyJobTransforms.trfArgs import addStandardTrfArgs, addFileValidationArgumen from PyJobTransforms.trfLogger import setRootLoggerLevel, stdLogLevels from PyJobTransforms.trfArgClasses import trfArgParser, argFile, argHISTFile, argument from PyJobTransforms.trfExitCodes import trfExit -from PyJobTransforms.trfUtils import shQuoteStrings, infanticide, pickledDump, JSONDump, cliToKey, convertToStr, isInteractiveEnv +from PyJobTransforms.trfUtils import shQuoteStrings, infanticide, pickledDump, JSONDump, cliToKey, convertToStr +from PyJobTransforms.trfUtils import isInteractiveEnv, calcCpuTime, calcWallTime from PyJobTransforms.trfReports import trfJobReport, defaultFileReport from PyJobTransforms.trfExe import transformExecutor from PyJobTransforms.trfGraph import executorGraph @@ -49,9 +50,15 @@ class transform(object): '''Transform class initialiser''' msg.debug('Welcome to ATLAS job transforms') - ## @brief Get starting timestamp as early as possible + ## @brief Get transform starting timestamp as early as possible self._transformStart = os.times() - + msg.debug('transformStart time is {0}'.format(self._transformStart)) + + self._inFileValidationStart = None + self._inFileValidationStop = None + self._outFileValidationStart = None + self._outFileValidationStop = None + ## @brief Get trf pre-data as early as possible self._trfPredata = os.environ.get('TRF_PREDATA') @@ -139,7 +146,59 @@ class transform(object): @property def transformStart(self): return self._transformStart - + + @property + def transformSetupCpuTime(self): + transformSetupCpuTime = None + if self._transformStart and self._inFileValidationStart: + transformSetupCpuTime = calcCpuTime(self._transformStart, self._inFileValidationStart) + + return transformSetupCpuTime + + @property + def transformSetupWallTime(self): + transformSetupWallTime = None + if self._transformStart and self._inFileValidationStart: + transformSetupWallTime = calcWallTime(self._transformStart, self._inFileValidationStart) + + return transformSetupWallTime + + @property + def inFileValidationCpuTime(self): + inFileValidationCpuTime = None + if self._inFileValidationStart and self._inFileValidationStop: + inFileValidationCpuTime = calcCpuTime(self._inFileValidationStart, self._inFileValidationStop) + + return inFileValidationCpuTime + + @property + def inFileValidationWallTime(self): + inFileValidationWallTime = None + if self._inFileValidationStart and self._inFileValidationStop: + inFileValidationWallTime = calcWallTime(self._inFileValidationStart, self._inFileValidationStop) + + return inFileValidationWallTime + + @property + def outFileValidationCpuTime(self): + outFileValidationCpuTime = None + if self._outFileValidationStart and self._outFileValidationStop: + outFileValidationCpuTime = calcCpuTime(self._outFileValidationStart, self._outFileValidationStop) + + return outFileValidationCpuTime + + @property + def outFileValidationWallTime(self): + outFileValidationWallTime = None + if self._outFileValidationStart and self._outFileValidationStop: + outFileValidationWallTime = calcWallTime(self._outFileValidationStart, self._outFileValidationStop) + + return outFileValidationWallTime + + @property + def outFileValidationStop(self): + return self._outFileValidationStop + @property def trfPredata(self): return self._trfPredata @@ -311,7 +370,6 @@ class transform(object): ## @brief Execute transform # @details This function calls the actual transform execution class and # sets \c self.exitCode, \c self.exitMsg and \c self.processedEvents transform data members. - # TODO: This method should be timed - try a decorator function for that # @return None. def execute(self): msg.debug('Entering transform execution phase') @@ -670,6 +728,10 @@ class transform(object): def validateInFiles(self): + if self._inFileValidationStart is None: + self._inFileValidationStart = os.times() + msg.debug('inFileValidationStart time is {0}'.format(self._inFileValidationStart)) + if (('skipFileValidation' in self._argdict and self._argdict['skipFileValidation'] is True) or ('skipInputFileValidation' in self._argdict and self._argdict['skipInputFileValidation'] is True) or ('fileValidation' in self._argdict and self._argdict['fileValidation'].value is False) or @@ -683,7 +745,14 @@ class transform(object): else: trfValidation.performStandardFileValidation(dictionary=self._dataDictionary, io='input') + self._inFileValidationStop = os.times() + msg.debug('inFileValidationStop time is {0}'.format(self._inFileValidationStop)) + def validateOutFiles(self): + if self._outFileValidationStart is None: + self._outFileValidationStart = os.times() + msg.debug('outFileValidationStart time is {0}'.format(self._outFileValidationStart)) + if (('skipFileValidation' in self._argdict and self._argdict['skipFileValidation'] is True) or ('skipOutputFileValidation' in self._argdict and self._argdict['skipOutputFileValidation'] is True) or ('fileValidation' in self._argdict and self._argdict['fileValidation'].value is False) or @@ -695,4 +764,7 @@ class transform(object): if 'parallelFileValidation' in self._argdict: trfValidation.performStandardFileValidation(dictionary=self._dataDictionary, io='output', parallelMode=self._argdict['parallelFileValidation'].value ) else: - trfValidation.performStandardFileValidation(dictionary=self._dataDictionary, io='output') \ No newline at end of file + trfValidation.performStandardFileValidation(dictionary=self._dataDictionary, io='output') + + self._outFileValidationStop = os.times() + msg.debug('outFileValidationStop time is {0}'.format(self._outFileValidationStop)) diff --git a/Tools/PyJobTransforms/python/trfExe.py b/Tools/PyJobTransforms/python/trfExe.py index 328b96fcdeb7302ec05dc8a6f3e19859624f1b28..28ec25ee40c27392492b1ce11ac3b5973f29ad4c 100755 --- a/Tools/PyJobTransforms/python/trfExe.py +++ b/Tools/PyJobTransforms/python/trfExe.py @@ -25,7 +25,7 @@ msg = logging.getLogger(__name__) from PyJobTransforms.trfJobOptions import JobOptionsTemplate from PyJobTransforms.trfUtils import asetupReport, unpackDBRelease, setupDBRelease, cvmfsDBReleaseCheck, forceToAlphaNum -from PyJobTransforms.trfUtils import ValgrindCommand, isInteractiveEnv +from PyJobTransforms.trfUtils import ValgrindCommand, isInteractiveEnv, calcCpuTime, calcWallTime from PyJobTransforms.trfExitCodes import trfExit from PyJobTransforms.trfLogger import stdLogLevels from PyJobTransforms.trfMPTools import detectAthenaMPProcs, athenaMPOutputHandler @@ -309,42 +309,42 @@ class transformExecutor(object): @property def preExeCpuTime(self): if self._preExeStart and self._exeStart: - return self.calcCpuTime(self._preExeStart, self._exeStart) + return calcCpuTime(self._preExeStart, self._exeStart) else: return None @property def preExeWallTime(self): if self._preExeStart and self._exeStart: - return int(self._exeStart[4] - self._preExeStart[4] + 0.5) + return calcWallTime(self._preExeStart, self._exeStart) else: return None @property def cpuTime(self): if self._exeStart and self._exeStop: - return self.calcCpuTime(self._exeStart, self._exeStop) + return calcCpuTime(self._exeStart, self._exeStop) else: return None @property def usrTime(self): if self._exeStart and self._exeStop: - return int(self._exeStop[2] - self._exeStart[2] + 0.5) + return self._exeStop[2] - self._exeStart[2] else: return None @property def sysTime(self): if self._exeStart and self._exeStop: - return int(self._exeStop[3] - self._exeStart[3] + 0.5) + return self._exeStop[3] - self._exeStart[3] else: return None @property def wallTime(self): if self._exeStart and self._exeStop: - return int(self._exeStop[4] - self._exeStart[4] + 0.5) + return calcWallTime(self._exeStart, self._exeStop) else: return None @@ -355,42 +355,42 @@ class transformExecutor(object): @property def postExeCpuTime(self): if self._exeStop and self._valStart: - return self.calcCpuTime(self._exeStop, self._valStart) + return calcCpuTime(self._exeStop, self._valStart) else: return None @property def postExeWallTime(self): if self._exeStop and self._valStart: - return int(self._valStart[4] - self._exeStop[4] + 0.5) + return calcWallTime(self._exeStop, self._valStart) else: return None @property def validationCpuTime(self): if self._valStart and self._valStop: - return self.calcCpuTime(self._valStart, self._valStop) + return calcCpuTime(self._valStart, self._valStop) else: return None @property def validationWallTime(self): if self._valStart and self._valStop: - return int(self._valStop[4] - self._valStart[4] + 0.5) + return calcWallTime(self._valStart, self._valStop) else: return None @property def cpuTimeTotal(self): if self._preExeStart and self._valStop: - return self.calcCpuTime(self._preExeStart, self._valStop) + return calcCpuTime(self._preExeStart, self._valStop) else: return None @property def wallTimeTotal(self): if self._preExeStart and self._valStop: - return int(self._valStop[4] - self._preExeStart[4] + 0.5) + return calcWallTime(self._preExeStart, self._valStop) else: return None @@ -406,22 +406,17 @@ class transformExecutor(object): def dbMonitor(self): return self._dbMonitor - # calculate cpuTime from os.times() times tuple - def calcCpuTime(self, start, stop): - if start and stop: - return int(reduce(lambda x1, x2: x1+x2, map(lambda x1, x2: x2-x1, start[2:4], stop[2:4])) + 0.5) - else: - return None # set start times, if not set already def setPreExeStart(self): if self._preExeStart is None: self._preExeStart = os.times() - msg.debug('+++ preExeStart time is {0}'.format(self._preExeStart)) + msg.debug('preExeStart time is {0}'.format(self._preExeStart)) + def setValStart(self): if self._valStart is None: self._valStart = os.times() - msg.debug('+++ valStart time is {0}'.format(self._valStart)) + msg.debug('valStart time is {0}'.format(self._valStart)) def preExecute(self, input = set(), output = set()): self.setPreExeStart() @@ -429,14 +424,14 @@ class transformExecutor(object): def execute(self): self._exeStart = os.times() - msg.debug('+++ exeStart time is {0}'.format(self._exeStart)) + msg.debug('exeStart time is {0}'.format(self._exeStart)) msg.info('Starting execution of %s' % self._name) self._hasExecuted = True self._rc = 0 self._errMsg = '' msg.info('%s executor returns %d' % (self._name, self._rc)) self._exeStop = os.times() - msg.debug('+++ preExeStop time is {0}'.format(self._exeStop)) + msg.debug('preExeStop time is {0}'.format(self._exeStop)) def postExecute(self): msg.info('Postexecute for %s' % self._name) @@ -448,7 +443,7 @@ class transformExecutor(object): self._isValidated = True self._errMsg = '' self._valStop = os.times() - msg.debug('+++ valStop time is {0}'.format(self._valStop)) + msg.debug('valStop time is {0}'.format(self._valStop)) ## Convenience function def doAll(self, input=set(), output=set()): @@ -522,7 +517,7 @@ class logscanExecutor(transformExecutor): self._errMsg = '' self._valStop = os.times() - msg.debug('+++ valStop time is {0}'.format(self._valStop)) + msg.debug('valStop time is {0}'.format(self._valStop)) class echoExecutor(transformExecutor): @@ -534,7 +529,7 @@ class echoExecutor(transformExecutor): def execute(self): self._exeStart = os.times() - msg.debug('+++ exeStart time is {0}'.format(self._exeStart)) + msg.debug('exeStart time is {0}'.format(self._exeStart)) msg.info('Starting execution of %s' % self._name) msg.info('Transform argument dictionary now follows:') for k, v in self.conf.argdict.iteritems(): @@ -544,7 +539,7 @@ class echoExecutor(transformExecutor): self._errMsg = '' msg.info('%s executor returns %d' % (self._name, self._rc)) self._exeStop = os.times() - msg.debug('+++ exeStop time is {0}'.format(self._exeStop)) + msg.debug('exeStop time is {0}'.format(self._exeStop)) class scriptExecutor(transformExecutor): @@ -655,7 +650,7 @@ class scriptExecutor(transformExecutor): msg.info('Starting execution of {0} ({1})'.format(self._name, self._cmd)) self._exeStart = os.times() - msg.debug('+++ exeStart time is {0}'.format(self._exeStart)) + msg.debug('exeStart time is {0}'.format(self._exeStart)) if ('execOnly' in self.conf.argdict and self.conf.argdict['execOnly'] == True): msg.info('execOnly flag is set - execution will now switch, replacing the transform') os.execvp(self._cmd[0], self._cmd) @@ -685,7 +680,7 @@ class scriptExecutor(transformExecutor): self._rc = p.returncode msg.info('%s executor returns %d' % (self._name, self._rc)) self._exeStop = os.times() - msg.debug('+++ exeStop time is {0}'.format(self._exeStop)) + msg.debug('exeStop time is {0}'.format(self._exeStop)) except OSError as e: errMsg = 'Execution of {0} failed and raised OSError: {1}'.format(self._cmd[0], e) msg.error(errMsg) @@ -718,7 +713,7 @@ class scriptExecutor(transformExecutor): def validate(self): if self._valStart is None: self._valStart = os.times() - msg.debug('+++ valStart time is {0}'.format(self._valStart)) + msg.debug('valStart time is {0}'.format(self._valStart)) self._hasValidated = True ## Check rc @@ -751,7 +746,7 @@ class scriptExecutor(transformExecutor): msg.info('Event counting for substep {0} passed'.format(self.name)) self._valStop = os.times() - msg.debug('+++ valStop time is {0}'.format(self._valStop)) + msg.debug('valStop time is {0}'.format(self._valStop)) @@ -1125,7 +1120,7 @@ class athenaExecutor(scriptExecutor): self._isValidated = True self._valStop = os.times() - msg.debug('+++ valStop time is {0}'.format(self._valStop)) + msg.debug('valStop time is {0}'.format(self._valStop)) ## @brief Prepare the correct command line to be used to invoke athena def _prepAthenaCommandLine(self): @@ -1426,7 +1421,7 @@ class optionalAthenaExecutor(athenaExecutor): self._errMsg = e.errMsg self._rc = e.errCode self._valStop = os.times() - msg.debug('+++ valStop time is {0}'.format(self._valStop)) + msg.debug('valStop time is {0}'.format(self._valStop)) class hybridPOOLMergeExecutor(athenaExecutor): @@ -1516,7 +1511,7 @@ class hybridPOOLMergeExecutor(athenaExecutor): # Ensure we count all the mergePOOL stuff in the resource report self._exeStop = os.times() - msg.debug('+++ exeStop time is {0}'.format(self._exeStop)) + msg.debug('exeStop time is {0}'.format(self._exeStop)) # And finally... msg.info('Renaming {0} to {1}'.format(self._hybridMergeTmpFile, self.conf.dataDictionary[list(self._output)[0]].value[0])) @@ -1694,7 +1689,7 @@ class DQMergeExecutor(scriptExecutor): self._isValidated = True self._valStop = os.times() - msg.debug('+++ valStop time is {0}'.format(self._valStop)) + msg.debug('valStop time is {0}'.format(self._valStop)) ## @brief Specialist execution class for merging NTUPLE files @@ -1786,7 +1781,7 @@ class bsMergeExecutor(scriptExecutor): if self._useStubFile: # Need to fake execution! self._exeStart = os.times() - msg.debug('+++ exeStart time is {0}'.format(self._exeStart)) + msg.debug('exeStart time is {0}'.format(self._exeStart)) msg.info("Using stub file for empty BS output - execution is fake") if self._outputFilename != self.conf.argdict['emptyStubFile'].value: os.rename(self.conf.argdict['emptyStubFile'].value, self._outputFilename) @@ -1794,7 +1789,7 @@ class bsMergeExecutor(scriptExecutor): self._hasExecuted = True self._rc = 0 self._exeStop = os.times() - msg.debug('+++ exeStop time is {0}'.format(self._exeStop)) + msg.debug('exeStop time is {0}'.format(self._exeStop)) else: super(bsMergeExecutor, self).execute() @@ -1854,7 +1849,7 @@ class tagMergeExecutor(scriptExecutor): raise trfExceptions.TransformValidationException(trfExit.nameToCode('TRF_EXEC_LOGERROR'), 'Exception raised while attempting to scan logfile {0}: {1}'.format(self._logFileName, e)) self._valStop = os.times() - msg.debug('+++ valStop time is {0}'.format(self._valStop)) + msg.debug('valStop time is {0}'.format(self._valStop)) ## @brief Archive transform - use tar diff --git a/Tools/PyJobTransforms/python/trfReports.py b/Tools/PyJobTransforms/python/trfReports.py index cb0d4adb79c154c0783fbd962d84c34a8e9ccf3d..638e0fd9d83f67679be7e90d0a268e88d89283fc 100644 --- a/Tools/PyJobTransforms/python/trfReports.py +++ b/Tools/PyJobTransforms/python/trfReports.py @@ -27,7 +27,7 @@ import PyJobTransforms.trfExceptions as trfExceptions import PyJobTransforms.trfArgClasses as trfArgClasses from PyJobTransforms.trfExitCodes import trfExit -from PyJobTransforms.trfUtils import shQuoteStrings, isodate, prettyXML +from PyJobTransforms.trfUtils import shQuoteStrings, isodate, prettyXML, calcCpuTime, calcWallTime ## @brief Default values for file reporting defaultFileReport = {'input': 'name', 'temporary': None, 'output': 'full'} @@ -105,7 +105,7 @@ class trfReport(object): class trfJobReport(trfReport): ## @brief This is the version counter for transform job reports # any changes to the format @b must be reflected by incrementing this - _reportVersion = '2.0.7' + _reportVersion = '2.0.9' _metadataKeyMap = {'AMIConfig': 'AMI', } _maxMsgLen = 256 _truncationMsg = " (truncated)" @@ -116,6 +116,7 @@ class trfJobReport(trfReport): # @param parentTrf Mandatory link to the transform this job report represents def __init__(self, parentTrf): self._trf = parentTrf + self._precisionDigits = 3 ## @brief generate the python transform job report # @param type The general type of this report (e.g. fast) @@ -170,10 +171,10 @@ class trfJobReport(trfReport): myDict['resource']['executor'][mergeStep.name] = exeResourceReport(mergeStep, self) if self._dbDataTotal > 0 or self._dbTimeTotal > 0: myDict['resource']['dbDataTotal'] = self._dbDataTotal - myDict['resource']['dbTimeTotal'] = self._dbTimeTotal + myDict['resource']['dbTimeTotal'] = self.roundoff(self._dbTimeTotal) # Resource consumption reportTime = os.times() - + # Calculate total cpu time we used - myCpuTime = reportTime[0] + reportTime[1] childCpuTime = reportTime[2] + reportTime[3] @@ -205,17 +206,30 @@ class trfJobReport(trfReport): pass msg.debug('maxWorkers: {0}, cpuTimeTotal: {1}, cpuTimePerWorker: {2}'.format(maxWorkers, cpuTime, cpuTimePerWorker)) - myDict['resource']['transform'] = {'cpuTime': int(myCpuTime + 0.5), - 'cpuTimeTotal': int(cpuTimeTotal + 0.5), - 'externalCpuTime': int(childCpuTime + 0.5), - 'wallTime': int(wallTime + 0.5),} + reportGenerationCpuTime = reportGenerationWallTime = None + if self._trf.outFileValidationStop and reportTime: + reportGenerationCpuTime = calcCpuTime(self._trf.outFileValidationStop, reportTime) + reportGenerationWallTime = calcWallTime(self._trf.outFileValidationStop, reportTime) + + myDict['resource']['transform'] = {'cpuTime': self.roundoff(myCpuTime), + 'cpuTimeTotal': self.roundoff(cpuTimeTotal), + 'externalCpuTime': self.roundoff(childCpuTime), + 'wallTime': self.roundoff(wallTime), + 'transformSetup': {'cpuTime': self.roundoff(self._trf.transformSetupCpuTime), + 'wallTime': self.roundoff(self._trf.transformSetupWallTime)}, + 'inFileValidation': {'cpuTime': self.roundoff(self._trf.inFileValidationCpuTime), + 'wallTime': self.roundoff(self._trf.inFileValidationWallTime)}, + 'outFileValidation': {'cpuTime': self.roundoff(self._trf.outFileValidationCpuTime), + 'wallTime': self.roundoff(self._trf.outFileValidationWallTime)}, + 'reportGeneration': {'cpuTime': self.roundoff(reportGenerationCpuTime), + 'wallTime': self.roundoff(reportGenerationWallTime)}, } if self._trf.processedEvents: - myDict['resource']['transform']['processedEvents'] = self._trf.processedEvents + myDict['resource']['transform']['processedEvents'] = self._trf.processedEvents myDict['resource']['transform']['trfPredata'] = self._trf.trfPredata # check for devision by zero for fast jobs, unit tests - if int(wallTime+0.5) > 0: - myDict['resource']['transform']['cpuEfficiency'] = round(int(cpuTime + 0.5)*1.0/maxWorkers/int(wallTime+0.5), 4) - myDict['resource']['transform']['cpuPWEfficiency'] = round(int(cpuTimePerWorker + 0.5)*1.0/int(wallTime+0.5), 4) + if wallTime > 0: + myDict['resource']['transform']['cpuEfficiency'] = round(cpuTime/maxWorkers/wallTime, 4) + myDict['resource']['transform']['cpuPWEfficiency'] = round(cpuTimePerWorker/wallTime, 4) myDict['resource']['machine'] = machineReport().python(fast = fast) return myDict @@ -316,6 +330,11 @@ class trfJobReport(trfReport): # Tier 0 expects the report to be in a top level dictionary under the prodsys key return {'prodsys' : trfDict} + # Helper method to format values to number of decimals configured for this jobReport. + # Safely allows possible and valid None values within jobReport. + def roundoff(self, value): + return round(value, self._precisionDigits) if (value is not None) else value + ## @brief Class to contain metadata for an executor class trfExecutorReport(object): @@ -554,7 +573,7 @@ class machineReport(object): machine[attr] = getattr(platform, attr).__call__() except AttributeError, e: msg.error('Failed to get "{0}" attribute from platform module: {1}'.format(attr, e)) - + # Now try to get processor information from /proc/cpuinfo try: with open('/proc/cpuinfo') as cpuinfo: @@ -593,23 +612,23 @@ def pyJobReportToFileDict(jobReport, io = 'all'): def exeResourceReport(exe, report): - exeResource = {'cpuTime': exe.cpuTime, - 'wallTime': exe.wallTime, + exeResource = {'cpuTime': report.roundoff(exe.cpuTime), + 'wallTime': report.roundoff(exe.wallTime), 'preExe': { - 'cpuTime': exe.preExeCpuTime, - 'wallTime': exe.preExeWallTime, + 'cpuTime': report.roundoff(exe.preExeCpuTime), + 'wallTime': report.roundoff(exe.preExeWallTime), }, 'postExe': { - 'cpuTime': exe.postExeCpuTime, - 'wallTime': exe.postExeWallTime, + 'cpuTime': report.roundoff(exe.postExeCpuTime), + 'wallTime': report.roundoff(exe.postExeWallTime), }, 'validation': { - 'cpuTime': exe.validationCpuTime, - 'wallTime': exe.validationWallTime, + 'cpuTime': report.roundoff(exe.validationCpuTime), + 'wallTime': report.roundoff(exe.validationWallTime), }, 'total': { - 'cpuTime': exe.cpuTimeTotal, - 'wallTime': exe.wallTimeTotal, + 'cpuTime': report.roundoff(exe.cpuTimeTotal), + 'wallTime': report.roundoff(exe.wallTimeTotal), }, } @@ -619,7 +638,7 @@ def exeResourceReport(exe, report): exeResource['nevents'] = exe.eventCount if exe.athenaMP: exeResource['mpworkers'] = exe.athenaMP - exeResource['cpuTimePerWorker'] = float(exe.cpuTime)/exe.athenaMP + exeResource['cpuTimePerWorker'] = report.roundoff(exe.cpuTime/exe.athenaMP) if exe.dbMonitor: exeResource['dbData'] = exe.dbMonitor['bytes'] exeResource['dbTime'] = exe.dbMonitor['time'] diff --git a/Tools/PyJobTransforms/python/trfUtils.py b/Tools/PyJobTransforms/python/trfUtils.py index 6ff164cf0c71a2c49c529dd740031a1c0c88f224..431d4d6825da2b03429d6d4618c8d687bbdfe1a3 100644 --- a/Tools/PyJobTransforms/python/trfUtils.py +++ b/Tools/PyJobTransforms/python/trfUtils.py @@ -1239,3 +1239,20 @@ def ValgrindCommand( format = returnFormat )) raise(Exception) + + +# calculate cpuTime from os.times() times tuple +def calcCpuTime(start, stop): + cpuTime = None + if start and stop: + cpuTime = reduce(lambda x1, x2: x1+x2, map(lambda x1, x2: x2-x1, start[2:4], stop[2:4])) + + return cpuTime + +# calculate wallTime from os.times() times tuple +def calcWallTime(start, stop): + wallTime = None + if start and stop: + wallTime = stop[4] - start[4] + + return wallTime \ No newline at end of file