
org.btrplace.scheduler.runner.disjoint.StaticPartitioning Maven / Gradle / Ivy
Show all versions of split Show documentation
/*
* Copyright 2020 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.runner.disjoint;
import org.btrplace.model.Instance;
import org.btrplace.plan.DefaultReconfigurationPlan;
import org.btrplace.plan.ReconfigurationPlan;
import org.btrplace.plan.event.Action;
import org.btrplace.scheduler.SchedulerException;
import org.btrplace.scheduler.choco.Parameters;
import org.btrplace.scheduler.choco.runner.InstanceSolver;
import org.btrplace.scheduler.choco.runner.SolvingStatistics;
import org.btrplace.scheduler.choco.runner.single.InstanceSolverRunner;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* An abstract solver that decompose statically an instance
* into multiple disjoint sub-instances than are solved in parallel.
*
* The resulting reconfiguration plan is composed by all the sub
* reconfiguration plans. Each sub-instance must then have a solution.
*
* The solving process relies on a master/worker paradigm with a number
* of workers equals to the number of available cores by default.
*
* @author Fabien Hermenier
*/
public abstract class StaticPartitioning implements InstanceSolver {
private int workersCount;
private StaticPartitioningStatistics stats;
private List runners;
/**
* Make a new partitioning algorithm.
* The number of workers is set to the number of available cores.
*/
protected StaticPartitioning() {
workersCount = Runtime.getRuntime().availableProcessors();
}
/**
* Get the number of workers that are used to solve instances.
*
* @return a number >= 1
*/
public int getWorkersCount() {
return workersCount;
}
/**
* Set the number of workers that solve instances.
*
* @param s a number >= 1
*/
public void setWorkersCount(int s) {
this.workersCount = s;
}
@Override
public ReconfigurationPlan solve(Parameters cra, Instance orig) throws SchedulerException {
stats = new StaticPartitioningStatistics(cra, orig, System.currentTimeMillis(), workersCount);
long d = -System.currentTimeMillis();
List partitions = split(cra, orig);
d += System.currentTimeMillis();
stats.setSplittingStatistics(partitions.size(), d);
ExecutorService exe = Executors.newFixedThreadPool(this.workersCount);
CompletionService completionService = new ExecutorCompletionService<>(exe);
List results = new ArrayList<>(partitions.size());
runners = new ArrayList<>();
long duration = -System.currentTimeMillis();
for (Instance partition : partitions) {
InstanceSolverRunner runner = new InstanceSolverRunner(cra, partition);
completionService.submit(runner);
runners.add(runner);
}
for (int i = 0; i < partitions.size(); i++) {
try {
results.add(completionService.take().get());
} catch (ExecutionException ignore) {
Throwable cause = ignore.getCause();
if (cause != null) {
throw new SplitException(null, cause.getMessage(), ignore);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new SplitException(orig.getModel(), e.getMessage(), e);
}
}
duration += System.currentTimeMillis();
stats.setSolvingDuration(duration);
exe.shutdown();
return merge(orig, results);
}
private ReconfigurationPlan merge(Instance i, Collection results) throws SplitException {
ReconfigurationPlan plan = new DefaultReconfigurationPlan(i.getModel());
//Only if there is a solution
for (SolvingStatistics result : results) {
getStatistics().addPartitionStatistics(result);
ReconfigurationPlan p = result.lastSolution();
if (p == null) {
return null;
}
for (Action a : p) {
if (!plan.add(a)) {
throw new SplitException(plan.getOrigin(),
"Unable to add action '" + a + "' while merging the sub-plans");
}
}
}
return plan;
}
@Override
public StaticPartitioningStatistics getStatistics() {
return stats;
}
/**
* Split an instance into several disjoint instances.
*
* @param ps the parameters for the solver
* @param i the instance to split
* @return a list of disjoint instances. Cannot be empty.
* @throws org.btrplace.scheduler.SchedulerException if an error prevent the splitting process
*/
public abstract List split(Parameters ps, Instance i) throws SchedulerException;
@Override
public void stop() {
if (runners != null) {
for (InstanceSolverRunner runner: runners) {
runner.stop();
}
}
}
}