package mvd.jester.simulator; import java.util.Comparator; import java.util.HashSet; import java.util.Optional; import java.util.Set; import java.util.TreeSet; import com.google.common.collect.TreeMultiset; import mvd.jester.model.SystemSetup; import mvd.jester.model.Task; import mvd.jester.priority.PriorityManager; import mvd.jester.priority.RateMonotonic; import mvd.jester.PairInterface; import mvd.jester.info.SchedulingInfo; import mvd.jester.info.TerminationInfo; import mvd.jester.simulator.internals.ProcessorContext; import mvd.jester.simulator.internals.TaskContextInterface; /** * AbstractSimulator */ public abstract class AbstractSimulator implements SimulatorInterface, PairInterface { protected final SystemSetup systemSetup; protected final Set processors; protected TreeMultiset readyTasks; protected long hyperPeriod; AbstractSimulator(SystemSetup systemSetup) { this.systemSetup = systemSetup; this.readyTasks = TreeMultiset.create((t1, t2) -> new RateMonotonic().compare(t1, t2)); processors = new HashSet<>(); for (int i = 0; i < systemSetup.getNumberOfProcessors(); ++i) { processors.add(new ProcessorContext(i)); } this.hyperPeriod = getHyperPeriod(); } protected abstract boolean releaseTasks(long timeStep); @Override public SchedulingInfo runSimulation(PriorityManager priorityManager) { SchedulingInfo schedulingInfo = new SchedulingInfo(); init(priorityManager); for (int t = 0; t < hyperPeriod; ++t) { if (!releaseTasks(t)) { throw new RuntimeException("Could not release a task. This should not happen!"); } Set sortedProcessors = sortProcessors(processors); for (ProcessorContext p : sortedProcessors) { for (TaskContextInterface tc : readyTasks) { if (p.acceptTask(tc, t)) { break; } } } for (ProcessorContext p : processors) { Optional optionalTc = p.updateExecution(t); if (optionalTc.isPresent()) { TaskContextInterface tc = optionalTc.get(); TerminationInfo terminationInfo = new TerminationInfo(tc.getReleaseTime(), tc.getDeadline(), t); schedulingInfo.addTerminationInfo(terminationInfo); if (t >= tc.getDeadline()) { EventPrinter.print("Time " + t + ": Task " + tc + " failed its deadline!"); schedulingInfo.setFailedTemrinationInfo(terminationInfo); return schedulingInfo; } readyTasks.remove(optionalTc.get()); } } } return schedulingInfo; } private void init(PriorityManager priorityManager) { this.readyTasks = TreeMultiset.create((t1, t2) -> priorityManager.compare(t1, t2)); for (ProcessorContext p : processors) { p.setJob(null); } this.hyperPeriod = getHyperPeriod(); } private Set sortProcessors(Set processors) { Set sortedProcessors = new TreeSet<>(new ProcessorComparator()); processors.forEach(p -> sortedProcessors.add(p)); return sortedProcessors; } private long getHyperPeriod() { return systemSetup.getTasks().stream().max(Comparator.comparing(Task::getPeriod)).get() .getPeriod() * 10; } private class ProcessorComparator implements Comparator { @Override public int compare(ProcessorContext p1, ProcessorContext p2) { if (!p1.getJob().isPresent()) { return -1; } else if (!p2.getJob().isPresent()) { return 1; } else { long p1Period = p1.getJob().get().getTaskContext().getTask().getPeriod(); long p2Period = p2.getJob().get().getTaskContext().getTask().getPeriod(); if (p1Period == p2Period) { return 1; } else { return (int) (p2.getJob().get().getTaskContext().getTask().getPeriod() - p1.getJob().get().getTaskContext().getTask().getPeriod()); } } } } }