FonsecaNelis.java 11.5 KB
Newer Older
1 2 3
package mvd.jester.tests;

import java.math.RoundingMode;
4
import java.util.Arrays;
5 6 7
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
8
import java.util.LinkedHashSet;
9 10
import java.util.List;
import java.util.Map;
11
import java.util.Optional;
12 13
import java.util.Set;
import com.google.common.collect.Lists;
14
import com.google.common.collect.Sets;
15
import com.google.common.math.LongMath;
Michael Schmid committed
16 17
import org.jgrapht.experimental.dag.DirectedAcyclicGraph;
import org.jgrapht.graph.DefaultEdge;
18 19 20
import mvd.jester.info.SchedulingInfo;
import mvd.jester.info.TerminationInfo;
import mvd.jester.model.DagTask;
Michael Schmid committed
21
import mvd.jester.model.Job;
22 23 24
import mvd.jester.model.Segment;
import mvd.jester.model.SortedTaskSet;
import mvd.jester.model.Task;
25
import mvd.jester.model.TreeJob;
26
import mvd.jester.utils.DagUtils;
27 28
import mvd.jester.priority.PriorityManager;
import mvd.jester.priority.RateMonotonic;
29
import mvd.jester.utils.BinaryDecompositionTree;
30 31
import mvd.jester.utils.BinaryDecompositionTree.Node;
import mvd.jester.utils.BinaryDecompositionTree.NodeType;
32 33 34 35 36

public class FonsecaNelis extends AbstractTest<DagTask> {

    private final Map<Task, TerminationInfo> responseTimes;
    private final PriorityManager priorityManager;
37
    private final Map<Task, Set<Segment>> carryOutSegments;
38

39
    public FonsecaNelis(final long numberOfProcessors) {
40 41 42
        super(numberOfProcessors);
        this.responseTimes = new HashMap<>();
        this.priorityManager = new RateMonotonic();
43
        this.carryOutSegments = new HashMap<>();
44 45 46 47 48 49 50 51
    }

    @Override
    public PriorityManager getPriorityManager() {
        return priorityManager;
    }

    @Override
52
    public SchedulingInfo runSchedulabilityCheck(final SortedTaskSet<DagTask> tasks) {
53
        carryOutSegments.clear();
54
        responseTimes.clear();
Michael Schmid committed
55
        createNFJandDecompositionTree(tasks);
56 57 58
        for (final DagTask t : tasks) {
            final long responseTime = calculateResponseTime(tasks, t);
            responseTimes.put(t, new TerminationInfo(t.getDeadline(), responseTime));
59 60
        }

61
        return new SchedulingInfo(responseTimes.values());
62 63
    }

64 65 66
    private void createNFJandDecompositionTree(final SortedTaskSet<DagTask> tasks) {
        for (final DagTask t : tasks) {
            final DirectedAcyclicGraph<Job, DefaultEdge> jobDag = t.getJobDag();
67

68 69 70
            final DirectedAcyclicGraph<Job, DefaultEdge> nfjJobDag =
                    DagUtils.createNFJGraph(jobDag);
            final BinaryDecompositionTree<Job> tree = DagUtils.createDecompositionTree(nfjJobDag);
71

72
            carryOutSegments.put(t, constructCarryOutDistribution(nfjJobDag, tree));
73 74 75
        }
    }

76
    private Set<Segment> constructCarryOutDistribution(
77 78 79 80
            final DirectedAcyclicGraph<Job, DefaultEdge> nfjDag,
            final BinaryDecompositionTree<Job> tree) {
        final Set<Segment> carryOutWorkload = new LinkedHashSet<>();
        final BinaryDecompositionTree<TreeJob> modifiedTree = transformTree(tree);
81 82 83

        boolean isEmpty = false;
        do {
84 85
            final Set<TreeJob> parallelJobs = getMaximumParallelism(modifiedTree.getRootNode());
            final Optional<TreeJob> min =
86 87
                    parallelJobs.stream().min((p1, p2) -> Long.compare(p1.getWcet(), p2.getWcet()));
            if (min.isPresent()) {
88
                final long width = min.get().getWcet();
89
                carryOutWorkload.add(new Segment(width, parallelJobs.size()));
90
                for (final TreeJob p : parallelJobs) {
91
                    p.setWcet(p.getWcet() - width);
92
                }
93 94 95 96 97 98 99 100 101 102
            } else {
                break;
            }
            isEmpty = parallelJobs.isEmpty();
        } while (!isEmpty);

        return carryOutWorkload;
    }


103 104 105 106
    private BinaryDecompositionTree<TreeJob> transformTree(
            final BinaryDecompositionTree<Job> tree) {
        final BinaryDecompositionTree<TreeJob> modifiedTree = new BinaryDecompositionTree<>();
        final Node<TreeJob> root = transformNode(null, tree.getRootNode());
107 108 109 110
        modifiedTree.setRoot(root);
        return modifiedTree;
    }

111
    private Node<TreeJob> transformNode(final Node<TreeJob> parent, final Node<Job> node) {
112 113 114
        if (node.getNodeType().equals(NodeType.LEAF)) {
            return new Node<TreeJob>(parent, new TreeJob(node.getObject()));
        } else {
115
            final Node<TreeJob> modifiedNode = new Node<TreeJob>(parent, node.getNodeType());
116 117 118 119 120 121
            modifiedNode.setLeftNode(transformNode(modifiedNode, node.getLeftNode()));
            modifiedNode.setRightNode(transformNode(modifiedNode, node.getRightNode()));
            return modifiedNode;
        }
    }

122 123
    private Set<TreeJob> getMaximumParallelism(final Node<TreeJob> node) {
        final NodeType nodeType = node.getNodeType();
124
        if (nodeType.equals(NodeType.PAR)) {
125 126
            final Set<TreeJob> left = getMaximumParallelism(node.getLeftNode());
            final Set<TreeJob> right = getMaximumParallelism(node.getRightNode());
127 128
            return Sets.union(left, right);
        } else if (nodeType.equals(NodeType.SEQ)) {
129 130
            final Set<TreeJob> left = getMaximumParallelism(node.getLeftNode());
            final Set<TreeJob> right = getMaximumParallelism(node.getRightNode());
131 132 133 134 135 136 137 138 139 140
            if (left.size() >= right.size()) {
                return left;
            } else {
                return right;
            }
        } else {
            if (node.getObject().getWcet() > 0) {
                return new HashSet<>(Arrays.asList(node.getObject()));
            } else {
                return new HashSet<>();
141
            }
Michael Schmid committed
142
        }
143 144
    }

145 146
    private long calculateResponseTime(final SortedTaskSet<DagTask> tasks, final DagTask task) {
        final long criticalPath = task.getCriticalPath();
147 148 149 150 151 152
        long responseTime = criticalPath;
        long previousResponseTime = 0;

        do {
            previousResponseTime = responseTime;
            double taskInterference = 0;
153
            for (final DagTask t : tasks) {
154 155 156 157 158 159 160
                if (t.getPeriod() < task.getPeriod()) {
                    taskInterference += getTaskInterference(t, responseTime);
                }
            }

            taskInterference /= numberOfProcessors;

161
            final double selfInterference = getSelfInterference(task);
162

163
            final long totalInterference = (long) Math.floor(taskInterference + selfInterference);
164 165 166 167 168 169 170
            responseTime = criticalPath + totalInterference;

        } while (responseTime != previousResponseTime);

        return responseTime;
    }

171 172 173
    private double getTaskInterference(final DagTask task, final long interval) {
        final long period = task.getPeriod();
        final long criticalPath = task.getCriticalPath();
174
        final long numberOfPeriods =
175
                LongMath.divide(interval - criticalPath, period, RoundingMode.FLOOR);
176
        final long carryInAndOutInterval = interval - Math.max(0, numberOfPeriods) * period;
177
        final long numberOfBodyJobs =
178 179
                LongMath.divide(interval - carryInAndOutInterval, period, RoundingMode.FLOOR);

180
        final long bodyWorkload = Math.max(0, numberOfBodyJobs) * task.getWorkload();
181 182


183
        final long carryInAndOutWorkload = getCarryInAndOutWorkload(task,
184
                task.getWorkloadDistribution(), carryOutSegments.get(task), carryInAndOutInterval);
185 186 187 188

        return carryInAndOutWorkload + bodyWorkload;
    }

189 190 191
    private long getCarryInAndOutWorkload(final DagTask task,
            final Set<Segment> carryInDistribution, final Set<Segment> carryOutDistribution,
            final long carryInAndOutPeriod) {
192 193 194
        long workload = getCarryOutWorkload(task, carryOutDistribution, carryInAndOutPeriod);
        long carryInPeriod = task.getPeriod() - responseTimes.get(task).getResponseTime();
        long carryOutPeriod = 0;
Michael Schmid committed
195 196
        final List<Segment> reverseCarryInList = Lists.newArrayList(carryInDistribution);
        Collections.reverse(reverseCarryInList);
197

Michael Schmid committed
198
        for (final Segment s : reverseCarryInList) {
199 200
            carryInPeriod += s.getJobWcet();
            carryOutPeriod = carryInAndOutPeriod - carryInPeriod;
201 202 203 204
            final long carryInWorkload =
                    getCarryInWorkload(task, carryInDistribution, carryInPeriod);
            final long carryOutWorkload =
                    getCarryOutWorkload(task, carryOutDistribution, carryOutPeriod);
205 206 207 208 209 210 211
            workload = Math.max(workload, carryInWorkload + carryOutWorkload);
        }

        workload = Math.max(workload,
                getCarryInWorkload(task, carryInDistribution, carryInAndOutPeriod));
        carryOutPeriod = 0;

212
        for (final Segment s : carryOutDistribution) {
213 214
            carryOutPeriod += s.getJobWcet();
            carryInPeriod = carryInAndOutPeriod - carryOutPeriod;
215 216 217 218
            final long carryInWorkload =
                    getCarryInWorkload(task, carryInDistribution, carryInPeriod);
            final long carryOutWorkload =
                    getCarryOutWorkload(task, carryOutDistribution, carryOutPeriod);
219 220 221 222 223 224
            workload = Math.max(workload, carryInWorkload + carryOutWorkload);
        }

        return workload;
    }

225 226
    private long getCarryOutWorkload(final DagTask task, final Set<Segment> carryOutDistribution,
            final long carryOutPeriod) {
227
        long workload = 0;
228 229
        final long taskWorkload = task.getWorkload();
        final long criticalPath = task.getCriticalPath();
230
        final List<Segment> distributionList = Lists.newArrayList(carryOutDistribution);
231 232

        for (int i = 0; i < distributionList.size(); ++i) {
233
            final Segment s = distributionList.get(i);
234 235 236 237
            long weightOfPreviousSegments = 0;
            for (int j = 0; j < i; ++j) {
                weightOfPreviousSegments += distributionList.get(j).getJobWcet();
            }
238
            final long width = carryOutPeriod - weightOfPreviousSegments;
239 240 241 242

            workload += Math.max(Math.min(width, s.getJobWcet()), 0) * s.getNumberOfJobs();
        }

243 244 245
        final long improvedWorkloadFromTask =
                taskWorkload - Math.max(0, criticalPath - carryOutPeriod);
        final long improvedWorkloadFromProcessors = carryOutPeriod * numberOfProcessors;
246

247 248
        return Math.min(Math.min(improvedWorkloadFromTask, improvedWorkloadFromProcessors),
                workload);
249 250
    }

251 252
    private long getCarryInWorkload(final DagTask task, final Set<Segment> carryInDistribution,
            final long carryInPeriod) {
253
        long workload = 0;
254 255 256
        final long period = task.getPeriod();
        final long responseTime = responseTimes.get(task).getResponseTime();
        final List<Segment> distributionList = Lists.newArrayList(carryInDistribution);
257

Michael Schmid committed
258 259
        for (int b = 0; b < carryInDistribution.size(); ++b) {
            final Segment s = distributionList.get(b);
260
            long weightOfRemainingSegments = 0;
Michael Schmid committed
261 262
            for (int p = b + 1; p < carryInDistribution.size(); ++p) {
                weightOfRemainingSegments += distributionList.get(p).getJobWcet();
263
            }
264
            final long width = carryInPeriod - period + responseTime - weightOfRemainingSegments;
265 266 267 268

            workload += Math.max(Math.min(width, s.getJobWcet()), 0) * s.getNumberOfJobs();
        }

269
        final long improvedWorkload =
270 271 272 273 274
                Math.max(carryInPeriod - (period - responseTime), 0) * numberOfProcessors;

        return Math.min(improvedWorkload, workload);
    }

275 276 277
    private double getSelfInterference(final DagTask task) {
        final long criticalPath = task.getCriticalPath();
        final long workload = task.getWorkload();
278 279 280 281 282 283 284 285 286 287 288

        return (double) (workload - criticalPath) / numberOfProcessors;
    }

    @Override
    public String getName() {
        return "FonsecaNelis";
    }


}