├── README.md ├── headers ├── CPU.h ├── Clock.h ├── DList.h ├── PCB.h ├── PCBGenerator.h ├── Schedulers.h └── StatUpdater.h ├── output ├── sample_outputFCFS.txt ├── sample_outputPP.txt ├── sample_outputRR1.txt ├── sample_outputRR4.txt └── sample_outputSRTF.txt ├── sample_input.txt └── source ├── CPU.cpp ├── Clock.cpp ├── PCBGenerator.cpp ├── Schedulers.cpp ├── StatUpdater.cpp └── main.cpp /README.md: -------------------------------------------------------------------------------- 1 | # Process Scheduling Simulator 2 | A software implementation of how an OS might schedule processes on a CPU given a file of "processes" designed for a class project. The simulator is programmed to simulate any one of four scheduling algorithms (FCFS, SRTF, RR, and PP), and output the results to a specified file. 3 | 4 | ## Getting Started 5 | 6 | The program will obviously need to be compiled and ran using some sort 7 | When running the program, execute it with the arguments in the following general form: 8 | ``` 9 | ./a.out inputFileName outputFileName AlgorithmNumber timeQuantum(if applicable) 10 | ``` 11 | 12 | An example on Linux using the provided input/output files: 13 | ``` 14 | ./a.out sample_input.txt sample_outputSRTF.txt 1 15 | ``` 16 | or 17 | ``` 18 | ./a.out sample_input.txt sample_outputRR4.txt 2 4 19 | ``` 20 | 21 | #### Input/Output File 22 | Each line in the input file must be of the form: 23 | ``` 24 | ProcessID ArrivalTime BurstTime Priority 25 | ``` 26 | Any valid filename will suffice for outputFileName. Numbers in output are considered to be ms and context switches account for 0.5ms 27 | 28 | An example input and output file is provided 29 | 30 | #### Algorithm Numbers 31 | 0 - FCFS, First Come First Serve 32 | 1 - SRTF, Shortest Remaining Time First (preemptive) 33 | 2 - RR, Round Robin (must enter time quantum to execute) 34 | 3 - PP, Preemptive Priority (uses provided priorities in input file) 35 | 36 | #### Time Quantum 37 | How long each process runs on the CPU (minimum = .5) 38 | 39 | ### Prerequisites 40 | 41 | Program can be compile and ran with specified arguments using most IDEs that support C++. Implementation will depend on platform. 42 | 43 | ## Built With 44 | 45 | * [CLion](https://www.jetbrains.com/clion/) - IDE Used 46 | 47 | ## Authors 48 | 49 | * **Joseph Dodson** - *Sole contributor* - [joedodson](https://github.com/joedodson) 50 | 51 | -------------------------------------------------------------------------------- /headers/CPU.h: -------------------------------------------------------------------------------- 1 | #ifndef LAB2_CPU_H 2 | #define LAB2_CPU_H 3 | 4 | #include "PCB.h" 5 | #include "DList.h" 6 | #include "Clock.h" 7 | #include "Schedulers.h" 8 | 9 | //forward declaration so that CPU can declare dispatcher as friend 10 | class Dispatcher; 11 | 12 | class CPU{ 13 | private: 14 | PCB *pcb; 15 | bool idle; 16 | Clock *clock; 17 | DList *finished_queue; //for terminated process, used later by statupdater 18 | friend Dispatcher; //allows dispatcher to switch out processes 19 | public: 20 | CPU(DList *fq, Clock *cl); 21 | PCB* getpcb(); 22 | bool isidle(); 23 | void execute(); 24 | void terminate(); 25 | }; 26 | 27 | #endif -------------------------------------------------------------------------------- /headers/Clock.h: -------------------------------------------------------------------------------- 1 | #ifndef LAB2_CLOCK_H 2 | #define LAB2_CLOCK_H 3 | 4 | //class that is shared with most other objects that need to be synced to a clock to manage timers and stat collection 5 | class Clock{ 6 | private: 7 | float time; 8 | public: 9 | Clock(){time=0;} 10 | void reset(); 11 | float gettime(); 12 | void step(); 13 | }; 14 | 15 | #endif //LAB2_CLOCK_H 16 | -------------------------------------------------------------------------------- /headers/DList.h: -------------------------------------------------------------------------------- 1 | #ifndef LAB2_DLIST_H 2 | #define LAB2_DLIST_H 3 | 4 | #include "PCB.h" 5 | #include 6 | #include 7 | 8 | template 9 | class DList{ 10 | struct node{ 11 | T data; 12 | node *next, *prev; 13 | explicit node(T data_):data(data_){ 14 | next = prev = NULL; 15 | } 16 | }; 17 | node *head, *tail; 18 | int _size; 19 | public: 20 | DList(){ 21 | head = tail = NULL; 22 | _size = 0; 23 | } 24 | ~DList(){clear();} 25 | void add_start(T p); 26 | void add_end(T p); 27 | T* gethead(); 28 | T* gettail(); 29 | T* getindex(int index); 30 | T remove_head(); 31 | T remove_tail(); 32 | T removeindex(int index); 33 | int size(); 34 | void print(); 35 | void clear(); 36 | }; 37 | 38 | template 39 | void DList::add_start(T p) { 40 | auto temp = new DList::node(p); 41 | if(_size > 0) head->prev = temp; 42 | else tail = temp; 43 | temp->next = head; 44 | temp->prev = NULL; 45 | head = temp; 46 | _size++; 47 | } 48 | 49 | template 50 | void DList::add_end(T data) { 51 | auto temp = new node(data); 52 | if(_size > 0) tail->next = temp; 53 | else head = temp; 54 | temp->next = NULL; 55 | temp->prev = tail; 56 | tail = temp; 57 | _size++; 58 | } 59 | 60 | template 61 | T* DList::gethead() {if(_size) return &(head->data);} 62 | 63 | template 64 | T* DList::gettail() {if(_size) return &(tail->data);} 65 | 66 | template 67 | T* DList::getindex(int index) { 68 | if(index < 0 || index >= _size) return NULL; 69 | node* curr = head; 70 | while(curr != NULL && index > 0){ 71 | curr = curr->next; 72 | index--; 73 | } 74 | if(curr != NULL) return &(curr->data); 75 | } 76 | 77 | template 78 | T DList::remove_head() { 79 | if(_size == 1) { 80 | T temp = head->data; 81 | clear(); 82 | return temp; 83 | } 84 | else if(_size > 1) { 85 | T temp = head->data; 86 | head = head->next; 87 | delete head->prev; 88 | head->prev = NULL; 89 | _size--; 90 | 91 | return temp; 92 | } 93 | } 94 | 95 | template 96 | T DList::remove_tail() { 97 | if(_size == 1){ 98 | T temp = tail->data; 99 | clear(); 100 | return temp; 101 | } 102 | else if(_size > 1) { 103 | T temp = tail->data; 104 | tail = tail->prev; 105 | delete tail->next; 106 | tail->next = NULL; 107 | _size--; 108 | return temp; 109 | } 110 | } 111 | 112 | template 113 | T DList::removeindex(int index) { 114 | if(index == 0) return remove_head(); 115 | else if(index == _size-1) return remove_tail(); 116 | else { 117 | node *curr = head; 118 | while (curr != NULL && index > 0) { 119 | curr = curr->next; 120 | index--; 121 | } 122 | if(curr != NULL) { 123 | curr->prev->next = curr->next; 124 | curr->next->prev = curr->prev; 125 | 126 | PCB temp(curr->data); 127 | delete curr; 128 | _size--; 129 | return temp; 130 | } 131 | } 132 | } 133 | 134 | template 135 | int DList::size() { 136 | return _size; 137 | } 138 | 139 | template 140 | void DList::clear() { 141 | node *next = head; 142 | while(head != NULL){ 143 | next = head->next; 144 | delete head; 145 | head = next; 146 | } 147 | tail = NULL; 148 | _size = 0; 149 | } 150 | 151 | template 152 | void DList::print() { 153 | std::cout << "----Back----" << std::endl; 154 | node *curr = head; 155 | while(curr != NULL){ 156 | curr->data.print(); 157 | curr = curr->next; 158 | } 159 | std::cout << "----Front----" << std::endl; 160 | } 161 | #endif //LAB2_DLIST_H 162 | -------------------------------------------------------------------------------- /headers/PCB.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Joseph on 10/7/2017. 3 | // 4 | 5 | #ifndef LAB2_PCB_H 6 | #define LAB2_PCB_H 7 | 8 | #include 9 | 10 | //data structure to hold process information 11 | struct PCB{ 12 | int pid, arrival, burst, priority, num_context; 13 | float time_left, resp_time, wait_time, finish_time; 14 | bool started; 15 | 16 | PCB(){pid = arrival = burst = time_left = priority = resp_time = wait_time = num_context = finish_time = started = 0;} 17 | PCB(int id, int arr, int time, int prio) : pid(id), arrival(arr), burst(time), time_left(time), priority(prio){ 18 | resp_time = wait_time = num_context = finish_time = started = 0; 19 | } 20 | void print(){ 21 | std::cout << pid << " " << arrival << " " << time_left << " " << priority << std::endl; 22 | } 23 | }; 24 | #endif //LAB2_PCB_H 25 | -------------------------------------------------------------------------------- /headers/PCBGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef LAB2_PCBGENERATOR_H 2 | #define LAB2_PCBGENERATOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "DList.h" 8 | #include "Clock.h" 9 | #include "PCB.h" 10 | 11 | class PCBGenerator{ 12 | private: 13 | std::ifstream infile; 14 | DList *ready_queue; 15 | Clock *clock; 16 | PCB nextPCB; 17 | bool _finished; 18 | int last_arr; 19 | bool *arrivals; 20 | bool *pids; 21 | int arr_size; 22 | public: 23 | PCBGenerator(std::string filename, DList *lst, Clock *c); 24 | ~PCBGenerator(); 25 | 26 | //checks the current time to see if its time to add next process to ready queue 27 | void generate(); 28 | 29 | //if there's still something in the file to read, set it as the next process to be added when its time 30 | void readnext(); 31 | 32 | //simple routine to let others know if more processes are coming 33 | bool finished(); 34 | void doublearrays(); 35 | }; 36 | 37 | #endif //LAB2_PCBGENERATOR_H 38 | -------------------------------------------------------------------------------- /headers/Schedulers.h: -------------------------------------------------------------------------------- 1 | #ifndef LAB2_SCHEDULER_H 2 | #define LAB2_SCHEDULER_H 3 | 4 | #include "DList.h" 5 | #include "CPU.h" 6 | 7 | class CPU; 8 | class Scheduler; 9 | //needs to be forward declared since Dispatcher and Scheduler mutually include each other 10 | class Dispatcher{ 11 | private: 12 | CPU *cpu; 13 | Scheduler *scheduler; 14 | DList *ready_queue; 15 | Clock *clock; 16 | bool _interrupt; 17 | public: 18 | Dispatcher(); 19 | Dispatcher(CPU *cp, Scheduler *sch, DList *rq, Clock *cl); 20 | PCB* switchcontext(int index); 21 | void execute(); 22 | void interrupt(); 23 | }; 24 | 25 | class Scheduler{ 26 | private: 27 | int next_pcb_index; 28 | DList *ready_queue; 29 | CPU *cpu; 30 | Dispatcher *dispatcher; 31 | int algorithm; 32 | float timeq, timer; //time quantum, timer to keep track of when to interrupt dispatcher 33 | public: 34 | Scheduler(); 35 | Scheduler(DList *rq, CPU *cp, int alg); 36 | Scheduler(DList *rq, CPU *cp, int alg, int tq); 37 | void setdispatcher(Dispatcher *disp); 38 | int getnext(); 39 | void execute(); 40 | void fcfs(); 41 | void srtf(); 42 | void rr(); 43 | void pp(); 44 | }; 45 | 46 | #endif //LAB2_SCHEDULER_H 47 | -------------------------------------------------------------------------------- /headers/StatUpdater.h: -------------------------------------------------------------------------------- 1 | #ifndef LAB2_STATUPDATER_H 2 | #define LAB2_STATUPDATER_H 3 | 4 | #include "DList.h" 5 | #include "PCB.h" 6 | #include "Clock.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using std::cout; 13 | 14 | //class that handles updating waiting times, response times, etc. 15 | //and prints them in a specific format to a provided file name 16 | class StatUpdater{ 17 | private: 18 | DList *ready_queue; 19 | DList *finished_queue; 20 | Clock *clock; 21 | int algorithm, num_tasks, timeq; 22 | float last_update; 23 | std::string filename; 24 | public: 25 | StatUpdater(DList *rq, DList *fq, Clock *cl, int alg, std::string fn, int tq); 26 | void execute(); 27 | void print(); 28 | }; 29 | #endif //LAB2_STATUPDATER_H 30 | -------------------------------------------------------------------------------- /output/sample_outputFCFS.txt: -------------------------------------------------------------------------------- 1 | ******************************************************************* 2 | Scheduling Algorithm: FCFS 3 | ******************************************************************* 4 | ---------------------------------------------------------------------------------------------------------------------- 5 | | PID | Arrival | CPU-Burst | Priority | Finish | Waiting | Turnaround | Response | C. Switches| 6 | ---------------------------------------------------------------------------------------------------------------------- 7 | | 1 | 0 | 10 | 37 | 10 | 0 | 10 | 0 | 0 | 8 | ---------------------------------------------------------------------------------------------------------------------- 9 | | 2 | 1 | 3 | 0 | 13 | 9 | 12 | 9 | 0 | 10 | ---------------------------------------------------------------------------------------------------------------------- 11 | | 3 | 2 | 8 | 51 | 21 | 11 | 19 | 11 | 0 | 12 | ---------------------------------------------------------------------------------------------------------------------- 13 | | 4 | 4 | 4 | 84 | 25 | 17 | 21 | 17 | 0 | 14 | ---------------------------------------------------------------------------------------------------------------------- 15 | | 5 | 5 | 5 | 44 | 30 | 20 | 25 | 20 | 0 | 16 | ---------------------------------------------------------------------------------------------------------------------- 17 | | 6 | 6 | 7 | 28 | 37 | 24 | 31 | 24 | 0 | 18 | ---------------------------------------------------------------------------------------------------------------------- 19 | | 7 | 9 | 2 | 97 | 39 | 28 | 30 | 28 | 0 | 20 | ---------------------------------------------------------------------------------------------------------------------- 21 | | 8 | 10 | 6 | 70 | 45 | 29 | 35 | 29 | 0 | 22 | ---------------------------------------------------------------------------------------------------------------------- 23 | | 9 | 13 | 1 | 15 | 46 | 32 | 33 | 32 | 0 | 24 | ---------------------------------------------------------------------------------------------------------------------- 25 | | 10 | 15 | 9 | 7 | 55 | 31 | 40 | 31 | 0 | 26 | ---------------------------------------------------------------------------------------------------------------------- 27 | 28 | Average CPU Burst Time: 5.5 ms Average Waiting Time: 20.1 ms 29 | Average Turnaround Time: 25.6 ms Average Response Time: 20.1 ms 30 | Total No. of Context Switching Performed: 0 31 | -------------------------------------------------------------------------------- /output/sample_outputPP.txt: -------------------------------------------------------------------------------- 1 | ******************************************************************* 2 | Scheduling Algorithm: Preemptive Priority 3 | ******************************************************************* 4 | ---------------------------------------------------------------------------------------------------------------------- 5 | | PID | Arrival | CPU-Burst | Priority | Finish | Waiting | Turnaround | Response | C. Switches| 6 | ---------------------------------------------------------------------------------------------------------------------- 7 | | 1 | 0 | 10 | 37 | 31.5 | 21.5 | 31.5 | 0 | 2 | 8 | ---------------------------------------------------------------------------------------------------------------------- 9 | | 2 | 1 | 3 | 0 | 4.5 | 0.5 | 3.5 | 0.5 | 0 | 10 | ---------------------------------------------------------------------------------------------------------------------- 11 | | 3 | 2 | 8 | 51 | 44.5 | 34.5 | 42.5 | 34.5 | 0 | 12 | ---------------------------------------------------------------------------------------------------------------------- 13 | | 4 | 4 | 4 | 84 | 54.5 | 46.5 | 50.5 | 46.5 | 0 | 14 | ---------------------------------------------------------------------------------------------------------------------- 15 | | 5 | 5 | 5 | 44 | 36.5 | 26.5 | 31.5 | 26.5 | 0 | 16 | ---------------------------------------------------------------------------------------------------------------------- 17 | | 6 | 6 | 7 | 28 | 15 | 2 | 9 | 0.5 | 1 | 18 | ---------------------------------------------------------------------------------------------------------------------- 19 | | 7 | 9 | 2 | 97 | 56.5 | 45.5 | 47.5 | 45.5 | 0 | 20 | ---------------------------------------------------------------------------------------------------------------------- 21 | | 8 | 10 | 6 | 70 | 50.5 | 34.5 | 40.5 | 34.5 | 0 | 22 | ---------------------------------------------------------------------------------------------------------------------- 23 | | 9 | 13 | 1 | 15 | 14.5 | 0.5 | 1.5 | 0.5 | 0 | 24 | ---------------------------------------------------------------------------------------------------------------------- 25 | | 10 | 15 | 9 | 7 | 24 | 0 | 9 | 0 | 0 | 26 | ---------------------------------------------------------------------------------------------------------------------- 27 | 28 | Average CPU Burst Time: 5.5 ms Average Waiting Time: 21.2 ms 29 | Average Turnaround Time: 26.7 ms Average Response Time: 18.9 ms 30 | Total No. of Context Switching Performed: 3 31 | -------------------------------------------------------------------------------- /output/sample_outputRR1.txt: -------------------------------------------------------------------------------- 1 | ******************************************************************* 2 | Scheduling Algorithm: Round Robin 3 | (No. Of Tasks = 10 Quantum = 1) 4 | ******************************************************************* 5 | ---------------------------------------------------------------------------------------------------------------------- 6 | | PID | Arrival | CPU-Burst | Priority | Finish | Waiting | Turnaround | Response | C. Switches| 7 | ---------------------------------------------------------------------------------------------------------------------- 8 | | 1 | 0 | 10 | 37 | 73.5 | 63.5 | 73.5 | 0 | 9 | 9 | ---------------------------------------------------------------------------------------------------------------------- 10 | | 2 | 1 | 3 | 0 | 16 | 12 | 15 | 0.5 | 2 | 11 | ---------------------------------------------------------------------------------------------------------------------- 12 | | 3 | 2 | 8 | 51 | 70 | 60 | 68 | 2.5 | 7 | 13 | ---------------------------------------------------------------------------------------------------------------------- 14 | | 4 | 4 | 4 | 84 | 41.5 | 33.5 | 37.5 | 3.5 | 3 | 15 | ---------------------------------------------------------------------------------------------------------------------- 16 | | 5 | 5 | 5 | 44 | 54.5 | 44.5 | 49.5 | 5.5 | 4 | 17 | ---------------------------------------------------------------------------------------------------------------------- 18 | | 6 | 6 | 7 | 28 | 71 | 57.5 | 65 | 7.5 | 6 | 19 | ---------------------------------------------------------------------------------------------------------------------- 20 | | 7 | 9 | 2 | 97 | 31.5 | 20 | 22.5 | 8.5 | 1 | 21 | ---------------------------------------------------------------------------------------------------------------------- 22 | | 8 | 10 | 6 | 70 | 67.5 | 51.5 | 57.5 | 9 | 5 | 23 | ---------------------------------------------------------------------------------------------------------------------- 24 | | 9 | 13 | 1 | 15 | 24.5 | 10.5 | 11.5 | 10.5 | 0 | 25 | ---------------------------------------------------------------------------------------------------------------------- 26 | | 10 | 15 | 9 | 7 | 76.5 | 52 | 61.5 | 12.5 | 6 | 27 | ---------------------------------------------------------------------------------------------------------------------- 28 | 29 | Average CPU Burst Time: 5.5 ms Average Waiting Time: 40.5 ms 30 | Average Turnaround Time: 46.15 ms Average Response Time: 6 ms 31 | Total No. of Context Switching Performed: 43 32 | -------------------------------------------------------------------------------- /output/sample_outputRR4.txt: -------------------------------------------------------------------------------- 1 | ******************************************************************* 2 | Scheduling Algorithm: Round Robin 3 | (No. Of Tasks = 10 Quantum = 4) 4 | ******************************************************************* 5 | ---------------------------------------------------------------------------------------------------------------------- 6 | | PID | Arrival | CPU-Burst | Priority | Finish | Waiting | Turnaround | Response | C. Switches| 7 | ---------------------------------------------------------------------------------------------------------------------- 8 | | 1 | 0 | 10 | 37 | 47.5 | 37.5 | 47.5 | 0 | 2 | 9 | ---------------------------------------------------------------------------------------------------------------------- 10 | | 2 | 1 | 3 | 0 | 7.5 | 3.5 | 6.5 | 3.5 | 0 | 11 | ---------------------------------------------------------------------------------------------------------------------- 12 | | 3 | 2 | 8 | 51 | 40 | 30 | 38 | 5.5 | 1 | 13 | ---------------------------------------------------------------------------------------------------------------------- 14 | | 4 | 4 | 4 | 84 | 16 | 8 | 12 | 8 | 0 | 15 | ---------------------------------------------------------------------------------------------------------------------- 16 | | 5 | 5 | 5 | 44 | 48.5 | 38.5 | 43.5 | 15.5 | 1 | 17 | ---------------------------------------------------------------------------------------------------------------------- 18 | | 6 | 6 | 7 | 28 | 51.5 | 38.5 | 45.5 | 19 | 1 | 19 | ---------------------------------------------------------------------------------------------------------------------- 20 | | 7 | 9 | 2 | 97 | 31.5 | 20.5 | 22.5 | 20.5 | 0 | 21 | ---------------------------------------------------------------------------------------------------------------------- 22 | | 8 | 10 | 6 | 70 | 53.5 | 37.5 | 43.5 | 21.5 | 1 | 23 | ---------------------------------------------------------------------------------------------------------------------- 24 | | 9 | 13 | 1 | 15 | 41 | 27 | 28 | 27 | 0 | 25 | ---------------------------------------------------------------------------------------------------------------------- 26 | | 10 | 15 | 9 | 7 | 58.5 | 34.5 | 43.5 | 26 | 1 | 27 | ---------------------------------------------------------------------------------------------------------------------- 28 | 29 | Average CPU Burst Time: 5.5 ms Average Waiting Time: 27.55 ms 30 | Average Turnaround Time: 33.05 ms Average Response Time: 14.65 ms 31 | Total No. of Context Switching Performed: 7 32 | -------------------------------------------------------------------------------- /output/sample_outputSRTF.txt: -------------------------------------------------------------------------------- 1 | ******************************************************************* 2 | Scheduling Algorithm: SRTF 3 | ******************************************************************* 4 | ---------------------------------------------------------------------------------------------------------------------- 5 | | PID | Arrival | CPU-Burst | Priority | Finish | Waiting | Turnaround | Response | C. Switches| 6 | ---------------------------------------------------------------------------------------------------------------------- 7 | | 1 | 0 | 10 | 37 | 47.5 | 37.5 | 47.5 | 0 | 1 | 8 | ---------------------------------------------------------------------------------------------------------------------- 9 | | 2 | 1 | 3 | 0 | 4.5 | 0.5 | 3.5 | 0.5 | 0 | 10 | ---------------------------------------------------------------------------------------------------------------------- 11 | | 3 | 2 | 8 | 51 | 38.5 | 28.5 | 36.5 | 28.5 | 0 | 12 | ---------------------------------------------------------------------------------------------------------------------- 13 | | 4 | 4 | 4 | 84 | 8.5 | 0.5 | 4.5 | 0.5 | 0 | 14 | ---------------------------------------------------------------------------------------------------------------------- 15 | | 5 | 5 | 5 | 44 | 17.5 | 7.5 | 12.5 | 3.5 | 2 | 16 | ---------------------------------------------------------------------------------------------------------------------- 17 | | 6 | 6 | 7 | 28 | 30.5 | 17.5 | 24.5 | 17.5 | 0 | 18 | ---------------------------------------------------------------------------------------------------------------------- 19 | | 7 | 9 | 2 | 97 | 11.5 | 0.5 | 2.5 | 0.5 | 0 | 20 | ---------------------------------------------------------------------------------------------------------------------- 21 | | 8 | 10 | 6 | 70 | 23.5 | 7.5 | 13.5 | 7.5 | 0 | 22 | ---------------------------------------------------------------------------------------------------------------------- 23 | | 9 | 13 | 1 | 15 | 14.5 | 0.5 | 1.5 | 0.5 | 0 | 24 | ---------------------------------------------------------------------------------------------------------------------- 25 | | 10 | 15 | 9 | 7 | 56.5 | 32.5 | 41.5 | 32.5 | 0 | 26 | ---------------------------------------------------------------------------------------------------------------------- 27 | 28 | Average CPU Burst Time: 5.5 ms Average Waiting Time: 13.3 ms 29 | Average Turnaround Time: 18.8 ms Average Response Time: 9.15 ms 30 | Total No. of Context Switching Performed: 3 31 | -------------------------------------------------------------------------------- /sample_input.txt: -------------------------------------------------------------------------------- 1 | 1 0 10 37 2 | 2 1 3 0 3 | 3 2 8 51 4 | 4 4 4 84 5 | 5 5 5 44 6 | 6 6 7 28 7 | 7 9 2 97 8 | 8 10 6 70 9 | 9 13 1 15 10 | 10 15 9 7 -------------------------------------------------------------------------------- /source/CPU.cpp: -------------------------------------------------------------------------------- 1 | #include "../headers/CPU.h" 2 | 3 | CPU::CPU(DList *fq, Clock *cl) { 4 | pcb = NULL; 5 | idle = true; 6 | finished_queue = fq; 7 | clock = cl; 8 | } 9 | 10 | //used by others to determine what the cpu is working on like priority and time left 11 | PCB* CPU::getpcb() { 12 | return pcb; 13 | } 14 | 15 | //check to see if cpu is currently working on a process 16 | bool CPU::isidle() { 17 | return idle; 18 | } 19 | 20 | //called every clock cycle 21 | void CPU::execute() { 22 | if(pcb != NULL){ 23 | idle = false; 24 | if(!pcb->started){ //helps determine response time, only increments it if pcb hasn't been worked on yet 25 | pcb->started = true; 26 | pcb->resp_time = clock->gettime() - pcb->arrival; 27 | } 28 | pcb->time_left -= .5; //simulate process being worked on for a clock cycle 29 | if(pcb->time_left <= 0) { //terminate it if its done and set self to idle 30 | terminate(); 31 | idle = true; 32 | } 33 | 34 | } 35 | } 36 | 37 | //routine to update termination related stats, for StatUpdater to use later 38 | void CPU::terminate() { 39 | pcb->finish_time = clock->gettime()+.5; 40 | finished_queue->add_end(*pcb); 41 | delete pcb; 42 | pcb = NULL; 43 | } -------------------------------------------------------------------------------- /source/Clock.cpp: -------------------------------------------------------------------------------- 1 | #include "../headers/Clock.h" 2 | 3 | void Clock::reset(){ 4 | time = 0; 5 | } 6 | 7 | float Clock::gettime(){ 8 | return time; 9 | } 10 | 11 | void Clock::step(){ 12 | time += .5; 13 | } 14 | -------------------------------------------------------------------------------- /source/PCBGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "../headers/PCBGenerator.h" 2 | 3 | PCBGenerator::PCBGenerator(std::string filename, DList *lst, Clock *c) { 4 | clock = c; 5 | ready_queue = lst; 6 | _finished = false; 7 | last_arr = 0; 8 | arr_size = 25; 9 | arrivals = new bool[arr_size]; 10 | pids = new bool[arr_size]; 11 | for(int i = 0; i < arr_size; ++i) { 12 | arrivals[i] = false; 13 | pids[i] = false; 14 | } 15 | infile.open(filename); 16 | readnext(); 17 | } 18 | 19 | PCBGenerator::~PCBGenerator(){ 20 | delete arrivals; 21 | delete pids; 22 | } 23 | 24 | void PCBGenerator::generate(){ 25 | if(!_finished && clock->gettime() >= nextPCB.arrival){ 26 | ready_queue->add_end(nextPCB); 27 | readnext(); 28 | } 29 | } 30 | 31 | void PCBGenerator::readnext(){ 32 | bool error = false; 33 | if(!infile.eof()){ 34 | std::stringstream ss; 35 | std::string line; 36 | float vals[5]; 37 | 38 | while(!infile.fail()){ 39 | getline(infile, line); 40 | if(line.length() <= 2) continue; 41 | break; 42 | } 43 | if(infile.eof()){ 44 | _finished = true; 45 | return; 46 | } 47 | 48 | ss << line; 49 | int count = 0; 50 | while(count < 4 && ss >> vals[count]){ 51 | count++; 52 | }; 53 | while(vals[0] >= arr_size || vals[1] >= arr_size) doublearrays(); 54 | 55 | //series of error checking and data validation, the if(error = true) just compacts code 56 | if(ss.fail() && !error) if(error = true) std::cout << "Missing data for process in file. Exiting Now." << std::endl; 57 | if(ss >> vals[5] && !error) if(error = true) std::cout << "Too many values for a process in file. Exiting now." << std::endl; 58 | if(vals[1] < 0 && !error) if(error = true) std::cout << "Arrival time can't be less than zero. Exiting now." << std::endl; 59 | if(vals[2] <= 0 && !error) if(error = true) std::cout << "CPU Burst time must be greater than 0. Exiting now." << std::endl; 60 | if(vals[1] < last_arr && !error) if(error = true) std::cout << "File needs to be sorted by arrival time. Exiting now." << std::endl; 61 | if(pids[int(vals[0])]) if(error = true) std::cout << "Can't have duplicate PIDs. Exiting now." << std::endl; 62 | if(arrivals[int(vals[1])]) if(error = true) std::cout << "Can't have duplicate arrival times. Exiting now." << std::endl; 63 | 64 | if(error) return(throw 1); 65 | 66 | //no error with data, continue 67 | arrivals[int(vals[1])] = true; 68 | pids[int(vals[0])] = true; 69 | nextPCB = PCB(vals[0], vals[1], vals[2], vals[3]); 70 | } 71 | else _finished = true; 72 | } 73 | 74 | bool PCBGenerator::finished(){ 75 | return _finished; 76 | } 77 | 78 | void PCBGenerator::doublearrays(){ 79 | arr_size *= 2; 80 | auto temp_arrs = new bool[arr_size]; 81 | auto temp_pids = new bool[arr_size]; 82 | for(int i = 0; i < arr_size; ++i) { 83 | if(i < arr_size/2){ 84 | temp_arrs[i] = arrivals[i]; 85 | temp_pids[i] = pids[i]; 86 | } 87 | else { 88 | temp_arrs[i] = false; 89 | temp_pids[i] = false; 90 | } 91 | } 92 | delete arrivals; 93 | delete pids; 94 | arrivals = temp_arrs; 95 | pids = temp_pids; 96 | } -------------------------------------------------------------------------------- /source/Schedulers.cpp: -------------------------------------------------------------------------------- 1 | #include "../headers/Schedulers.h" 2 | 3 | Scheduler::Scheduler() { 4 | next_pcb_index = -1; 5 | ready_queue = NULL; 6 | } 7 | 8 | //constructor for non-RR algs 9 | Scheduler::Scheduler(DList *rq, CPU *cp, int alg){ 10 | ready_queue = rq; 11 | cpu = cp; 12 | dispatcher = NULL; 13 | next_pcb_index = -1; 14 | algorithm = alg; 15 | } 16 | 17 | //constructor for RR alg 18 | Scheduler::Scheduler(DList *rq, CPU *cp, int alg, int tq){ 19 | ready_queue = rq; 20 | cpu = cp; 21 | dispatcher = NULL; 22 | next_pcb_index = -1; 23 | algorithm = alg; 24 | timeq = timer = tq; 25 | } 26 | 27 | //dispatcher needed to be set after construction since they mutually include each other 28 | //can only be set once 29 | void Scheduler::setdispatcher(Dispatcher *disp) { 30 | if(dispatcher == NULL) dispatcher = disp; 31 | } 32 | 33 | //dispatcher uses this to determine which process in the queue to grab 34 | int Scheduler::getnext() { 35 | return next_pcb_index; 36 | } 37 | 38 | //switch for the different algorithms 39 | void Scheduler::execute() { 40 | if(timer > 0) timer -= .5; 41 | if(ready_queue->size()) { 42 | switch (algorithm) { 43 | case 0: 44 | fcfs(); 45 | break; 46 | case 1: 47 | srtf(); 48 | break; 49 | case 2: 50 | rr(); 51 | break; 52 | case 3: 53 | pp(); 54 | break; 55 | default: 56 | break; 57 | } 58 | } 59 | } 60 | 61 | //simply waits for cpu to go idle and then tells dispatcher to load next in queue 62 | void Scheduler::fcfs() { 63 | next_pcb_index = 0; 64 | if(cpu->isidle()) dispatcher->interrupt(); 65 | } 66 | 67 | //shortest remaining time first 68 | void Scheduler::srtf() { 69 | float short_time; 70 | int short_index = -1; 71 | 72 | //if cpu is idle, initialize shortest time to head of queue 73 | if(!cpu->isidle()) short_time = cpu->getpcb()->time_left; 74 | else { 75 | short_time = ready_queue->gethead()->time_left; 76 | short_index = 0; 77 | } 78 | 79 | //now search through queue for actual shortest time 80 | for(int index = 0; index < ready_queue->size(); ++index){ 81 | if(ready_queue->getindex(index)->time_left < short_time){ //less than ensures FCFS is used for tie 82 | short_index = index; 83 | short_time = ready_queue->getindex(index)->time_left; 84 | } 85 | } 86 | 87 | //-1 means nothing to schedule, only happens if cpu is already working on shortest 88 | if(short_index >= 0) { 89 | next_pcb_index = short_index; 90 | dispatcher->interrupt(); 91 | } 92 | } 93 | 94 | //round robin, simply uses timer and interrupts dispatcher when timer is up, schedules next in queue 95 | void Scheduler::rr() { 96 | if(cpu->isidle() || timer <= 0){ 97 | timer = timeq; 98 | next_pcb_index = 0; 99 | dispatcher->interrupt(); 100 | } 101 | } 102 | 103 | //preemptive priority 104 | void Scheduler::pp() { 105 | int low_prio; 106 | int low_index = -1; 107 | 108 | //if cpu is idle, set next pcb in queue as lowest priority initially 109 | if(!cpu->isidle()) low_prio = cpu->getpcb()->priority; 110 | else{ 111 | low_prio = ready_queue->gethead()->priority; 112 | low_index = 0; 113 | } 114 | 115 | //search through entire queue for actual lowest priority 116 | for(int index = 0; index < ready_queue->size(); ++index){ 117 | int temp_prio = ready_queue->getindex(index)->priority; 118 | if(temp_prio < low_prio){ //less than ensures FCFS is used for ties 119 | low_prio = temp_prio; 120 | low_index = index; 121 | } 122 | } 123 | 124 | //only -1 if couldn't find a pcb to schedule, happens if cpu is already working on lowest priority 125 | if(low_index >= 0){ 126 | next_pcb_index = low_index; 127 | dispatcher->interrupt(); 128 | } 129 | } 130 | 131 | /* 132 | * 133 | * Dispatcher Implementation 134 | * 135 | */ 136 | Dispatcher::Dispatcher(){ 137 | cpu = NULL; 138 | scheduler = NULL; 139 | ready_queue = NULL; 140 | clock = NULL; 141 | _interrupt = false; 142 | } 143 | 144 | Dispatcher::Dispatcher(CPU *cp, Scheduler *sch, DList *rq, Clock *cl) { 145 | cpu = cp; 146 | scheduler = sch; 147 | ready_queue = rq; 148 | clock = cl; 149 | _interrupt = false; 150 | }; 151 | 152 | //function to handle switching out pcbs and storing back into ready queue 153 | PCB* Dispatcher::switchcontext(int index) { 154 | PCB* old_pcb = cpu->pcb; 155 | PCB* new_pcb = new PCB(ready_queue->removeindex(scheduler->getnext())); 156 | cpu->pcb = new_pcb; 157 | return old_pcb; 158 | } 159 | 160 | //executed every clock cycle, only if scheduler interrupts it 161 | void Dispatcher::execute() { 162 | if(_interrupt) { 163 | PCB* old_pcb = switchcontext(scheduler->getnext()); 164 | if(old_pcb != NULL){ //only consider it a switch if cpu was still working on process 165 | old_pcb->num_context++; 166 | cpu->getpcb()->wait_time += .5; 167 | clock->step(); 168 | ready_queue->add_end(*old_pcb); 169 | delete old_pcb; 170 | } 171 | _interrupt = false; 172 | } 173 | } 174 | 175 | //routine for scheudler to interrupt it 176 | void Dispatcher::interrupt() { 177 | _interrupt = true; 178 | } -------------------------------------------------------------------------------- /source/StatUpdater.cpp: -------------------------------------------------------------------------------- 1 | #include "../headers/StatUpdater.h" 2 | 3 | StatUpdater::StatUpdater(DList *rq, DList *fq, Clock *cl, int alg, std::string fn, int tq){ 4 | ready_queue = rq; 5 | finished_queue = fq; 6 | clock = cl; 7 | algorithm = alg; 8 | timeq = tq; 9 | filename = fn; 10 | last_update = 0; 11 | } 12 | 13 | //main function that gets called every clock cycle to update times of pcbs 14 | void StatUpdater::execute() { 15 | //increment handles situations where a context switch happens in middle of cycle 16 | //allows updater to increment times 17 | float increment = clock->gettime() - last_update; 18 | last_update = clock->gettime(); 19 | for(int index = 0; index < ready_queue->size(); ++index){ 20 | //get pointer to each pcb in queue and update their waiting times 21 | PCB* temp = ready_queue->getindex(index); 22 | temp->wait_time += increment; 23 | } 24 | } 25 | 26 | 27 | //straightforward print function that prints to file using iomanip and column for a table format 28 | //uses finished queue to tally up final stats 29 | void StatUpdater::print() { 30 | num_tasks = finished_queue->size(); 31 | std::string alg; 32 | int colwidth = 11; 33 | float tot_burst, tot_turn, tot_wait, tot_resp; 34 | int contexts; 35 | tot_burst = tot_turn = tot_wait = tot_resp = contexts = 0; 36 | 37 | std::ofstream outfile(filename); 38 | 39 | 40 | switch(algorithm){ 41 | case 0: 42 | alg = "FCFS"; 43 | break; 44 | case 1: 45 | alg = "SRTF"; 46 | break; 47 | case 2: 48 | alg = "Round Robin"; 49 | break; 50 | case 3: 51 | alg = "Preemptive Priority"; 52 | break; 53 | } 54 | 55 | outfile << "*******************************************************************" << std::endl; 56 | outfile << "Scheduling Algorithm: " << alg << std::endl; 57 | if(timeq != -1) outfile << "(No. Of Tasks = " << finished_queue->size() << " Quantum = " << timeq << ")" << std::endl; 58 | outfile << "*******************************************************************" << std::endl; 59 | 60 | outfile << "----------------------------------------------------------------------------------------------------------------------" << std::endl; 61 | outfile << "| " << std::left << std::setw(colwidth) << "PID" << "| " << std::left << std::setw(colwidth) << "Arrival" 62 | << "| " << std::left << std::setw(colwidth) << "CPU-Burst" << "| " << std::left << std::setw(colwidth) << "Priority" 63 | << "| " << std::left << std::setw(colwidth) << "Finish" << "| " << std::left << std::setw(colwidth) << "Waiting" 64 | << "| " << std::left << std::setw(colwidth) << "Turnaround" << "| " << std::left << std::setw(colwidth) << "Response" 65 | << "| " << std::left << std::setw(colwidth) << "C. Switches" << "| " << std::endl 66 | << "----------------------------------------------------------------------------------------------------------------------" << std::endl; 67 | 68 | for(int id = 1; id < num_tasks+1; ++id){ 69 | for(int index = 0; index < finished_queue->size(); ++index){ 70 | if(finished_queue->getindex(index)->pid == id){ 71 | PCB temp = finished_queue->removeindex(index); 72 | float turnaround = temp.finish_time - temp.arrival; 73 | tot_burst += temp.burst; 74 | tot_turn += turnaround; 75 | tot_wait += temp.wait_time; 76 | tot_resp += temp.resp_time; 77 | contexts += temp.num_context; 78 | 79 | outfile << "| " << std::left << std::setw(colwidth) << temp.pid << "| " << std::left << std::setw(colwidth) 80 | << temp.arrival << "| " << std::left << std::setw(colwidth) << temp.burst << "| " << std::left 81 | << std::setw(colwidth) << temp.priority << "| " << std::left << std::setw(colwidth) << temp.finish_time 82 | << "| " << std::left << std::setw(colwidth) << temp.wait_time << "| " << std::left << std::setw(colwidth) 83 | << turnaround << "| " << std::left << std::setw(colwidth) << temp.resp_time << "| " << std::left << std::setw(colwidth) 84 | << temp.num_context << "|" << std::endl; 85 | outfile << "----------------------------------------------------------------------------------------------------------------------" << std::endl; 86 | } 87 | } 88 | } 89 | outfile << std::endl; 90 | outfile << "Average CPU Burst Time: " << tot_burst/num_tasks << " ms\t\tAverage Waiting Time: " << tot_wait/num_tasks << " ms" << std::endl 91 | << "Average Turnaround Time: " << tot_turn/num_tasks << " ms\t\tAverage Response Time: " << tot_resp/num_tasks << " ms" << std::endl 92 | << "Total No. of Context Switching Performed: " << contexts << std::endl; 93 | } -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../headers/Clock.h" 4 | #include "../headers/PCBGenerator.h" 5 | #include "../headers/CPU.h" 6 | #include "../headers/StatUpdater.h" 7 | using namespace std; 8 | 9 | int main(int argc, char* argv[]) { 10 | //initial args validation 11 | if(argc < 4){ 12 | cout << "Not enough arguments sent to main." << endl; 13 | cout << "Format should be: ./lab2 inputfile outputfile algorithm timequantum(if algorithm == 2)" << endl; 14 | return EXIT_FAILURE; 15 | } 16 | if(atoi(argv[3]) == 2 && argc == 4){ 17 | cout << "Need to provide time quantum when using Round Robin algorithm" << endl; 18 | return EXIT_FAILURE; 19 | } 20 | //variables to hold initial arguments 21 | int algorithm = atoi(argv[3]); 22 | int timeq = -1; 23 | if(algorithm == 2) timeq = atoi(argv[4]); 24 | 25 | //queues to hold PCBs throughout 26 | auto ready_queue = new DList(); 27 | auto finished_queue = new DList(); 28 | 29 | try { 30 | //all the objects that will work together to simulate OS process management 31 | Clock clock; 32 | PCBGenerator pgen(argv[1], ready_queue, &clock); 33 | StatUpdater stats(ready_queue, finished_queue, &clock, algorithm, argv[2], timeq); 34 | CPU cpu(finished_queue, &clock); 35 | Scheduler scheduler(ready_queue, &cpu, algorithm, timeq); 36 | Dispatcher dispatcher(&cpu, &scheduler, ready_queue, &clock); 37 | scheduler.setdispatcher(&dispatcher); 38 | 39 | //loop will continue until no more processes are going to be generated, no more in ready queue, and cpu is done 40 | while (!pgen.finished() || ready_queue->size() || !cpu.isidle()) { 41 | pgen.generate(); 42 | scheduler.execute(); 43 | dispatcher.execute(); 44 | cpu.execute(); 45 | stats.execute(); 46 | clock.step(); 47 | } 48 | 49 | //final printing of stats 50 | stats.print(); 51 | 52 | }catch(int){ 53 | delete ready_queue; 54 | delete finished_queue; 55 | return EXIT_FAILURE; 56 | } 57 | 58 | return 0; 59 | } --------------------------------------------------------------------------------