From 950727470aa0be90cfa513078b9218a865088b44 Mon Sep 17 00:00:00 2001 From: danilopeixoto Date: Thu, 2 May 2019 03:03:50 -0300 Subject: [PATCH] Initial commit --- Burnout/Burnout.pde | 100 ++++++++++++++++++++++++++ Burnout/CPUDevice.pde | 65 +++++++++++++++++ Burnout/Device.pde | 24 +++++++ Burnout/Process.pde | 67 +++++++++++++++++ Burnout/ProcessBuilder.pde | 7 ++ Burnout/RandomProcessGenerator.pde | 43 +++++++++++ Burnout/RoundRobinScheduler.pde | 61 ++++++++++++++++ Burnout/Scheduler.pde | 97 +++++++++++++++++++++++++ Burnout/Shape.pde | 19 +++++ Burnout/ShortestJobFirstScheduler.pde | 40 +++++++++++ LICENSE | 26 +++++++ README.md | 12 ++++ 12 files changed, 561 insertions(+) create mode 100644 Burnout/Burnout.pde create mode 100644 Burnout/CPUDevice.pde create mode 100644 Burnout/Device.pde create mode 100644 Burnout/Process.pde create mode 100644 Burnout/ProcessBuilder.pde create mode 100644 Burnout/RandomProcessGenerator.pde create mode 100644 Burnout/RoundRobinScheduler.pde create mode 100644 Burnout/Scheduler.pde create mode 100644 Burnout/Shape.pde create mode 100644 Burnout/ShortestJobFirstScheduler.pde create mode 100644 LICENSE create mode 100644 README.md diff --git a/Burnout/Burnout.pde b/Burnout/Burnout.pde new file mode 100644 index 0000000..39ff0d8 --- /dev/null +++ b/Burnout/Burnout.pde @@ -0,0 +1,100 @@ +float speed = 1.0; +int seed = 0; +int minimumBurstTime = 5; +int maximumBurstTime = 15; +int quantum = 5; + +Scheduler scheduler; +ShortestJobFirstScheduler shortestJobFirstScheduler; +RoundRobinScheduler roundRobinScheduler; + +boolean pause = false; + +void setup() { + size(800, 600); + + ProcessBuilder processBuilder = new RandomProcessBuilder(seed, minimumBurstTime, maximumBurstTime); + + ArrayList devices = new ArrayList(); + + devices.add(new CPUDevice()); + devices.add(new CPUDevice()); + + shortestJobFirstScheduler = new ShortestJobFirstScheduler(processBuilder, devices); + roundRobinScheduler = new RoundRobinScheduler(processBuilder, devices, quantum); + + scheduler = shortestJobFirstScheduler; +} + +void draw() { + background(255); + + delay(int(1000 / speed)); + + if (!pause) + scheduler.update(); + + scheduler.draw(); + + drawMainScreen(); +} + +void drawMainScreen() { + pushStyle(); + + fill(0); + + textSize(32); + textAlign(CENTER, CENTER); + text("Burnout Scheduler", width / 2.0, 50.0); + + textSize(12); + textAlign(CENTER, CENTER); + text("Copyright © 2019, Danilo Peixoto and Débora Bacelar. All rights reserved.", width / 2.0, height - 20.0); + + textSize(12); + textAlign(CENTER, CENTER); + text("OPTIONS", width / 2.0, 440.0); + + textSize(12); + textAlign(LEFT, CENTER); + text("1 - Add CPU Device\n" + + "2 - Remove CPU Device\n" + + "3 - Clear and Release Processes\n" + + "4 - Switch Scheduler Algorithm (Non-Preemptive Shortest Job First or Round Robin)\n" + + "5 - Pause/Resume", 10.0, 500.0); + + popStyle(); +} + +void keyPressed() { + if (key == '1') { + ArrayList devices = scheduler.getDevices(); + devices.add(new CPUDevice()); + } + else if (key == '2') { + ArrayList devices = scheduler.getDevices(); + int size = devices.size(); + + if (size > 0) + devices.remove(size - 1); + } + if (key == '3') { + AbstractCollection collection = scheduler.getCollection(); + collection.clear(); + + for (Device device : scheduler.getDevices()) + device.release(); + } + else if (key == '4') { + scheduler = scheduler.getType() == SchedulerType.ShortestJobFirst ? roundRobinScheduler : shortestJobFirstScheduler; + + AbstractCollection collection = scheduler.getCollection(); + collection.clear(); + + for (Device device : scheduler.getDevices()) + device.release(); + } + else if (key == '5') + pause = !pause; +} diff --git a/Burnout/CPUDevice.pde b/Burnout/CPUDevice.pde new file mode 100644 index 0000000..812d331 --- /dev/null +++ b/Burnout/CPUDevice.pde @@ -0,0 +1,65 @@ +final class CPUDevice extends Device { + public CPUDevice() { + super(); + } + + @Override + public void commit(Process process) { + this.process = process; + execute(); + } + @Override + public void release() { + this.process = null; + } + @Override + public void execute() { + process.execute(); + } + + @Override + public boolean isIdle() { + if (process == null) + return true; + + return process.getExecutionTime() >= process.getBurstTime(); + } + @Override + public boolean isInterrupted(int quantum) { + if (process == null) + return true; + + return process.getExecutionTime() % quantum == 0; + } + + @Override + public void draw() { + float padding = 20; + float size = 60 + padding; + float textSize = 16; + + pushStyle(); + + noFill(); + + stroke(0); + strokeWeight(2.0); + + rect(anchorPoint.x, anchorPoint.y, size, size, 8.0); + + fill(0); + textSize(textSize); + textAlign(CENTER, CENTER); + text("CPU" + String.valueOf(id), anchorPoint.x + size / 2.0, anchorPoint.y + size + textSize); + + popStyle(); + + float halfPadding = padding / 2.0; + PVector position = new PVector(anchorPoint.x + halfPadding, anchorPoint.y + halfPadding); + + if (process != null) { + process.setAnchorPoint(position); + process.draw(); + } + } +} diff --git a/Burnout/Device.pde b/Burnout/Device.pde new file mode 100644 index 0000000..6147370 --- /dev/null +++ b/Burnout/Device.pde @@ -0,0 +1,24 @@ +static int globalCPUCount = 0; + +abstract class Device extends Shape { + protected int id; + protected Process process; + + public Device() { + id = globalCPUCount++; + } + + public int getID() { + return id; + } + public Process getProcess() { + return process; + } + + public abstract void commit(Process process); + public abstract void release(); + public abstract void execute(); + + public abstract boolean isIdle(); + public abstract boolean isInterrupted(int quantum); +} diff --git a/Burnout/Process.pde b/Burnout/Process.pde new file mode 100644 index 0000000..a19a0b7 --- /dev/null +++ b/Burnout/Process.pde @@ -0,0 +1,67 @@ +final class Process extends Shape implements Comparable { + private int pid; + private int burstTime; + private int executionTime; + + public Process() { + super(); + } + public Process(int pid, int burstTime) { + super(); + this.pid = pid; + this.burstTime = burstTime; + } + + public void setPID(int pid) { + this.pid = pid; + } + public void setBurstTime(int burstTime) { + this.burstTime = burstTime; + } + public int getPID() { + return pid; + } + public int getBurstTime() { + return burstTime; + } + public int getExecutionTime() { + return executionTime; + } + + public void execute() { + executionTime++; + } + + @Override + public int compareTo(Process other) { + if (burstTime < other.burstTime) + return -1; + else if (burstTime > other.burstTime) + return 1; + + return 0; + } + + @Override + public void draw() { + float size = 60; + float textSize = 16; + + pushStyle(); + + noStroke(); + + fill(220, 220, 220); + rect(anchorPoint.x, anchorPoint.y, size, size, 8.0); + + fill(0, 255, 125); + rect(anchorPoint.x, anchorPoint.y, size * executionTime / burstTime, size, 8.0); + + fill(0); + textSize(textSize); + textAlign(CENTER, CENTER); + text("PID" + String.valueOf(pid) + "\n" + "BT" + String.valueOf(burstTime), anchorPoint.x + size / 2.0, anchorPoint.y + size / 2.0); + + popStyle(); + } +} diff --git a/Burnout/ProcessBuilder.pde b/Burnout/ProcessBuilder.pde new file mode 100644 index 0000000..b6a929c --- /dev/null +++ b/Burnout/ProcessBuilder.pde @@ -0,0 +1,7 @@ +static int globalProcessCount = 0; + +abstract class ProcessBuilder { + public ProcessBuilder() {} + + public abstract Process next(); +} diff --git a/Burnout/RandomProcessGenerator.pde b/Burnout/RandomProcessGenerator.pde new file mode 100644 index 0000000..2ecbce5 --- /dev/null +++ b/Burnout/RandomProcessGenerator.pde @@ -0,0 +1,43 @@ +import java.util.Random; + +final class RandomProcessBuilder extends ProcessBuilder { + private int seed; + private int minimumBurstTime; + private int maximumBurstTime; + private Random random; + + public RandomProcessBuilder() { + random = new Random(); + } + public RandomProcessBuilder(int seed, int minimumBurstTime, int maximumBurstTime) { + this(); + this.seed = seed; + this.minimumBurstTime = minimumBurstTime; + this.maximumBurstTime = maximumBurstTime; + } + + public void setSeed(int seed) { + this.seed = seed; + random.setSeed(seed); + } + public void setMinimumBurstTime(int minimumBurstTime) { + this.minimumBurstTime = minimumBurstTime; + } + public void setMaximumBurstTime(int maximumBurstTime) { + this.maximumBurstTime = maximumBurstTime; + } + public int getSeed() { + return seed; + } + public int getMinimumBurstTime() { + return minimumBurstTime; + } + public int getMaximumBurstTime() { + return maximumBurstTime; + } + + @Override + public Process next() { + return new Process(globalProcessCount++, int(minimumBurstTime + (maximumBurstTime - minimumBurstTime) * random.nextFloat())); + } +} diff --git a/Burnout/RoundRobinScheduler.pde b/Burnout/RoundRobinScheduler.pde new file mode 100644 index 0000000..4f2d6af --- /dev/null +++ b/Burnout/RoundRobinScheduler.pde @@ -0,0 +1,61 @@ +import java.util.LinkedList; + +final class RoundRobinScheduler extends Scheduler { + private int quantum; + + public RoundRobinScheduler() { + super(SchedulerType.RoundRobin); + collection = new LinkedList(); + } + public RoundRobinScheduler(ProcessBuilder processBuilder, ArrayList devices, int quantum) { + super(processBuilder, devices, SchedulerType.RoundRobin); + this.quantum = quantum; + collection = new LinkedList(); + } + + public void setQuantum(int quantum) { + this.quantum = quantum; + } + public int getQuantum() { + return quantum; + } + + @Override + protected void update() { + enqueue(processBuilder.next()); + + for (Device device : devices) { + if (device.isInterrupted(quantum)) { + if (!device.isIdle()) + enqueue(device.getProcess()); + + device.release(); + + if (hasNext()) + device.commit(dispatch()); + } + else { + if (device.isIdle()) { + device.release(); + + if (hasNext()) + device.commit(dispatch()); + } + + device.execute(); + } + } + } + @Override + protected void enqueue(Process process) { + collection.add(process); + } + @Override + protected Process dispatch() { + return ((LinkedList)collection).poll(); + } + @Override + protected boolean hasNext() { + return !collection.isEmpty(); + } +} diff --git a/Burnout/Scheduler.pde b/Burnout/Scheduler.pde new file mode 100644 index 0000000..0d78fee --- /dev/null +++ b/Burnout/Scheduler.pde @@ -0,0 +1,97 @@ +import java.util.AbstractCollection; +import java.util.Iterator; + +enum SchedulerType { + ShortestJobFirst, + RoundRobin +} + +abstract class Scheduler extends Shape { + protected ProcessBuilder processBuilder; + protected ArrayList devices; + protected AbstractCollection collection; + protected SchedulerType type; + + public Scheduler(SchedulerType type) { + this.type = type; + } + public Scheduler(ProcessBuilder processBuilder, ArrayList devices, SchedulerType type) { + this(type); + this.processBuilder = processBuilder; + this.devices = devices; + } + + public void setProcessBuilder(ProcessBuilder processBuilder) { + this.processBuilder = processBuilder; + } + public void setDevices(ArrayList devices) { + this.devices = devices; + } + public ProcessBuilder getProcessBuilder() { + return processBuilder; + } + public ArrayList getDevices() { + return devices; + } + public AbstractCollection getCollection() { + return collection; + } + public SchedulerType getType() { + return type; + } + + protected abstract void update(); + protected abstract void enqueue(Process process); + protected abstract Process dispatch(); + protected abstract boolean hasNext(); + + @Override + public void draw() { + float spacing = 10.0; + + float processOffset = 60.0 + spacing; + float deviceOffset = 80.0 + spacing; + + pushStyle(); + + fill(0); + + textSize(18); + textAlign(CENTER, CENTER); + + switch (type) { + case ShortestJobFirst: + text("Shortest Job First", width / 2.0, 85.0); + break; + case RoundRobin: + text("Round Robin", width / 2.0, 85.0); + break; + default: + break; + } + + textSize(18); + textAlign(LEFT, CENTER); + + text("PROCESSES", 10.0, 130.0); + text("DEVICES", 10.0, 280.0); + + popStyle(); + + int i = 0; + + for (Iterator iterator = collection.iterator(); iterator.hasNext(); i++) { + Process process = iterator.next(); + + process.setAnchorPoint(new PVector(spacing + i * processOffset, height / 4.0)); + process.draw(); + } + + for (i = 0; i < devices.size(); i++) { + Device device = devices.get(i); + + device.setAnchorPoint(new PVector(spacing + i * deviceOffset, height / 2.0)); + device.draw(); + } + } +} diff --git a/Burnout/Shape.pde b/Burnout/Shape.pde new file mode 100644 index 0000000..a41d8ae --- /dev/null +++ b/Burnout/Shape.pde @@ -0,0 +1,19 @@ +abstract class Shape { + protected PVector anchorPoint; + + public Shape() { + anchorPoint = new PVector(0, 0); + } + public Shape(PVector anchorPoint) { + this.anchorPoint = anchorPoint; + } + + public void setAnchorPoint(PVector anchorPoint) { + this.anchorPoint = anchorPoint; + } + public PVector getAnchorPoint() { + return anchorPoint; + } + + public abstract void draw(); +} diff --git a/Burnout/ShortestJobFirstScheduler.pde b/Burnout/ShortestJobFirstScheduler.pde new file mode 100644 index 0000000..c57f1a5 --- /dev/null +++ b/Burnout/ShortestJobFirstScheduler.pde @@ -0,0 +1,40 @@ +import java.util.PriorityQueue; + +final class ShortestJobFirstScheduler extends Scheduler { + public ShortestJobFirstScheduler() { + super(SchedulerType.ShortestJobFirst); + collection = new PriorityQueue(); + } + public ShortestJobFirstScheduler(ProcessBuilder processBuilder, ArrayList devices) { + super(processBuilder, devices, SchedulerType.ShortestJobFirst); + collection = new PriorityQueue(); + } + + @Override + protected void update() { + enqueue(processBuilder.next()); + + for (Device device : devices) { + if (device.isIdle()) { + device.release(); + + if (hasNext()) + device.commit(dispatch()); + } + else + device.execute(); + } + } + @Override + protected void enqueue(Process process) { + collection.add(process); + } + @Override + protected Process dispatch() { + return ((PriorityQueue)collection).poll(); + } + @Override + protected boolean hasNext() { + return !collection.isEmpty(); + } +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..da8edd6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2019, Danilo Peixoto and Débora Bacelar. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..386834b --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +# Burnout +An implementation of operating system scheduling algorithms. + +Dependencies +------------ +This project requires [Processing 3](https://processing.org). + +Copyright and License +--------------------- +Copyright © 2019, Danilo Peixoto and Débora Bacelar. All rights reserved. + +Project developed under the [BSD-3-Clause license](LICENSE). \ No newline at end of file