org.evosuite.continuous.job.schedule.HistorySchedule Maven / Gradle / Ivy
/**
* Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite
* contributors
*
* This file is part of EvoSuite.
*
* EvoSuite is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* EvoSuite is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EvoSuite. If not, see .
*/
package org.evosuite.continuous.job.schedule;
import org.evosuite.continuous.job.JobDefinition;
import org.evosuite.continuous.job.JobScheduler;
import org.evosuite.continuous.project.ProjectStaticData;
import org.evosuite.continuous.project.ProjectStaticData.ClassInfo;
import org.evosuite.utils.LoggingUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
/**
*
* HistorySchedule class.
*
*
* @author José Campos
*/
public class HistorySchedule extends OneTimeSchedule {
private static double MODIFIED = 2.0;
private static double NOT_MODIFIED = 1.0;
public static final int COMMIT_IMPROVEMENT = 3;
public HistorySchedule(JobScheduler scheduler) {
super(scheduler);
}
@Override
protected List createScheduleOnce() {
ProjectStaticData data = this.scheduler.getProjectData();
int maximumBudgetPerCore = 60 * this.scheduler.getConfiguration().timeInMinutes;
// the total budget we need to choose how to allocate
int totalBudget =
maximumBudgetPerCore * this.scheduler.getConfiguration().getNumberOfUsableCores();
// a part of the budget is fixed, as each CUT needs a minimum of it
int minTime = 60 * this.scheduler.getConfiguration().minMinutesPerJob
* data.getTotalNumberOfTestableCUTs();
// this is what left from the minimum allocation, and that now we can
// choose how best to allocate
int extraTime = totalBudget - minTime;
// check how much time we can give extra for each branch in a CUT
int number_of_branches = data.getTotalNumberOfBranches();
double timePerBranch =
number_of_branches == 0.0 ? 0.0 : (double) extraTime / (double) number_of_branches;
List classesInfo = new ArrayList(data.getClassInfos());
// classes that have been changed first
Collections.sort(classesInfo, new Comparator() {
@Override
public int compare(ClassInfo a, ClassInfo b) {
if (a.hasChanged() && !b.hasChanged()) {
return -1;
} else if (!a.hasChanged() && b.hasChanged()) {
return 1;
}
// otherwise, get the most difficult classes first
return Integer.compare(b.numberOfBranches, a.numberOfBranches);
}
});
int totalLeftOver = 0;
int totalBudgetUsed = 0;
List jobs = new LinkedList();
for (ClassInfo c_info : classesInfo) {
if (!c_info.isTestable()) {
continue;
}
if (!c_info.hasChanged() && !c_info.isToTest()) {
LoggingUtils.getEvoLogger().info("- Skipping class " + c_info.getClassName()
+ " because it does not seem to be worth it");
continue;
}
double budget = 60.0 * scheduler.getConfiguration().minMinutesPerJob
+ (c_info.numberOfBranches * timePerBranch);
// classes that have been modified could get more time than 'normal' classes
budget *= c_info.hasChanged() ? HistorySchedule.MODIFIED : HistorySchedule.NOT_MODIFIED;
if (budget > maximumBudgetPerCore) {
/*
* Need to guarantee that no job has more than maximumBudgetPerCore regardless of number of
* cores
*/
totalLeftOver += (budget - maximumBudgetPerCore);
budget = maximumBudgetPerCore;
}
if ((totalBudgetUsed + budget) <= totalBudget) {
totalBudgetUsed += budget;
LoggingUtils.getEvoLogger()
.info("+ Going to generate test cases for " + c_info.getClassName()
+ " using a time budget of " + budget + " seconds. Status of it ["
+ (c_info.hasChanged() ? "modified" : "not modified") + "]");
jobs.add(new JobDefinition((int) budget,
this.scheduler.getConfiguration().getConstantMemoryPerJob(), c_info.getClassName(), 0,
null, null));
} else {
LoggingUtils.getEvoLogger()
.info("- There is not enough time budget to test " + c_info.getClassName()
+ ". Status of it [" + (c_info.hasChanged() ? "modified" : "not modified") + "]");
// mark this CUT as not tested. this is useful to later on distinguish
// classes that EvoSuite failed to generate test cases and classes that
// we didn't actually create any job for
c_info.isToTest(false);
}
}
totalLeftOver += (totalBudget - totalBudgetUsed);
/*
* do we still have some more budget to allocate? and is it less
* than totalBudget? (because if it is equal to totalBudget, means
* that we have skipped all classes, and therefore there is not point
* of distributing left over budget as all classes will be skipped)
*/
if (totalLeftOver > 0 && totalLeftOver < totalBudget) {
LoggingUtils.getEvoLogger().info("Distributing left budget (" + totalLeftOver + ")");
distributeExtraBudgetEvenly(jobs, totalLeftOver, maximumBudgetPerCore);
}
return jobs;
}
}