diff --git a/src/main/java/mvd/jester/App.java b/src/main/java/mvd/jester/App.java index 0f1c448..4665191 100644 --- a/src/main/java/mvd/jester/App.java +++ b/src/main/java/mvd/jester/App.java @@ -5,6 +5,7 @@ import java.util.List; import mvd.jester.model.DagTask; import mvd.jester.model.SystemManager; import mvd.jester.model.SystemManager.DagTaskBuilder; +import mvd.jester.model.SystemManager.DeadlineType; import mvd.jester.tests.AbstractTest; import mvd.jester.tests.JiangYi; import mvd.jester.tests.SchmidMottok; @@ -26,7 +27,6 @@ public class App { List> tests = te.registerTests(Arrays.asList( new SchmidMottok(new UnknownStructure(), manager), // - // new Tester(new UnknownStructure(),manager), // new MelaniButtazzo(manager),, // new FonsecaNelis(manager), // // new DongLiu(manager), // @@ -34,77 +34,38 @@ public class App { new JiangYi(manager)// )); - te.varyRenyiUtilization(manager, tests, 200); + te.varyRenyiUtilization(manager, tests, 200, DeadlineType.IMPLICIT); } { SystemManager manager = new SystemManager<>(DagTaskBuilder.class); - manager.setNumberOfProcessors(16); + manager.setNumberOfProcessors(8); TestEnvironment te = new TestEnvironment(); - List> tests = te.registerTests(Arrays.asList( + List> tests = te.registerTests(Arrays.asList( // new SchmidMottok(new UnknownStructure(), manager), // - // new Tester(new UnknownStructure(),manager), - // new MelaniButtazzo(manager),, + // new Tester(new UnknownStructure(), manager), // + // new MelaniButtazzo(manager), // // new FonsecaNelis(manager), // - // new DongLiu(manager), // new UeterAgrawal(manager), // - new JiangYi(manager)// - )); + new JiangYi(manager))); - te.varyRenyiUtilization(manager, tests, 200); + te.varyNumberOfProcessors(manager, tests, 200); } { SystemManager manager = new SystemManager<>(DagTaskBuilder.class); - manager.setNumberOfProcessors(32); + manager.setNumberOfProcessors(8); TestEnvironment te = new TestEnvironment(); - List> tests = te.registerTests(Arrays.asList( + List> tests = te.registerTests(Arrays.asList( // new SchmidMottok(new UnknownStructure(), manager), // - // new Tester(new UnknownStructure(),manager), - // new MelaniButtazzo(manager),, + // new MelaniButtazzo(manager), // // new FonsecaNelis(manager), // - // new DongLiu(manager), // new UeterAgrawal(manager), // - new JiangYi(manager)// - )); + new JiangYi(manager))); - te.varyRenyiUtilization(manager, tests, 200); + te.varyNumberOfTasks(manager, tests, 200); } - // { - // SystemManager manager = new - // SystemManager<>(DagTaskBuilder.class); - // manager.setNumberOfProcessors(8); - // TestEnvironment te = new TestEnvironment(); - - // List> tests = te.registerTests(Arrays.asList( // - // // new SchmidMottok(new KnownStructure(), manager), // - // new SchmidMottok(new UnknownStructure(), manager), // - // // new Tester(new UnknownStructure(), manager), // - // // new MelaniButtazzo(manager), // - // new FonsecaNelis(manager), // - // new UeterAgrawal(manager), // - // new JiangYi(manager))); - - // te.varyNumberOfProcessors(manager, tests, 200); - // } - // { - // SystemManager manager = new - // SystemManager<>(DagTaskBuilder.class); - // manager.setNumberOfProcessors(8); - // TestEnvironment te = new TestEnvironment(); - - // List> tests = te.registerTests(Arrays.asList( // - // // new SchmidMottok(new KnownStructure(), manager), // - // new SchmidMottok(new UnknownStructure(), manager), // - // // new Tester(new UnknownStructure(), manager), // - // // new MelaniButtazzo(manager), // - // new FonsecaNelis(manager), // - // new UeterAgrawal(manager), // - // new JiangYi(manager))); - - // te.varyNumberOfTasks(manager, tests, 200); - // } } } diff --git a/src/main/java/mvd/jester/TestEnvironment.java b/src/main/java/mvd/jester/TestEnvironment.java index 1bb5bef..fe91b41 100644 --- a/src/main/java/mvd/jester/TestEnvironment.java +++ b/src/main/java/mvd/jester/TestEnvironment.java @@ -16,12 +16,14 @@ import mvd.jester.model.SynchronousTask; import mvd.jester.model.SystemManager; import mvd.jester.model.Task; import mvd.jester.model.SystemManager.DagTaskBuilder; +import mvd.jester.model.SystemManager.DeadlineType; import mvd.jester.model.SystemManager.SynchronousTaskBuilder; import mvd.jester.priority.PriorityManager; import mvd.jester.tests.AbstractTest; /** * TestEnvironment + * This class is responsible for running the evaluations on multiple task sets */ public class TestEnvironment { @@ -33,7 +35,13 @@ public class TestEnvironment { return new ArrayList<>(tests); } - + /*** + * OUTDATED: For Parallel Synchronous Task model + * @param builder + * @param abstractTestInstances + * @param numberOfProcessors + * @param numberOfTaskSets + */ public void runExperiments(final SynchronousTaskBuilder builder, final Set>> abstractTestInstances, final long numberOfProcessors, final long numberOfTaskSets) { @@ -78,6 +86,12 @@ public class TestEnvironment { // resultLogger.logTests(abstractTestInstances); } + /*** + * Measure the performance of each test + * @param manager SystemManager that is used to generate random task sets + * @param abstractTestInstances List of feasibility tests + * @param numberOfMeasurements Number of measurements performed for each test + */ public void measureExecutionTimes(final SystemManager manager, final List> abstractTestInstances, final long numberOfMeasurements) { @@ -108,6 +122,12 @@ public class TestEnvironment { } + /*** + * Computes the feasibility varying the number of processors in the systen + * @param manager SystemManager that is used to generate task sets + * @param abstractTestInstances List of feasibility tests + * @param numberOfTaskSetsPerStep Number of task sets that are to be generated for each step (number of processors) + */ public void varyNumberOfProcessors(final SystemManager manager, final List> abstractTestInstances, final long numberOfTaskSetsPerStep) { @@ -124,7 +144,7 @@ public class TestEnvironment { resultMap.replaceAll((k, v) -> (long) 0); for (int i = 0; i < numberOfTaskSetsPerStep; ++i) { final Set taskSet = manager.getBuilder().generateUUnifastTaskSet( - (long) (1.5 * numberOfProcessors), (double) numberOfProcessors * 0.75); + (long) (1.5*numberOfProcessors), (double) numberOfProcessors * 0.75); System.out.print(checkedTasksets + "/" + numberOfTaskSets + " tasksets tested!\r"); for (final AbstractTest testInstance : abstractTestInstances) { @@ -149,7 +169,12 @@ public class TestEnvironment { resultLogger.finalize(); } - + /*** + * Computes the feasibility varying the number of tasks in the task set + * @param manager SystemManager that is used to generate task sets + * @param abstractTestInstances List of feasibility tests + * @param numberOfTaskSetsPerStep Number of task sets that are to be generated for each step (number of tasks) + */ public void varyNumberOfTasks(final SystemManager manager, final List> abstractTestInstances, final long numberOfTaskSetsPerStep) { @@ -191,6 +216,12 @@ public class TestEnvironment { resultLogger.finalize(); } + /*** + * Computes the feasibility varying the total system utilization of the task set + * @param manager SystemManager that is used to generate task sets + * @param abstractTestInstances List of feasibility tests + * @param numberOfTaskSetsPerUtil Number of task sets that are to be generated for each step (system utilization) + */ public void varyUtilization(final SystemManager manager, final List> abstractTestInstances, final long numberOfTaskSetsPerUtil) { @@ -231,9 +262,16 @@ public class TestEnvironment { resultLogger.finalize(); } + /*** + * Computes the feasibility varying the total system utilization of the task set (Task set is generated by the Renyi method) + * @param manager SystemManager that is used to generate task sets + * @param abstractTestInstances List of feasibility tests + * @param numberOfTaskSetsPerUtil Number of task sets that are to be generated for each step (system utilization) + * @param deadlineType Deadline model (implicit or constrained) + */ public void varyRenyiUtilization(final SystemManager manager, final List> abstractTestInstances, - final long numberOfTaskSetsPerUtil) { + final long numberOfTaskSetsPerUtil, DeadlineType deadlineType) { final long numberOfProcessors = manager.getNumberOfProcessors(); long checkedTasksets = 0; final long numberOfTaskSets = ((numberOfProcessors * 4) - 3) * numberOfTaskSetsPerUtil; @@ -248,7 +286,7 @@ public class TestEnvironment { (double) numberOfProcessors / 32) { resultMap.replaceAll((k, v) -> (long) 0); for (int i = 0; i < numberOfTaskSetsPerUtil; ++i) { - final Set taskSet = manager.getBuilder().generateRenyiTaskSet(util); + final Set taskSet = manager.getBuilder().generateRenyiTaskSet(util, deadlineType); System.out.print(checkedTasksets + "/" + numberOfTaskSets + " tasksets tested!\r"); for (final AbstractTest testInstance : abstractTestInstances) { @@ -273,6 +311,13 @@ public class TestEnvironment { resultLogger.finalize(); } + + /*** + * Computes the feasibility varying the probability in the Renyi method the task set (Task set is generated by the Renyi method) + * @param manager SystemManager that is used to generate task sets + * @param abstractTestInstances List of feasibility tests + * @param numberOfTaskSetsPerStep Number of task sets that are to be generated for each step (probability) + */ public void varyPropability(final SystemManager manager, final List> abstractTestInstances, final long numberOfTaskSetsPerStep) { @@ -288,7 +333,7 @@ public class TestEnvironment { manager.setPropability(p_add); resultMap.replaceAll((k, v) -> (long) 0); for (int i = 0; i < numberOfTaskSetsPerStep; ++i) { - final Set taskSet = manager.getBuilder().generateRenyiTaskSet(5.5); + final Set taskSet = manager.getBuilder().generateRenyiTaskSet(5.5, DeadlineType.IMPLICIT); System.out.print(checkedTasksets + "/" + numberOfTaskSets + " tasksets tested!\r"); for (final AbstractTest testInstance : abstractTestInstances) { diff --git a/src/main/java/mvd/jester/model/SystemManager.java b/src/main/java/mvd/jester/model/SystemManager.java index 699f161..9912eaf 100644 --- a/src/main/java/mvd/jester/model/SystemManager.java +++ b/src/main/java/mvd/jester/model/SystemManager.java @@ -17,7 +17,7 @@ import mvd.jester.utils.DagUtils; import mvd.jester.model.SystemManager.Builder; /** - * TaskSet + * The SystemManager is a class to generate random task sets (either Dag Tasks or Synchronous Tasks depending on the specified Builder) */ public class SystemManager implements SystemManagerInterface { @@ -53,6 +53,12 @@ public class SystemManager implements SystemManagerInterface return builder; } + public enum DeadlineType { + CONSTRAINED, + + IMPLICIT + } + public static interface Builder { public long getNumberOfProcessors(); @@ -62,6 +68,10 @@ public class SystemManager implements SystemManagerInterface public Builder setPropability(long p); } + /** + * OUTDATED + * Task builder for Parallel Synchronous Task model + */ public static class SynchronousTaskBuilder implements Builder { private long numberOfProcessors = 4; private long minPeriod = 100; @@ -182,6 +192,9 @@ public class SystemManager implements SystemManagerInterface } } + /** + * Task builder for DAG Task model + */ public static class DagTaskBuilder implements Builder { private long numberOfProcessors = 8; private long minimumWcet = 1; @@ -203,12 +216,18 @@ public class SystemManager implements SystemManagerInterface return ThreadLocalRandom.current().nextLong(0, 100); } - public Set generateRenyiTaskSet(final double totalUtilization) { + /*** + * Generates a random task set according to the UUniFast method for utilization and Renyi method for the DAG structure + * @param totalUtilization Total system utilization of the task set + * @param deadlineType Deadline model (implicit or constrained) + * @return Randomly generated task set + */ + public Set generateRenyiTaskSet(final double totalUtilization, DeadlineType deadlineType) { final LinkedHashSet taskSet = new LinkedHashSet<>(); double currentUtilization = 0; while (currentUtilization <= totalUtilization) { - final DagTask task = generateRenyiTask(totalUtilization); + final DagTask task = generateRenyiTask(totalUtilization, deadlineType); if (currentUtilization + task.getUtilization() < totalUtilization) { currentUtilization += task.getUtilization(); @@ -218,12 +237,17 @@ public class SystemManager implements SystemManagerInterface final long period = (long) Math.ceil(task.getWorkload() / remainingUtilization); final long criticalPath = task.getCriticalPath(); if (period >= criticalPath) { - final long deadline = randomNumberInRange( - criticalPath + (period - criticalPath) / 4, period); // TODO: - // deadline = - // period? - - // final long deadline = period; + final long deadline; + switch (deadlineType) { + case CONSTRAINED: + deadline = randomNumberInRange( + criticalPath + (period - criticalPath) / 4, period); + break; + case IMPLICIT: + default: + deadline = period; + break; + } long numberOfThreads = LongMath.divide(task.getWorkload() - criticalPath, deadline - criticalPath, RoundingMode.CEILING); @@ -243,6 +267,12 @@ public class SystemManager implements SystemManagerInterface return taskSet; } + /*** + * Generates a random task set according to the UUniFast method + * @param numberOfTasks Number of tasks the set is supposed to have + * @param totalUtilization Total system utilization of the task set + * @return Randomly generated task set + */ public Set generateUUnifastTaskSet(final long numberOfTasks, final double totalUtilization) { final LinkedHashSet taskSet = new LinkedHashSet<>(); @@ -263,6 +293,11 @@ public class SystemManager implements SystemManagerInterface return taskSet; } + /** + * Generates a random task set with given total system utilization + * @param totalUtilization Total system utilization of the task set + * @return Randomly generated task set + */ public Set generateTaskSet(final double totalUtilization) { final LinkedHashSet taskSet = new LinkedHashSet<>(); double currentUtilization = 0; @@ -288,6 +323,11 @@ public class SystemManager implements SystemManagerInterface return taskSet; } + /*** + * Generate random DAG task with given utilization according to Renyi method + * @param utilization Utilization of the task that will be generated + * @return Randomly generated task + */ public DagTask generateRenyiTaskForUUniFast(final double utilization) { final DirectedAcyclicGraph jobDag = new DirectedAcyclicGraph<>(DefaultEdge.class); @@ -315,7 +355,13 @@ public class SystemManager implements SystemManagerInterface return new DagTask(jobDag, period, numberOfThreads); } - public DagTask generateRenyiTask(final double totalUtilization) { + /*** + * Generates a random DAG task according to the Renyi method + * @param totalUtilization Total system utilization + * @param deadlineType Deadline model (implicit or constrained) + * @return Randomly generated task + */ + public DagTask generateRenyiTask(final double totalUtilization, DeadlineType deadlineType) { final DirectedAcyclicGraph jobDag = new DirectedAcyclicGraph<>(DefaultEdge.class); final long numberOfVertices = randomNumberInRange(50, 250); @@ -331,12 +377,17 @@ public class SystemManager implements SystemManagerInterface final long workload = DagUtils.calculateWorkload(jobDag); final long criticalPath = DagUtils.calculateCriticalPath(jobDag); final long period = randomRenyiPeriod(workload, criticalPath, totalUtilization); - final long deadline = - randomNumberInRange(criticalPath + (period - criticalPath) / 4, period); // TODO: - // oder - // period? - // final long deadline = period; + final long deadline; + switch (deadlineType) { + case CONSTRAINED: + deadline = randomNumberInRange(criticalPath + (period - criticalPath) / 4, period); // TODO: + break; + case IMPLICIT: + default: + deadline = period; + break; + } final long numberOfThreads = LongMath.divide(workload - criticalPath, deadline - criticalPath, RoundingMode.CEILING); @@ -348,6 +399,13 @@ public class SystemManager implements SystemManagerInterface return new DagTask(jobDag, period, deadline, numberOfThreads); } + /*** + * Generate random period according to Renyi method + * @param workload Workload of the task + * @param criticalPath Critical Path of the task + * @param totalUtilization Total system utilization + * @return Period + */ private long randomRenyiPeriod(final long workload, final long criticalPath, final double totalUtilization) { final double firstPart = @@ -358,6 +416,10 @@ public class SystemManager implements SystemManagerInterface return (long) Math.ceil(firstPart * secondPart); } + /*** + * Add source and sink nodes the the DAG generated by the Renyi method + * @param jobDag Object holding the current DAG structure + */ private void addSourceAndSink(final DirectedAcyclicGraph jobDag) { final Multimap edgePairs = ArrayListMultimap.create(); Job source = new Job(randomNumberInRange(50, 100)); @@ -383,7 +445,11 @@ public class SystemManager implements SystemManagerInterface } } } - + /*** + * Generates a random nested fork-join task with given utilization + * @param utilization Utilization of the task + * @return randomly generated Task + */ public DagTask generateTask(double utilization) { final DirectedAcyclicGraph jobDag = new DirectedAcyclicGraph<>(DefaultEdge.class); @@ -399,6 +465,10 @@ public class SystemManager implements SystemManagerInterface return new DagTask(jobDag, period, numberOfProcessors); } + /*** + * Generates a random nested fork-join task + * @return Randomly generated task + */ public DagTask generateTask() { final DirectedAcyclicGraph jobDag = new DirectedAcyclicGraph<>(DefaultEdge.class); @@ -418,6 +488,13 @@ public class SystemManager implements SystemManagerInterface return new DagTask(jobDag, period, numberOfThreads); } + /*** + * Function for joining the DAG that was partly generated by fork + * @param jobDag Object holding the current DAG structure + * @param current The fork node + * @param childs The children/successors of the fork-node + * @return returns the fork node (@param current) + */ private Job join(final DirectedAcyclicGraph jobDag, final Job current, final Set childs) { if (childs.size() > 0) { @@ -435,6 +512,13 @@ public class SystemManager implements SystemManagerInterface return current; } + /*** + * Function for creating nested fork/join DAGs + * @param jobDag Object holding the current DAG structure + * @param predecessor fork node + * @param depth maximum depth of the nested fork-join structure + * @return the latest Job in the nested fork-join structure + */ private Job fork(final DirectedAcyclicGraph jobDag, final Optional predecessor, final long depth) { final Job job = new Job(randomWcet()); @@ -457,6 +541,10 @@ public class SystemManager implements SystemManagerInterface return join(jobDag, job, childs); } + /*** + * Generate random edges + * @param jobDag + */ private void randomEdges(final DirectedAcyclicGraph jobDag) { final Multimap edgePairs = ArrayListMultimap.create(); for (final Job j1 : jobDag) { @@ -476,6 +564,10 @@ public class SystemManager implements SystemManagerInterface } } + /*** + * Generate random edges according to Renyi DAG generation method + * @param jobDag + */ private void randomEdgesRenyi(final DirectedAcyclicGraph jobDag) { final Multimap edgePairs = ArrayListMultimap.create(); for (final Job j1 : jobDag) { diff --git a/src/main/java/mvd/jester/tests/FonsecaNelis.java b/src/main/java/mvd/jester/tests/FonsecaNelis.java index 850a3c1..f5c3cce 100644 --- a/src/main/java/mvd/jester/tests/FonsecaNelis.java +++ b/src/main/java/mvd/jester/tests/FonsecaNelis.java @@ -31,6 +31,10 @@ import mvd.jester.utils.BinaryDecompositionTree; import mvd.jester.utils.BinaryDecompositionTree.Node; import mvd.jester.utils.BinaryDecompositionTree.NodeType; +/*** + * Response time analysis presented by Fonseca et al. + * " Improved Response Time Analysis of Sporadic DAG Tasks for Global FP Scheduling" + */ public class FonsecaNelis extends AbstractTest { private final Map responseTimes; diff --git a/src/main/java/mvd/jester/tests/JiangYi.java b/src/main/java/mvd/jester/tests/JiangYi.java index 4bcbc12..81ad377 100644 --- a/src/main/java/mvd/jester/tests/JiangYi.java +++ b/src/main/java/mvd/jester/tests/JiangYi.java @@ -17,6 +17,10 @@ import mvd.jester.model.Task; import mvd.jester.priority.EarliestDeadlineFirst; import mvd.jester.priority.PriorityManager; +/*** + * Semi-Federated Scheduling presented by Jiang et al. + * "Semi-Federated Scheduling of Parallel Real-Time Tasks on Multiprocessor" + */ public class JiangYi extends AbstractTest { private final EarliestDeadlineFirst priorityManager; diff --git a/src/main/java/mvd/jester/tests/MelaniButtazzo.java b/src/main/java/mvd/jester/tests/MelaniButtazzo.java index bc367f3..2fca9fa 100644 --- a/src/main/java/mvd/jester/tests/MelaniButtazzo.java +++ b/src/main/java/mvd/jester/tests/MelaniButtazzo.java @@ -14,6 +14,10 @@ import mvd.jester.model.Task; import mvd.jester.priority.PriorityManager; import mvd.jester.priority.RateMonotonic; +/*** + * Response time analysis presented by Melani et al. + * "Response-Time Analysis of Conditional DAG Tasks in Multiprocessor Systems" + */ public class MelaniButtazzo extends AbstractTest { private final Map responseTimes; diff --git a/src/main/java/mvd/jester/tests/SchmidMottok.java b/src/main/java/mvd/jester/tests/SchmidMottok.java index 53c43f2..9de387a 100644 --- a/src/main/java/mvd/jester/tests/SchmidMottok.java +++ b/src/main/java/mvd/jester/tests/SchmidMottok.java @@ -15,7 +15,7 @@ import mvd.jester.priority.DeadlineMonotonic; import mvd.jester.priority.PriorityManager; /** - * SchmidMottok + * Our response time analysis */ public class SchmidMottok extends AbstractTest { @@ -52,6 +52,10 @@ public class SchmidMottok extends AbstractTest { return "SchmidMottok" + "_" + structure.getType(); } + /*** + * Computes the number of threads for each task + * @param tasks The set of tasks + */ private void reassignNumberOfThreads(Set tasks) { long numberOfProcessors = manager.getNumberOfProcessors(); long occupiedProcessors = 0; @@ -65,6 +69,12 @@ public class SchmidMottok extends AbstractTest { } } + /*** + * Computes the response time for given task + * @param tasks Set of tasks in the system + * @param task Task for which the response time is computed + * @return Response time of task + */ private long calculateResponseTime(final Set tasks, final DagTask task) { final long minimumWcet = task.getCriticalPath(); long responseTime = minimumWcet; diff --git a/src/main/java/mvd/jester/tests/TypeFunction.java b/src/main/java/mvd/jester/tests/TypeFunction.java index e2cac64..5a4df0c 100644 --- a/src/main/java/mvd/jester/tests/TypeFunction.java +++ b/src/main/java/mvd/jester/tests/TypeFunction.java @@ -9,6 +9,10 @@ import mvd.jester.model.Segment; import mvd.jester.model.SystemManagerInterface; import mvd.jester.model.Task; +/*** + * Different methods given if the structure of the DAG is known in advance. + * Only UnknownStructure is presented in the paper. + */ public interface TypeFunction { public double getTaskInterference(final DagTask task, @@ -79,6 +83,9 @@ public interface TypeFunction { } } + /*** + * This class is presented in the paper + */ public class UnknownStructure implements TypeFunction { @Override diff --git a/src/main/java/mvd/jester/tests/UeterAgrawal.java b/src/main/java/mvd/jester/tests/UeterAgrawal.java index 131c63b..d707326 100644 --- a/src/main/java/mvd/jester/tests/UeterAgrawal.java +++ b/src/main/java/mvd/jester/tests/UeterAgrawal.java @@ -18,6 +18,10 @@ import mvd.jester.model.Task; import mvd.jester.priority.EarliestDeadlineFirst; import mvd.jester.priority.PriorityManager; +/*** + * Reservation-based federated scheduling presented by Ueter et al. + * "Reservation-Based Federated Scheduling for Parallel Real-Time Tasks" + */ public class UeterAgrawal extends AbstractTest { private final EarliestDeadlineFirst priorityManager; @@ -101,7 +105,6 @@ public class UeterAgrawal extends AbstractTest { final long second = (long) Math .ceil(((double) workload - criticalPath) / (criticalPath * (strechRatio - 1))); - // TODO: what are those boundaries? final long max = Math.max(first, second); return max; @@ -160,6 +163,10 @@ public class UeterAgrawal extends AbstractTest { } } + /*** + * Assigns threads and the stretch ratio to each task + * @param tasks Set of tasks in the system + */ private void assignThreadsAndStretchRatio(Set tasks) { for (DagTask t : tasks) { final long criticalPath = t.getCriticalPath();