From b00f2d0e814f80400dce656d3c1008bde3dd8331 Mon Sep 17 00:00:00 2001 From: Michael Schmid Date: Wed, 12 Aug 2020 11:23:42 +0200 Subject: [PATCH] Simulator now works --- src/main/java/mvd/jester/App.java | 5 ++++- src/main/java/mvd/jester/model/DagTask.java | 5 +++++ src/main/java/mvd/jester/model/Subtask.java | 6 ++++++ src/main/java/mvd/jester/model/SystemManager.java | 10 +++++----- src/main/java/mvd/jester/simulator/GlobalScheduler.java | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------ src/main/java/mvd/jester/simulator/events/AbstractContextEvent.java | 4 ++-- src/main/java/mvd/jester/simulator/events/AbstractSubtaskEvent.java | 2 +- src/main/java/mvd/jester/simulator/events/ISubtaskEvent.java | 2 +- src/main/java/mvd/jester/simulator/events/SubtaskActivatedEvent.java | 16 +++------------- src/main/java/mvd/jester/simulator/events/SubtaskCompletedEvent.java | 3 ++- src/main/java/mvd/jester/simulator/events/TaskReleasedEvent.java | 2 +- src/main/java/mvd/jester/simulator/model/ExtendedSubtaskContext.java | 5 +++++ src/main/java/mvd/jester/simulator/model/JobContext.java | 24 +++++++++++++++++++++++- src/main/java/mvd/jester/simulator/model/ProcessorContext.java | 25 +++++++++++++++++++++++++ 14 files changed, 159 insertions(+), 74 deletions(-) diff --git a/src/main/java/mvd/jester/App.java b/src/main/java/mvd/jester/App.java index 03a4f80..a4d893a 100644 --- a/src/main/java/mvd/jester/App.java +++ b/src/main/java/mvd/jester/App.java @@ -7,6 +7,8 @@ import mvd.jester.model.SystemManager; import mvd.jester.model.SystemManager.DagTaskBuilder; import mvd.jester.priority.RateMonotonic; import mvd.jester.simulator.GlobalScheduler; +import mvd.jester.simulator.model.ExtendedSubtaskContext; +import mvd.jester.simulator.model.JobContext; import mvd.jester.tests.AbstractTest; import mvd.jester.tests.FonsecaNelis; import mvd.jester.tests.MelaniButtazzo; @@ -25,7 +27,8 @@ public class App { GlobalScheduler scheduler = new GlobalScheduler(new RateMonotonic(), 4); DagTaskBuilder builder = new DagTaskBuilder().setNumberOfProcessors(4); - scheduler.schedule(builder.generateTaskSet(3), 10000); + scheduler.schedule(builder.generateTaskSet(1.0), 10000); + // { // SystemManager manager = new SystemManager(8); // DagTaskBuilder builder = new DagTaskBuilder(); diff --git a/src/main/java/mvd/jester/model/DagTask.java b/src/main/java/mvd/jester/model/DagTask.java index 6ea5256..61e3261 100644 --- a/src/main/java/mvd/jester/model/DagTask.java +++ b/src/main/java/mvd/jester/model/DagTask.java @@ -98,4 +98,9 @@ public class DagTask implements Task { return numberOfThreads; } + + @Override + public String toString() { + return "(P=" + period + ", D=" + deadline + ")"; + } } diff --git a/src/main/java/mvd/jester/model/Subtask.java b/src/main/java/mvd/jester/model/Subtask.java index 7e5ddc4..8702fa3 100644 --- a/src/main/java/mvd/jester/model/Subtask.java +++ b/src/main/java/mvd/jester/model/Subtask.java @@ -27,4 +27,10 @@ public class Subtask { public void setRelativeCompletionTime(long relativeCompletionTime) { this.relativeCompletionTime = relativeCompletionTime; } + + @Override + public String toString() { + return "(C=" + wcet + ")"; + } + } diff --git a/src/main/java/mvd/jester/model/SystemManager.java b/src/main/java/mvd/jester/model/SystemManager.java index 8e881f6..a350144 100644 --- a/src/main/java/mvd/jester/model/SystemManager.java +++ b/src/main/java/mvd/jester/model/SystemManager.java @@ -160,10 +160,10 @@ public class SystemManager { private long numberOfProcessors = 8; private long minimumWcet = 1; private long maximumWcet = 100; - private long maxNumberOfBranches = 5; - private long depth = 2; + private long maxNumberOfBranches = 3; // TODO: Change back to 5 + private long depth = 1; // TODO: Change back to 2 private long p_par = 80; - private long p_add = 20; + private long p_add = 10; // TODO: Change back to 20 public DagTaskBuilder() { } @@ -252,8 +252,8 @@ public class SystemManager { return new DagTask(jobDag, period, numberOfProcessors); } - private Subtask join(final DirectedAcyclicGraph jobDag, final Subtask current, - final Set childs) { + private Subtask join(final DirectedAcyclicGraph jobDag, + final Subtask current, final Set childs) { if (childs.size() > 0) { final Subtask job = new Subtask(randomWcet()); jobDag.addVertex(job); diff --git a/src/main/java/mvd/jester/simulator/GlobalScheduler.java b/src/main/java/mvd/jester/simulator/GlobalScheduler.java index 94b72a7..9acab73 100644 --- a/src/main/java/mvd/jester/simulator/GlobalScheduler.java +++ b/src/main/java/mvd/jester/simulator/GlobalScheduler.java @@ -4,37 +4,43 @@ import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.stream.Collector; +import java.util.stream.Collectors; import org.jgrapht.Graphs; import mvd.jester.model.DagTask; import mvd.jester.model.Subtask; import mvd.jester.priority.PriorityManager; import mvd.jester.simulator.events.*; +import mvd.jester.simulator.exceptions.DeadlineMissedException; import mvd.jester.simulator.exceptions.SchedulingException; import mvd.jester.simulator.model.ExtendedSubtaskContext; import mvd.jester.simulator.model.JobContext; import mvd.jester.simulator.model.ProcessorContext; +import mvd.jester.simulator.model.ProcessorContext.ProcessorComparator; public class GlobalScheduler { private final int nbProcessors; private final PriorityManager priorityManager; - public GlobalScheduler(PriorityManager priorityManager, int nbProcessors) { + public GlobalScheduler(final PriorityManager priorityManager, final int nbProcessors) { this.priorityManager = priorityManager; this.nbProcessors = nbProcessors; } - public void schedule(Set taskSet, long duration) { - SchedulingContext sc = new SchedulingContext(priorityManager, nbProcessors, duration); + public void schedule(final Set taskSet, final long duration) { + final SchedulingContext sc = new SchedulingContext(priorityManager, nbProcessors, duration); taskSet.forEach(t -> sc.events.offer(new TaskReleasedEvent(0, t))); while (!sc.events.isEmpty()) { - IEvent event = sc.events.poll(); + final IEvent event = sc.events.poll(); updateExecution(sc, event.getTime()); handle(event, sc); } } - private void handle(IEvent event, SchedulingContext sc) { + private void handle(final IEvent event, final SchedulingContext sc) { event.log(); switch (event.getType()) { case SUBTASK_ACTIVATED: @@ -58,6 +64,9 @@ public class GlobalScheduler { case JOB_ACTIVATED: handleJobActivated((JobActivatedEvent) event, sc); break; + case JOB_COMPLETED: + handleJobCompleted((JobCompletedEvent) event, sc); + break; case TASK_RELEASED: handleTaskReleased((TaskReleasedEvent) event, sc); break; @@ -67,62 +76,78 @@ public class GlobalScheduler { } } - private void handleSubtaskActivated(SubtaskActivatedEvent event, SchedulingContext sc) { - Subtask subtask = event.getSubtask(); - JobContext job = event.getJobContext(); + private void handleJobCompleted(final JobCompletedEvent event, final SchedulingContext sc) { + if (event.getTime() > event.getJobContext().getDeadline()) { + throw new DeadlineMissedException(event.getJobContext() + " misses its deadline"); + } + } + + private void handleSubtaskActivated(final SubtaskActivatedEvent event, + final SchedulingContext sc) { + final Subtask subtask = event.getSubtask(); + final JobContext job = event.getJobContext(); sc.waitingQueue.offer(new ExtendedSubtaskContext(job, subtask)); updateAdmission(sc, event.getTime()); } - private void handleSubtaskCheckCompleted(SubtaskCheckCompletedEvent event, - SchedulingContext sc) { - ProcessorContext processor = event.getProcessor(); - if (processor.isIdle() || !processor.getSubtask().get().equals(event.getSubtaskContext())) { + private void handleSubtaskCheckCompleted(final SubtaskCheckCompletedEvent event, + final SchedulingContext sc) { + final ProcessorContext processor = event.getProcessor(); + if (processor.isIdle()) { throw new SchedulingException( processor + " should execute " + event.getSubtaskContext()); } - Optional context = processor.getSubtask(); + final Optional context = processor.getSubtask(); if (context.isPresent() && context.get().getRemainingExecutionTime() == 0) { sc.events.offer(new SubtaskStoppedEvent(event.getTime(), context.get(), processor)); } } - private void handleSubtaskCompleted(SubtaskCompletedEvent event, SchedulingContext sc) { - ExtendedSubtaskContext subtask = event.getSubtaskContext(); - JobContext job = subtask.getJobContext(); + private void handleSubtaskCompleted(final SubtaskCompletedEvent event, + final SchedulingContext sc) { + final ExtendedSubtaskContext subtask = event.getSubtaskContext(); + final JobContext job = subtask.getJobContext(); - DagTask task = subtask.getJobContext().getTask(); - List successor = Graphs.successorListOf(task.getJobDag(), subtask.getSubtask()); + job.registerFinishedSubtask(subtask); + final DagTask task = subtask.getJobContext().getTask(); + final List successor = + Graphs.successorListOf(task.getJobDag(), subtask.getSubtask()); if (successor.isEmpty()) { sc.events.offer(new JobCompletedEvent(event.getTime(), job)); updateAdmission(sc, event.getTime()); } else { - for (Subtask s : successor) { - sc.events.offer(new SubtaskActivatedEvent(event.getTime(), job, s)); + final List finishedSubtasks = job.getFinishedSubtasks().stream() + .map(esc -> esc.getSubtask()).collect(Collectors.toList()); + for (final Subtask s : successor) { + final List predecessors = Graphs.predecessorListOf(task.getJobDag(), s); + if (finishedSubtasks.containsAll(predecessors)) { + sc.events.offer(new SubtaskActivatedEvent(event.getTime(), job, s)); + } } } } - private void handleSubtaskPreempted(SubtaskPreemptedEvent event, SchedulingContext sc) { - ProcessorContext processor = event.getProcessor(); - long time = event.getTime(); - sc.events.offer(new SubtaskStoppedEvent(time, event.getNextSubtask(), processor)); - sc.events.offer(new SubtaskStartedEvent(time, event.getSubtaskContext(), processor)); + private void handleSubtaskPreempted(final SubtaskPreemptedEvent event, + final SchedulingContext sc) { + final ProcessorContext processor = event.getProcessor(); + final long time = event.getTime(); + sc.events.offer(new SubtaskStartedEvent(time, event.getNextSubtask(), processor)); + sc.events.offer(new SubtaskStoppedEvent(time, event.getSubtaskContext(), processor)); } - private void handleSubtaskStarted(SubtaskStartedEvent event, SchedulingContext sc) { - long time = event.getTime(); - ProcessorContext processor = event.getProcessor(); - ExtendedSubtaskContext context = event.getSubtaskContext(); + private void handleSubtaskStarted(final SubtaskStartedEvent event, final SchedulingContext sc) { + final long time = event.getTime(); + final ProcessorContext processor = event.getProcessor(); + final ExtendedSubtaskContext context = event.getSubtaskContext(); if (processor.accept(context, time)) { sc.events.offer(new SubtaskCheckCompletedEvent( time + context.getRemainingExecutionTime(), context, processor)); } } - private void handleSubtaskStopped(SubtaskStoppedEvent event, SchedulingContext sc) { - ExtendedSubtaskContext context = event.getSubtaskContext(); - ProcessorContext processor = event.getProcessor(); + private void handleSubtaskStopped(final SubtaskStoppedEvent event, final SchedulingContext sc) { + final ExtendedSubtaskContext context = event.getSubtaskContext(); + final ProcessorContext processor = event.getProcessor(); if (context.getRemainingExecutionTime() > 0) { sc.waitingQueue.offer(context); } else { @@ -131,30 +156,33 @@ public class GlobalScheduler { processor.free(); } - private void handleJobActivated(JobActivatedEvent event, SchedulingContext sc) { - JobContext job = event.getJobContext(); + private void handleJobActivated(final JobActivatedEvent event, final SchedulingContext sc) { + final JobContext job = event.getJobContext(); - DagTask task = job.getTask(); - long nextRelease = event.getTime() + task.getPeriod(); + final DagTask task = job.getTask(); + final long nextRelease = event.getTime() + task.getPeriod(); if (nextRelease < sc.duration) { - JobContext nextJob = new JobContext(task, nextRelease); + final JobContext nextJob = new JobContext(task, nextRelease); sc.events.offer(new JobActivatedEvent(nextRelease, nextJob)); } sc.events.offer(new SubtaskActivatedEvent(event.getTime(), job, job.getSource())); } - private void handleTaskReleased(TaskReleasedEvent event, SchedulingContext sc) { - DagTask task = event.getTask(); - long release = event.getTime(); - JobContext job = new JobContext(task, release); + private void handleTaskReleased(final TaskReleasedEvent event, final SchedulingContext sc) { + final DagTask task = event.getTask(); + final long release = event.getTime(); + final JobContext job = new JobContext(task, release); sc.events.offer(new JobActivatedEvent(release, job)); } - private void updateAdmission(SchedulingContext sc, long time) { - for (ProcessorContext processor : sc.processors) { + private void updateAdmission(final SchedulingContext sc, final long time) { + Set sortedProcessors = + new TreeSet<>(new ProcessorComparator(priorityManager)); + sortedProcessors.addAll(sc.processors); + for (final ProcessorContext processor : sortedProcessors) { if (processor.canAccept(sc.waitingQueue.peek(), priorityManager)) { - ExtendedSubtaskContext context = sc.waitingQueue.poll(); + final ExtendedSubtaskContext context = sc.waitingQueue.poll(); if (processor.isIdle()) { sc.events.offer(new SubtaskStartedEvent(time, context, processor)); } else { @@ -165,8 +193,8 @@ public class GlobalScheduler { } } - private void updateExecution(SchedulingContext sc, long time) { - for (ProcessorContext processor : sc.processors) { + private void updateExecution(final SchedulingContext sc, final long time) { + for (final ProcessorContext processor : sc.processors) { processor.update(time); } } @@ -178,8 +206,8 @@ public class GlobalScheduler { private final WaitQueue waitingQueue; private final long duration; - private SchedulingContext(PriorityManager priorityManager, int nbProcessors, - long duration) { + private SchedulingContext(final PriorityManager priorityManager, final int nbProcessors, + final long duration) { this.events = new EventQueue(priorityManager); this.waitingQueue = new WaitQueue(priorityManager); this.processors = new HashSet<>(); diff --git a/src/main/java/mvd/jester/simulator/events/AbstractContextEvent.java b/src/main/java/mvd/jester/simulator/events/AbstractContextEvent.java index 07eed1b..88f4290 100644 --- a/src/main/java/mvd/jester/simulator/events/AbstractContextEvent.java +++ b/src/main/java/mvd/jester/simulator/events/AbstractContextEvent.java @@ -3,7 +3,7 @@ package mvd.jester.simulator.events; import mvd.jester.simulator.model.ExtendedSubtaskContext; import mvd.jester.simulator.model.JobContext; -public abstract class AbstractContextEvent extends AbstractSubtaskEvent implements ISubtaskEvent { +public abstract class AbstractContextEvent extends AbstractSubtaskEvent { private final ExtendedSubtaskContext subtask; @@ -13,7 +13,7 @@ public abstract class AbstractContextEvent extends AbstractSubtaskEvent implemen this.subtask = subtask; } - @Override + // @Override public ExtendedSubtaskContext getSubtaskContext() { return subtask; } diff --git a/src/main/java/mvd/jester/simulator/events/AbstractSubtaskEvent.java b/src/main/java/mvd/jester/simulator/events/AbstractSubtaskEvent.java index f90abec..1cb06b0 100644 --- a/src/main/java/mvd/jester/simulator/events/AbstractSubtaskEvent.java +++ b/src/main/java/mvd/jester/simulator/events/AbstractSubtaskEvent.java @@ -2,7 +2,7 @@ package mvd.jester.simulator.events; import mvd.jester.simulator.model.JobContext; -public abstract class AbstractSubtaskEvent extends AbstractEvent { +public abstract class AbstractSubtaskEvent extends AbstractEvent implements ISubtaskEvent { private final JobContext jobContext; diff --git a/src/main/java/mvd/jester/simulator/events/ISubtaskEvent.java b/src/main/java/mvd/jester/simulator/events/ISubtaskEvent.java index 296b858..c7990ec 100644 --- a/src/main/java/mvd/jester/simulator/events/ISubtaskEvent.java +++ b/src/main/java/mvd/jester/simulator/events/ISubtaskEvent.java @@ -5,7 +5,7 @@ import mvd.jester.simulator.model.JobContext; public interface ISubtaskEvent extends IEvent { - public ExtendedSubtaskContext getSubtaskContext(); + // public ExtendedSubtaskContext getSubtaskContext(); public JobContext getJobContext(); diff --git a/src/main/java/mvd/jester/simulator/events/SubtaskActivatedEvent.java b/src/main/java/mvd/jester/simulator/events/SubtaskActivatedEvent.java index cb97842..997afff 100644 --- a/src/main/java/mvd/jester/simulator/events/SubtaskActivatedEvent.java +++ b/src/main/java/mvd/jester/simulator/events/SubtaskActivatedEvent.java @@ -3,25 +3,15 @@ package mvd.jester.simulator.events; import mvd.jester.model.Subtask; import mvd.jester.simulator.model.JobContext; -public class SubtaskActivatedEvent extends AbstractEvent { +public class SubtaskActivatedEvent extends AbstractSubtaskEvent { - private final JobContext job; private final Subtask subtask; public SubtaskActivatedEvent(final long time, final JobContext job, final Subtask subtask) { - super(EventType.SUBTASK_ACTIVATED, time); - this.job = job; + super(EventType.SUBTASK_ACTIVATED, time, job); this.subtask = subtask; } - - /** - * @return the job - */ - public JobContext getJobContext() { - return job; - } - /** * @return the subtask */ @@ -31,7 +21,7 @@ public class SubtaskActivatedEvent extends AbstractEvent { @Override protected String getLoggingMessage() { - return "Subtask " + getSubtask() + " released"; + return "Subtask " + getSubtask() + " of task " + getJobContext().getTask() + " released"; } } diff --git a/src/main/java/mvd/jester/simulator/events/SubtaskCompletedEvent.java b/src/main/java/mvd/jester/simulator/events/SubtaskCompletedEvent.java index f54696b..f933fc6 100644 --- a/src/main/java/mvd/jester/simulator/events/SubtaskCompletedEvent.java +++ b/src/main/java/mvd/jester/simulator/events/SubtaskCompletedEvent.java @@ -10,7 +10,8 @@ public class SubtaskCompletedEvent extends AbstractContextEvent { @Override protected String getLoggingMessage() { - return "Subtask " + getSubtaskContext() + " completed"; + return "Subtask " + getSubtaskContext() + " of task " + getJobContext().getTask() + + " completed"; } } diff --git a/src/main/java/mvd/jester/simulator/events/TaskReleasedEvent.java b/src/main/java/mvd/jester/simulator/events/TaskReleasedEvent.java index 39c7fb0..8fe8cc0 100644 --- a/src/main/java/mvd/jester/simulator/events/TaskReleasedEvent.java +++ b/src/main/java/mvd/jester/simulator/events/TaskReleasedEvent.java @@ -16,6 +16,6 @@ public class TaskReleasedEvent extends AbstractEvent { @Override public String getLoggingMessage() { - return "task " + getTask() + " started"; + return "Task " + getTask() + " started"; } } diff --git a/src/main/java/mvd/jester/simulator/model/ExtendedSubtaskContext.java b/src/main/java/mvd/jester/simulator/model/ExtendedSubtaskContext.java index 60bca6d..9130fb5 100644 --- a/src/main/java/mvd/jester/simulator/model/ExtendedSubtaskContext.java +++ b/src/main/java/mvd/jester/simulator/model/ExtendedSubtaskContext.java @@ -15,4 +15,9 @@ public class ExtendedSubtaskContext extends SubtaskContext { public JobContext getJobContext() { return jobContext; } + + @Override + public String toString() { + return getSubtask() + " of task " + getJobContext().getTask(); + } } diff --git a/src/main/java/mvd/jester/simulator/model/JobContext.java b/src/main/java/mvd/jester/simulator/model/JobContext.java index a31eb85..140417f 100644 --- a/src/main/java/mvd/jester/simulator/model/JobContext.java +++ b/src/main/java/mvd/jester/simulator/model/JobContext.java @@ -1,5 +1,7 @@ package mvd.jester.simulator.model; +import java.util.HashSet; +import java.util.Set; import org.jgrapht.experimental.dag.DirectedAcyclicGraph; import org.jgrapht.graph.DefaultEdge; import mvd.jester.model.DagTask; @@ -11,6 +13,7 @@ public class JobContext { private final long releaseTime; private final long deadline; private final Subtask source; + private final Set finishedSubtasks; // private long activeThreads; // TODO: Use threads public JobContext(DagTask task, long releaseTime) { @@ -18,6 +21,7 @@ public class JobContext { this.releaseTime = releaseTime; this.deadline = releaseTime + task.getDeadline(); this.source = findSource(task); + this.finishedSubtasks = new HashSet<>(); // this.activeThreads = task.getNumberOfThreads(); } @@ -59,8 +63,26 @@ public class JobContext { return releaseTime; } + /** + * @return the finishedSubtasks + */ + public Set getFinishedSubtasks() { + return finishedSubtasks; + } + + public void registerFinishedSubtask(ExtendedSubtaskContext subtaskContext) { + if (!finishedSubtasks.add(subtaskContext)) { + throw new RuntimeException( + "Subtask could not be added to finished subtask which means it was executed twice!"); + } + } + public boolean checkRemainingThreads() { - return false; + return true; // TODO: implement check in future + } + + public String toString() { + return "of task " + getTask(); } } diff --git a/src/main/java/mvd/jester/simulator/model/ProcessorContext.java b/src/main/java/mvd/jester/simulator/model/ProcessorContext.java index 67b7f3e..2b4944b 100644 --- a/src/main/java/mvd/jester/simulator/model/ProcessorContext.java +++ b/src/main/java/mvd/jester/simulator/model/ProcessorContext.java @@ -1,5 +1,6 @@ package mvd.jester.simulator.model; +import java.util.Comparator; import java.util.Optional; import mvd.jester.priority.PriorityManager; import mvd.jester.simulator.exceptions.DeadlineMissedException; @@ -96,4 +97,28 @@ public class ProcessorContext { return "Processor " + processorId; } + + public static class ProcessorComparator implements Comparator { + + private final PriorityManager priorityManager; + + public ProcessorComparator(PriorityManager priorityManager) { + this.priorityManager = priorityManager; + + } + + @Override + public int compare(ProcessorContext p1, ProcessorContext p2) { + if (!p1.getSubtask().isPresent()) { + return -1; + } else if (!p2.getSubtask().isPresent()) { + return 1; + } else { + // Sort in reverse + return priorityManager.compare(p2.currentSubtask.get().getJobContext(), + p1.currentSubtask.get().getJobContext()); + } + } + } + } -- libgit2 0.26.0