-
Notifications
You must be signed in to change notification settings - Fork 843
unified architecture v0.1 #418
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
a9b1828
bcce807
c77bfb2
8acff29
f94a2b3
4f76985
2715115
27c6bbf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package com.linkedin.drelephant.tuning; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import org.apache.log4j.Logger; | ||
|
|
||
|
|
||
| public abstract class AbstractAlgorithmManager implements Manager { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Algorithm=>Tuning/TuningType? We are using the term tuning type to differentiate between HBT/OBT. OBT will then have further algorithms. Keep the code consistent with that terminology?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. agreed . |
||
| protected final String JSON_CURRENT_POPULATION_KEY = "current_population"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As the generation of param for each job is different, we can have a thread pool here, in the baseline manager, and in fitness compute manager as well to parallelize execution as much as possible.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes we are planning to have ThreadPool for each manager . That would be in nxt version |
||
| private final Logger logger = Logger.getLogger(getClass()); | ||
| protected abstract List<JobTuningInfo> detectJobsForParameterGeneration(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move the method declaration below variable declaration. |
||
| protected ExecutionEngine _executionEngine; | ||
|
|
||
| protected Boolean generateParameters(List<JobTuningInfo> jobsForParameterSuggestion){ | ||
| List<JobTuningInfo> updatedJobTuningInfoList = new ArrayList<JobTuningInfo>(); | ||
| for (JobTuningInfo jobTuningInfo : jobsForParameterSuggestion) { | ||
| JobTuningInfo newJobTuningInfo = generateParamSet(jobTuningInfo); | ||
| updatedJobTuningInfoList.add(newJobTuningInfo); | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
|
|
||
| protected abstract JobTuningInfo generateParamSet(JobTuningInfo jobTuningInfo); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As these abstract methods will have to be implemented, write a javadoc in detail explaining what each abstract method is supposed to do. Good for maintainability. |
||
|
|
||
|
|
||
| protected abstract Boolean updateDatabase(List<JobTuningInfo> tuningJobDefinitions); | ||
|
|
||
| public final Boolean execute() { | ||
| logger.info("Executing Tuning Algorithm"); | ||
| Boolean parameterGenerationDone = false, databaseUpdateDone = false, updateMetricsDone = false; | ||
| List<JobTuningInfo> jobTuningInfo = detectJobsForParameterGeneration(); | ||
| if (jobTuningInfo != null && jobTuningInfo.size() >= 1) { | ||
| logger.info("Generating Parameters "); | ||
| parameterGenerationDone = generateParameters(jobTuningInfo); | ||
| } | ||
| if (parameterGenerationDone) { | ||
| logger.info("Updating Database"); | ||
| databaseUpdateDone = updateDatabase(jobTuningInfo); | ||
| } | ||
| logger.info("Param Generation Done"); | ||
| return databaseUpdateDone; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| package com.linkedin.drelephant.tuning; | ||
|
|
||
| import com.avaje.ebean.Ebean; | ||
| import com.avaje.ebean.SqlRow; | ||
| import com.linkedin.drelephant.mapreduce.heuristics.CommonConstantsHeuristic; | ||
| import java.util.List; | ||
| import models.TuningJobDefinition; | ||
| import org.apache.commons.io.FileUtils; | ||
| import org.apache.log4j.Logger; | ||
| import controllers.AutoTuningMetricsController; | ||
|
|
||
|
|
||
| public abstract class AbstractBaselineManager implements Manager { | ||
| protected final String BASELINE_EXECUTION_COUNT = "baseline.execution.count"; | ||
| protected Integer NUM_JOBS_FOR_BASELINE_DEFAULT = 30; | ||
| protected String baseLineCalculationSQL = | ||
| "SELECT AVG(resource_used) AS resource_used, AVG(execution_time) AS execution_time FROM " | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could use the java ebeans rather than hard coding the sql statements here. You may refer to other parts of Dr. Elephant for reference. |
||
| + "(SELECT job_exec_id, SUM(resource_used/(1024 * 3600)) AS resource_used, " | ||
| + "SUM((finish_time - start_time - total_delay)/(1000 * 60)) AS execution_time, " | ||
| + "MAX(start_time) AS start_time " + "FROM yarn_app_result WHERE job_def_id=:jobDefId " | ||
| + "GROUP BY job_exec_id " + "ORDER BY start_time DESC " + "LIMIT :num) temp"; | ||
| protected String avgInputSizeSQL = "SELECT AVG(inputSizeInBytes) as avgInputSizeInMB FROM " | ||
| + "(SELECT job_exec_id, SUM(cast(value as decimal)) inputSizeInBytes, MAX(start_time) AS start_time " | ||
| + "FROM yarn_app_result yar INNER JOIN yarn_app_heuristic_result yahr " + "ON yar.id=yahr.yarn_app_result_id " | ||
| + "INNER JOIN yarn_app_heuristic_result_details yahrd " + "ON yahr.id=yahrd.yarn_app_heuristic_result_id " | ||
| + "WHERE job_def_id=:jobDefId AND yahr.heuristic_name='" + CommonConstantsHeuristic.MAPPER_SPEED + "' " | ||
| + "AND yahrd.name='" + CommonConstantsHeuristic.TOTAL_INPUT_SIZE_IN_MB + "' " | ||
| + "GROUP BY job_exec_id ORDER BY start_time DESC LIMIT :num ) temp"; | ||
| private final Logger logger = Logger.getLogger(getClass()); | ||
| protected Integer _numJobsForBaseline = null; | ||
|
|
||
| /* | ||
| Execute the whole logic for Base line Computing | ||
| 1) Get the jobs for which Baseline have to be calculated | ||
| 2) Calculate the baseline | ||
| 3) Update the base line | ||
| 4) Update the metrics . | ||
| */ | ||
| @Override | ||
| public final Boolean execute() { | ||
| logger.info("Executing BaseLine"); | ||
| Boolean baseLineComputationDone = false, databaseUpdateDone = false, updateMetricsDone = false; | ||
| List<TuningJobDefinition> tuningJobDefinitions = detectJobsForBaseLineComputation(); | ||
| if (tuningJobDefinitions != null && tuningJobDefinitions.size() >= 1) { | ||
| logger.info("Computing BaseLine"); | ||
| baseLineComputationDone = calculateBaseLine(tuningJobDefinitions); | ||
| } | ||
| if (baseLineComputationDone) { | ||
| logger.info("Updating Database"); | ||
| databaseUpdateDone = updateDataBase(tuningJobDefinitions); | ||
| } | ||
| if (databaseUpdateDone) { | ||
| logger.info("Updating Metrics"); | ||
| updateMetricsDone = updateMetrics(tuningJobDefinitions); | ||
| } | ||
| logger.info("Baseline Done"); | ||
| return updateMetricsDone; | ||
| } | ||
|
|
||
| /** | ||
| * Fetches the jobs whose baseline is to be computed. | ||
| * This is done by returning the jobs with null average resource usage | ||
| * @return List of jobs whose baseline needs to be added | ||
| */ | ||
|
|
||
| protected abstract List<TuningJobDefinition> detectJobsForBaseLineComputation(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a javadoc here |
||
|
|
||
| /** | ||
| * Adds baseline metric values for a job | ||
| * @param tuningJobDefinitions Job for which baseline is to be computed | ||
| */ | ||
|
|
||
| protected Boolean calculateBaseLine(List<TuningJobDefinition> tuningJobDefinitions) { | ||
| for (TuningJobDefinition tuningJobDefinition : tuningJobDefinitions) { | ||
| try { | ||
| logger.info("Computing and updating baseline metric values for job: " + tuningJobDefinition.job.jobName); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tuning_job_definition has a column named tuningAlgorithm which is meant for PSO/IPSO. While with only two tuning types i.e. HBT/OBT as of now, we can probably use this table for HBT when tuningAlgorithm is NULL. But we should ideally have a column for tuning type to make the code extensible for a new tuning type in future (say ML based).Same goes for other tables as well |
||
| logger.debug("Running query for baseline computation " + baseLineCalculationSQL); | ||
| SqlRow baseline = Ebean.createSqlQuery(baseLineCalculationSQL) | ||
| .setParameter("jobDefId", tuningJobDefinition.job.jobDefId) | ||
| .setParameter("num", _numJobsForBaseline) | ||
| .findUnique(); | ||
| Double avgResourceUsage = 0D; | ||
| Double avgExecutionTime = 0D; | ||
| avgResourceUsage = baseline.getDouble("resource_used"); | ||
| avgExecutionTime = baseline.getDouble("execution_time"); | ||
| tuningJobDefinition.averageExecutionTime = avgExecutionTime; | ||
| tuningJobDefinition.averageResourceUsage = avgResourceUsage; | ||
| tuningJobDefinition.averageInputSizeInBytes = getAvgInputSizeInBytes(tuningJobDefinition.job.jobDefId); | ||
| logger.debug( | ||
| "Baseline metric values: Average resource usage=" + avgResourceUsage + " and Average execution time=" | ||
| + avgExecutionTime); | ||
| } catch (Exception e) { | ||
| logger.error("Error in computing baseline for job: " + tuningJobDefinition.job.jobName, e); | ||
| return false; | ||
| } | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the average input size in bytes of a job (over last _numJobsForBaseline executions) | ||
| * @param jobDefId job definition id of the job | ||
| * @return average input size in bytes as long | ||
| */ | ||
| private Long getAvgInputSizeInBytes(String jobDefId) { | ||
| logger.debug("Running query for average input size computation " + avgInputSizeSQL); | ||
|
|
||
| SqlRow baseline = Ebean.createSqlQuery(avgInputSizeSQL) | ||
| .setParameter("jobDefId", jobDefId) | ||
| .setParameter("num", _numJobsForBaseline) | ||
| .findUnique(); | ||
| Double avgInputSizeInBytes = baseline.getDouble("avgInputSizeInMB") * FileUtils.ONE_MB; | ||
| return avgInputSizeInBytes.longValue(); | ||
| } | ||
|
|
||
| /** | ||
| * This method update database for auto tuning monitoring for baseline computation | ||
| * @param tuningJobDefinitions | ||
| */ | ||
| protected Boolean updateDataBase(List<TuningJobDefinition> tuningJobDefinitions) { | ||
| for (TuningJobDefinition tuningJobDefinition : tuningJobDefinitions) { | ||
| tuningJobDefinition.update(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if an exception is thrown during update? If it's taken up in next run, returning true from this method and checking it in caller is inconsequential
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes , agreed. Actually I return true for the sake of completeness in most of the methods. I am adding exception handling now in all those cases. |
||
| logger.info("Updated baseline metric value for job: " + tuningJobDefinition.job.jobName); | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * This method update metrics for auto tuning monitoring for baseline computation | ||
| * @param tuningJobDefinitions | ||
| */ | ||
|
|
||
| protected Boolean updateMetrics(List<TuningJobDefinition> tuningJobDefinitions) { | ||
| int baselineComputeWaitJobs = 0; | ||
| for (TuningJobDefinition tuningJobDefinition : tuningJobDefinitions) { | ||
| if (tuningJobDefinition.averageResourceUsage == null) { | ||
| baselineComputeWaitJobs++; | ||
| } else { | ||
| AutoTuningMetricsController.markBaselineComputed(); | ||
| } | ||
| } | ||
| AutoTuningMetricsController.setBaselineComputeWaitJobs(baselineComputeWaitJobs); | ||
| return true; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. true is always returned. Any need for this method to return boolean?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again if exception is there , it should return false . Changed the code |
||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Remove the commented code