diff --git a/src/main/java/mvd/jester/model/DagTask.java b/src/main/java/mvd/jester/model/DagTask.java index a0d818d..c7fef52 100644 --- a/src/main/java/mvd/jester/model/DagTask.java +++ b/src/main/java/mvd/jester/model/DagTask.java @@ -1,14 +1,21 @@ package mvd.jester.model; +import java.util.Arrays; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; +import com.google.common.collect.Iterables; +import com.google.common.collect.Sets; import org.jgrapht.Graphs; +import org.jgrapht.alg.shortestpath.AllDirectedPaths; import org.jgrapht.experimental.dag.DirectedAcyclicGraph; import org.jgrapht.graph.DefaultEdge; -import org.jgrapht.traverse.BreadthFirstIterator; +import mvd.jester.utils.BinaryDecompositionTree; +import mvd.jester.utils.BinaryDecompositionTree.Node; +import mvd.jester.utils.BinaryDecompositionTree.NodeType; public class DagTask implements Task { @@ -115,6 +122,10 @@ public class DagTask implements Task { public static long calculateCriticalPath(DirectedAcyclicGraph jobDag) { long criticalPath = 0; + // BreadthFirstIterator breadthFirstIterator = + // new BreadthFirstIterator<>(jobDag); + // while (breadthFirstIterator.hasNext()) { + // Job job = breadthFirstIterator.next(); for (Job job : jobDag) { Set edges = jobDag.incomingEdgesOf(job); long longestRelativeCompletionTime = 0; @@ -161,25 +172,37 @@ public class DagTask implements Task { public static DirectedAcyclicGraph createNFJGraph( DirectedAcyclicGraph jobDag) { - DirectedAcyclicGraph modifiedJobDag = - new DirectedAcyclicGraph<>(DefaultEdge.class); - Graphs.addGraph(modifiedJobDag, jobDag); LinkedList joinNodes = new LinkedList<>(); - List forkNodes = new LinkedList<>(); + LinkedList forkNodes = new LinkedList<>(); + + collectForksAndJoins(jobDag, forkNodes, joinNodes); + return createNFJGraph(jobDag, forkNodes, joinNodes); + } - BreadthFirstIterator breadthFirstIterator = - new BreadthFirstIterator<>(modifiedJobDag); - while (breadthFirstIterator.hasNext()) { - Job j = breadthFirstIterator.next(); - if (modifiedJobDag.inDegreeOf(j) > 1) { + public static void collectForksAndJoins(DirectedAcyclicGraph jobDag, + LinkedList forkNodes, LinkedList joinNodes) { + for (Job j : jobDag) { + if (jobDag.inDegreeOf(j) > 1) { joinNodes.add(j); } - if (modifiedJobDag.outDegreeOf(j) > 1) { + if (jobDag.outDegreeOf(j) > 1) { forkNodes.add(j); } } + } - Job sink = joinNodes.getLast(); + public static DirectedAcyclicGraph createNFJGraph( + DirectedAcyclicGraph jobDag, LinkedList forkNodes, + LinkedList joinNodes) { + DirectedAcyclicGraph modifiedJobDag = + new DirectedAcyclicGraph<>(DefaultEdge.class); + Graphs.addGraph(modifiedJobDag, jobDag); + + if (!(joinNodes.size() > 1)) { + return modifiedJobDag; + } + + final Job sink = joinNodes.getLast(); for (Job j : joinNodes) { Set edgeSet = new HashSet<>(modifiedJobDag.incomingEdgesOf(j)); @@ -201,34 +224,107 @@ public class DagTask implements Task { break; } } - // Find fork node f following the path along this edge e - // if f has successor that is not ancestor of j -> e is conflicting edge - // get sorcetarget of e - // remove e - // if sourcetarget has no successor -> connect sourcetraget to sink - // if indegree = 1 -> break; } - // if (!DagUtils.checkProperty1(modifiedJobDag)) { - // throw new RuntimeException("abs"); - // } return modifiedJobDag; } - private static boolean checkProperty1(DirectedAcyclicGraph jobDag) { + public static BinaryDecompositionTree createDecompositionTree( + DirectedAcyclicGraph jobDag) { LinkedList joinNodes = new LinkedList<>(); - List forkNodes = new LinkedList<>(); + LinkedList forkNodes = new LinkedList<>(); - BreadthFirstIterator breadthFirstIterator = - new BreadthFirstIterator<>(jobDag); - while (breadthFirstIterator.hasNext()) { - Job j = breadthFirstIterator.next(); - if (jobDag.inDegreeOf(j) > 1) { - joinNodes.add(j); + collectForksAndJoins(jobDag, forkNodes, joinNodes); + return createDecompositionTree(jobDag, forkNodes, joinNodes); + } + + public static BinaryDecompositionTree createDecompositionTree( + DirectedAcyclicGraph jobDag, LinkedList forkNodes, + LinkedList joinNodes) { + Job source = forkNodes.getFirst(); + Job sink = joinNodes.getLast(); + Job current = source; + + BinaryDecompositionTree tree = new BinaryDecompositionTree<>(); + DagUtils.constructTree(jobDag, null, current, tree, forkNodes, joinNodes, sink); + + return tree; + } + + private static Node constructTree(DirectedAcyclicGraph jobDag, + Node parent, Job current, BinaryDecompositionTree tree, + LinkedList forkVertices, LinkedList joinVertices, Job sink) { + if (forkVertices.contains(current)) { + Job join = findJoin(jobDag, current, sink, joinVertices); + if (jobDag.outDegreeOf(join) > 1) { + throw new RuntimeException("Join und Fork in Einem! Ohoh!"); } - if (jobDag.outDegreeOf(j) > 1) { - forkNodes.add(j); + + Node forkNode = new Node(parent, NodeType.SEQ); + if (tree.isEmpty()) { + tree.setRoot(forkNode); } + forkNode.setLeftNode(new Node(forkNode, current)); + final Node continuationNode; + if (!tree.contains(join)) { + forkNode.setRightNode(new Node(forkNode, NodeType.SEQ)); + Node joinNode = forkNode.getRightNode(); + Iterator successorIterator = + Graphs.successorListOf(jobDag, join).iterator(); + if (successorIterator.hasNext()) { + Job successor = successorIterator.next(); + if (!tree.contains(successor)) { + joinNode.setRightNode(new Node<>(joinNode, NodeType.SEQ)); + Node successorNode = joinNode.getRightNode(); + successorNode.setLeftNode(new Node<>(successorNode, join)); + Node subTree = constructTree(jobDag, successorNode, successor, + tree, forkVertices, joinVertices, sink); + successorNode.setRightNode(subTree); + } else { + joinNode.setRightNode(new Node<>(joinNode, join)); + } + } else { + joinNode.setRightNode(new Node<>(joinNode, join)); + } + joinNode.setLeftNode(new Node<>(joinNode, NodeType.PAR)); + continuationNode = joinNode.getLeftNode(); + } else { + forkNode.setRightNode(new Node<>(forkNode, NodeType.PAR)); + continuationNode = forkNode.getRightNode(); + } + + Node successorParent = continuationNode; + List successors = Graphs.successorListOf(jobDag, current); + // create leftSide of joinNode + for (int i = 0; i < successors.size(); ++i) { + Job succ = successors.get(i); + Node thisNode = constructTree(jobDag, successorParent, succ, tree, + forkVertices, joinVertices, sink); + if (i == successors.size() - 1) { + successorParent.setRightNode(thisNode); + } else if (i == successors.size() - 2) { + successorParent.setLeftNode(thisNode); + } else { + successorParent.setLeftNode(thisNode); + successorParent.setRightNode(new Node<>(successorParent, NodeType.PAR)); + successorParent = successorParent.getRightNode(); + } + } + + return forkNode; + } else { + return new Node<>(parent, current); + } + } + + public static boolean checkNFJProperty(DirectedAcyclicGraph jobDag) { + LinkedList joinNodes = new LinkedList<>(); + LinkedList forkNodes = new LinkedList<>(); + + collectForksAndJoins(jobDag, forkNodes, joinNodes); + + if (!(joinNodes.size() > 1)) { + return true; } for (Job j : joinNodes) { @@ -257,14 +353,29 @@ public class DagTask implements Task { return false; } + private static Job findJoin(DirectedAcyclicGraph jobDag, Job forkNode, + Job sink, List joinNodes) { + for (Job j : joinNodes) { + final Set edgeSet = new HashSet<>(); + AllDirectedPaths finder = new AllDirectedPaths<>(jobDag); + finder.getAllPaths(forkNode, j, true, null) + .forEach(g -> edgeSet.addAll(g.getEdgeList())); + Set outgoingEdges = jobDag.outgoingEdgesOf(forkNode); + if (edgeSet.containsAll(outgoingEdges)) { + return j; + } + } + + return sink; + } + private static boolean checkForFork(DirectedAcyclicGraph jobDag, Job joinNode, List forkNodes, Job job) { List pred = Graphs.predecessorListOf(jobDag, job); for (Job p : pred) { if (forkNodes.contains(p)) { - for (DefaultEdge successorEdge : jobDag.outgoingEdgesOf(p)) { - Job successor = jobDag.getEdgeSource(successorEdge); + for (Job successor : Graphs.successorListOf(jobDag, p)) { if (jobDag.getAncestors(jobDag, joinNode).contains(successor)) { return false; } @@ -277,5 +388,81 @@ public class DagTask implements Task { return true; } + + public static DirectedAcyclicGraph createNFJfromDecompositionTree( + BinaryDecompositionTree tree) { + DirectedAcyclicGraph jobDag = + new DirectedAcyclicGraph<>(DefaultEdge.class); + + traverseNodes(jobDag, tree.getRootNode(), TraversalOrder.LEFT); + + return jobDag; + + } + + private static Set traverseNodes(DirectedAcyclicGraph jobDag, + Node node, TraversalOrder order) { + switch (node.getNodeType()) { + case LEAF: { + Job j = node.getObject(); + jobDag.addVertex(j); + return new HashSet(Arrays.asList(j)); + } + case SEQ: { + Set left = traverseNodes(jobDag, node.getLeftNode(), TraversalOrder.LEFT); + Set right = + traverseNodes(jobDag, node.getRightNode(), TraversalOrder.RIGHT); + try { + for (Job l : left) { + for (Job r : right) { + jobDag.addDagEdge(l, r); + } + } + } catch (Exception e) { + } + if (order == TraversalOrder.LEFT) { + Set openEndJobs = new HashSet<>(); + for (Job j : right) { + if (jobDag.outDegreeOf(j) == 0) { + openEndJobs.add(j); + } + for (Job d : jobDag.getDescendants(jobDag, j)) { + if (jobDag.outDegreeOf(d) == 0) { + openEndJobs.add(d); + } + } + } + return openEndJobs; + } else { + return left; + } + // return order == TraversalOrder.LEFT ? right : left; // left -> right; right + // -> + } + case PAR: { + Set left = traverseNodes(jobDag, node.getLeftNode(), order); + Set right = traverseNodes(jobDag, node.getRightNode(), order); + return Sets.newHashSet(Iterables.concat(left, right)); + } + default: + break; + } + return new HashSet<>(); + } + + private class GraphEndPoints { + public Set left; + public Set right; + + public GraphEndPoints(Set left, Set right) { + this.left = left; + this.right = right; + } + } + + private enum TraversalOrder { + LEFT, RIGHT + } + } } diff --git a/src/main/java/mvd/jester/model/SystemSetup.java b/src/main/java/mvd/jester/model/SystemSetup.java index 5475773..5c76f0f 100644 --- a/src/main/java/mvd/jester/model/SystemSetup.java +++ b/src/main/java/mvd/jester/model/SystemSetup.java @@ -211,7 +211,7 @@ public class SystemSetup { private long p_par = 80; private long p_add = 20; - private double getBeta() { + public double getBeta() { return 0.035 * numberOfProcessors; } @@ -253,7 +253,6 @@ public class SystemSetup { fork(jobDag, Optional.of(j), this.depth); randomEdges(jobDag); - final long workload = DagUtils.calculateWorkload(jobDag); final long criticalPath = DagUtils.calculateCriticalPath(jobDag); diff --git a/src/main/java/mvd/jester/tests/FonsecaNelis.java b/src/main/java/mvd/jester/tests/FonsecaNelis.java index 425ddb6..ff40b8c 100644 --- a/src/main/java/mvd/jester/tests/FonsecaNelis.java +++ b/src/main/java/mvd/jester/tests/FonsecaNelis.java @@ -4,6 +4,7 @@ import java.math.RoundingMode; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; @@ -11,6 +12,7 @@ import com.google.common.collect.Lists; import com.google.common.math.LongMath; import org.jgrapht.experimental.dag.DirectedAcyclicGraph; import org.jgrapht.graph.DefaultEdge; +import org.jgrapht.traverse.BreadthFirstIterator; import mvd.jester.info.SchedulingInfo; import mvd.jester.info.TerminationInfo; import mvd.jester.info.TerminationInfo.Level; @@ -22,6 +24,7 @@ import mvd.jester.model.Task; import mvd.jester.model.DagTask.DagUtils; import mvd.jester.priority.PriorityManager; import mvd.jester.priority.RateMonotonic; +import mvd.jester.utils.BinaryDecompositionTree; public class FonsecaNelis extends AbstractTest { @@ -57,14 +60,25 @@ public class FonsecaNelis extends AbstractTest { private void createNFJandDecompositionTree(SortedTaskSet tasks) { for (DagTask t : tasks) { + DirectedAcyclicGraph jobDag = t.getJobDag(); + LinkedList joinNodes = new LinkedList<>(); + LinkedList forkNodes = new LinkedList<>(); + + BreadthFirstIterator breadthFirstIterator = + new BreadthFirstIterator<>(jobDag); + while (breadthFirstIterator.hasNext()) { + Job j = breadthFirstIterator.next(); + if (jobDag.inDegreeOf(j) > 1) { + joinNodes.add(j); + } + if (jobDag.outDegreeOf(j) > 1) { + forkNodes.add(j); + } + } DirectedAcyclicGraph modifiedJobDag = - DagUtils.createNFJGraph(t.getJobDag()); - // List sortedSegment = new LinkedList<>(t.getWorkloadDistribution()); - // Collections.sort(sortedSegment, - // (s1, s2) -> (int) (s2.getNumberOfJobs() - s1.getNumberOfJobs())); - - // Set sortedSet = new LinkedHashSet<>(sortedSegment); - // sortedSegments.put(t, sortedSet); + DagUtils.createNFJGraph(jobDag, forkNodes, joinNodes); + BinaryDecompositionTree tree = + DagUtils.createDecompositionTree(modifiedJobDag, forkNodes, joinNodes); } } diff --git a/src/main/java/mvd/jester/utils/BinaryDecompositionTree.java b/src/main/java/mvd/jester/utils/BinaryDecompositionTree.java new file mode 100644 index 0000000..dd2f4e9 --- /dev/null +++ b/src/main/java/mvd/jester/utils/BinaryDecompositionTree.java @@ -0,0 +1,107 @@ +package mvd.jester.utils; + +public class BinaryDecompositionTree { + + private Node root; + + public BinaryDecompositionTree() { + } + + public Node getRootNode() { + return root; + } + + public boolean contains(N object) { + return root.contains(object); + } + + public boolean isEmpty() { + return root == null; + } + + public void setRoot(Node root) { + this.root = root; + } + + public static class Node { + private final Node parentNode; + private Node leftNode; + private Node rightNode; + private NodeType nodeType; + private T object; + + public Node(Node parentNode, NodeType nodeType) { + this.parentNode = parentNode; + this.nodeType = nodeType; + } + + public boolean contains(T object) { + if (nodeType.equals(NodeType.LEAF)) { + return this.object == object; + } else { + boolean leftContains = false; + boolean rightContains = false; + if (leftNode != null) { + leftContains = leftNode.contains(object); + } + if (rightNode != null) { + rightContains = rightNode.contains(object); + } + return leftContains || rightContains; + } + } + + public Node(Node parentNode, T object) { + this.parentNode = parentNode; + this.nodeType = NodeType.LEAF; + this.object = object; + } + + /** + * @return the parentNode + */ + public Node getParentNode() { + return parentNode; + } + + public NodeType getNodeType() { + return nodeType; + } + + public T getObject() { + return object; + } + + /** + * @param leftNode the leftNode to set + */ + public void setLeftNode(Node leftNode) { + this.leftNode = leftNode; + } + + /** + * @return the leftNode + */ + public Node getLeftNode() { + return leftNode; + } + + /** + * @param rightNode the rightNode to set + */ + public void setRightNode(Node rightNode) { + this.rightNode = rightNode; + } + + /** + * @return the rightNode + */ + public Node getRightNode() { + return rightNode; + } + } + + public enum NodeType { + SEQ, PAR, LEAF + } +} diff --git a/src/test/java/mvd/jester/model/TestDagUtils.java b/src/test/java/mvd/jester/model/TestDagUtils.java new file mode 100644 index 0000000..53e9bed --- /dev/null +++ b/src/test/java/mvd/jester/model/TestDagUtils.java @@ -0,0 +1,138 @@ +package mvd.jester.model; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.jgrapht.experimental.dag.DirectedAcyclicGraph; +import org.jgrapht.graph.DefaultEdge; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import mvd.jester.model.DagTask.DagUtils; +import mvd.jester.model.SystemSetup.DagTaskBuilder; +import mvd.jester.utils.BinaryDecompositionTree; + +public class TestDagUtils { + + @Test + @DisplayName("Test if a NFJ Graph is created correctly.") + public void checkNFJCreation() { + for (int i = 0; i < 100; ++i) { + DagTaskBuilder builder = new DagTaskBuilder(); + DirectedAcyclicGraph jobDag = builder.generateTask().getJobDag(); + + DirectedAcyclicGraph modifiedJobDag = DagUtils.createNFJGraph(jobDag); + + assertTrue(DagUtils.checkNFJProperty(modifiedJobDag)); + } + } + + + @Test + @DisplayName("Test if dynamic segments are constructed correctly.") + public void checkPathLength() { + DirectedAcyclicGraph jobDag = createJobDag(); + long criticalPath = DagUtils.calculateCriticalPath(jobDag); + + for (Job j : jobDag) { + assertTrue(j.getRelativeCompletionTime() <= criticalPath); + } + for (DefaultEdge e : jobDag.edgeSet()) { + Job source = jobDag.getEdgeSource(e); + Job target = jobDag.getEdgeTarget(e); + assertTrue(source.getRelativeCompletionTime() < target.getRelativeCompletionTime()); + } + + assertTrue(criticalPath == 155); + } + + + @Test + @DisplayName("Check if Decomposition Tree is created correctly for NFJ Dag.") + void checkDecompositionTreeCreation() { + DirectedAcyclicGraph jobDag = createJobDag(); + + BinaryDecompositionTree tree = DagUtils.createDecompositionTree(jobDag); + DirectedAcyclicGraph jobDagFromTree = + DagUtils.createNFJfromDecompositionTree(tree); + + assertTrue(jobDag.equals(jobDagFromTree)); + } + + + private DirectedAcyclicGraph createJobDag() { + DirectedAcyclicGraph jobDag = + new DirectedAcyclicGraph<>(DefaultEdge.class); + + Job source = new Job(20); + Job pathA = new Job(10); + Job pathB = new Job(30); + Job pathC = new Job(40); + + Job child1OfA = new Job(5); + Job child2OfA = new Job(15); + Job child3OfA = new Job(5); + + Job childsOfAJoin = new Job(10); + + Job child1OfC = new Job(5); + Job child2OfC = new Job(10); + Job child3OfC = new Job(15); + Job child4OfC = new Job(20); + + Job firstJoin = new Job(20); + + Job intermediateFork = new Job(10); + + Job forkChild1 = new Job(5); + Job forkChild2 = new Job(10); + Job forkChild3 = new Job(15); + + Job sink = new Job(30); + try { + jobDag.addVertex(source); + jobDag.addVertex(pathA); + jobDag.addVertex(pathB); + jobDag.addVertex(pathC); + jobDag.addVertex(child1OfA); + jobDag.addVertex(child2OfA); + jobDag.addVertex(child3OfA); + jobDag.addVertex(childsOfAJoin); + jobDag.addVertex(child1OfC); + jobDag.addVertex(child2OfC); + jobDag.addVertex(child3OfC); + jobDag.addVertex(child4OfC); + jobDag.addVertex(firstJoin); + jobDag.addVertex(intermediateFork); + jobDag.addVertex(forkChild1); + jobDag.addVertex(forkChild2); + jobDag.addVertex(forkChild3); + jobDag.addVertex(sink); + jobDag.addDagEdge(source, pathA); + jobDag.addDagEdge(pathA, child1OfA); + jobDag.addDagEdge(pathA, child2OfA); + jobDag.addDagEdge(pathA, child3OfA); + jobDag.addDagEdge(child1OfA, childsOfAJoin); + jobDag.addDagEdge(child2OfA, childsOfAJoin); + jobDag.addDagEdge(child3OfA, childsOfAJoin); + jobDag.addDagEdge(childsOfAJoin, firstJoin); + jobDag.addDagEdge(source, pathB); + jobDag.addDagEdge(pathB, firstJoin); + jobDag.addDagEdge(source, pathC); + jobDag.addDagEdge(pathC, child1OfC); + jobDag.addDagEdge(pathC, child2OfC); + jobDag.addDagEdge(pathC, child3OfC); + jobDag.addDagEdge(pathC, child4OfC); + jobDag.addDagEdge(child1OfC, firstJoin); + jobDag.addDagEdge(child2OfC, firstJoin); + jobDag.addDagEdge(child3OfC, firstJoin); + jobDag.addDagEdge(child4OfC, firstJoin); + jobDag.addDagEdge(firstJoin, intermediateFork); + jobDag.addDagEdge(intermediateFork, forkChild1); + jobDag.addDagEdge(intermediateFork, forkChild2); + jobDag.addDagEdge(intermediateFork, forkChild3); + jobDag.addDagEdge(forkChild1, sink); + jobDag.addDagEdge(forkChild2, sink); + jobDag.addDagEdge(forkChild3, sink); + } catch (Exception e) { + } + return jobDag; + } +} diff --git a/src/test/java/mvd/jester/model/TestSegment.java b/src/test/java/mvd/jester/model/TestSegment.java index f58e327..161cfdf 100644 --- a/src/test/java/mvd/jester/model/TestSegment.java +++ b/src/test/java/mvd/jester/model/TestSegment.java @@ -1,7 +1,6 @@ package mvd.jester.model; import static org.junit.jupiter.api.Assertions.assertTrue; -import com.google.common.math.LongMath; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/src/test/java/mvd/jester/model/TestSystemSetup.java b/src/test/java/mvd/jester/model/TestSystemSetup.java index ed077a1..36814da 100644 --- a/src/test/java/mvd/jester/model/TestSystemSetup.java +++ b/src/test/java/mvd/jester/model/TestSystemSetup.java @@ -2,18 +2,10 @@ package mvd.jester.model; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; -import java.awt.Color; -import java.awt.image.BufferedImage; -import java.io.File; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; -import javax.imageio.ImageIO; import com.google.common.math.DoubleMath; -import com.mxgraph.layout.mxCircleLayout; -import com.mxgraph.layout.mxIGraphLayout; -import com.mxgraph.util.mxCellRenderer; import org.jgrapht.experimental.dag.DirectedAcyclicGraph; -import org.jgrapht.ext.JGraphXAdapter; import org.jgrapht.graph.DefaultEdge; import org.junit.Rule; import org.junit.jupiter.api.DisplayName; @@ -86,40 +78,45 @@ public class TestSystemSetup { @Test @DisplayName("Check if DagTaskBuilder works correctly") void testDagTaskBuilder() { - DagTaskBuilder builder = new DagTaskBuilder(); - DirectedAcyclicGraph j = builder.generateTask().getJobDag(); - - JGraphXAdapter graphAdapter = new JGraphXAdapter(j); - - mxIGraphLayout layout = new mxCircleLayout(graphAdapter); - layout.execute(graphAdapter.getDefaultParent()); + for (int i = 0; i < 100; ++i) { + DagTaskBuilder builder = new DagTaskBuilder(); + DagTask task = builder.generateTask(); + DirectedAcyclicGraph jobDag = task.getJobDag(); - BufferedImage image = - mxCellRenderer.createBufferedImage(graphAdapter, null, 2, Color.WHITE, true, null); + assertTrue(task.getCriticalPath() <= task.getPeriod()); + assertTrue(task.getPeriod() <= (long) (task.getWorkload() / builder.getBeta())); - File imgFile = new File("src/test/resources/graph.png"); - try { - ImageIO.write(image, "PNG", imgFile); - } catch (Exception e) { + for (Job j : jobDag) { + assertTrue(1 <= j.getWcet() && j.getWcet() <= 100); + assertTrue(j.getRelativeCompletionTime() <= task.getCriticalPath()); + if (jobDag.outDegreeOf(j) == 0) { + assertTrue(j.getRelativeCompletionTime() == task.getCriticalPath()); + } + } + for (DefaultEdge e : jobDag.edgeSet()) { + Job source = jobDag.getEdgeSource(e); + Job target = jobDag.getEdgeTarget(e); + assertTrue(source.getRelativeCompletionTime() < target.getRelativeCompletionTime()); + } } - assertTrue(imgFile.exists()); - } @Test @DisplayName("Check if utilization works correctly.") void testUtil() { - for (double d = 0.25; d < 4; d += 0.25) { - DagTaskBuilder builder = new DagTaskBuilder(); - Set taskSet = builder.generateTaskSet(d); - double taskSetUtil = 0; - for (DagTask t : taskSet) { - taskSetUtil += t.getUtilization(); - } + for (int i = 0; i < 5; ++i) { + for (double d = 0.25; d < 4; d += 0.25) { + DagTaskBuilder builder = new DagTaskBuilder(); + Set taskSet = builder.generateTaskSet(d); + double taskSetUtil = 0; + for (DagTask t : taskSet) { + taskSetUtil += t.getUtilization(); + } - assertTrue(DoubleMath.fuzzyEquals(taskSetUtil, d, 0.002)); + assertTrue(DoubleMath.fuzzyEquals(taskSetUtil, d, 0.002)); + } } }