
org.btrplace.scheduler.choco.constraint.migration.CMinMigrations Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scheduler-choco Show documentation
Show all versions of scheduler-choco Show documentation
Implementation of the VM scheduler that use
the Constraint Programming solver CHOCO to compute solutions.
The newest version!
/*
* Copyright 2023 The BtrPlace Authors. All rights reserved.
* Use of this source code is governed by a LGPL-style
* license that can be found in the LICENSE.txt file.
*/
package org.btrplace.scheduler.choco.constraint.migration;
import gnu.trove.map.TObjectIntMap;
import org.btrplace.model.Instance;
import org.btrplace.model.Mapping;
import org.btrplace.model.Model;
import org.btrplace.model.VM;
import org.btrplace.model.constraint.MinMigrations;
import org.btrplace.model.view.ShareableResource;
import org.btrplace.scheduler.SchedulerException;
import org.btrplace.scheduler.choco.Parameters;
import org.btrplace.scheduler.choco.ReconfigurationProblem;
import org.btrplace.scheduler.choco.Slice;
import org.btrplace.scheduler.choco.constraint.CObjective;
import org.btrplace.scheduler.choco.constraint.mttr.*;
import org.btrplace.scheduler.choco.constraint.mttr.load.BiggestDimension;
import org.btrplace.scheduler.choco.transition.RelocatableVM;
import org.btrplace.scheduler.choco.transition.Transition;
import org.btrplace.scheduler.choco.transition.VMTransition;
import org.btrplace.scheduler.choco.view.CShareableResource;
import org.chocosolver.solver.Solver;
import org.chocosolver.solver.search.strategy.Search;
import org.chocosolver.solver.search.strategy.selectors.values.IntDomainMax;
import org.chocosolver.solver.search.strategy.selectors.values.IntDomainMin;
import org.chocosolver.solver.search.strategy.selectors.values.IntValueSelector;
import org.chocosolver.solver.search.strategy.selectors.variables.FirstFail;
import org.chocosolver.solver.search.strategy.strategy.AbstractStrategy;
import org.chocosolver.solver.search.strategy.strategy.IntStrategy;
import org.chocosolver.solver.search.strategy.strategy.StrategiesSequencer;
import org.chocosolver.solver.variables.IntVar;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Implements {@link MinMigrations}.
* Currently, same heuristics that with MinMttr but a different objective
*
* @author Fabien Hermenier
*/
public class CMinMigrations implements CObjective {
private boolean costActivated = false;
private boolean useResources = false;
private ReconfigurationProblem rp;
private IntVar cost;
/**
* Make a new objective.
* @param m the user-side objective.
*/
public CMinMigrations(@SuppressWarnings("unused") MinMigrations m) {
// Required: this is used by the reflection API to instantiate this object.
}
public CMinMigrations() {
this(null);
}
@Override
public boolean inject(Parameters ps, ReconfigurationProblem p) throws SchedulerException {
this.rp = p;
costActivated = false;
cost = rp.getModel().intVar(rp.makeVarLabel("#migs"), 0, Integer.MAX_VALUE / 100, true);
rp.setObjective(true, cost);
injectPlacementHeuristic(p, ps, cost);
return true;
}
private void injectPlacementHeuristic(ReconfigurationProblem p, Parameters ps, IntVar cost) {
List rcs = rp.getSourceModel().getViews().stream()
.filter(ShareableResource.class::isInstance)
.map(v -> (CShareableResource) rp.getRequiredView(v.getIdentifier()))
.collect(Collectors.toList());
useResources = !rcs.isEmpty();
Model mo = p.getSourceModel();
Mapping map = mo.getMapping();
OnStableNodeFirst schedHeuristic = new OnStableNodeFirst(p);
//Get the VMs to place
Set onBadNodes = new HashSet<>(p.getManageableVMs());
//Get the VMs that runs and have a pretty low chances to move
Set onGoodNodes = map.getRunningVMs(map.getOnlineNodes());
onGoodNodes.removeAll(onBadNodes);
List goodActions = p.getVMActions(onGoodNodes);
List badActions = p.getVMActions(onBadNodes);
Solver s = p.getSolver();
//Get the VMs to move for exclusion issue
Set vmsToExclude = new HashSet<>(p.getManageableVMs());
for (Iterator ite = vmsToExclude.iterator(); ite.hasNext(); ) {
VM vm = ite.next();
if (!(map.isRunning(vm) && p.getFutureRunningVMs().contains(vm))) {
ite.remove();
}
}
List> strategies = new ArrayList<>();
Map pla = VMPlacementUtils.makePlacementMap(p);
if (!vmsToExclude.isEmpty()) {
List actions = new LinkedList<>();
//Get all the involved slices
for (VM vm : vmsToExclude) {
if (p.getFutureRunningVMs().contains(vm)) {
actions.add(p.getVMAction(vm));
}
}
placeVMs(ps, strategies, actions, schedHeuristic, pla);
}
TObjectIntMap costs = CShareableResource.getWeights(rp, rcs);
badActions.sort((v2, v1) -> costs.get(v1.getVM()) - costs.get(v2.getVM()));
goodActions.sort((v2, v1) -> costs.get(v1.getVM()) - costs.get(v2.getVM()));
placeVMs(ps, strategies, badActions, schedHeuristic, pla);
placeVMs(ps, strategies, goodActions, schedHeuristic, pla);
//Reinstantations. Try to reinstantiate first
List migs = new ArrayList<>();
for (VMTransition t : rp.getVMActions()) {
if (t instanceof RelocatableVM) {
migs.add(((RelocatableVM) t).getRelocationMethod());
}
}
strategies.add(
Search.intVarSearch(
new FirstFail(rp.getModel()), new IntDomainMax(), migs.toArray(new IntVar[migs.size()]))
);
if (!p.getNodeActions().isEmpty()) {
//Boot some nodes if needed
IntVar[] starts = p.getNodeActions().stream().map(Transition::getStart).toArray(IntVar[]::new);
strategies.add(new IntStrategy(starts, new FirstFail(rp.getModel()), new IntDomainMin()));
//Fix the duration. The side effect will be that states will be fixed as well
//with the objective to not do un-necessary actions
IntVar[] durations = p.getNodeActions().stream().map(Transition::getDuration).toArray(IntVar[]::new);
strategies.add(new IntStrategy(durations, new FirstFail(rp.getModel()), new IntDomainMin()));
}
postCostConstraints();
///SCHEDULING PROBLEM
MovementGraph gr = new MovementGraph(rp);
IntVar[] starts = dSlices(rp.getVMActions()).map(Slice::getStart).filter(v -> !v.isInstantiated()).toArray(IntVar[]::new);
strategies.add(new IntStrategy(starts, new StartOnLeafNodes(rp, gr), new IntDomainMin()));
strategies.add(new IntStrategy(schedHeuristic.getScope(), schedHeuristic, new IntDomainMin()));
IntVar[] ends = rp.getVMActions().stream().map(Transition::getEnd).filter(v -> !v.isInstantiated()).toArray(IntVar[]::new);
strategies.add(Search.intVarSearch(new MyInputOrder<>(s), new IntDomainMin(), ends));
//At this stage only it matters to plug the cost constraints
strategies.add(new IntStrategy(new IntVar[]{p.getEnd(), cost}, new MyInputOrder<>(s, this), new IntDomainMin()));
s.setSearch(new StrategiesSequencer(s.getEnvironment(), strategies.toArray(new AbstractStrategy[strategies.size()])));
}
/*
* Try to place the VMs associated on the actions in a random node while trying first to stay on the current node
*/
private void placeVMs(Parameters ps, List> strategies, List actions, OnStableNodeFirst schedHeuristic, Map map) {
IntValueSelector rnd = new WorstFit(map, rp, new BiggestDimension());
if (!useResources) {
rnd = new RandomVMPlacement(rp, map, true, ps.getRandomSeed());
}
IntVar[] hosts = dSlices(actions).map(Slice::getHoster).filter(v -> !v.isInstantiated()).toArray(IntVar[]::new);
if (hosts.length > 0) {
strategies.add(new IntStrategy(hosts, new HostingVariableSelector(rp.getModel(), schedHeuristic), rnd));
}
}
@Override
public Set getMisPlacedVMs(Instance i) {
return Collections.emptySet();
}
private static Stream dSlices(List l) {
return l.stream().map(VMTransition::getDSlice).filter(Objects::nonNull);
}
@Override
public void postCostConstraints() {
if (!costActivated) {
costActivated = true;
rp.getLogger().debug("Post the cost-oriented constraints");
List stays = new ArrayList<>();
for (VMTransition t : rp.getVMActions()) {
if (t instanceof RelocatableVM && rp.getManageableVMs().contains(t.getVM())) {
stays.add(t.getDuration());
}
}
//With choco 4.0.1, we cannot post a simple sum() constraint due to hardcore
//simplification it made. So we bypass the optimisation phase and post the propagator
rp.getModel().post(rp.getModel().sum(stays.toArray(new IntVar[0]), "=", cost));
}
}
@Override
public String toString() {
return "minMigrations";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy