|
// CPU scheduling simulator - CS139 assignment 2 |
|
// Zed Chance |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
|
|
#include "simulator.h" |
|
|
|
// from assignment: assume the maximum queue length is 20. |
|
#define SIZE 20 |
|
|
|
// stats variables |
|
int pcount = 0; |
|
int time = 0; |
|
int idle_time = 0; |
|
int * pid_index; // array of pids, used for indexes for arrays below |
|
int * computational_time; // time on CPU |
|
int * response_time; // first wait time |
|
int * turnaround_time; // finish - arrival |
|
|
|
void print_stats() |
|
{ |
|
// cpu usage |
|
double avg_cpu = ((double)(time - idle_time) / time) * 100; |
|
|
|
// response time |
|
double avg_response = 0; |
|
for (int i = 0; i < pcount; i++) |
|
{ |
|
avg_response = avg_response + response_time[i]; |
|
} |
|
avg_response = avg_response / pcount; |
|
|
|
// turnaround time |
|
double avg_turnaround = 0; |
|
for (int i = 0; i < pcount; i++) |
|
{ |
|
avg_turnaround = avg_turnaround + turnaround_time[i]; |
|
} |
|
avg_turnaround = avg_turnaround / pcount; |
|
|
|
// wait time |
|
double avg_wait = 0; |
|
for (int i = 0; i < pcount; i++) |
|
{ |
|
avg_wait = avg_wait + (turnaround_time[i] - computational_time[i]); |
|
} |
|
avg_wait = avg_wait / pcount; |
|
|
|
printf("\n== STATS ===========================\n"); |
|
printf(" Average CPU usage : %6.2f %%\n", avg_cpu); |
|
printf(" Average wait time : %6.2f\n", avg_wait); |
|
printf(" Average response time : %6.2f\n", avg_response); |
|
printf(" Average turnaround time : %6.2f\n", avg_turnaround); |
|
printf("====================================\n\n"); |
|
} |
|
|
|
int get_index_of_pid(int pid) |
|
{ |
|
for (int i = 0; i < pcount; i++) |
|
{ |
|
if (pid_index[i] == pid) |
|
{ |
|
return i; |
|
} |
|
} |
|
return -1; |
|
} |
|
|
|
int sort_by_arrival_time(const void * a, const void * b) |
|
{ |
|
pcb * aa = (pcb *)a; |
|
pcb * bb = (pcb *)b; |
|
return aa->arrival - bb->arrival; |
|
} |
|
|
|
int sort_by_burst(const void * a, const void * b) |
|
{ |
|
pcb * aa = (pcb *)a; |
|
pcb * bb = (pcb *)b; |
|
return aa->burst - bb->burst; |
|
} |
|
|
|
// first come first served |
|
void fcfs(pcb * processes, int pcount) |
|
{ |
|
// sort by arrival time |
|
qsort(processes, pcount, sizeof(pcb), sort_by_arrival_time); |
|
|
|
// run in order |
|
int running = 0; |
|
int local_pcount = pcount; |
|
while(local_pcount--) |
|
{ |
|
// get current process |
|
pcb current = processes[running]; |
|
|
|
// wait until arrival |
|
while (current.arrival > time) |
|
{ |
|
printf("<system time %4d> CPU IS IDLE\n", time++); |
|
idle_time++; |
|
} |
|
|
|
// "run" process |
|
response_time[get_index_of_pid(current.pid)] = time - current.arrival; |
|
for (int i = 0; i < current.burst; i++) |
|
{ |
|
printf("<system time %4d> process %4d is running\n", time++, current.pid); |
|
computational_time[get_index_of_pid(current.pid)]++; |
|
} |
|
turnaround_time[get_index_of_pid(current.pid)] = time - current.arrival; |
|
printf("<system time %4d> process %4d is finished...\n", time, current.pid); |
|
running++; |
|
} |
|
printf("<system time %4d> all processes finished...\n", time); |
|
print_stats(); |
|
} |
|
|
|
// round robin |
|
void rr(pcb * processes, int pcount, int quantum) |
|
{ |
|
pcb * running = NULL; |
|
|
|
// loop thru time |
|
int runtime = 0; |
|
for (int total_process = pcount; ; time++) |
|
{ |
|
// check if new arrivals |
|
for (int i = 0; i < pcount; i++) |
|
{ |
|
if (time == processes[i].arrival) |
|
{ |
|
// add to queue |
|
push_tail(processes + i); |
|
} |
|
} |
|
|
|
// check if switching processes |
|
if (runtime <= 0) |
|
{ |
|
// currently running process goes to queue |
|
if (running != NULL) |
|
{ |
|
// push back on queue if remaining burst |
|
if (running->burst > 0) |
|
{ |
|
push_tail(running); |
|
} |
|
else |
|
{ |
|
printf("<system time %4d> process %4d is finished...\n", time, running->pid); |
|
total_process--; |
|
turnaround_time[get_index_of_pid(running->pid)] = time - running->arrival; |
|
|
|
// check if we're done |
|
if (total_process == 0) |
|
{ |
|
break; |
|
} |
|
} |
|
} |
|
|
|
// head of queue is new running process |
|
running = pop_head(); |
|
|
|
// determine runtime |
|
if (running == NULL) |
|
{ |
|
runtime = -1; |
|
} |
|
else |
|
{ |
|
// min(burst, quantum) |
|
runtime = (running->burst < quantum) ? running->burst : quantum; |
|
} |
|
} |
|
|
|
// "run" process |
|
if (runtime > 0) |
|
{ |
|
// run for 1 unit of burst |
|
printf("<system time %4d> process %4d is running\n", time, running->pid); |
|
running->burst--; |
|
runtime--; |
|
computational_time[get_index_of_pid(running->pid)]++; |
|
|
|
// calc response if first time running |
|
if (response_time[get_index_of_pid(running->pid)] == -1) |
|
{ |
|
response_time[get_index_of_pid(running->pid)] = time - running->arrival; |
|
} |
|
} |
|
else if (runtime == -1) |
|
{ |
|
printf("<system time %4d> CPU IS IDLE\n", time); |
|
idle_time++; |
|
} |
|
} |
|
printf("<system time %4d> all processes finished...\n", time); |
|
print_stats(); |
|
} |
|
|
|
// shortest run time first |
|
void srtf(pcb * processes, int pcount) |
|
{ |
|
pcb * queue = malloc(sizeof(pcb) * SIZE); |
|
int qcount = 0; |
|
|
|
// loop thru time |
|
int currently_running = 0; |
|
for (int total_process = pcount; ; time++) |
|
{ |
|
// check if new arrivals |
|
for (int i = 0; i < pcount; i++) |
|
{ |
|
if (time == processes[i].arrival) |
|
{ |
|
queue[qcount++] = processes[i]; |
|
} |
|
} |
|
|
|
// sort by burst time |
|
qsort(queue, qcount, sizeof(pcb), sort_by_burst); |
|
|
|
// "run" process |
|
pcb * running = queue + currently_running; |
|
if (running->burst == 0 && qcount > currently_running) |
|
{ |
|
printf("<system time %4d> process %4d is finished...\n", time, running->pid); |
|
total_process--; |
|
turnaround_time[currently_running] = time - running->arrival; |
|
|
|
// check if we're done |
|
if (total_process == 0) |
|
{ |
|
break; |
|
} |
|
else |
|
{ |
|
// bump to next process |
|
running = queue + ++currently_running; |
|
} |
|
} |
|
if (total_process > 0 && running->burst > 0) |
|
{ |
|
printf("<system time %4d> process %4d is running\n", time, running->pid); |
|
running->burst--; |
|
computational_time[currently_running]++; |
|
|
|
// calc response if first time running |
|
if (response_time[get_index_of_pid(running->pid)] == -1) |
|
{ |
|
response_time[get_index_of_pid(running->pid)] = time - running->arrival; |
|
} |
|
} |
|
else if (currently_running >= qcount) |
|
{ |
|
printf("<system time %4d> CPU IS IDLE\n", time); |
|
idle_time++; |
|
} |
|
} |
|
printf("<system time %4d> all processes finished...\n", time); |
|
print_stats(); |
|
|
|
free(queue); |
|
} |
|
|
|
int main(int argc, char ** argv) |
|
{ |
|
// check args |
|
if (argc < 3) |
|
{ |
|
fprintf(stderr, "Not enough arguments\n"); |
|
fprintf(stderr, "Usage: %s input_file FCFS|RR|SRTF [time quantum]\n", argv[0]); |
|
exit(1); |
|
} |
|
|
|
// open input file |
|
FILE * input = fopen(argv[1], "r"); |
|
if (!input) |
|
{ |
|
fprintf(stderr, "Can't open %s for reading.\n", argv[1]); |
|
exit(1); |
|
} |
|
|
|
// read into processes array |
|
pcb * processes = malloc(sizeof(pcb) * SIZE); |
|
pid_index = malloc(sizeof(int) * SIZE); |
|
char line[1000]; |
|
while (fgets(line, 1000, input) != NULL) |
|
{ |
|
int p, a, b; |
|
sscanf(line, "%d %d %d", &p, &a, &b); |
|
processes[pcount].pid = p; |
|
processes[pcount].arrival = a; |
|
processes[pcount].burst = b; |
|
pid_index[pcount] = p; |
|
pcount++; |
|
} |
|
printf("Total %d tasks are read from %s\n", pcount, argv[1]); |
|
fclose(input); |
|
|
|
// allocate stat variables |
|
computational_time = malloc(sizeof(int) * SIZE); |
|
response_time = malloc(sizeof(int) * SIZE); |
|
turnaround_time = malloc(sizeof(int) * SIZE); |
|
for (int i = 0; i < pcount; i++) |
|
{ |
|
// -1 indicates process has not yet been responded to |
|
response_time[i] = -1; |
|
} |
|
|
|
// get schedule mode, and call sim function |
|
if (strcmp(argv[2], "FCFS") == 0) |
|
{ |
|
printf("Scheduling algorithm: FCFS.\n"); |
|
fcfs(processes, pcount); |
|
} |
|
else if (strcmp(argv[2], "RR") == 0) |
|
{ |
|
// get quantum |
|
if (argc < 4) |
|
{ |
|
fprintf(stderr, "Not enough arguments, missing time quantum\n"); |
|
fprintf(stderr, "Usage: %s input_file RR time_quantum\n", argv[0]); |
|
exit(1); |
|
} |
|
int quantum = 0; |
|
sscanf(argv[3], "%d", &quantum); |
|
|
|
printf("Scheduling algorithm: RR with quantum = %d.\n", quantum); |
|
rr(processes, pcount, quantum); |
|
} |
|
else if (strcmp(argv[2], "SRTF") == 0) |
|
{ |
|
printf("Scheduling algorithm: SRTF.\n"); |
|
srtf(processes, pcount); |
|
} |
|
else |
|
{ |
|
printf("I don't know the '%s' scheduling algorithm.\n", argv[2]); |
|
} |
|
|
|
free(processes); |
|
free(pid_index); |
|
free(computational_time); |
|
free(response_time); |
|
free(turnaround_time); |
|
} |
input.1
output for all 3 scheduling algorithms:input.2
output for all 3 scheduling algorithms:input.3
output for all 3 scheduling algorithms: