diff --git a/src/main/java/mvd/jester/App.java b/src/main/java/mvd/jester/App.java index 9cf2331..1770f40 100644 --- a/src/main/java/mvd/jester/App.java +++ b/src/main/java/mvd/jester/App.java @@ -1,9 +1,7 @@ package mvd.jester; +import java.io.File; import mvd.jester.model.SystemSetup; -import mvd.jester.tests.MaiaBertogna; -import mvd.jester.tests.SchmidMottok; -import mvd.jester.tests.TestEnvironment; /** * Hello world! @@ -11,14 +9,39 @@ import mvd.jester.tests.TestEnvironment; */ public class App { public static void main(String[] args) { - SystemSetup.Builder builder = new SystemSetup.Builder().setNumberOfProcessors(8); + boolean runTests = false; + if (runTests) { - TestEnvironment te = new TestEnvironment(builder, 40000); + SystemSetup.Builder builder = new SystemSetup.Builder().setNumberOfProcessors(8); - te.registerTestInterface(SchmidMottok.class); - te.registerTestInterface(MaiaBertogna.class); + TestEnvironment te = new TestEnvironment(builder, 40000); + + // te.registerTestInterface(SchmidMottok.class); + te.registerTestPair(mvd.jester.tests.MaiaBertogna.class, + mvd.jester.simulator.MaiaBertogna.class); + + + te.runTests(); + } else { + File folder = new File("results"); + + for (File f : folder.listFiles()) { + SystemSetup systemSetup = SystemSetup.fromFile(f.toPath().toString()); + + mvd.jester.simulator.MaiaBertogna mb_sim = + new mvd.jester.simulator.MaiaBertogna(systemSetup); + mvd.jester.tests.MaiaBertogna mb_test = + new mvd.jester.tests.MaiaBertogna(systemSetup); + + boolean simCheck = mb_sim.runSimulation(); + boolean schedCheck = mb_test.runSchedulabilityCheck(); + + if (simCheck == false && schedCheck == true) { + System.out.println(f.getName()); + } + } + } - te.runTests(); } } diff --git a/src/main/java/mvd/jester/TestEnvironment.java b/src/main/java/mvd/jester/TestEnvironment.java new file mode 100644 index 0000000..b2c88d2 --- /dev/null +++ b/src/main/java/mvd/jester/TestEnvironment.java @@ -0,0 +1,175 @@ +package mvd.jester; + +import java.io.PrintWriter; +import java.lang.reflect.Constructor; +import java.time.LocalTime; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import mvd.jester.model.SystemSetup; +import mvd.jester.simulator.AbstractSimulator; +import mvd.jester.tests.AbstractTest; +import mvd.jester.utils.Logger; + +/** + * TestEnvironment + */ +public class TestEnvironment { + + private final long numberOfTaskSets; + private final SystemSetup systemSetup; + private final SystemSetup.Builder builder; + private final Map, Constructor> abstractTestPairs; + + public TestEnvironment(SystemSetup.Builder builder, long numberOfTaskSets) { + this.numberOfTaskSets = numberOfTaskSets; + abstractTestPairs = new HashMap<>(); + + this.builder = builder; + this.systemSetup = builder.build(); + } + + public TestEnvironment registerTestPair(Class abstractTest, + Class abstractSimulator) { + try { + abstractTestPairs.put(abstractTest.getConstructor(SystemSetup.class), + abstractSimulator.getConstructor(SystemSetup.class)); + } catch (Exception e) { + System.out.println("Missing constructor!"); + } + + return this; + } + + public void runTests() { + Map testPairs = new HashMap<>(); + + Map> testResults = new HashMap<>(); + Map> simulatorResults = new HashMap<>(); + + for (Map.Entry, Constructor> kv : abstractTestPairs + .entrySet()) { + try { + testPairs.put(kv.getKey().newInstance(this.systemSetup), + kv.getValue().newInstance(this.systemSetup)); + } catch (Exception e) { + System.out.println("Could not instantiate object of AbstractTest!"); + } + } + + long checkedTasksets = 0; + + while (checkedTasksets < numberOfTaskSets) { + builder.rebuild(this.systemSetup); + + double utilization = this.systemSetup.getUtilization(); + + while (utilization <= this.systemSetup.getNumberOfProcessors() + && checkedTasksets < numberOfTaskSets) { + checkedTasksets++; + + if (checkedTasksets % 100 == 0) { + System.out.println(checkedTasksets + " bereits geschafft"); + } + + long roundedUtilization = (long) (utilization * 10); + for (Map.Entry kv : testPairs.entrySet()) { + boolean schedCheck = kv.getKey().runSchedulabilityCheck(); + boolean simCheck = kv.getValue().runSimulation(); + if (schedCheck) { + testResults + .computeIfAbsent(roundedUtilization, + k -> new HashMap()) + .compute(kv.getKey(), (k, v) -> (v == null) ? 1 : v + 1); + } + if (simCheck) { + simulatorResults + .computeIfAbsent(roundedUtilization, + k -> new HashMap()) + .compute(kv.getValue(), (k, v) -> (v == null) ? 1 : v + 1); + } + if (schedCheck == true && simCheck == false) { + boolean sched = kv.getKey().runSchedulabilityCheck(); + boolean sim = kv.getValue().runSimulation(); + + if (sched == true && sim == false) { + try (PrintWriter out = new PrintWriter( + "results/manualCheck" + checkedTasksets + ".txt")) { + out.println(systemSetup); + } catch (Exception e) { + System.out.println("Ähm something went horribly wrong!"); + } + } + } + } + builder.addTask(systemSetup); + + utilization = this.systemSetup.getUtilization(); + } + } + + logResults(testPairs.keySet(), testResults); + logSimulations(new HashSet(testPairs.values()), simulatorResults); + } + + private void logResults(Set testCases, + Map> results) { + LocalTime date = LocalTime.now(); + Logger log = new Logger("./results/results_" + systemSetup.getNumberOfProcessors() + "_" + + date.getHour() + ":" + date.getMinute() + ".txt"); + String firstLine = new String("Utilization"); + + for (AbstractTest t : testCases) { + firstLine = firstLine + "\t" + t.getName(); + } + + log.log(firstLine); + + for (Long util : results.keySet()) { + String line = String.valueOf((double) util / 10); + Map tests = results.get(util); + + for (AbstractTest t : testCases) { + if (tests.containsKey(t)) { + line += "\t" + tests.get(t); + } else { + line += "\t" + "0"; + } + } + log.log(line); + } + + log.finalize(); + } + + private void logSimulations(Set testCases, + Map> results) { + LocalTime date = LocalTime.now(); + Logger log = new Logger("./results/results_sim_" + systemSetup.getNumberOfProcessors() + "_" + + date.getHour() + ":" + date.getMinute() + ".txt"); + String firstLine = new String("Utilization"); + + for (AbstractSimulator t : testCases) { + firstLine = firstLine + "\t" + t.getName(); + } + + log.log(firstLine); + + for (Long util : results.keySet()) { + String line = String.valueOf((double) util / 10); + Map tests = results.get(util); + + for (AbstractSimulator t : testCases) { + if (tests.containsKey(t)) { + line += "\t" + tests.get(t); + } else { + line += "\t" + "0"; + } + } + log.log(line); + } + + log.finalize(); + } +} diff --git a/src/main/java/mvd/jester/model/Segment.java b/src/main/java/mvd/jester/model/Segment.java index 1693911..8c45b89 100644 --- a/src/main/java/mvd/jester/model/Segment.java +++ b/src/main/java/mvd/jester/model/Segment.java @@ -1,6 +1,6 @@ package mvd.jester.model; -import com.google.common.math.LongMath; +// import com.google.common.math.LongMath; public class Segment { diff --git a/src/main/java/mvd/jester/model/SortedTaskSet.java b/src/main/java/mvd/jester/model/SortedTaskSet.java index 0c08913..bdcc22b 100644 --- a/src/main/java/mvd/jester/model/SortedTaskSet.java +++ b/src/main/java/mvd/jester/model/SortedTaskSet.java @@ -1,7 +1,14 @@ package mvd.jester.model; +import java.lang.reflect.Type; import java.util.TreeSet; +import com.google.gson.JsonArray; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; import mvd.jester.priority.PriorityManager; +import mvd.jester.priority.RateMonotonic; /** * SortedTaskSet @@ -13,4 +20,20 @@ public class SortedTaskSet extends TreeSet { public SortedTaskSet(PriorityManager priorityMananger) { super((t1, t2) -> priorityMananger.compare(t1, t2)); } + + public static class Deserializer implements JsonDeserializer { + + @Override + public SortedTaskSet deserialize(JsonElement json, Type typeOfT, + JsonDeserializationContext context) throws JsonParseException { + SortedTaskSet taskSet = new SortedTaskSet(new RateMonotonic()); + if (json.isJsonArray()) { + JsonArray array = json.getAsJsonArray(); + array.forEach(e -> { + taskSet.add(context.deserialize(e, Task.class)); + }); + } + return taskSet; + } + } } diff --git a/src/main/java/mvd/jester/model/SystemSetup.java b/src/main/java/mvd/jester/model/SystemSetup.java index 4cf81ff..dc97c8e 100644 --- a/src/main/java/mvd/jester/model/SystemSetup.java +++ b/src/main/java/mvd/jester/model/SystemSetup.java @@ -1,8 +1,14 @@ package mvd.jester.model; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.LinkedHashSet; import java.util.Set; import java.util.concurrent.ThreadLocalRandom; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import mvd.jester.priority.PriorityManager; import mvd.jester.priority.RateMonotonic; @@ -45,6 +51,33 @@ public class SystemSetup { return utilization; } + @Override + public String toString() { + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + return gson.toJson(tasks); + } + + public static SystemSetup fromFile(String path) { + String jsonString; + try { + byte[] encoded = Files.readAllBytes(Paths.get(path)); + jsonString = new String(encoded, Charset.defaultCharset()); + } catch (IOException e) { + System.out.println(e.getMessage()); + jsonString = new String(""); + } + return SystemSetup.fromString(jsonString); + } + + public static SystemSetup fromString(String json) { + Gson gson = new GsonBuilder() + .registerTypeAdapter(SortedTaskSet.class, new SortedTaskSet.Deserializer()) + .create(); + + SortedTaskSet tasks = gson.fromJson(json, SortedTaskSet.class); + return new SystemSetup(tasks, 8); + } + public static class Builder { private long numberOfProcessors = 4; private long minPeriod = 100; diff --git a/src/main/java/mvd/jester/simulator/AbstractSimulator.java b/src/main/java/mvd/jester/simulator/AbstractSimulator.java new file mode 100644 index 0000000..2c17afc --- /dev/null +++ b/src/main/java/mvd/jester/simulator/AbstractSimulator.java @@ -0,0 +1,47 @@ +package mvd.jester.simulator; + +import java.util.HashSet; +import java.util.Set; +import com.google.common.math.LongMath; +import mvd.jester.model.SystemSetup; +import mvd.jester.model.Task; +import mvd.jester.priority.RateMonotonic; +import mvd.jester.simulator.internals.ProcessorContext; +import mvd.jester.simulator.internals.SortedTaskContextSet; +import mvd.jester.simulator.internals.TaskContext; + + +/** + * AbstractSimulator + */ +public abstract class AbstractSimulator implements SimulatorInterface { + + protected final SystemSetup systemSetup; + protected final Set processors; + protected final SortedTaskContextSet readyTasks; + protected final long hyperPeriod; + + AbstractSimulator(SystemSetup systemSetup) { + this.systemSetup = systemSetup; + this.readyTasks = new SortedTaskContextSet(new RateMonotonic()); + processors = new HashSet<>(); + for (int i = 0; i < systemSetup.getNumberOfProcessors(); ++i) { + processors.add(new ProcessorContext(i)); + } + this.hyperPeriod = systemSetup.getTasks().last().getPeriod() * 10; + // LongMath.pow(systemSetup.getTasks().last().getPeriod(), 2); + } + + + protected boolean releaseTasks(long timeStep) { + for (Task t : systemSetup.getTasks()) { + if (timeStep % t.getPeriod() == 0) { + if (!readyTasks.add(new TaskContext(t, timeStep))) { + return false; + } + } + } + return true; + } + +} diff --git a/src/main/java/mvd/jester/simulator/MaiaBertogna.java b/src/main/java/mvd/jester/simulator/MaiaBertogna.java new file mode 100644 index 0000000..193d8bd --- /dev/null +++ b/src/main/java/mvd/jester/simulator/MaiaBertogna.java @@ -0,0 +1,62 @@ +package mvd.jester.simulator; + +import java.util.Comparator; +import java.util.Optional; +import java.util.TreeSet; +import mvd.jester.model.SystemSetup; +import mvd.jester.simulator.internals.ProcessorContext; +import mvd.jester.simulator.internals.TaskContext; + +/** + * MaiaBertogna + */ +public class MaiaBertogna extends AbstractSimulator { + + public MaiaBertogna(SystemSetup systemSetup) { + super(systemSetup); + } + + @Override + public boolean runSimulation() { + readyTasks.clear(); + for (int t = 0; t < hyperPeriod; ++t) { + if (!releaseTasks(t)) { + return false; + } + + TreeSet sortedProcessors = + new TreeSet<>((p1, p2) -> (int) (!p1.getJob().isPresent() ? -1 + : !p2.getJob().isPresent() ? 1 : -1)); + + processors.forEach(p -> sortedProcessors.add(p)); + for (ProcessorContext p : sortedProcessors) { + for (TaskContext tc : readyTasks) { + if (p.acceptTask(tc, t)) { + break; + } + } + + } + + for (ProcessorContext p : processors) { + Optional optionalTc = p.updateExecution(t); + if (optionalTc.isPresent()) { + TaskContext tc = optionalTc.get(); + if (t >= tc.getDeadline()) { + return false; + } + readyTasks.remove(optionalTc.get()); + } + } + } + + return true; + } + + @Override + public String getName() { + return "MaiaBertogna"; + } + + +} diff --git a/src/main/java/mvd/jester/simulator/SchmidMottok.java b/src/main/java/mvd/jester/simulator/SchmidMottok.java new file mode 100644 index 0000000..bf1e7e8 --- /dev/null +++ b/src/main/java/mvd/jester/simulator/SchmidMottok.java @@ -0,0 +1,23 @@ +package mvd.jester.simulator; + +import mvd.jester.model.SystemSetup; + +/** + * SchmidMottok + */ +public class SchmidMottok extends AbstractSimulator { + + SchmidMottok(SystemSetup systemSetup) { + super(systemSetup); + } + + @Override + public boolean runSimulation() { + return false; + } + + @Override + public String getName() { + return "SchmidMottok"; + } +} diff --git a/src/main/java/mvd/jester/simulator/SimulatorInterface.java b/src/main/java/mvd/jester/simulator/SimulatorInterface.java new file mode 100644 index 0000000..5f986fb --- /dev/null +++ b/src/main/java/mvd/jester/simulator/SimulatorInterface.java @@ -0,0 +1,12 @@ +package mvd.jester.simulator; + +/** + * SimulatorInterface + */ +public interface SimulatorInterface { + + public boolean runSimulation(); + + public String getName(); + +} diff --git a/src/main/java/mvd/jester/simulator/internals/JobContext.java b/src/main/java/mvd/jester/simulator/internals/JobContext.java new file mode 100644 index 0000000..b2e82e5 --- /dev/null +++ b/src/main/java/mvd/jester/simulator/internals/JobContext.java @@ -0,0 +1,86 @@ +package mvd.jester.simulator.internals; + +import java.util.Optional; + +/** + * Job + * + * @param + */ +public class JobContext { + + private final TaskContext taskContext; + private final SegmentContext segmentContext; + private final long wcet; + private Optional currentProcessor; + private long executionTime; + + + public JobContext(TaskContext taskContext, SegmentContext segmentContext) { + this.currentProcessor = Optional.empty(); + this.taskContext = taskContext; + this.segmentContext = segmentContext; + this.wcet = segmentContext.getSegment().getJobWcet(); + this.executionTime = wcet; + } + + public Optional updateExecution(long time) { + executionTime--; + + if (executionTime == 0) { + // System.out.println("Time " + time + ": " + currentProcessor.get() + // + " finished execution of job " + this + "!"); + currentProcessor.get().setJob(null); + currentProcessor = Optional.empty(); + return taskContext.acceptNotification(time); + } + + return Optional.empty(); + } + + public boolean checkExecutionTime() { + return executionTime > 0; + } + + /** + * @return the wcet + */ + public long getWcet() { + return wcet; + } + + /** + * @param processor the currentProcessor to set + */ + public void setCurrentProcessor(ProcessorContext processor) { + this.currentProcessor = Optional.ofNullable(processor); + } + + /** + * @return the currentProcessor + */ + public Optional getCurrentProcessor() { + return currentProcessor; + } + + /** + * @return the segmentContext + */ + public SegmentContext getSegmentContext() { + return segmentContext; + } + + + /** + * @return the taskContext + */ + public TaskContext getTaskContext() { + return taskContext; + } + + @Override + public String toString() { + return "(jobWcet=" + wcet + ")"; + } + +} diff --git a/src/main/java/mvd/jester/simulator/internals/ProcessorContext.java b/src/main/java/mvd/jester/simulator/internals/ProcessorContext.java new file mode 100644 index 0000000..1ca94fe --- /dev/null +++ b/src/main/java/mvd/jester/simulator/internals/ProcessorContext.java @@ -0,0 +1,65 @@ +package mvd.jester.simulator.internals; + +import java.util.Optional; + +/** + * Processor + */ +public class ProcessorContext { + + private Optional currentJob; + private final long processorId; + + public ProcessorContext(long processorId) { + currentJob = Optional.empty(); + this.processorId = processorId; + } + + public void setJob(JobContext job) { + this.currentJob = Optional.ofNullable(job); + } + + /** + * @return the currentJob + */ + public Optional getJob() { + return currentJob; + } + + public Optional updateExecution(long time) { + if (currentJob.isPresent()) { + return currentJob.get().updateExecution(time); + } + + return Optional.empty(); + } + + + public boolean acceptTask(TaskContext taskContext, int t) { + if (!currentJob.isPresent() || currentJob.get().getTaskContext().getTask() + .getPeriod() > taskContext.getTask().getPeriod()) { + Optional optionalJob = taskContext.getNextJob(); + + if (optionalJob.isPresent()) { + if (currentJob.isPresent()) { + currentJob.get().setCurrentProcessor(null); + } + currentJob = optionalJob; + currentJob.get().setCurrentProcessor(this); + // System.out.println("Time " + t + ": " + this + " started job " + currentJob + // + " of task" + taskContext + "!"); + return true; + } else { + return false; + } + } + + return false; + } + + @Override + public String toString() { + return "Processor " + processorId; + } + +} diff --git a/src/main/java/mvd/jester/simulator/internals/SegmentContext.java b/src/main/java/mvd/jester/simulator/internals/SegmentContext.java new file mode 100644 index 0000000..a1fdeab --- /dev/null +++ b/src/main/java/mvd/jester/simulator/internals/SegmentContext.java @@ -0,0 +1,49 @@ +package mvd.jester.simulator.internals; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import mvd.jester.model.Segment; + +/** + * Segment + */ +public class SegmentContext { + private final Segment segment; + private final Set jobs; + private final Set tasklets; + + public SegmentContext(TaskContext taskContext, Segment segment) { + this.segment = segment; + jobs = new HashSet<>(); + tasklets = new HashSet<>(); + + for (int j = 0; j < segment.getNumberOfJobs(); ++j) { + jobs.add(new JobContext(taskContext, this)); + } + + for (int t = 0; t < segment.getNumberOfTasklets(); ++t) { + tasklets.add(new TaskletContext(this)); + } + } + + + /** + * @return the segment + */ + public Segment getSegment() { + return segment; + } + + Optional getNextJob() { + return jobs.stream() + .filter(j -> !j.getCurrentProcessor().isPresent() && j.checkExecutionTime()) + .findFirst(); + } + + + @Override + public String toString() { + return "(nJobs=" + segment.getNumberOfJobs() + ", jobWcet=" + segment.getJobWcet() + ")"; + } +} diff --git a/src/main/java/mvd/jester/simulator/internals/SortedTaskContextSet.java b/src/main/java/mvd/jester/simulator/internals/SortedTaskContextSet.java new file mode 100644 index 0000000..0c3521a --- /dev/null +++ b/src/main/java/mvd/jester/simulator/internals/SortedTaskContextSet.java @@ -0,0 +1,17 @@ +package mvd.jester.simulator.internals; + +import java.util.TreeSet; +import mvd.jester.priority.PriorityManager; + +/** + * SortedTaskContextSet + */ +public class SortedTaskContextSet extends TreeSet { + + private static final long serialVersionUID = 4808544133562675597L; + + public SortedTaskContextSet(PriorityManager priorityMananger) { + super((t1, t2) -> priorityMananger.compare(t1.getTask(), t2.getTask())); + } +} + diff --git a/src/main/java/mvd/jester/simulator/internals/TaskContext.java b/src/main/java/mvd/jester/simulator/internals/TaskContext.java new file mode 100644 index 0000000..b07ab4b --- /dev/null +++ b/src/main/java/mvd/jester/simulator/internals/TaskContext.java @@ -0,0 +1,79 @@ +package mvd.jester.simulator.internals; + +import java.util.ArrayList; +import java.util.Optional; +import mvd.jester.model.Segment; +import mvd.jester.model.Task; + +/** + * TaskContext + */ +public class TaskContext { + + private final Task task; + private final ArrayList segments; + private final long deadline; + private int currentSegment; + private int segmentCounter; + + + public TaskContext(Task task, long timeStep) { + this.task = task; + this.segments = new ArrayList<>(); + this.currentSegment = 0; + this.segmentCounter = 0; + this.deadline = timeStep + task.getDeadline(); + + for (Segment s : task.getSegments()) { + segments.add(new SegmentContext(this, s)); + } + } + + /** + * @return the task + */ + public Task getTask() { + return task; + } + + /** + * @return the deadline + */ + public long getDeadline() { + return deadline; + } + + public Optional acceptNotification(long time) { + segmentCounter++; + + if (segmentCounter >= segments.get(currentSegment).getSegment().getNumberOfJobs()) { + currentSegment++; + segmentCounter = 0; + if (currentSegment >= segments.size()) { + // System.out.println("Time " + time + ": Task " + this + "finished!"); + return Optional.of(this); + } + } + + + return Optional.empty(); + } + + public Optional getNextJob() { + if (currentSegment < segments.size()) { + Optional optionalJob = segments.get(currentSegment).getNextJob(); + if (optionalJob.isPresent()) { + return optionalJob; + } + } + + return Optional.empty(); + } + + + @Override + public String toString() { + return "(period=" + task.getPeriod() + ", deadline=" + deadline + ", segments=" + + segments.size() + ")"; + } +} diff --git a/src/main/java/mvd/jester/simulator/internals/TaskletContext.java b/src/main/java/mvd/jester/simulator/internals/TaskletContext.java new file mode 100644 index 0000000..6d9feb6 --- /dev/null +++ b/src/main/java/mvd/jester/simulator/internals/TaskletContext.java @@ -0,0 +1,19 @@ +package mvd.jester.simulator.internals; + + +/** + * Tasklet + */ +public class TaskletContext { + + private final SegmentContext segment; + private final long wcet; + private long executionTime; + + + public TaskletContext(SegmentContext segment) { + this.segment = segment; + this.wcet = segment.getSegment().getTaskletWcet(); + this.executionTime = 0; + } +}