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