Skip to content

Commit

Permalink
Merge pull request #1189 from khansaad/kruize-55
Browse files Browse the repository at this point in the history
Fix Box Plots Issues
  • Loading branch information
dinogun authored May 14, 2024
2 parents 3aa0c47 + 4960ab1 commit 8146907
Show file tree
Hide file tree
Showing 4 changed files with 205 additions and 131 deletions.
109 changes: 83 additions & 26 deletions src/main/java/com/autotune/analyzer/plots/PlotManager.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.autotune.analyzer.plots;

import com.autotune.analyzer.recommendations.model.CostBasedRecommendationModel;
import com.autotune.analyzer.recommendations.term.Terms;
import com.autotune.analyzer.utils.AnalyzerConstants;
import com.autotune.common.data.metrics.MetricResults;
import com.autotune.common.data.result.IntervalResults;
import com.autotune.common.utils.CommonUtils;
import com.autotune.utils.KruizeConstants;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

import static com.autotune.analyzer.recommendations.RecommendationConstants.RecommendationEngine.PercentileConstants.*;

Expand All @@ -35,7 +38,7 @@ public PlotData.PlotsData generatePlots() {
sortedResultsHashMap.putAll(containerResultsMap);

// Retrieve entries within the specified range
Map<Timestamp, IntervalResults> resultInRange = sortedResultsHashMap.subMap(monitoringEndTime, true, monitoringStartTime, true);
Map<Timestamp, IntervalResults> resultInRange = sortedResultsHashMap.subMap(monitoringEndTime, true, monitoringStartTime, false);

int delimiterNumber = (int) (resultInRange.size() / recommendationTerm.getPlots_datapoints());

Expand All @@ -58,37 +61,91 @@ public PlotData.PlotsData generatePlots() {
calendar.add(Calendar.MILLISECOND, (int) millisecondsToAdd);
// Convert the modified Calendar back to a Timestamp
Timestamp newTimestamp = new Timestamp(calendar.getTimeInMillis());
PlotData.UsageData cpuUsage = getUsageData(sortedResultsHashMap.subMap(newTimestamp, true, incrementStartTime, true), AnalyzerConstants.MetricName.cpuUsage, "cores");
PlotData.UsageData memoryUsage = getUsageData(sortedResultsHashMap.subMap(newTimestamp, true, incrementStartTime, true), AnalyzerConstants.MetricName.memoryUsage, "MiB");
PlotData.UsageData cpuUsage = getUsageData(sortedResultsHashMap.subMap(newTimestamp, true,
incrementStartTime,false), AnalyzerConstants.MetricName.cpuUsage);
PlotData.UsageData memoryUsage = getUsageData(sortedResultsHashMap.subMap(newTimestamp, true,
incrementStartTime, false), AnalyzerConstants.MetricName.memoryUsage);
plotsDataMap.put(newTimestamp, new PlotData.PlotPoint(cpuUsage, memoryUsage));
incrementStartTime = newTimestamp;
}

return new PlotData.PlotsData(recommendationTerm.getPlots_datapoints(), plotsDataMap);
}

PlotData.UsageData getUsageData(Map<Timestamp, IntervalResults> resultInRange, AnalyzerConstants.MetricName metricName, String format) {
// Extract CPU values
List<Double> cpuValues = resultInRange.values().stream()
.filter(intervalResults -> intervalResults.getMetricResultsMap().containsKey(metricName))
.mapToDouble(intervalResults -> {
MetricResults metricResults = intervalResults.getMetricResultsMap().get(metricName);
return (metricResults != null && metricResults.getAggregationInfoResult() != null) ? metricResults.getAggregationInfoResult().getSum() : 0.0;
})
.boxed() // Convert double to Double
.collect(Collectors.toList());
if (cpuValues.size() > 0) {
double q1 = CommonUtils.percentile(TWENTYFIVE_PERCENTILE, cpuValues);
double q3 = CommonUtils.percentile(SEVENTYFIVE_PERCENTILE, cpuValues);
double median = CommonUtils.percentile(FIFTY_PERCENTILE, cpuValues);
// Find max and min
double max = Collections.max(cpuValues);
double min = Collections.min(cpuValues);
return new PlotData.UsageData(min, q1, median, q3, max, format);
} else {
return null;
PlotData.UsageData getUsageData(Map<Timestamp, IntervalResults> resultInRange, AnalyzerConstants.MetricName metricName) {
// stream through the results value and extract the CPU values
try {
if (metricName.equals(AnalyzerConstants.MetricName.cpuUsage)) {
JSONArray cpuValues = CostBasedRecommendationModel.getCPUUsageList(resultInRange);
LOGGER.debug("cpuValues : {}", cpuValues);
if (!cpuValues.isEmpty()) {
// Extract "max" values from cpuUsageList
List<Double> cpuMaxValues = new ArrayList<>();
List<Double> cpuMinValues = new ArrayList<>();
for (int i = 0; i < cpuValues.length(); i++) {
JSONObject jsonObject = cpuValues.getJSONObject(i);
double maxValue = jsonObject.getDouble(KruizeConstants.JSONKeys.MAX);
double minValue = jsonObject.getDouble(KruizeConstants.JSONKeys.MIN);
cpuMaxValues.add(maxValue);
cpuMinValues.add(minValue);
}
LOGGER.debug("cpuMaxValues : {}", cpuMaxValues);
LOGGER.debug("cpuMinValues : {}", cpuMinValues);
return getPercentileData(cpuMaxValues, cpuMinValues, resultInRange, metricName);
}

} else {
// loop through the results value and extract the memory values
CostBasedRecommendationModel costBasedRecommendationModel = new CostBasedRecommendationModel();
List<Double> memUsageMinList = new ArrayList<>();
List<Double> memUsageMaxList = new ArrayList<>();
boolean memDataAvailable = false;
for (IntervalResults intervalResults: resultInRange.values()) {
JSONObject jsonObject = costBasedRecommendationModel.calculateMemoryUsage(intervalResults);
if (!jsonObject.isEmpty()) {
memDataAvailable = true;
Double memUsageMax = jsonObject.getDouble(KruizeConstants.JSONKeys.MAX);
Double memUsageMin = jsonObject.getDouble(KruizeConstants.JSONKeys.MIN);
memUsageMaxList.add(memUsageMax);
memUsageMinList.add(memUsageMin);
}
}
LOGGER.debug("memValues Max : {}, Min : {}", memUsageMaxList, memUsageMinList);
if (memDataAvailable)
return getPercentileData(memUsageMaxList, memUsageMinList, resultInRange, metricName);
}
} catch (JSONException e) {
LOGGER.error("Exception occurred while extracting metric values: {}", e.getMessage());
}
return null;
}


private PlotData.UsageData getPercentileData(List<Double> metricValuesMax, List<Double> metricValuesMin, Map<Timestamp, IntervalResults> resultInRange, AnalyzerConstants.MetricName metricName) {
try {
if (!metricValuesMax.isEmpty()) {
double q1 = CommonUtils.percentile(TWENTYFIVE_PERCENTILE, metricValuesMax);
double q3 = CommonUtils.percentile(SEVENTYFIVE_PERCENTILE, metricValuesMax);
double median = CommonUtils.percentile(FIFTY_PERCENTILE, metricValuesMax);
// Find max and min
double max = Collections.max(metricValuesMax);
double min;
// check for non zero values
boolean nonZeroCheck = metricValuesMin.stream().noneMatch(value -> value.equals(0.0));
if (nonZeroCheck) {
min = Collections.min(metricValuesMin);
} else {
min = 0.0;
}

LOGGER.debug("q1 : {}, q3 : {}, median : {}, max : {}, min : {}", q1, q3, median, max, min);
String format = CostBasedRecommendationModel.getFormatValue(resultInRange, metricName);
return new PlotData.UsageData(min, q1, median, q3, max, format);
} else {
return null;
}
} catch (Exception e) {
LOGGER.error("Exception occurred while generating percentiles: {}", e.getMessage());
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -586,13 +586,14 @@ private boolean generateRecommendationsBasedOnTerms(ContainerData containerData,
mappedRecommendationForTerm.addNotification(recommendationNotification);
}
mappedRecommendationForTerm.setMonitoringStartTime(monitoringStartTime);
}
Terms.setDurationBasedOnTerm(containerData, mappedRecommendationForTerm, recommendationTerm);
if (KruizeDeploymentInfo.plots == true) {
if (null != monitoringStartTime) {
mappedRecommendationForTerm.setPlots(new PlotManager(containerData.getResults(), terms, monitoringStartTime, monitoringEndTime).generatePlots());
// generate plots when minimum data is available for the term
if (KruizeDeploymentInfo.plots) {
if (null != monitoringStartTime) {
mappedRecommendationForTerm.setPlots(new PlotManager(containerData.getResults(), terms, monitoringStartTime, monitoringEndTime).generatePlots());
}
}
}
Terms.setDurationBasedOnTerm(containerData, mappedRecommendationForTerm, recommendationTerm);
timestampRecommendation.setRecommendationForTermHashMap(recommendationTerm, mappedRecommendationForTerm);

}
Expand Down
Loading

0 comments on commit 8146907

Please sign in to comment.