private void updateExecutionMetrics(List<TuningJobExecutionParamSet> completedJobExecutionParamSets) {
    for (TuningJobExecutionParamSet completedJobExecutionParamSet : completedJobExecutionParamSets) {

      JobExecution jobExecution = completedJobExecutionParamSet.jobExecution;
      JobSuggestedParamSet jobSuggestedParamSet = completedJobExecutionParamSet.jobSuggestedParamSet;
      JobDefinition job = jobExecution.job;

      logger.info("Updating execution metrics and fitness for execution: " + jobExecution.jobExecId);
      try {
        TuningJobDefinition tuningJobDefinition = TuningJobDefinition.find.select("*")
            .fetch(TuningJobDefinition.TABLE.job, "*")
            .where()
            .eq(TuningJobDefinition.TABLE.job + "." + JobDefinition.TABLE.id, job.id)
            .order()
            .desc(TuningJobDefinition.TABLE.createdTs)
            .findUnique();

        List<AppResult> results = AppResult.find.select("*")
            .fetch(AppResult.TABLE.APP_HEURISTIC_RESULTS, "*")
            .fetch(AppResult.TABLE.APP_HEURISTIC_RESULTS + "." + AppHeuristicResult.TABLE.APP_HEURISTIC_RESULT_DETAILS,
                "*")
            .where()
            .eq(AppResult.TABLE.FLOW_EXEC_ID, jobExecution.flowExecution.flowExecId)
            .eq(AppResult.TABLE.JOB_EXEC_ID, jobExecution.jobExecId)
            .findList();

        if (results != null && results.size() > 0) {
          Double totalResourceUsed = 0D;
          Double totalInputBytesInBytes = 0D;

          for (AppResult appResult : results) {
            totalResourceUsed += appResult.resourceUsed;
            totalInputBytesInBytes += getTotalInputBytes(appResult);
          }

          Long totalRunTime = Utils.getTotalRuntime(results);
          Long totalDelay = Utils.getTotalWaittime(results);
          Long totalExecutionTime = totalRunTime - totalDelay;

          if (totalExecutionTime != 0) {
            jobExecution.executionTime = totalExecutionTime * 1.0 / (1000 * 60);
            jobExecution.resourceUsage = totalResourceUsed * 1.0 / (1024 * 3600);
            jobExecution.inputSizeInBytes = totalInputBytesInBytes;
            jobExecution.update();
            logger.info(
                "Metric Values for execution " + jobExecution.jobExecId + ": Execution time = " + totalExecutionTime
                    + ", Resource usage = " + totalResourceUsed + " and total input size = " + totalInputBytesInBytes);
          }

          if (tuningJobDefinition.averageResourceUsage == null && totalExecutionTime != 0) {
            tuningJobDefinition.averageResourceUsage = jobExecution.resourceUsage;
            tuningJobDefinition.averageExecutionTime = jobExecution.executionTime;
            tuningJobDefinition.averageInputSizeInBytes = jobExecution.inputSizeInBytes.longValue();
            tuningJobDefinition.update();
          }

          //Compute fitness

          if (!jobSuggestedParamSet.paramSetState.equals(ParamSetStatus.FITNESS_COMPUTED)) {
            if (jobExecution.executionState.equals(JobExecution.ExecutionState.SUCCEEDED)) {
              logger.info("Execution id: " + jobExecution.id + " succeeded");
              updateJobSuggestedParamSetSucceededExecution(jobExecution, jobSuggestedParamSet, tuningJobDefinition);
            } else {
              // Resetting param set to created state because this case captures the scenarios when
              // either the job failed for reasons other than auto tuning or was killed/cancelled/skipped etc.
              // In all the above scenarios, fitness cannot be computed for the param set correctly.
              // Note that the penalty on failures caused by auto tuning is applied when the job execution is retried
              // after failure.
              logger.info("Execution id: " + jobExecution.id + " was not successful for reason other than tuning."
                  + "Resetting param set: " + jobSuggestedParamSet.id + " to CREATED state");
              resetParamSetToCreated(jobSuggestedParamSet);
            }
          }
        } else {
          long diff = System.currentTimeMillis() - jobExecution.updatedTs.getTime();
          logger.debug("Current Time in millis: " + System.currentTimeMillis() + ", job execution last updated time "
              + jobExecution.updatedTs.getTime());
          if (diff > ignoreExecutionWaitInterval) {
            logger.info("Fitness of param set " + jobSuggestedParamSet.id  + " corresponding to execution id: " +
                jobExecution.id + " not computed for more than the maximum duration specified to compute fitness. "
                + "Resetting the param set to CREATED state");
            resetParamSetToCreated(jobSuggestedParamSet);
          }
        }
      } catch (Exception e) {
        logger.error("Error updating fitness of execution: " + jobExecution.id + "\n Stacktrace: ", e);
      }
    }
    logger.info("Execution metrics updated");
  }
Updates the execution metrics
@param completedJobExecutionParamSets List of completed executions
app/com/linkedin/drelephant/tuning/FitnessComputeUtil.java