/* * Copyright (c) Fabien Hermenier * * This file is part of Entropy. * * Entropy 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. * * Entropy 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 Entropy. If not, see <http://www.gnu.org/licenses/>. */ package entropy.plan.choco; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import entropy.configuration.Configuration; import entropy.configuration.ConfigurationsException; import entropy.configuration.ManagedElementSet; import entropy.configuration.Node; import entropy.configuration.VirtualMachine; import entropy.plan.CustomizablePlannerModule; import entropy.plan.Plan; import entropy.plan.PlanException; import entropy.plan.SolutionStatistics; import entropy.plan.SolvingStatistics; import entropy.plan.TimedReconfigurationPlan; import entropy.plan.TimedReconfigurationPlans; import entropy.plan.TimedReconfigurationPlansException; import entropy.plan.durationEvaluator.DurationEvaluator; import entropy.plan.partitioner.OtherPartitioning; import entropy.plan.partitioner.Partition; import entropy.plan.partitioner.PartitioningException; import entropy.plan.partitioner.PlanPartitioner; import entropy.plan.partitioner.PlanThread; import entropy.vjob.Ban; import entropy.vjob.Fence; import entropy.vjob.PlacementConstraint; import entropy.vjob.Spread; import entropy.vjob.VJob; /** * @author Fabien Hermenier */ public class CustomizableSplitablePlannerModule extends CustomizablePlannerModule { private boolean repair = true; private ArrayList<PlanThread> subs; private ArrayList<SolvingStatistics> solvingStatistics; private ArrayList<List<SolutionStatistics>> solutionStatistics; public static enum PartitioningMode {none, sequential, parallel} private PartitioningMode partMode = PartitioningMode.none; public CustomizableSplitablePlannerModule(DurationEvaluator d) { super(d); subs = new ArrayList<PlanThread>(); solutionStatistics = new ArrayList<List<SolutionStatistics>>(); solvingStatistics = new ArrayList<SolvingStatistics>(); } @Override public TimedReconfigurationPlan compute(Configuration src, ManagedElementSet<VirtualMachine> run, ManagedElementSet<VirtualMachine> wait, ManagedElementSet<VirtualMachine> sleep, ManagedElementSet<VirtualMachine> stop, ManagedElementSet<Node> on, ManagedElementSet<Node> off, List<VJob> queue) throws PlanException { subs.clear(); solutionStatistics.clear(); solvingStatistics.clear(); List<Partition> parts = null; int nbConstraints = 0; for (VJob v : queue) { nbConstraints += v.getConstraints().size(); } if (nbConstraints == 0 || partMode == PartitioningMode.none) { if (nbConstraints == 0) { logger.debug("No partitioning as there is no placement constraints"); } else { logger.debug("No partitioning allowed"); } parts = new LinkedList<Partition>(); Partition p = new Partition(); p.getNodes().addAll(src.getAllNodes()); p.getVirtualMachines().addAll(src.getAllVirtualMachines()); for (VJob v : queue) { if (v.getConstraints() != null) { p.getConstraints().addAll(v.getConstraints()); } } parts.add(p); } else { PlanPartitioner partitioner = new OtherPartitioning(src); //We have to push all the constraints, expect fences at the end List<PlacementConstraint> cs = new LinkedList<PlacementConstraint>(); for (VJob v : queue) { for (PlacementConstraint c : v.getConstraints()) { if (!(c instanceof Fence)) { cs.add(c); } else { //if (c instanceof Fence) { try { Plan.logger.info("Part wrt. " + c + " " + ((Fence) c).getNodes().definition()); partitioner.part((Fence) c); } catch (PartitioningException e) { Plan.logger.error(e.getMessage(), e); } } } } for (PlacementConstraint c : cs) { try { if (c instanceof Spread) { partitioner.part((Spread) c); } else if (c instanceof Ban) { partitioner.part((Ban) c); } /*else if (c instanceof OneOf) { partitioner.part((OneOf) c); } else { Plan.logger.warn("Unsupported constraint: " + c); } */ } catch (PartitioningException e) { Plan.logger.error(e.getMessage(), e); } } parts = partitioner.getResultingPartitions(); logger.debug("Problem was splitted into " + parts.size() + ". Solving method: " + partMode); } for (Partition p : parts) { try { PlanThread t = new PlanThread(p, getDurationEvaluator(), src, run, wait, sleep, stop, on, off); t.setTimeout(getTimeLimit()); t.setRepairMode(repair); subs.add(t); t.start(); if (partMode == PartitioningMode.none || partMode == PartitioningMode.sequential) { try { t.join(); System.gc(); //Clear memory please } catch (InterruptedException e) { Plan.logger.error(e.getMessage(), e); } } } catch (ConfigurationsException e) { Plan.logger.error(e.getMessage(), e); } } if (partMode == PartitioningMode.parallel) { for (PlanThread t : subs) { try { t.join(); } catch (InterruptedException e) { Plan.logger.error(e.getMessage(), e); } } } StringBuilder fullEx = new StringBuilder(); List<TimedReconfigurationPlan> ress = new LinkedList<TimedReconfigurationPlan>(); for (PlanThread t : subs) { if (t.getException() == null) { TimedReconfigurationPlan r = t.getResultingPlan(); if (r != null) { ress.add(r); } } else { fullEx.append(t.getRunID() + ": " + t.getException()); } } if (fullEx.length() > 0) { throw new PlanException(fullEx.toString()); } try { TimedReconfigurationPlan full = TimedReconfigurationPlans.merge(ress); return full; } catch (TimedReconfigurationPlansException e) { logger.error(e.getMessage(), e); } return null; } /** * Get the solving statistics. * If there is only one sub problem, all the statistics are * returned. Otherwise, the last statistics of each sub problem are merged: * Opened nodes, backtracks and objective values are summed while the maximum * timecount is returned. * * @return a list of statistics that may be empty */ @Override public List<SolutionStatistics> getSolutionsStatistics() { //We retrieve the last statistics of each model, sum counters //and the maximum timecount if (subs.size() == 1) { return subs.get(0).getSolutionsStatistics(); } else { int nbNodes = 0; int nbBacktracks = 0; int objectives = 0; int timecount = 0; boolean timeout = false; for (PlanThread t : subs) { SolutionStatistics st = t.getSolutionsStatistics().get(t.getSolutionsStatistics().size() - 1); nbNodes += st.getNbNodes(); nbBacktracks += st.getNbBacktracks(); timeout |= st.hasReachedTimeout(); objectives += st.getObjective(); if (st.getTimeCount() > timecount) { timecount = st.getTimeCount(); } } List<SolutionStatistics> res = new ArrayList<SolutionStatistics>(); res.add(new SolutionStatistics(nbNodes, nbBacktracks, timecount, timeout, objectives)); return res; } } @Override public SolvingStatistics getSolvingStatistics() { int nbNodes = 0; int nbBacktracks = 0; boolean timeout = false; int timecount = 0; for (PlanThread t : subs) { SolvingStatistics s = t.getSolvingStatistics(); nbNodes += s.getNbNodes(); nbBacktracks += s.getNbBacktracks(); timeout |= s.hasReachedTimeout(); if (s.getTimeCount() > timecount) { timecount = s.getTimeCount(); } } return new SolvingStatistics(nbNodes, nbBacktracks, timecount, timeout); } public void setPartitioningMode(PartitioningMode m) { this.partMode = m; } public PartitioningMode getPartitioningMode() { return this.partMode; } /** * Use the repair mode. * * @param b {@code true} to use the repair mode */ public void setRepairMode(boolean b) { this.repair = b; } public boolean isRepairModeUsed() { return this.repair; } }