@Override
  public HeuristicResult apply(TonyApplicationData data) {
    _LOGGER.debug("Applying TaskGPUHeuristic");
    Map<String, Map<Integer, TonyTaskData>> taskMap = data.getTaskMap();
    Configuration conf = data.getConfiguration();

    Set<String> taskTypes = com.linkedin.tony.util.Utils.getAllJobTypes(conf);
    Severity finalSeverity = Severity.NONE;
    List<HeuristicResultDetails> details = new ArrayList<>();

    for (String taskType : taskTypes) {
      details.add(new HeuristicResultDetails("Number of " + taskType + " tasks",
          Integer.toString(taskMap.get(taskType).size())));

      // get number of GPU resource requested, if any
      int numGPUsRequested = conf.getInt(TonyConfigurationKeys.getResourceKey(taskType, Constants.GPUS), 0);
      if (numGPUsRequested > 0) {
        details.add(new HeuristicResultDetails("Number of GPUs requested per " + taskType + " tasks",
            Integer.toString(numGPUsRequested)));
      }

      // get global max gpu utilization metrics
      for (String maxMetricToApply : MAX_METRICS_TO_APPLY) {
        double maxMetric = TonyUtils.getMaxMetricForTaskTypeAndMetricName(taskMap, taskType, maxMetricToApply);

        if (maxMetric <= 0 || Double.isNaN(maxMetric)) {
          details.add(new HeuristicResultDetails(maxMetricToApply + " in any " + taskType + " task", "Unknown"));
          continue;
        }
        details.add(new HeuristicResultDetails(maxMetricToApply + " in any " + taskType + " task",
            String.format("%.2f", maxMetric) + "%"));
      }

      // get global average gpu utilization metrics
      for (String avgMetricToApply : AVG_METRICS_TO_APPLY) {
        double avgMetric = TonyUtils.getAvgMetricForTaskTypeAndMetricName(taskMap, taskType, avgMetricToApply);

        if (avgMetric <= 0 || Double.isNaN(avgMetric)) {
          details.add(new HeuristicResultDetails(avgMetricToApply + " in any " + taskType + " task", "Unknown"));
          continue;
        }
        details.add(new HeuristicResultDetails(avgMetricToApply + " in any " + taskType + " task",
            String.format("%.2f", avgMetric) + "%"));
      }

      // compare to threshold and update severity
      // TODO: pass all metrics collected as not severe for now, update heuristic when collected enough data to
      // determine the appropriate threshold.
    }

    return new HeuristicResult(_heuristicConfData.getClassName(), _heuristicConfData.getHeuristicName(), finalSeverity,
        0, details);
  }
Constructor for {@link TaskGPUHeuristic}.
@param heuristicConfData  the configuration for this heuristic
app/com/linkedin/drelephant/tony/heuristics/TaskGPUHeuristic.java