
org.btrplace.scheduler.choco.runner.single.InstanceSolverRunner Maven / Gradle / Ivy
/*
* Copyright (c) 2016 University Nice Sophia Antipolis
*
* This file is part of btrplace.
* This library 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 of the License, or (at your option) any later version.
*
* This library 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 General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
package org.btrplace.scheduler.choco.runner.single;
import org.btrplace.model.Instance;
import org.btrplace.model.Model;
import org.btrplace.model.Node;
import org.btrplace.model.VM;
import org.btrplace.model.constraint.*;
import org.btrplace.plan.ReconfigurationPlan;
import org.btrplace.scheduler.SchedulerException;
import org.btrplace.scheduler.choco.DefaultReconfigurationProblemBuilder;
import org.btrplace.scheduler.choco.Parameters;
import org.btrplace.scheduler.choco.ReconfigurationProblem;
import org.btrplace.scheduler.choco.constraint.ChocoConstraint;
import org.btrplace.scheduler.choco.constraint.ChocoMapper;
import org.btrplace.scheduler.choco.runner.SolutionStatistics;
import org.btrplace.scheduler.choco.runner.SolvingStatistics;
import org.btrplace.scheduler.choco.view.ChocoView;
import org.btrplace.scheduler.choco.view.ChocoViews;
import org.chocosolver.solver.Cause;
import org.chocosolver.solver.exception.ContradictionException;
import org.chocosolver.solver.search.loop.monitors.IMonitorSolution;
import org.chocosolver.solver.search.measure.IMeasures;
import org.chocosolver.solver.search.solution.Solution;
import org.chocosolver.solver.trace.Chatterbox;
import java.util.*;
import java.util.concurrent.Callable;
/**
* A basic solver that solve a whole instance.
* Use {@link #call()} to compute a solution
*
* @author Fabien Hermenier
*/
public class InstanceSolverRunner implements Callable {
private Parameters params;
private ReconfigurationProblem rp;
private Collection cstrs;
private OptConstraint obj;
private Model origin;
private Instance instance;
private SingleRunnerStatistics stats;
/**
* Choco version of the constraints.
*/
private List cConstraints;
private List views;
/**
* Make a new runner.
*
* @param ps the parameters for the solving process
* @param i the instance to solve
*/
public InstanceSolverRunner(Parameters ps, Instance i) {
instance = i;
cstrs = i.getSatConstraints();
obj = i.getOptConstraint();
origin = i.getModel();
params = ps;
}
@Override
public SolvingStatistics call() throws SchedulerException {
stats = new SingleRunnerStatistics(params, instance, System.currentTimeMillis());
rp = null;
//Build the core problem
long d = -System.currentTimeMillis();
rp = buildRP();
d += System.currentTimeMillis();
stats.setCoreBuildDuration(d);
stats.setNbManagedVMs(rp.getManageableVMs().size());
//Customize the core problem
d = -System.currentTimeMillis();
if (!specialise()) {
stats.setSpecialisationDuration(d);
return getStatistics();
}
d += System.currentTimeMillis();
stats.setSpecialisationDuration(d);
//statistics
stats.setMeasures(rp.getSolver().getMeasures().duplicate());
rp.getLogger().debug(stats.toString());
//The solution monitor to store the measures at each solution
rp.getSolver().plugMonitor((IMonitorSolution) () -> {
Solution solution = new Solution();
solution.record(rp.getSolver());
ReconfigurationPlan plan = rp.buildReconfigurationPlan(solution, origin);
views.forEach(v -> v.insertActions(rp, solution, plan));
IMeasures m = rp.getSolver().getMeasures().duplicate();
stats.addSolution(new SolutionStatistics(m, plan));
});
setVerbosity();
//The actual solving process
rp.solve(params.getTimeLimit(), params.doOptimize());
return getStatistics();
}
private void setVerbosity() {
if (params.getVerbosity() >=1) {
Chatterbox.showSolutions(rp.getSolver());
}
if (params.getVerbosity() >= 2) {
//every second
Chatterbox.showStatisticsDuringResolution(rp.getSolver(), 1000);
}
if (params.getVerbosity() >= 3) {
Chatterbox.showDecisions(rp.getSolver());
}
if (params.getVerbosity() >= 4) {
Chatterbox.showContradiction(rp.getSolver());
}
}
private boolean specialise() {
//Resolve the view dependencies, add them and inject them
views = ChocoViews.resolveDependencies(origin, views, rp.getViews());
views.forEach(rp::addView);
return views.stream().allMatch(v -> v.inject(params, rp)) &&
cConstraints.stream().allMatch(c -> c.inject(params, rp)) &&
views.stream().allMatch(v -> v.beforeSolve(rp));
}
private ReconfigurationProblem buildRP() throws SchedulerException {
//Build the RP. As VM state management is not possible
//We extract VM-state related constraints first.
//For other constraint, we just create the right choco constraint
Set toRun = new HashSet<>();
Set toForge = new HashSet<>();
Set toKill = new HashSet<>();
Set toSleep = new HashSet<>();
cConstraints = new ArrayList<>();
for (SatConstraint cstr : cstrs) {
checkNodesExistence(origin, cstr.getInvolvedNodes());
//We cannot check for VMs that are going to the ready state
//as they are not forced to be a part of the initial model
//(when they will be forged)
if (!(cstrs instanceof Ready)) {
checkUnknownVMsInMapping(origin, cstr.getInvolvedVMs());
}
if (cstr instanceof Running) {
toRun.addAll(cstr.getInvolvedVMs());
} else if (cstr instanceof Sleeping) {
toSleep.addAll(cstr.getInvolvedVMs());
} else if (cstr instanceof Ready) {
checkUnknownVMsInMapping(origin, cstr.getInvolvedVMs());
toForge.addAll(cstr.getInvolvedVMs());
} else if (cstr instanceof Killed) {
checkUnknownVMsInMapping(origin, cstr.getInvolvedVMs());
toKill.addAll(cstr.getInvolvedVMs());
}
cConstraints.add(build(cstr));
}
cConstraints.add(build(obj));
views = makeViews();
DefaultReconfigurationProblemBuilder rpb = new DefaultReconfigurationProblemBuilder(origin)
.setNextVMsStates(toForge, toRun, toSleep, toKill)
.setParams(params);
if (params.doRepair()) {
Set toManage = new HashSet<>();
cConstraints.forEach(c -> toManage.addAll(c.getMisPlacedVMs(instance)));
views.forEach(v -> toManage.addAll(v.getMisPlacedVMs(instance)));
rpb.setManageableVMs(toManage);
}
//The core views have been instantiated and available through rp.getViews()
//Set the maximum duration
ReconfigurationProblem p = rpb.build();
try {
p.getEnd().updateUpperBound(params.getMaxEnd(), Cause.Null);
} catch (ContradictionException e) {
p.getLogger().error("Unable to restrict the maximum plan duration to " + params.getMaxEnd(), e);
return null;
}
return p;
}
private List makeViews() throws SchedulerException {
List l = new ArrayList<>();
ChocoMapper mapper = params.getMapper();
origin.getViews().stream().filter(v -> mapper.viewHasMapping(v.getClass())).forEach(v -> l.add(mapper.get(v)));
return l;
}
/**
* Build a sat constraint
*
* @param cstr the model-side constraint
* @return the solver-side constraint
* @throws SchedulerException if the process failed
*/
private ChocoConstraint build(Constraint cstr) throws SchedulerException {
ChocoMapper mapper = params.getMapper();
ChocoConstraint cc = mapper.get(cstr);
if (cc == null) {
throw new SchedulerException(origin, "No implementation mapped to '" + cstr.getClass().getSimpleName() + "'");
}
return cc;
}
private static void checkUnknownVMsInMapping(Model m, Collection vms) throws SchedulerException {
for (VM v : vms) {
//This loop prevent from a useless allocation of memory when there is no issue
if (!m.getMapping().contains(v)) {
Set unknown = new HashSet<>(vms);
unknown.removeAll(m.getMapping().getAllVMs());
throw new SchedulerException(m, "Unknown VMs: " + unknown);
}
}
}
/**
* Check for the existence of nodes in a model
*
* @param mo the model to check
* @param ns the nodes to check
* @throws org.btrplace.scheduler.SchedulerException if at least one of the given nodes is not in the RP.
*/
private static void checkNodesExistence(Model mo, Collection ns) throws SchedulerException {
for (Node node : ns) {
if (!mo.getMapping().contains(node)) {
throw new SchedulerException(mo, "Unknown node '" + node + "'");
}
}
}
/**
* Get the statistics about the solving process.
*
* @return the statistics
*/
public SingleRunnerStatistics getStatistics() {
IMeasures m = rp.getSolver().getMeasures().duplicate();
stats.setMeasures(m);
stats.setCompleted(!rp.getSolver().hasReachedLimit());
return stats;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy