Last active
April 17, 2023 23:28
-
-
Save jatesy/9919429 to your computer and use it in GitHub Desktop.
The simulation of a system process scheduler, which can implement scheduling algorithms including First Come First Serve(FCFS), RoundRobin, Last Come First Serve(LCFS) and Shortest Job First(SJF). The system is to be implemented as a Discrete Event Simulation (DES). Implemented in C++.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include<stdio.h> | |
#include<stdlib.h> | |
#include<ctype.h> | |
#include<string.h> | |
#include<string> | |
#include<iostream> | |
#include<numeric> | |
#include<algorithm> | |
#include<list> | |
#include<functional> | |
#include<vector> | |
#include<fstream> | |
#include <unistd.h> | |
#define MAX 1000 | |
using namespace std; | |
FILE *rstream; | |
FILE *randfile; | |
ofstream fout; | |
class Event | |
{ | |
public: | |
Event(int a,int i, int b, string c, string d, int e, int f, int g) : timestamp(a), pid(i),ts(b), from(c), to(d), rem(e), ib(f), cb(g){} | |
int timestamp; | |
int pid; | |
int ts; | |
string from; | |
string to; | |
int rem; | |
int ib; | |
int cb; | |
}; | |
list <Event> evnt_list; | |
list<Event>::iterator evnt_index; | |
class Process | |
{ | |
public: | |
Process(int v, int w, int x, int y, int z) :pid(v), at(w), tc(x), scb(y), sio(z), rt(x){ it = 0; cw = 0; need = true; last_running = false; } | |
int pid; //process ID | |
int at; //arrival time | |
int tc; //total cpu | |
int cb; //cpu burst | |
int io; //I / O burst | |
int ft; //finishing time | |
int tt; //Turnaround time ( finishing time - AT ) | |
int it; //I / O Time(time in blocked state) | |
int cw; //CPU Waiting time(time in Ready state) | |
int rt; //remaining time | |
int stcs; //start time of current state | |
bool need; | |
int scb; | |
int sio; | |
bool last_running; | |
}; | |
list <Process> process_list; | |
list <Process>::iterator p_index; | |
list <Process> ready_queue; | |
list <Process>::iterator r_iter; | |
list <Process> block_queue; | |
list <Process>::iterator b_iter; | |
int thetime=0; | |
int c_spare_time = 0; | |
int io_spare_time = 0; | |
int io_spare_start; | |
int io_spare_end; | |
int gb_time; | |
string alg; | |
int randvals[100000000]; | |
int ofs=0; | |
int r_size; | |
int qtm; | |
bool spare; | |
void build_proclist(); | |
void build_ready_queue(); | |
void build_event(int timestamp, Process a, string from, string to); | |
void get_event(); | |
void put_event(); | |
void sjf_sort(list <Process>::iterator i); | |
bool cpr_rt(const Process & a, const Process & b); | |
bool cpr_stcs(const Process & a, const Process & b); | |
void print_sum(); | |
bool cpr_rt(const Process & a,const Process & b) | |
{ | |
return a.rt > b.rt; | |
} | |
bool cpr_stcs(const Process & a, const Process & b) | |
{ | |
return a.stcs > b.stcs; | |
} | |
void sjf_sort(list <Process>::iterator i) | |
{ | |
vector <Process> v; | |
list <Process>::iterator j; | |
int k; | |
int a, b; | |
int y; | |
for (j = i; j != ready_queue.end(); j++) | |
{ | |
Process a = *j; | |
v.push_back(a); | |
} | |
sort(v.begin(), v.end(), cpr_rt); | |
for (k = 0; k < (v.size()-1); k++) | |
{ | |
a = k; | |
b = k+1; | |
while ((b <= (v.size() - 1)) && (v[a].rt == v[b].rt)) | |
{ | |
b++; | |
if (b == v.size()) | |
{ | |
b--; | |
break; | |
} | |
} | |
sort(&v[a], &v[b], cpr_stcs); | |
} | |
y = 0; | |
j = i; | |
while (j != ready_queue.end()) | |
{ | |
*j = v[y]; | |
y++; | |
j++; | |
} | |
} | |
void build_ready_queue() | |
{ | |
for (p_index = process_list.begin(); p_index != process_list.end(); p_index++) | |
{ | |
for (r_iter = ready_queue.begin(); r_iter != ready_queue.end(); r_iter++) | |
{ | |
if ((r_iter->at) > (p_index->at))break; | |
} | |
if (r_iter == ready_queue.end()) | |
{ | |
ready_queue.push_back(*p_index); | |
r_iter--; | |
} | |
else | |
{ | |
ready_queue.insert(r_iter, *p_index); | |
r_iter--; | |
} | |
r_iter->stcs = r_iter->at; | |
build_event(r_iter->at, *r_iter, "READY", "READY"); | |
} | |
thetime = ready_queue.begin()->at; | |
c_spare_time += thetime; | |
if (alg == "SJF") | |
{ | |
r_iter = ready_queue.begin(); | |
for (r_iter = ready_queue.begin(); r_iter!=ready_queue.end(); r_iter++) | |
{ | |
if(r_iter->at != ready_queue.begin()->at)break; | |
} | |
r_iter--; | |
ready_queue.reverse(); | |
sjf_sort(r_iter); | |
ready_queue.reverse(); | |
} | |
} | |
int get_random(int burst) | |
{ | |
char r_token[MAX]; | |
if (ofs > r_size) | |
{ | |
ofs = ofs%r_size; | |
} | |
else | |
{ | |
fgets(r_token, MAX, randfile); | |
randvals[ofs] = atoi(strtok(r_token, " \t\n")); | |
} | |
ofs++; | |
return 1 + (randvals[ofs-1] % burst); | |
} | |
void build_proclist() | |
{ | |
char line_token[MAX]; | |
int p_index = 0; | |
int a, b, c, d; | |
while (feof(rstream) == 0) | |
{ | |
fgets(line_token, MAX, rstream); | |
if (feof(rstream) != 0) | |
break; | |
a = atoi(strtok(line_token, " \t\n")); | |
b = atoi(strtok(NULL, " \t\n")); | |
c = atoi(strtok(NULL, " \t\n")); | |
d = atoi(strtok(NULL, " \t\n")); | |
Process p(p_index, a, b, c, d); | |
process_list.push_back(p); | |
p_index++; | |
} | |
} | |
void get_event() | |
{ | |
Process c = Process(0,0,0,0,0); | |
int dt; | |
int old_cb=0; | |
int old_rt=0; | |
// LCFS takes process from theoretical tail of the queue | |
if (ready_queue.empty())return; | |
if (alg == "LCFS") | |
{ | |
ready_queue.reverse(); | |
for (r_iter = ready_queue.begin(); r_iter != ready_queue.end(); r_iter++) | |
{ | |
if (thetime >= r_iter->at)break; | |
} | |
if (r_iter == ready_queue.end()) | |
{ | |
c = *(--ready_queue.end()); | |
r_iter--; | |
} | |
else c = *r_iter; | |
if (c.at > thetime) | |
{ | |
if (block_queue.empty() || | |
(!block_queue.empty() && (block_queue.begin()->io + block_queue.begin()->stcs) >= c.at)) | |
{ | |
c_spare_time += (c.at - thetime); | |
thetime = c.at; | |
} | |
else | |
{ | |
spare = true; | |
return; | |
} | |
} | |
spare = false; | |
ready_queue.erase(r_iter); | |
if (ready_queue.empty()) | |
{ | |
spare = true; | |
} | |
ready_queue.reverse(); | |
} | |
//Other algrothms take process from head of the queue | |
else | |
{ | |
c = *ready_queue.begin(); | |
if (c.at > thetime) | |
{ | |
if (block_queue.empty() || | |
(!block_queue.empty() && (block_queue.begin()->io + block_queue.begin()->stcs) >= c.at)) | |
{ | |
c_spare_time += (c.at - thetime); | |
thetime = c.at; | |
} | |
else | |
{ | |
spare = true; | |
return; | |
} | |
} | |
spare = false; | |
ready_queue.pop_front(); | |
if (ready_queue.empty()) | |
{ | |
spare = true; | |
} | |
} | |
//deal with quantum and cpu burst | |
if (alg == "RR") | |
{ | |
if (c.need == true) | |
{ | |
c.cb = get_random(c.scb); | |
} | |
//choose the min one | |
old_cb = c.cb; | |
old_rt = c.rt; | |
if (c.cb <= c.rt && c.cb<=qtm) dt = c.cb; | |
else if (c.rt <= c.cb && c.rt <= qtm) dt = c.rt; | |
else if (qtm <= c.cb && qtm <= c.rt) dt = qtm; | |
c.cw += (thetime - c.stcs); | |
build_event(thetime, c, "READY", "RUNNG"); | |
if (dt == qtm) | |
{ | |
c.cb -= qtm; | |
if (c.cb == 0)c.need = true; | |
else c.need = false; | |
} | |
else if (dt == c.cb)c.need = true; | |
c.rt -= dt; | |
c.stcs = thetime; | |
thetime += dt; | |
} | |
else | |
{ | |
c.cb = get_random(c.scb); | |
if (c.cb > c.rt)c.cb = c.rt; | |
c.cw += (thetime - c.stcs); | |
build_event(thetime, c, "READY", "RUNNG"); | |
c.rt -= c.cb; | |
c.stcs = thetime; | |
thetime += c.cb; | |
} | |
if (c.rt == 0) | |
{ | |
c.ft = thetime; | |
c.tt = c.ft - c.at; | |
build_event(thetime, c, "RUNNG", "Done"); | |
//write final result into proc_list | |
for (p_index = process_list.begin(); p_index != process_list.end(); p_index++) | |
{ | |
if (p_index->pid == c.pid) | |
{ | |
*p_index = c; | |
break; | |
} | |
} | |
} | |
else if (alg == "RR" && dt == qtm && qtm < old_cb) | |
{ | |
build_event(thetime, c, "RUNNG", "READY"); | |
c.stcs = thetime; | |
c.last_running = true; | |
//put process into ready queue | |
ready_queue.reverse(); | |
r_iter = ready_queue.begin(); | |
while (r_iter != ready_queue.end()) | |
{ | |
if (thetime >= r_iter->at)break; | |
r_iter++; | |
} | |
if (r_iter != ready_queue.end()) | |
{ | |
while (r_iter != ready_queue.end()) | |
{ | |
if (r_iter->stcs > c.stcs) | |
{ | |
r_iter++; | |
} | |
else break; | |
} | |
} | |
if (r_iter == ready_queue.end()){ | |
ready_queue.push_back(c); | |
} | |
else ready_queue.insert(r_iter, c); | |
ready_queue.reverse(); | |
} | |
else | |
{ | |
c.io = get_random(c.sio); | |
build_event(thetime, c, "RUNNG", "BLOCK"); | |
c.stcs = thetime; | |
//put process into block queue | |
if (block_queue.empty()) | |
{ | |
io_spare_end = thetime; | |
io_spare_time += (io_spare_end - io_spare_start); | |
block_queue.push_back(c); | |
return; | |
} | |
for (b_iter = block_queue.begin(); b_iter != block_queue.end(); b_iter++) | |
{ | |
if ((b_iter->io + b_iter->stcs) == (c.stcs + c.io)) | |
{ | |
if (b_iter->stcs > c.stcs)break; | |
else continue; | |
} | |
else if ((b_iter->io + b_iter->stcs) > (c.stcs + c.io))break; | |
} | |
if (b_iter == block_queue.end()) | |
{ | |
b_iter--; | |
int cao = b_iter->io + b_iter->stcs; | |
if (cao > (c.stcs + c.io)) | |
{ | |
block_queue.insert(b_iter, c); | |
} | |
else if (cao < (c.stcs + c.io)) | |
{ | |
block_queue.push_back(c); | |
} | |
else if (cao == (c.stcs + c.io)) | |
{ | |
if (b_iter->stcs > c.stcs) | |
{ | |
block_queue.insert(b_iter, c); | |
} | |
else block_queue.push_back(c); | |
} | |
} | |
else | |
{ | |
block_queue.insert(b_iter, c); | |
} | |
} | |
} | |
void put_event() | |
{ | |
int gsn_time=thetime; | |
if (alg == "SJF") | |
{ | |
ready_queue.reverse(); | |
for (r_iter = ready_queue.begin(); r_iter != ready_queue.end(); r_iter++) | |
{ | |
if (thetime >= r_iter->at)break; | |
} | |
if (r_iter == ready_queue.end()); | |
else | |
{ | |
sjf_sort(r_iter); | |
} | |
ready_queue.reverse(); | |
} | |
if (block_queue.empty())return; | |
int cy_time = (block_queue.begin()->io + block_queue.begin()->stcs); | |
if (thetime < cy_time && spare==true && | |
(ready_queue.empty() || cy_time < ( ready_queue.begin()->at ) )) | |
{ | |
c_spare_time += (cy_time - thetime); | |
thetime = cy_time; | |
} | |
else if (thetime < cy_time)return; | |
while (thetime >= cy_time) | |
{ | |
Process b = *block_queue.begin(); | |
block_queue.pop_front(); //remove from block_queue | |
b.it += (cy_time - b.stcs); | |
build_event((b.io + b.stcs), b, "BLOCK", "READY"); | |
b.stcs = cy_time; | |
if (alg == "SJF") | |
{ | |
ready_queue.reverse(); | |
for (r_iter = ready_queue.begin(); r_iter != ready_queue.end(); r_iter++) | |
{ | |
if (thetime >= r_iter->at)break; | |
} | |
if (r_iter == ready_queue.end()) ready_queue.push_back(b); | |
else | |
{ | |
ready_queue.insert(r_iter, b); | |
r_iter--; | |
sjf_sort(r_iter); | |
} | |
ready_queue.reverse(); | |
} | |
else | |
{ | |
b.last_running = false; | |
ready_queue.reverse(); | |
r_iter = ready_queue.begin(); | |
while (r_iter != ready_queue.end()) | |
{ | |
if (thetime >= r_iter->at)break; | |
r_iter++; | |
} | |
if (r_iter != ready_queue.end()) | |
{ | |
while (r_iter != ready_queue.end()) | |
{ | |
if (r_iter->stcs > b.stcs) | |
{ | |
r_iter++; | |
} | |
else if (r_iter->stcs == b.stcs && r_iter->last_running == true) | |
{ | |
r_iter++; | |
} | |
else break; | |
} | |
} | |
if (r_iter == ready_queue.end())ready_queue.push_back(b); | |
else ready_queue.insert(r_iter, b); | |
ready_queue.reverse(); | |
} | |
if (block_queue.empty()) | |
{ | |
io_spare_start = cy_time; | |
break; | |
} | |
gsn_time = cy_time; | |
cy_time = (block_queue.begin()->io + block_queue.begin()->stcs); | |
} | |
if (!block_queue.empty()) | |
{ | |
for (b_iter = block_queue.begin(); b_iter != block_queue.end(); b_iter++) | |
{ | |
if (b_iter->stcs != thetime)return; | |
} | |
io_spare_time += (thetime - gsn_time); | |
} | |
} | |
void scheduler() | |
{ | |
while (!ready_queue.empty()) | |
{ | |
get_event(); | |
put_event(); | |
} | |
} | |
int main(int argc, char *argv[]) | |
{ | |
char *filename; | |
char *rfilename; | |
char rs_token[MAX]; | |
char *svalue = NULL; | |
int index; | |
int c; | |
opterr = 0; | |
while ((c = getopt(argc, argv, "s:")) != -1) | |
switch (c) | |
{ | |
case 's': | |
svalue = optarg; | |
break; | |
case '?': | |
if (optopt == 's') | |
printf("Option -%c requires an argument.\n", optopt); | |
else if (isprint(optopt)) | |
printf("Unknown option -'%c'.\n", optopt); | |
else | |
printf("Unknown option character '\\x%x'.\n",optopt); | |
return 1; | |
default: | |
abort(); | |
} | |
filename = argv[2]; | |
rfilename = argv[3]; | |
qtm = 0; | |
if (svalue[0] == 'R') | |
{ | |
alg = "RR"; | |
qtm = atoi(&svalue[1]); | |
} | |
else if (svalue[0] == 'F') | |
{ | |
alg = "FCFS"; | |
} | |
else if (svalue[0] == 'S') | |
{ | |
alg = "SJF"; | |
} | |
else if (svalue[0] == 'L') | |
{ | |
alg = "LCFS"; | |
} | |
if (fopen(filename, "r") == NULL)printf("Failed to open input file!\n"); | |
if (fopen(rfilename, "r") == NULL)printf("Failed to open rand file!\n"); | |
else | |
{ | |
//open two files | |
rstream = fopen(filename, "r"); | |
randfile = fopen(rfilename, "r"); | |
//get the number of random numbers | |
fgets(rs_token, MAX, randfile); | |
r_size = atoi(strtok(rs_token, " \t\n")); | |
//main job | |
build_proclist(); | |
build_ready_queue(); | |
scheduler(); | |
print_sum(); | |
} | |
return 1; | |
} | |
void print_sum() | |
{ | |
int ftle=0; //Finishing time of the last event (i.e. the last process finished execution) | |
float c_utlz; //CPU utilization (i.e. percentage (0.0 – 100.0) of time at least one process is running | |
float i_utlz; //IO utilization (i.e. percentage (0.0 – 100.0) of time at least one process is performing IO | |
float atat; //Average turnaround time among processes | |
float acwt; //Average cpu waiting time among processes | |
float thruput; //Throughput of number processes per 100 time units | |
int tp1 = 0; | |
int tp2 = 0; | |
for (p_index = process_list.begin(); p_index != process_list.end(); p_index++) | |
{ | |
if (p_index->ft > ftle)ftle = p_index->ft; | |
} | |
io_spare_time += (ftle - io_spare_start); | |
c_utlz = ((float)(ftle - c_spare_time)) / ((float)ftle) * 100.00; | |
i_utlz = ((float)(ftle - io_spare_time)) / ((float)ftle) * 100.00; | |
for (p_index = process_list.begin(); p_index != process_list.end(); p_index++) | |
tp1 += p_index->tt; | |
atat = ((float)tp1) / ((float)(process_list.size())); | |
for (p_index = process_list.begin(); p_index != process_list.end(); p_index++) | |
tp2 += p_index->cw; | |
acwt = ((float)tp2) / ((float)(process_list.size())); | |
thruput = ((float)(process_list.size())) / ((float)ftle) * 100.00; | |
if (alg=="RR")cout << alg<<" "<< qtm << endl; | |
else cout << alg << endl; | |
for (p_index = process_list.begin(); p_index != process_list.end(); p_index++) | |
{ | |
printf("%04d: %4d %4d %4d %4d | %4d %4d %4d %4d\n", p_index->pid, p_index->at, p_index->tc, p_index->scb, p_index->sio, p_index->ft, p_index->tt, p_index->it, p_index->cw); | |
} | |
printf("SUM: %d %.2lf %.2lf %.2lf %.2lf %.3lf\n",ftle,c_utlz,i_utlz,atat,acwt,thruput); | |
} | |
void build_event(int timestamp, Process a, string from, string to) | |
{ | |
Event e(timestamp, a.pid, a.stcs, from, to, a.rt, a.io, a.cb); | |
for (evnt_index = evnt_list.begin(); evnt_index != evnt_list.end();evnt_index++) | |
{ | |
if ((evnt_index->timestamp) > e.timestamp)break; | |
else if ((evnt_index->timestamp) == e.timestamp) | |
{ | |
if (evnt_index->ts <= e.ts)continue; | |
else if (evnt_index->ts > e.ts)break; | |
} | |
} | |
//evnt_index--; | |
evnt_list.insert(evnt_index, e); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment