package mvd.jester.model; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import org.jgrapht.experimental.dag.DirectedAcyclicGraph; import org.jgrapht.graph.DefaultEdge; import mvd.jester.utils.DagUtils; /** * TaskSet */ public class SystemManager { private long numberOfProcessors; public SystemManager(final long numberOfProcessors) { this.numberOfProcessors = numberOfProcessors; } /** * @return the numberOfProcessors */ public long getNumberOfProcessors() { return numberOfProcessors; } /** * @param numberOfProcessors the numberOfProcessors to set */ public void setNumberOfProcessors(long numberOfProcessors) { this.numberOfProcessors = numberOfProcessors; } public static class SynchronousTaskBuilder { private long numberOfProcessors = 4; private long minPeriod = 100; private long maxSequentialPeriod = 1000; private long maxParallelPeriod = 10000; private long minNumberOfSegments = 3; private long maxNumberOfSegments = 7; private long minNumberOfJobs = 2; private long maxNumberOfJobs = 3 * numberOfProcessors / 2; private final long minWcet = 1; private long ratio = randomTaskRatio(this.parallelTaskRatio); private final long parallelTaskRatio = 0; public SynchronousTaskBuilder() { } private long randomSequentialTaskPeriod() { return ThreadLocalRandom.current().nextLong(minPeriod, maxSequentialPeriod); } private long randomParallelTaskPeriod() { return ThreadLocalRandom.current().nextLong(minPeriod, maxParallelPeriod); } private long randomTaskRatio(final long min) { return ThreadLocalRandom.current().nextLong(min, 100); } private long randomNumberOfSegments() { return ThreadLocalRandom.current().nextLong(minNumberOfSegments, maxNumberOfSegments); } private long randomNumberOfJobs() { this.maxNumberOfJobs = 3 * this.numberOfProcessors / 2; return ThreadLocalRandom.current().nextLong(minNumberOfJobs, maxNumberOfJobs); } private long randomWcet(final long period, final long numberOfSegments) { final long maxWcet = period / numberOfSegments; return ThreadLocalRandom.current().nextLong(minWcet, maxWcet); } private SynchronousTask generateTask() { final boolean serial = randomTaskRatio(0) > this.ratio; final long period = serial ? randomSequentialTaskPeriod() : randomParallelTaskPeriod(); final long numberOfSegments = serial ? 1 : randomNumberOfSegments(); final long parallelNumberOfJobs = serial ? 1 : randomNumberOfJobs(); final Set segments = new LinkedHashSet(); for (int i = 0; i < numberOfSegments; ++i) { final long numberOfJobs = i % 2 == 1 ? parallelNumberOfJobs : 1; final long wcet = randomWcet(period, numberOfSegments); segments.add(new Segment(wcet, numberOfJobs)); } return new SynchronousTask(segments, period, numberOfProcessors); } public Set generateTaskSet() { this.ratio = randomTaskRatio(this.parallelTaskRatio); final Set taskSet = new HashSet<>(); for (int i = 0; i < numberOfProcessors; ++i) { final SynchronousTask task = generateTask(); taskSet.add(task); } return taskSet; } // public SystemSetup build() { // this.ratio = randomTaskRatio(this.parallelTaskRatio); // final Set taskSet = generateTaskSet(); // return new SystemSetup<>(taskSet, numberOfProcessors); // } // public Set rebuild(final SystemSetup systemSetup) { // this.ratio = randomTaskRatio(this.parallelTaskRatio); // return generateTaskSet(); // } public boolean addTask(final Set taskSet) { return taskSet.add(generateTask()); } public SynchronousTaskBuilder setNumberOfProcessors(final long numberOfProcessors) { this.numberOfProcessors = numberOfProcessors; return this; } public SynchronousTaskBuilder setNumberOfSegments(final long minNumberOfSegments, final long maxNumberOfSegments) { this.minNumberOfSegments = minNumberOfSegments; this.maxNumberOfSegments = maxNumberOfSegments; return this; } public SynchronousTaskBuilder setPeriods(final long minPeriod, final long maxSequentialPeriod, final long maxParallelPeriod) { this.minPeriod = minPeriod; this.maxSequentialPeriod = maxSequentialPeriod; this.maxParallelPeriod = maxParallelPeriod; return this; } /** * @param maxNumberOfJobs the maxNumberOfJobs to set */ public SynchronousTaskBuilder setNumberOfJobs(final long minNumberOfJobs, final long maxNumberOfJobs) { this.minNumberOfJobs = minNumberOfJobs; this.maxNumberOfJobs = maxNumberOfJobs; return this; } } public static class DagTaskBuilder { private long numberOfProcessors = 8; private long minimumWcet = 1; private long maximumWcet = 100; private long maxNumberOfBranches = 5; private long depth = 2; private long p_par = 80; private long p_add = 20; public DagTaskBuilder() { } public double getBeta() { return 0.035 * numberOfProcessors; } private long randomProbability() { return ThreadLocalRandom.current().nextLong(0, 100); } public Set generateUUnifastTaskSet(final long numberOfTasks, final double totalUtilization) { final LinkedHashSet taskSet = new LinkedHashSet<>(); if (numberOfTasks > 0) { double sumU = totalUtilization; for (int i = 1; i <= numberOfTasks - 1; i++) { Double nextSumU = sumU * Math.pow(ThreadLocalRandom.current().nextDouble(), (1.0 / (double) (numberOfTasks - i))); DagTask task = generateTask(sumU - nextSumU); taskSet.add(task); sumU = nextSumU; } DagTask task = generateTask(sumU); taskSet.add(task); } return taskSet; } public Set generateTaskSet(final double totalUtilization) { final LinkedHashSet taskSet = new LinkedHashSet<>(); double currentUtilization = 0; while (currentUtilization <= totalUtilization) { final DagTask dagTask = generateTask(); if (currentUtilization + dagTask.getUtilization() < totalUtilization) { currentUtilization += dagTask.getUtilization(); taskSet.add(dagTask); } else { final double remainingUtilization = totalUtilization - currentUtilization; final long period = (long) Math.ceil(dagTask.getWorkload() / remainingUtilization); if (period >= dagTask.getCriticalPath()) { final DagTask modifiedTask = new DagTask(dagTask.getJobDag(), period, numberOfProcessors); taskSet.add(modifiedTask); break; } } } return taskSet; } public DagTask generateTask(double utilization) { final DirectedAcyclicGraph jobDag = new DirectedAcyclicGraph<>(DefaultEdge.class); final Job j = fork(jobDag, Optional.empty(), this.depth); fork(jobDag, Optional.of(j), this.depth); randomEdges(jobDag); final long workload = DagUtils.calculateWorkload(jobDag); final long period = Math.round(workload / utilization); return new DagTask(jobDag, period, numberOfProcessors); } public DagTask generateTask() { final DirectedAcyclicGraph jobDag = new DirectedAcyclicGraph<>(DefaultEdge.class); final Job j = fork(jobDag, Optional.empty(), this.depth); fork(jobDag, Optional.of(j), this.depth); randomEdges(jobDag); final long workload = DagUtils.calculateWorkload(jobDag); final long criticalPath = DagUtils.calculateCriticalPath(jobDag); final long period = randomTaskPeriod(criticalPath, workload); return new DagTask(jobDag, period, numberOfProcessors); } private Job join(final DirectedAcyclicGraph jobDag, final Job current, final Set childs) { if (childs.size() > 0) { final Job job = new Job(randomWcet()); jobDag.addVertex(job); for (final Job c : childs) { try { jobDag.addDagEdge(c, job); } catch (final Exception e) { System.out.println("Failed to join nodes!"); } } return job; } return current; } private Job fork(final DirectedAcyclicGraph jobDag, final Optional predecessor, final long depth) { final Job job = new Job(randomWcet()); jobDag.addVertex(job); final Set childs = new HashSet<>(); if (predecessor.isPresent()) { try { jobDag.addDagEdge(predecessor.get(), job); } catch (final Exception e) { System.out.println("Adding fork edge failed!"); } } if (depth >= 0 && randomProbability() < p_par) { final long numberOfJobs = randomNumberOfBranches(); for (int i = 0; i < numberOfJobs; ++i) { childs.add(fork(jobDag, Optional.of(job), depth - 1)); } } return join(jobDag, job, childs); } private void randomEdges(final DirectedAcyclicGraph jobDag) { final Multimap edgePairs = ArrayListMultimap.create(); for (final Job j1 : jobDag) { for (final Job j2 : jobDag) { if (randomProbability() < p_add) { edgePairs.put(j1, j2); } } } for (final Map.Entry pairs : edgePairs.entries()) { try { jobDag.addDagEdge(pairs.getKey(), pairs.getValue()); } catch (final Exception e) { // nothing to do here } } } private long randomTaskPeriod(final long criticalPathLength, final long workload) { return ThreadLocalRandom.current().nextLong(criticalPathLength, (long) (workload / getBeta())); } private long randomNumberOfBranches() { return ThreadLocalRandom.current().nextLong(2, maxNumberOfBranches); } private long randomWcet() { return ThreadLocalRandom.current().nextLong(minimumWcet, maximumWcet); } /** * @param numberOfProcessors the numberOfProcessors to set */ public DagTaskBuilder setNumberOfProcessors(final long numberOfProcessors) { this.numberOfProcessors = numberOfProcessors; return this; } /** * @return the numberOfProcessors */ public long getNumberOfProcessors() { return numberOfProcessors; } public DagTaskBuilder setWcets(final long minimumWcet, final long maximumWcet) { this.minimumWcet = minimumWcet; this.maximumWcet = maximumWcet; return this; } /** * @param maxNumberOfBranches the maxNumberOfBranches to set */ public DagTaskBuilder setMaxNumberOfBranches(final long maxNumberOfBranches) { this.maxNumberOfBranches = maxNumberOfBranches; return this; } public DagTaskBuilder setPropabilities(final long p_par, final long p_add) { this.p_par = p_par; this.p_add = p_add; return this; } /** * @param depth the depth to set */ public DagTaskBuilder setDepth(final long depth) { this.depth = depth; return this; } } }