Created
December 8, 2017 04:51
-
-
Save SibTiger/6504a69e9add924df974a9958de0d246 to your computer and use it in GitHub Desktop.
Operating Systems: CPU Schedulers [First Come First Serve, Shortest Job First, Priority, and Round Robin Quantum 4 and Quantum 8]
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
// ===================================================== | |
// Programmer: Nicholas Gautier | |
// Class: CS3513; Operating System | |
// Assignment #: 4 | |
// Due Date: 21. November. 2017 | |
// Instructor: Dr. Zhao | |
// Description: This program is designed simulate certain CPU Schedulers. | |
// Within the program, the processes generated will be in | |
// a 'Process Chain' and from there, the processes will be | |
// initialized with a Process struct. This will provide | |
// the processor with unique properties and data. | |
// Each process within the Chain will be processed and | |
// 'executed' by means of the CPU Schedulers, the schedulers | |
// report the Average Waiting Time and Average Turn around Time | |
// after finishing the initial execution. | |
// ---- | |
// CRITICAL NOTE: | |
// In this program, we will use a 'long double' to store and calculate | |
// average times. This is done to assure: finer accuracy and | |
// prevent overflow values. | |
// ---- | |
// OUTPUT FILE: | |
// This program will output the results to a file and store | |
// the file to the host system's secondary storage file-system. | |
// | |
// Supported Schedulers: | |
// 1) First Come First Serve Scheduler | |
// Calculate and execute the data that arrives first | |
// 2) Shortest Job First Scheduler | |
// Calculate and execute the data that is the shortest first | |
// 3) Round Robin Scheduler | |
// Calculate and execute the data in an equal amount of bursts | |
// 4) Priority Scheduler | |
// Calculate and execute the data that has higher priority over others. | |
// NOTES: Pointers, Pointers Everywhere! { https://i.imgur.com/u44xRM9.png } | |
// Credits: | |
// Return Codes: | |
// 0 = Successful Operation | |
// 1 = Logging is enabled but unable to open the output file; error-close | |
// 2 = Heap memory allocation failure [Primary && Slaved process chain] | |
// ===================================================== | |
#pragma region Inclusions | |
#include <fcntl.h> // File Control | |
#include <stdio.h> // Basic input and output | |
#include <stdbool.h> // Because I was spoiled in C[++ | #]; give me bool data types! | |
#include <ctype.h> // Used for tolower() function for strings | |
#include <stddef.h> // NULLPTR; used for pointers | |
#include <stdlib.h> // Pointer Memory allocation | |
#include <time.h> // Used for the seed which is used for the rand() function | |
#pragma endregion | |
#pragma region Structs | |
// Individual Process Data | |
struct Process | |
{ | |
// Information about the process | |
int pid; // Process ID | |
int incomingArrival;// Arrival time of the process; this should be default to 0. | |
int burstCPU; // Data within the process; simulation purposes only | |
int timeRemaining; // How much data is remaining | |
int priority; // Priority level of the individual process | |
}; | |
// Calculation for Process Chain | |
struct ProcessChainCalculation | |
{ | |
long double averageWaitingTime; // Average Waiting Time | |
long double averageTurnTime; // Average Turn around Time | |
}; | |
#pragma endregion | |
#pragma region Function Prototypes | |
void DrawHeader(); // Display the program header | |
void DrawInstructions(); // Display the instructions to the user | |
void DrawAbout(); // Display what the program is about to the user. | |
int FetchNumber(); // Retrieve how many processes the user wants | |
char RunAgainQuestion(); // Ask the user if they want to exit the program | |
void CloseProgram(); // Protocols for closing the program; if any | |
void AllocateMemory_Process(struct Process**, int); // Allocate the memory space required for each process within the process chain (pointers) | |
void DeallocateMemory_Process(struct Process**); // Thrash the memory space that was utilizes by the process chain (pointers) | |
void PopulateProcessChain(struct Process*, int); // Used to automatically populate the process chain | |
void DisplayProcessChain(struct Process*, int, FILE*); // Display the entire process chain's processes. | |
void SortProcessChain(struct Process*, int); // Sort the process chain's process by data size. | |
void SortProcessPriority(struct Process*, int); // Sort the processes by priority; critical (or runtime) to idle | |
void SwapProcess(struct Process*, int, int); // Swap processes from one location to another | |
void MirrorProcessChain(struct Process*, struct Process*, int); // Copy one process chain to another. | |
void OverAllAverageCalculation(struct ProcessChainCalculation*, int, FILE*); // This function will compute the average overall wait and turnaround time. | |
void DeallocateMemory_ProcessChainCalculation(struct ProcessChainCalculation**); // Thrash the memory space used from the computations | |
void AllocateMemory_ProcessChainCalculation(struct ProcessChainCalculation**, int); // Allocate the memory space required for process computation | |
// ---- | |
void SchedulerFirstComeFirstServe(struct Process*, int, struct ProcessChainCalculation*, int, FILE*); // This function will perform the 'FCFS' scheduler | |
void SchedulerShortestJobFirst(struct Process*, int, struct ProcessChainCalculation*, int, FILE*); // This function will perform the 'SJF' scheduler | |
void SchedulerPriority(struct Process*, int, struct ProcessChainCalculation*, int, FILE*); // This function will perform the 'Priority' scheduler | |
void SchedulerRoundRobin(struct Process*, int, struct ProcessChainCalculation*, int, int, FILE*); // This function will perform the 'RR' scheduler | |
#pragma endregion | |
#pragma region Global Definitions | |
#define _NAME_ "The UltraMega CPU Scheduler" // Name of this program | |
#define _VERSION_ "1.0" // Version of this program | |
#define _VERSION_NAME_ "Pointeramaina!" // Because this program is loaded with pointers, | |
// like every time I look - there is a pointer in | |
// my FREAKIN' POINTER WHICH IN ITSELF IS POINTING | |
// TO ANOTHER POINTER! Holy crap, make the horror stop! | |
// Might as well add this: | |
// http://s2.quickmeme.com/img/58/58fe6b229144b7fe5ebe88afe9ff5cabe2dd0863e1e79b2d02b4103c30b465dd.jpg | |
#define _MAX_USER_INPUT_LENGTH_ 1000 // How many characters to expect from end-user | |
#define _MINIMUM_PROCESSES_ 100 // Minimum processes we can have within a Process Chain [default is: 100; debug: 3] | |
#define _MAXIMUM_PROCESSES_ 9000 // Maximum processes that we can have within a Process Chain. Without this, the results | |
// may be inaccurate due to overflowed values. | |
#define _MINIMUM_CPUBURST_ 3 // Minimum CPU Burst possible | |
#define _MAXIMUM_CPUBURST_ 20 // Maximum CPU Burst possible [default is: 20; Fear-Factor: RAND_MAX] | |
#define _CPU_PROCESS_EMULATION_ true // When true, this will loosely emulate CPU processing of a process within the Process Chain. | |
#define _MAXIMUM_PRIORITY_LEVEL_ 7 // Maximum Priority level | |
#define _LOOP_COUNT_ 100 // Loop through each scheduler [default is: 100] | |
#define _DEBUG_PROCCHAIN_ false // Output process chain's individual processes [default is: false] | |
// NOTE: Turning this to 'true' will cause a serious performance degrade as it takes | |
// a lot of resources to push output to the screen as quickly as it can. | |
#define _DEBUG_CALC_ false // Output calculations, such as AWT && ATT or deeper information. [default is: false] | |
#define _DEBUG_STEPWISE_ false // Output what the program is doing in each step. [default is: false] | |
// will take more time then the normal operations. Enable | |
// this if the output is necessary; do note that large outputs | |
// can take a lot of time to render on the terminal buffer. | |
#define _OUTPUT_FILE_FLAG_ true // Output data to a file? [default is: true] | |
#define _OUTPUT_FILE_NAME_ "SimulatorResults" // Output filename | |
#define _OUTPUT_FILE_EXT_ "log" // Output file extension | |
#pragma endregion | |
// Main | |
// ==================================== | |
// Main program entry point and the spin of the entire program. | |
int main() | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int numberProcess; // How many processes does the user want | |
char userChoice = 'n'; // This will be used to determine if the | |
// user wants to evaluate more processes. | |
int i = 0; // For-loop, because I can not use this directly in a for-loop. | |
struct Process *mainProcessChain; // Main process chain array | |
struct Process *slaveProcessChain; // Secondary process chain array that will be used for altering within the schedulers. | |
bool firstRun = true; // Allows specific instructions to execute (or not) if the program just started. | |
FILE * fileOutput; // This will retain the output file that will be used to log all of the output that is | |
// produced in this program. This will be used when '_OUTPUT_FILE_FLAG_' is true. | |
char fileNameString[255]; // This is terrible hard-limit, but using strlen() (even with const flag) caused all sorts of troubles. | |
// So, instead, we will just use the basic filesystem NTFS (Windows 2000 and later) limit of 256bytes. | |
// There IS a better way to do this, but due to time constraints - we will leave this here for now. | |
// -------------------------------- | |
srand((unsigned int)time(NULL)); // Initialize random seed - pure randomness! | |
// This will be used for populating process information | |
// Setup the File Output | |
// ---- | |
snprintf(fileNameString, sizeof(fileNameString), | |
"%s.%s", _OUTPUT_FILE_NAME_, _OUTPUT_FILE_EXT_); // Setup the filename | |
fileOutput = fopen(fileNameString, "a"); // Initialize the output file | |
// Check to see if the file opened successfully | |
if (fileOutput == NULL) | |
printf("<!> ERROR <!>\n=============================\nUnable to open file!\n\n"); // Tell the user that there was an issue opening the file | |
if (fileOutput == NULL && _OUTPUT_FILE_FLAG_) | |
return 1; // Because this code is not strictly refined well to handle these cases, close the program with this error code. | |
// ---- | |
// Perform the main program loop | |
do { | |
if (!firstRun) | |
printf("\n\n\n\n"); // Provide some extra padding before | |
// displaying any new information on the | |
// terminal buffer. | |
// Initial Run | |
DrawHeader(); // Display the program header | |
DrawAbout(); // Display the program's about | |
DrawInstructions(); // Display the instructions | |
// How many processes should be created within the chain? | |
do { | |
printf("How many processes would you like to generate?\n"); | |
numberProcess = FetchNumber(); // How many processes does the user want | |
// Check to see if the input was valid; if not - warn the user. | |
if (!(numberProcess >= _MINIMUM_PROCESSES_ && numberProcess <= _MAXIMUM_PROCESSES_)) | |
{ | |
printf("Invalid number of process range.\nMinimum Processes Possible: %d\nMaximum Processes Possible: %d\n", _MINIMUM_PROCESSES_, _MAXIMUM_PROCESSES_); | |
printf("\n\n"); | |
numberProcess = 0; | |
} // | |
} while (!(numberProcess >= _MINIMUM_PROCESSES_ && numberProcess <= _MAXIMUM_PROCESSES_));// Make sure that the input fits the range, if not - ask again. | |
// ---- | |
// If logging is enable, log the size of processes that was requested in this job. | |
if (_OUTPUT_FILE_FLAG_) | |
{ | |
fprintf(fileOutput, "Number of Processes Requested to Generate: %d\n", numberProcess); | |
fprintf(fileOutput, "================================================\n"); | |
fprintf(fileOutput, "================================================\n\n\n"); | |
} // IF : Logging | |
// ---- | |
// Initialize the necessary process chains within the memory heap space for the Primary Process Chain | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Initialization of Process Chain with [ %d ] Processes. . .\n", numberProcess); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Initialization of Process Chain with[%d] Processes. . .\n", numberProcess); | |
} // IF: STEPWISE DEBUGGING | |
AllocateMemory_Process(&mainProcessChain, numberProcess); // Setup the primary process chain | |
// ---- | |
// Initialize the necessary process chains within the memory heap space for the Slaved Process Chain | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Initialization of Slaved Process Chain with [ %d ] Processes. . .\n", numberProcess); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Initialization of Slaved Process Chain with [ %d ] Processes. . .\n", numberProcess); | |
} // IF: STEPWISE DEBUGGING | |
AllocateMemory_Process(&slaveProcessChain, numberProcess); // Setup the slaved process chain | |
// ---- | |
// Did the allocation for Primary and Slaved Process Chain fail? | |
if (mainProcessChain == NULL || slaveProcessChain == NULL) | |
{ | |
printf("<!> ERROR <!>\n=============================\nUnable to allocate sufficient heap memory for Process Chain!\n\n"); | |
return 2; // Close the program due to allocation fault | |
} // IF: Failure to allocate process chain | |
// ---- | |
// Setup the Process Chain Calculations | |
// Yes, this is sloppy and there IS a better way to do this, | |
// but I can't think of any right now - so lets make our ears | |
// bleed with rock music and lets make things messy! | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Creating new instances of the process calculations. . .\n"); | |
// Output to the file, if required | |
if(_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Creating new instances of the process calculations. . .\n"); | |
} // IF: STEPWISE DEBUGGING | |
struct ProcessChainCalculation *calcFCFS; // FCFS | |
struct ProcessChainCalculation *calcSJF; // SJF | |
struct ProcessChainCalculation *calcPriority; // Priority | |
struct ProcessChainCalculation *calcRR4; // Round Robin:4 | |
struct ProcessChainCalculation *calcRR8; // Round Robin:8 | |
// ---- | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Initializing process calculation memory space. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Initializing process calculation memory space. . .\n"); | |
} // IF: STEPWISE DEBUGGING | |
AllocateMemory_ProcessChainCalculation(&calcFCFS, _LOOP_COUNT_); // Allocate to the maximum times we are going to loop through | |
AllocateMemory_ProcessChainCalculation(&calcSJF, _LOOP_COUNT_); // These pointers will be necessary later when we present | |
AllocateMemory_ProcessChainCalculation(&calcPriority, _LOOP_COUNT_); // each pass and overall results to the end-user on screen | |
AllocateMemory_ProcessChainCalculation(&calcRR4, _LOOP_COUNT_); // and in a file. | |
AllocateMemory_ProcessChainCalculation(&calcRR8, _LOOP_COUNT_); | |
// ---- | |
// The main loop | |
for (i = 0; i < _LOOP_COUNT_; ++i) | |
{ | |
// ****************************************************** | |
// THE NECESSARY SETUP | |
// ****************************************************** | |
// Setup the necessary data required for the primary process chain | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Populating Process Chain's individual processes with data. . .\n"); | |
// Output to the file, if required | |
if(_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Populating Process Chain's individual processes with data. . .\n"); | |
} // IF: STEPWISE DEBUGGING | |
PopulateProcessChain(mainProcessChain, numberProcess); | |
// ---- | |
// Mirror the Process Chains | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
} // IF: STEPWISE DEBUGGING | |
MirrorProcessChain(mainProcessChain, slaveProcessChain, numberProcess); | |
// ---- | |
// Display all of the processes within the Process Chain | |
if (_DEBUG_PROCCHAIN_) | |
DisplayProcessChain(mainProcessChain, numberProcess, fileOutput); | |
// ****************************************************** | |
// CPU SCHEDULERS | |
// ****************************************************** | |
// First Come, First Serve | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Executing CPU Scheduler: First Come, First Serve. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Executing CPU Scheduler: First Come, First Serve. . .\n"); | |
} // IF: STEPWISE | |
SchedulerFirstComeFirstServe(slaveProcessChain, numberProcess, calcFCFS, i, fileOutput); | |
// ---- | |
// Mirror the Process Chains; Only in-case if the previous scheduler altered with the Process Chain | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
} // IF: STEPWISE | |
MirrorProcessChain(mainProcessChain, slaveProcessChain, numberProcess); | |
// ==================================== | |
// ==================================== | |
// ==================================== | |
// Shortest Job First | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Executing CPU Scheduler: Shortest Job First. . .\n"); | |
// Output to the fike, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Executing CPU Scheduler: Shortest Job First. . .\n"); | |
} // IF: STEPWISE | |
SchedulerShortestJobFirst(slaveProcessChain, numberProcess, calcSJF, i, fileOutput); | |
// ---- | |
// Mirror the Process Chains; Only in-case if the previous scheduler altered with the Process Chain | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
} // IF: STEPWISE | |
MirrorProcessChain(mainProcessChain, slaveProcessChain, numberProcess); | |
// ==================================== | |
// ==================================== | |
// ==================================== | |
// Priority | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Executing CPU Scheduler: Priority. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Executing CPU Scheduler: Priority. . .\n"); | |
} // IF: STEPWISE | |
SchedulerPriority(slaveProcessChain, numberProcess, calcPriority, i, fileOutput); | |
// ---- | |
// Mirror the Process Chains; Only in-case if the previous scheduler altered with the Process Chain | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
} // IF: STEPWISE | |
MirrorProcessChain(mainProcessChain, slaveProcessChain, numberProcess); | |
// ==================================== | |
// ==================================== | |
// ==================================== | |
// Round Robin [Quantum: 4] | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Executing CPU Scheduler: Round Robin [CPU Quantum Level: 4]. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Executing CPU Scheduler: Round Robin [CPU Quantum Level: 4]. . .\n"); | |
} // IF: STEPWISE | |
SchedulerRoundRobin(slaveProcessChain, numberProcess, calcRR4, i, 4, fileOutput); | |
// ---- | |
// Mirror the Process Chains; Only in-case if the previous scheduler altered with the Process Chain | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Mirroring Slave Process Chain to reflect from the Primary Process Chain. . .\n"); | |
} // IF: STEPWISE | |
MirrorProcessChain(mainProcessChain, slaveProcessChain, numberProcess); | |
// ==================================== | |
// ==================================== | |
// ==================================== | |
// Round Robin [Quantum: 8] | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Executing CPU Scheduler: [CPU Quantum Level: 8]. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Executing CPU Scheduler: [CPU Quantum Level: 8]. . .\n"); | |
} // IF: STEPWISE | |
SchedulerRoundRobin(slaveProcessChain, numberProcess, calcRR8, i, 8, fileOutput); | |
} // For-loop | |
// Calculate the overall average wait time and turn around time | |
printf("First Come, First Serve\n"); // Overall: First Come, First Serve [FIFO] | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "First Come, First Serve\n"); | |
OverAllAverageCalculation(calcFCFS, _LOOP_COUNT_, fileOutput); | |
// ---- | |
printf("Shortest Job First\n"); // Overall: Shortest Job First | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Shortest Job First\n"); | |
OverAllAverageCalculation(calcSJF, _LOOP_COUNT_, fileOutput); | |
// ---- | |
printf("Priority\n"); // Overall: Priority | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Priority\n"); | |
OverAllAverageCalculation(calcPriority, _LOOP_COUNT_, fileOutput); | |
// ---- | |
printf("Round Robin: 4\n"); // Overall: Round Robin [Quantum: 4] | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Round Robin: 4\n"); | |
OverAllAverageCalculation(calcRR4, _LOOP_COUNT_, fileOutput); | |
// ---- | |
printf("Round Robin: 8\n"); // Overall: Round Robin [Quantum: 8] | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Round Robin: 8\n"); | |
OverAllAverageCalculation(calcRR8, _LOOP_COUNT_, fileOutput); | |
// ---- | |
// Thrash the process chain; clean slate | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Thrashing the Primary Process Chain. . .\n"); | |
// Output to the file, if required | |
if(_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Thrashing the Primary Process Chain. . .\n"); | |
} // IF: STEPWISE | |
DeallocateMemory_Process(&mainProcessChain); | |
// ---- | |
// Thrash the slaved process chain; clean slate | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Thrashing the Slaved Process Chain. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Thrashing the Slaved Process Chain. . .\n"); | |
} // IF: STEPWISE | |
DeallocateMemory_Process(&slaveProcessChain); | |
// ---- | |
// Thrash all of the process calculations | |
if (_DEBUG_STEPWISE_) | |
{ | |
// Output to the STDOUT | |
printf("Thrashing the Process Calculations. . .\n"); | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "Thrashing the Process Calculations. . .\n"); | |
} // IF: STEPWISE | |
DeallocateMemory_ProcessChainCalculation(&calcFCFS); | |
DeallocateMemory_ProcessChainCalculation(&calcSJF); | |
DeallocateMemory_ProcessChainCalculation(&calcPriority); | |
DeallocateMemory_ProcessChainCalculation(&calcRR4); | |
DeallocateMemory_ProcessChainCalculation(&calcRR8); | |
// ---- | |
// Were we running this program for the first time? | |
if (firstRun) | |
// We are no longer running the program for the first time | |
firstRun = !firstRun; // Merely flip the bit | |
// ---- | |
// Make a notification sound to notify the user that the operation finished | |
printf("\a"); | |
// ---- | |
// Run again? | |
userChoice = RunAgainQuestion(); | |
} while (tolower(userChoice) == 'y'); | |
// Terminating Protocols | |
CloseProgram(); // Tell the user that the program is terminating | |
fclose(fileOutput); // Close the output file | |
// Terminate the program | |
return 0; | |
} // main() | |
// Closing Program | |
// ==================================== | |
// This function will perform any protocols before the program's instance | |
// is destroyed. | |
void CloseProgram() | |
{ | |
printf("Closing program...\n\n\n"); | |
} // CloseProgram() | |
// Draw Header | |
// ==================================== | |
// This function is designed to provide a header to the top-most space on the terminal buffer. | |
void DrawHeader() | |
{ | |
printf("%s - Version: %s\n", _NAME_, _VERSION_); | |
printf("%s\n", _VERSION_NAME_); | |
printf("--------------------------------------------\n\n"); | |
} // DrawHeader() | |
// Draw Instructions() | |
// ==================================== | |
// This function will provide instructions to the end-user, along with how | |
// this program works. | |
void DrawInstructions() | |
{ | |
printf("Instructions\n"); | |
printf("----------------\n"); | |
printf("Enter in how many 'simulated' processes you want this program to execute.\n"); | |
printf("For faster performance, use the minimal amount of processes possible. The more processes used, the longer it could take to complete the execution of said processes.\n"); | |
printf("======================================\n"); | |
printf("\n\n"); | |
} // DrawInstructions() | |
// Draw About | |
// ==================================== | |
// This function is merely designed to display what this program is about and its primary purpose. | |
void DrawAbout() | |
{ | |
printf("This program is designed to simulate some well-known CPU Schedulers and to evaluate which algorithm performs faster. In order to evaluate, this program will run as many as %d processes or more, depending on the user request.\n\n", _MINIMUM_PROCESSES_); | |
} // DrawAbout() | |
// Fetch Number | |
// ==================================== | |
// This function will retrieve a number from the end-user and send it back to the calling function. | |
// NOTE: This function uses scanf; if '0' is returned - then '0' will be used, even if it was | |
// accidental by the user. For instance, instead of a number the user inputs a char, from there | |
// scanf() will use '0'. | |
// ---- | |
// Output: | |
// int | |
// Provides any number to the calling function. | |
int FetchNumber() | |
{ | |
// Declaration and Initializations | |
// -------------------------------- | |
char sizeChoiceRaw[_MAX_USER_INPUT_LENGTH_]; // This will be used to capture user input - unfiltered. | |
int filteredInput; // This variable will hold the user's size choice - filtered. | |
// -------------------------------- | |
// Capture the input from the end-user | |
printf(">>>>>> "); | |
fgets(sizeChoiceRaw, sizeof(sizeChoiceRaw), stdin); // Fetch the input | |
sscanf(sizeChoiceRaw, "%d", &filteredInput); // Filter the input | |
// If non-int values exists, then this will return '0' | |
// or 'EOL'. If a number is given before non-int's, | |
// this a number will be captured - anything after will | |
// be dropped. | |
// Example: 83y2 | |
// Saved: 83 | |
// Dropped: y2 | |
return (int)filteredInput; // Casting for assurance sakes | |
} // FetchNumber() | |
// Run Again Question | |
// ==================================== | |
// This function is dedicated into asking the end-user if they want | |
// to terminate the program or run again. | |
// ---- | |
// Output: | |
// char | |
// Returns only 'one' character of any value directly from the user. | |
char RunAgainQuestion() | |
{ | |
// Declaration and Initializations | |
// ------------------------ | |
char choice; // Used for capturing STDIN from the end-user [keyboard] | |
bool badInput = true; // Make sure that the input is valid | |
// ------------------------ | |
do | |
{ | |
printf("Evaluate another series of processes?\n"); | |
printf("\t[Y]es OR [N]o\n"); | |
printf(">>>>>> "); | |
choice = getchar(); | |
getchar(); // Get rid of the 'enter key ghosting'. | |
// Because the enter key is STILL in STDIN. | |
if ((tolower(choice) != 'y') && (tolower(choice) != 'n')) | |
// Bad input | |
printf("Input of [ %c ] was invalid!\n\n", choice); | |
else | |
// Valid input | |
badInput = false; | |
} while (badInput); | |
return choice; | |
} // RunAgainQuestion() | |
// Allocate Memory (Pointers) [STRUCT: Process] | |
// ==================================== | |
// This function will allocate the memory locations necessary for the requested processes. | |
// ---- | |
// Parameters: | |
// processChain [struct Process**] | |
// The series of processes in which is going to be allocated | |
// processCount [int] | |
// How many processes are requested | |
void AllocateMemory_Process(struct Process** processChain, int processCount) | |
{ | |
// Initialization and Declarations | |
// ------------------------ | |
int i = 0; // Utilized for the 'for' loop; as we can not declare within the for-loop. | |
// ------------------------ | |
// Setup the memory space | |
*processChain = (struct Process *) malloc(processCount * sizeof(struct Process)); | |
} // AllocateMemory_Process() | |
// Allocate Memory (Pointers) [Struct ProcessChainCalculation] | |
// ==================================== | |
// This function will allocate the memory locations necessary for the requested process calculations. | |
// ---- | |
// Parameters: | |
// processChain [struct ProcessChainCalculation**] | |
// The series of process calculations in which is going to be allocated | |
// processCount [int] | |
// How many calculations that will be performed | |
void AllocateMemory_ProcessChainCalculation(struct ProcessChainCalculation** processChain, int processCount) | |
{ | |
// Initialization and Declarations | |
// ------------------------ | |
int i = 0; // Utilized for the 'for' loop; as we can not declare within the for-loop. | |
// ------------------------ | |
// Setup the memory space | |
*processChain = (struct ProcessChainCalculation *) malloc(processCount * sizeof(struct ProcessChainCalculation)); | |
} // AllocateMemory_ProcessChainCalculation() | |
// Deallocate Memory (Pointers) [Struct Process] | |
// ==================================== | |
// This function is designed to thrash the memory locations | |
// previously initialized within the pointer array of the process chain. | |
// ---- | |
// Parameters: | |
// processChain [struct Process**] | |
// The series of processes in which is going to be deallocated | |
void DeallocateMemory_Process(struct Process** processChain) | |
{ | |
// Deallocate the memory space | |
free(*processChain); | |
// Set the primary instance to NULL | |
processChain = NULL; | |
} // DeallocateMemory_Process() | |
// Deallocate Memory (Pointers) [Struct ProcessChainCalculation] | |
// ==================================== | |
// This function is designed to thrash the memory locations | |
// previously initialized within the pointer array of the process calculations. | |
// ---- | |
// Parameters: | |
// processChain [struct ProcessChainCalculation**] | |
// The series of process calculations in which is going to be deallocated | |
void DeallocateMemory_ProcessChainCalculation(struct ProcessChainCalculation** processChain) | |
{ | |
// Deallocate the memory space | |
free(*processChain); | |
// Set the primary instance to NULL | |
processChain = NULL; | |
} // DeallocateMemory_ProcessChainCalculation() | |
// Populate Process Chain | |
// ==================================== | |
// This function will populate the entire process chain with the necessary data required for the CPU Scheduler | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// This will be the process chain that will be populated with the necessary data. | |
// numberProcess [int] | |
// How many processes are within the process chain | |
void PopulateProcessChain(struct Process *processChain, int numberProcess) | |
{ | |
// Declaration and Initializations | |
// ------------------------ | |
int i = 0; // Used for the for-loop | |
// ------------------------ | |
// Automatically populate the process chain | |
for (i = 0; i < numberProcess; i++) | |
{ | |
processChain[i].pid = i; // Process ID | |
processChain[i].incomingArrival = 0; // Arrival time; default is '0'. | |
processChain[i].timeRemaining = 0; // Time remaining; used for Round Robin. | |
processChain[i].burstCPU = _MINIMUM_CPUBURST_ + (rand() % _MAXIMUM_CPUBURST_);// Data to be calculate | |
processChain[i].priority = rand() % _MAXIMUM_PRIORITY_LEVEL_; // Priority level | |
} // for; scan entire process-chain | |
} // PopulateProcessChain() | |
// Display Process Chain | |
// ==================================== | |
// This function will display all of the processes within the process chain. | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// The process chain processes that will be displayed | |
// numberProcess [int] | |
// How many processes exists within the process chain | |
// fileOutput [FILE*] | |
// File in which is to log events | |
void DisplayProcessChain(struct Process* processChain, int numberProcess, FILE* fileOutput) | |
{ | |
// Declaration and Initializations | |
// ------------------------ | |
int i = 0; // Used for the for-loop | |
// ------------------------ | |
// Automatically populate the process chain | |
for (i = 0; i < numberProcess; i++) | |
{ | |
// Output to the STDOUT | |
printf("Process ID: %d\n", processChain[i].pid); | |
printf("Process Arrival Time: %d\n", processChain[i].incomingArrival); | |
printf("Process Time Remaining: %d\n", processChain[i].timeRemaining); | |
printf("CPU Burst: %d\n", processChain[i].burstCPU); | |
printf("Process Priority: %d\n", processChain[i].priority); | |
printf("\n\n\n"); | |
// ---- | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
{ | |
fprintf(fileOutput, "Process ID: %d\n", processChain[i].pid); | |
fprintf(fileOutput, "Process Arrival Time: %d\n", processChain[i].incomingArrival); | |
fprintf(fileOutput, "Process Time Remaining: %d\n", processChain[i].timeRemaining); | |
fprintf(fileOutput, "CPU Burst: %d\n", processChain[i].burstCPU); | |
fprintf(fileOutput, "Process Priority: %d\n", processChain[i].priority); | |
fprintf(fileOutput, "\n\n\n"); | |
} // IF: Logging is True | |
} // for; scan entire process-chain | |
} // DisplayProcessChain() | |
// Mirror Process Chain | |
// ==================================== | |
// This function will duplicate one process chain to another. This will be necessary for some CPU Schedulers that will alter processes positions. | |
// For example, array[3] will be relocated to array[8] and vice-versa. | |
// ---- | |
// Parameters: | |
// sourceProcessChain [struct Process*] | |
// The process chain that contains already populated data | |
// targetProcessChain [struct Process*] | |
// The process chain that is going to be populated by the source. | |
// Meaning, that this process chain will mirror all data given by the source. | |
// numberProcess [int] | |
// How many processes exists within the process chain | |
void MirrorProcessChain(struct Process *sourceProcessChain, struct Process *targetProcessChain, int numberProcess) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int i = 0; // For-loop | |
// -------------------------------- | |
for (i = 0; i < numberProcess; i++) | |
{ | |
targetProcessChain[i].pid = sourceProcessChain[i].pid; | |
targetProcessChain[i].incomingArrival = sourceProcessChain[i].incomingArrival; | |
targetProcessChain[i].timeRemaining = sourceProcessChain[i].timeRemaining; | |
targetProcessChain[i].burstCPU = sourceProcessChain[i].burstCPU; | |
targetProcessChain[i].priority = sourceProcessChain[i].priority; | |
} // for; mirroring | |
} // MirrorProcessChain() | |
// Sort Process Chain | |
// ==================================== | |
// This function will sort the requested process chain by how big the data is within each individual process. | |
// We will use the Bubble Sort Algorithm to perform the sorting. This function will have a dependency with | |
// another function named 'SwapProcess()', which is detected to swapping indexes suitable for the Process struct. | |
// NOTE: Bubble Sort Algorithm | |
// DEPENDENCY: SwapProcess() | |
// Default sorting: Lowest -> Highest | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// The process chain that is to be sorted | |
// numberProcess [int] | |
// How many processes exists within the process chain. | |
void SortProcessChain(struct Process *processChain, int numberProcess) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int i = 0; // For-outer loop | |
int j = 0; // For-inner loop | |
// -------------------------------- | |
for (i = 0; i < numberProcess - 1; ++i) | |
for (j = 0; j < numberProcess - i - 1; ++j) | |
if (processChain[i].burstCPU > processChain[i + 1].burstCPU) // Make sure that the processes are | |
SwapProcess(processChain, i, i + 1); // in order of: Lowest to greatest | |
} // SortProcessChain() | |
// Sort Process Priority | |
// ==================================== | |
// This function will sort the requested process chain by the individual process priority. | |
// We will use the Bubble Sort Algorithm to perform the sorting. This function will have a dependency with | |
// another function named 'SwapProcess()', which is detected to swapping indexes suitable for the Process struct. | |
// NOTE: Bubble Sort Algorithm | |
// DEPENDENCY: SwapProcess() | |
// Default sorting: Highest -> Lowest | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// The process chain that is to be sorted | |
// numberProcess [int] | |
// How many processes exists within the process chain. | |
void SortProcessPriority(struct Process *processChain, int numberProcess) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int i = 0; // For-outer loop | |
int j = 0; // For-inner loop | |
// -------------------------------- | |
for (i = 0; i < numberProcess - 1; ++i) | |
for (j = 0; j < numberProcess - i - 1; ++j) | |
if (processChain[i].priority > processChain[i + 1].priority) // Make sure that the processes are | |
SwapProcess(processChain, i, i + 1); // in order of: Lowest to greatest | |
} // SortProcessPriority() | |
// Swap Process | |
// ==================================== | |
// This function is dedicated to swapping a process from one location within the process chain to another location. | |
// NOTE: This function is dedicated to the Process structure | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// The process chain that will have processes swapped around | |
// target [int] | |
// The index that is to be swapped | |
// destination [int] | |
// The index that will be swapped | |
void SwapProcess(struct Process *processChain, int target, int destination) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
struct Process tempInstance; // This will be a temporary container | |
// for moving data from location to another. | |
// -------------------------------- | |
// First: Copy the contents from the 'destination' index to the temporary container | |
tempInstance.burstCPU = processChain[destination].burstCPU; | |
tempInstance.incomingArrival = processChain[destination].incomingArrival; | |
tempInstance.pid = processChain[destination].pid; | |
tempInstance.priority = processChain[destination].priority; | |
tempInstance.timeRemaining = processChain[destination].timeRemaining; | |
// Second: Swap the 'target' data to the 'destination' | |
processChain[destination].burstCPU = processChain[target].burstCPU; | |
processChain[destination].incomingArrival = processChain[target].incomingArrival; | |
processChain[destination].pid = processChain[target].pid; | |
processChain[destination].priority = processChain[target].priority; | |
processChain[destination].timeRemaining = processChain[target].timeRemaining; | |
// Third: Move the temporary data to the 'target' process. | |
processChain[target].burstCPU = tempInstance.burstCPU; | |
processChain[target].incomingArrival = tempInstance.incomingArrival; | |
processChain[target].pid = tempInstance.pid; | |
processChain[target].priority = tempInstance.priority; | |
processChain[target].timeRemaining = tempInstance.timeRemaining; | |
} // SwapProcess() | |
// Overall Average Calculation | |
// ==================================== | |
// This function will calculate the overall average of each | |
// Average Waiting Time and Average Turnaround Time. | |
// ---- | |
// Parameters: | |
// processCalc [struct ProcessChainCalculation*] | |
// The previous calculations that is to be computed for overall stats. | |
// calculationLoop [int] | |
// How many times did the program loop through each new | |
// process or process instance. | |
// fileOutput [FILE*] | |
// File in which is to log events | |
void OverAllAverageCalculation(struct ProcessChainCalculation *processCalc, int calculationLoop, FILE* fileOutput) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int i = 0; // for-loop | |
long double averageWaitTime = 0.0;// Average Wait Time | |
long double averageTurnTime = 0.0;// Average Turn Around Time | |
// -------------------------------- | |
// Gather the average waiting time | |
for (i = 0; i < calculationLoop; i++) | |
averageWaitTime += processCalc[i].averageWaitingTime; | |
averageWaitTime = averageWaitTime / calculationLoop; | |
// Gather the average turn around time | |
for (i = 0; i < calculationLoop; i++) | |
averageTurnTime += processCalc[i].averageTurnTime; | |
averageTurnTime = averageTurnTime / calculationLoop; | |
// Output to the STDOUT | |
printf("Overall Average Waiting Time: %Lf\n", averageWaitTime); | |
printf("Overall Average Turn around Time: %Lf\n", averageTurnTime); | |
// Output to the log file if logging is enabled | |
if (_OUTPUT_FILE_FLAG_) | |
{ | |
fprintf(fileOutput, "Overall Average Waiting Time: %Lf\n", averageWaitTime); | |
fprintf(fileOutput, "Overall Average Turn around Time: %Lf\n", averageTurnTime); | |
} // IF: LOGGING is True | |
} // OverAllAverageCalculation() | |
// ========================================================================================== | |
// ========================================================================================== | |
// ========================================================================================== | |
// ========================================================================================== | |
// Scheduler: First Come, First Serve | |
// ==================================== | |
// This function is dedicated to performing the 'First Come, First Serve' scheduling algorithm. | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// The process chain that contains all of the processes that is ready to be processed\executed | |
// numberProcess [int] | |
// Number of processes that exists within the process chain | |
// timingFCFS [struct ProcessChainCalculation*] | |
// Data to be saved; related to AWT && ATT | |
// calculationKey [int] | |
// Index key for timingFCFS's array | |
// fileOutput [FILE*] | |
// File in which is to log events | |
void SchedulerFirstComeFirstServe(struct Process* processChain, int numberProcess, struct ProcessChainCalculation* timingFCFS, int calculationKey, FILE* fileOutput) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int i = 0; // for-loop | |
int j = 0; // for-loop, nested | |
long double averageWaitTime = 0.0;// Average Wait Time | |
long double averageTurnTime = 0.0;// Average Turn Around Time | |
int waitTime = 0; // Wait time without the average | |
int maxCPUTime = 0; // Maximum CPU time required | |
int *processStartTime = malloc(numberProcess * sizeof(int)); // Pointer array of int's; used to capture the Wait Time | |
// -------------------------------- | |
// First: What is the maximum time needed for the CPU to complete | |
// this Process Chain? | |
for (i = 0; i < numberProcess; i++) | |
maxCPUTime += processChain[i].burstCPU; | |
// Second: Calculate the Waiting Time | |
// NOTE: All processes all arrived at time: 0 | |
// As part of the problem statement, so no need to | |
// factor in the Arrival Time. | |
processStartTime[0] = 0; // The first process arrives immediately at '0' | |
for (i = 1; i < numberProcess; i++) // Capture and append the pending process's queued time | |
processStartTime[i] = processChain[i - 1].burstCPU + processStartTime[i - 1]; | |
for (i = 0; i < numberProcess; i++) // Gather overall wait time and save it for further computations | |
waitTime += processStartTime[i]; | |
// Third: Calculate the Average Wait Time | |
averageWaitTime = (long double)waitTime / (long double)numberProcess; | |
// Fourth: Calculate the Average Turn around Time | |
averageTurnTime = ((long double)maxCPUTime + (long double)waitTime) / (long double)numberProcess; | |
// Debug; make sure everything didn't fall apart | |
if (_DEBUG_CALC_) // Display the results, if allowed | |
{ | |
// Output to the STDOUT | |
printf("FCFS >> Max CPU Time: %d\n", maxCPUTime); | |
printf("FCFS >> Waiting Time: %d\n", waitTime); | |
printf("FCFS >> Average Waiting Time: %Lf\n", averageWaitTime); | |
printf("FCFS >> Average Turn Around Time: %Lf\n", averageTurnTime); | |
printf("--------------------------------------------------\n"); | |
// ---- | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
{ | |
fprintf(fileOutput, "FCFS >> Max CPU Time: %d\n", maxCPUTime); | |
fprintf(fileOutput, "FCFS >> Waiting Time: %d\n", waitTime); | |
fprintf(fileOutput, "FCFS >> Average Waiting Time: %Lf\n", averageWaitTime); | |
fprintf(fileOutput, "FCFS >> Average Turn Around Time: %Lf\n", averageTurnTime); | |
fprintf(fileOutput, "--------------------------------------------------\n"); | |
} // IF: LOGGING is True | |
for (i = 0; i < numberProcess; i++) | |
{ | |
printf("FCFS >> PROCESS ID [%d] STARTING AT (GANTT): %d\n", i, processStartTime[i]); | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "FCFS >> PROCESS ID [%d] STARTING AT (GANTT): %d\n", i, processStartTime[i]); | |
} // FOR: PROCESS DETAILS | |
} // IF :: Debug | |
// Fifth: Save the results | |
timingFCFS[calculationKey].averageWaitingTime = averageWaitTime; | |
timingFCFS[calculationKey].averageTurnTime = averageTurnTime; | |
// Sixth: Simulate that the process was executed | |
for (i = 0; i < numberProcess; i++) | |
if (_CPU_PROCESS_EMULATION_) | |
for (j = 0; j < processChain[i].burstCPU; j++) | |
processChain[i].burstCPU--; | |
else | |
processChain[i].burstCPU = 0; | |
// Thrash the pointer we used in this function | |
free(processStartTime); | |
} // SchedulerFirstComeFirstServe() | |
// Scheduler: Shortest Job First | |
// ==================================== | |
// This function is dedicated to performing the 'Shortest job first' scheduling algorithm. | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// The process chain that contains all of the processes that is ready to be processed\executed | |
// numberProcess [int] | |
// Number of processes that exists within the process chain | |
// timingSJF [struct ProcessChainCalculation*] | |
// Data to be saved; related to AWT && ATT | |
// calculationKey [int] | |
// Index key for timingSJF's array | |
// fileOutput [FILE*] | |
// File in which is to log events | |
void SchedulerShortestJobFirst(struct Process* processChain, int numberProcess, struct ProcessChainCalculation* timingSJF, int calculationKey, FILE* fileOutput) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int i = 0; // for-loop | |
int j = 0; // for-loop, nested | |
long double averageWaitTime = 0.0;// Average Wait Time | |
long double averageTurnTime = 0.0;// Average Turn Around Time | |
int waitTime = 0; // Wait time without the average | |
int maxCPUTime = 0; // Maximum CPU time required | |
int *processStartTime = malloc(numberProcess * sizeof(int)); // Pointer array of int's; used to capture the Wait Time | |
// -------------------------------- | |
// First: Sort the Process Chain's processes to least -> greatest | |
SortProcessChain(processChain, numberProcess); // This can take time if the Process Chain is large | |
// Second: What is the maximum time needed for the CPU to complete | |
// this Process Chain? | |
for (i = 0; i < numberProcess; i++) | |
maxCPUTime += processChain[i].burstCPU; | |
// Third: Calculate the Waiting Time | |
// NOTE: All processes all arrived at time: 0 | |
// As part of the problem statement, so no need to | |
// factor in the Arrival Time. | |
processStartTime[0] = 0; // The first process arrives immediately at '0' | |
for (i = 1; i < numberProcess; i++) // Capture and append the pending process's queued time | |
processStartTime[i] = processChain[i - 1].burstCPU + processStartTime[i - 1]; | |
for (i = 0; i < numberProcess; i++) // Gather overall wait time and save it for further computations | |
waitTime += processStartTime[i]; | |
// Fourth: Calculate the Average Wait Time | |
averageWaitTime = (long double)waitTime / (long double)numberProcess; | |
// Fifth: Calculate the Average Turn around Time | |
averageTurnTime = ((long double)maxCPUTime + (long double)waitTime) / (long double)numberProcess; | |
// Debug; make sure everything didn't fall apart | |
if (_DEBUG_CALC_) // Display the results, if allowed | |
{ | |
// Output to the STDOUT | |
printf("SJF >> Max CPU Time: %d\n", maxCPUTime); | |
printf("SJF >> Waiting Time: %d\n", waitTime); | |
printf("SJF >> Average Waiting Time: %Lf\n", averageWaitTime); | |
printf("SJF >> Average Turn Around Time: %Lf\n", averageTurnTime); | |
printf("--------------------------------------------------\n"); | |
// ---- | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
{ | |
fprintf(fileOutput, "SJF >> Max CPU Time: %d\n", maxCPUTime); | |
fprintf(fileOutput, "SJF >> Waiting Time: %d\n", waitTime); | |
fprintf(fileOutput, "SJF >> Average Waiting Time: %Lf\n", averageWaitTime); | |
fprintf(fileOutput, "SJF >> Average Turn Around Time: %Lf\n", averageTurnTime); | |
fprintf(fileOutput, "--------------------------------------------------\n"); | |
} // IF: LOGGING is True | |
for (i = 0; i < numberProcess; i++) | |
{ | |
printf("SJF >> PROCESS ID [%d] STARTING AT (GANTT): %d\n", i, processStartTime[i]); | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "SJF >> PROCESS ID [%d] STARTING AT (GANTT): %d\n", i, processStartTime[i]); | |
} // FOR: PROCESS DETAILS | |
} // IF :: Debug | |
// Sixth: Save the results | |
timingSJF[calculationKey].averageWaitingTime = averageWaitTime; | |
timingSJF[calculationKey].averageTurnTime = averageTurnTime; | |
// Sixth: Simulate that the process was executed | |
for (i = 0; i < numberProcess; i++) | |
if (_CPU_PROCESS_EMULATION_) | |
for (j = 0; j < processChain[i].burstCPU; j++) | |
processChain[i].burstCPU--; | |
else | |
processChain[i].burstCPU = 0; | |
// Thrash the pointer we used in this function | |
free(processStartTime); | |
} // SchedulerShortestJobFirst() | |
// Scheduler: Priority | |
// ==================================== | |
// This function is dedicated to performing the 'Priority' scheduling algorithm. | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// The process chain that contains all of the processes that is ready to be processed\executed | |
// numberProcess [int] | |
// Number of processes that exists within the process chain | |
// timingPriority [struct ProcessChainCalculation*] | |
// Data to be saved; related to AWT && ATT | |
// calculationKey [int] | |
// Index key for timingPriority's array | |
// fileOutput [FILE*] | |
// File in which is to log events | |
void SchedulerPriority(struct Process* processChain, int numberProcess, struct ProcessChainCalculation* timingPriority, int calculationKey, FILE* fileOutput) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int i = 0; // for-loop | |
int j = 0; // for-loop, nested | |
long double averageWaitTime = 0.0;// Average Wait Time | |
long double averageTurnTime = 0.0;// Average Turn Around Time | |
int waitTime = 0; // Wait time without the average | |
int maxCPUTime = 0; // Maximum CPU time required | |
int *processStartTime = malloc(numberProcess * sizeof(int)); // Pointer array of int's; used to capture the Wait Time | |
// -------------------------------- | |
// First: Sort the Process Chain's processes based by their priority from critical -> idle | |
SortProcessPriority(processChain, numberProcess); // This can take time if the Process Chain is large | |
// Second: What is the maximum time needed for the CPU to complete | |
// this Process Chain? | |
for (i = 0; i < numberProcess; i++) | |
maxCPUTime += processChain[i].burstCPU; | |
// Third: Calculate the Waiting Time | |
// NOTE: All processes all arrived at time: 0 | |
// As part of the problem statement, so no need to | |
// factor in the Arrival Time. | |
processStartTime[0] = 0; // The first process arrives immediately at '0' | |
for (i = 1; i < numberProcess; i++) // Capture and append the pending process's queued time | |
processStartTime[i] = processChain[i - 1].burstCPU + processStartTime[i - 1]; | |
for (i = 0; i < numberProcess; i++) // Gather overall wait time and save it for further computations | |
waitTime += processStartTime[i]; | |
// Fourth: Calculate the Average Wait Time | |
averageWaitTime = (long double)waitTime / (long double)numberProcess; | |
// Fifth: Calculate the Average Turn around Time | |
averageTurnTime = ((long double)maxCPUTime + (long double)waitTime) / (long double)numberProcess; | |
// Debug; make sure everything didn't fall apart | |
if (_DEBUG_CALC_) // Display the results, if allowed | |
{ | |
// Output to the STDOUT | |
printf("PRIORITY >> Max CPU Time: %d\n", maxCPUTime); | |
printf("PRIORITY >> Waiting Time: %d\n", waitTime); | |
printf("PRIORITY >> Average Waiting Time: %Lf\n", averageWaitTime); | |
printf("PRIORITY >> Average Turn Around Time: %Lf\n", averageTurnTime); | |
printf("--------------------------------------------------\n"); | |
// ---- | |
// Output to the file, if required | |
if (_OUTPUT_FILE_FLAG_) | |
{ | |
fprintf(fileOutput, "PRIORITY >> Max CPU Time: %d\n", maxCPUTime); | |
fprintf(fileOutput, "PRIORITY >> Waiting Time: %d\n", waitTime); | |
fprintf(fileOutput, "PRIORITY >> Average Waiting Time: %Lf\n", averageWaitTime); | |
fprintf(fileOutput, "PRIORITY >> Average Turn Around Time: %Lf\n", averageTurnTime); | |
fprintf(fileOutput, "--------------------------------------------------\n"); | |
} // IF: LOGGING is True | |
for (i = 0; i < numberProcess; i++) | |
{ | |
printf("PRIORITY >> PROCESS ID [%d] WITH PRIORITY [%d] STARTING AT (GANTT): %d\n", i, processChain[i].priority, processStartTime[i]); | |
if (_OUTPUT_FILE_FLAG_) | |
fprintf(fileOutput, "PRIORITY >> PROCESS ID [%d] WITH PRIORITY [%d] STARTING AT (GANTT): %d\n", i, processChain[i].priority, processStartTime[i]); | |
} // FOR: PROCESS DETAILS | |
} // IF :: Debug | |
// Sixth: Save the results | |
timingPriority[calculationKey].averageWaitingTime = averageWaitTime; | |
timingPriority[calculationKey].averageTurnTime = averageTurnTime; | |
// Seventh: Simulate that the process was executed | |
for (i = 0; i < numberProcess; i++) | |
if (_CPU_PROCESS_EMULATION_) | |
for (j = 0; j < processChain[i].burstCPU; j++) | |
processChain[i].burstCPU--; | |
else | |
processChain[i].burstCPU = 0; | |
// Thrash the pointer we used in this function | |
free(processStartTime); | |
} // SchedulerPriority() | |
// Scheduler: Round Robin | |
// ==================================== | |
// This function is dedicated to performing the 'Round Robin' scheduling algorithm | |
// ---- | |
// Parameters: | |
// processChain [struct Process*] | |
// The process chain that contains all of the processes that is ready to be processed\executed | |
// numberProcess [int] | |
// Number of processes that exists within the process chain | |
// timingRR [struct ProcessChainCalculation*] | |
// Data to be saved; related to AWT && ATT | |
// calculationKey [int] | |
// Index key for timingRR's array | |
// quantrumLevel [int] | |
// CPU Quantum level | |
// fileOutput [FILE*] | |
// File in which is to log events | |
void SchedulerRoundRobin(struct Process* processChain, int numberProcess, struct ProcessChainCalculation* timingRR, int calculationKey, int quantumLevel, FILE* fileOutput) | |
{ | |
// Declarations and Initializations | |
// -------------------------------- | |
int i = 0; // for-loop | |
int timeSpent = 0; // CPU Time | |
long double averageWaitTime = 0; // Average Wait Time | |
long double averageTurnTime = 0; // Average Turn Around Time | |
int *processStartTime = malloc(numberProcess * sizeof(int)); // Pointer array of int's; used to capture the Wait Time | |
int *processTurnTime = malloc(numberProcess * sizeof(int)); // Pointer array of int's; used to capture the Turn around Time | |
int totalWaitTime = 0; // We will use this to append the wait time | |
int totalTurnTime = 0; // We will also use this to append the turn time. | |
// -------------------------------- | |
//First: quickly mirror all of the 'timeRemainings' of all the | |
// processes respectively. We will use this for the Round Robin algorithm | |
for (i = 0; i < numberProcess; i++) | |
processChain[i].timeRemaining = processChain[i].burstCPU; | |
// Second: Scan through each process within the process chain | |
// and perform the Round Robin protocol | |
while (true) | |
{ | |
// Processes are done; could change depending on conditions later | |
bool done = true; | |
for (i = 0; i < numberProcess; i++) | |
{ | |
// Is there anything to process? | |
if (processChain[i].timeRemaining > 0) | |
{ | |
done = false; // There is more to process | |
// Is the process equal to or greater than quantum? | |
if (processChain[i].timeRemaining > quantumLevel) | |
{ | |
timeSpent += quantumLevel; // Declare how much time was spent from the process | |
// Update the process's CPU Burst time | |
if (_CPU_PROCESS_EMULATION_) | |
{ // Simulate the processing | |
int quantumLevel_cache = quantumLevel; // How much of the time has been given to the process | |
while (quantumLevel_cache > 0) | |
{ | |
processChain[i].timeRemaining--; // Decrement the process's CPU Burst | |
quantumLevel_cache--; // Decrement the time quantum time alloted for task | |
} // WHILE : Quantum Level Cache > 0 | |
} // IF : Process Emulation | |
else | |
processChain[i].timeRemaining -= quantumLevel; // Remove quantum time from the process's CPU burst. | |
} // IF : Process is larger than or equal to quantum | |
else | |
{ | |
timeSpent += processChain[i].timeRemaining; // Declare how much time was spent from the process. | |
// Update the process's CPU Burst time | |
if (_CPU_PROCESS_EMULATION_) | |
while (processChain[i].timeRemaining > 0) | |
processChain[i].timeRemaining--; // Process the task until CPU Burst time has been depleted. | |
else | |
processChain[i].timeRemaining = 0; // Process has been executed; reset the burst to zero. | |
processStartTime[i] = timeSpent - processChain[i].burstCPU; // State how much time it took to execute the process. | |
} // ELSE : Process is less than quantum | |
} // IF : Process Time > 0 | |
} // for | |
// Are all processes finished? | |
if (done == true) | |
break; | |
} | |
// Third: calculate the Turn Around Times | |
for (i = 0; i < numberProcess; i++) | |
processTurnTime[i] = processChain[i].burstCPU + processStartTime[i]; | |
// Fourth: calculate the Wait Time and Turn Around time | |
for (i = 0; i < numberProcess; i++) | |
{ | |
totalWaitTime += processStartTime[i]; | |
totalTurnTime += processTurnTime[i]; | |
} // For : Calculate Turn around Time and Wait Time | |
//Fifth: finally Get the averages and store them | |
averageWaitTime = (long double)totalWaitTime / (long double)numberProcess; | |
averageTurnTime = (long double)totalTurnTime / (long double)numberProcess; | |
// Debug; make sure everything didn't fall apart | |
if (_DEBUG_CALC_) // Display the results, if allowed | |
{ | |
printf("ROUND ROBIN >> Quantum Level: %d\n", quantumLevel); | |
printf("ROUND ROBIN >> Max CPU Time: %d\n", timeSpent); | |
printf("ROUND ROBIN >> Waiting Time: %d\n", totalWaitTime); | |
printf("ROUND ROBIN >> Average Waiting Time: %Lf\n", averageWaitTime); | |
printf("ROUND ROBIN >> Average Turn Around Time: %Lf\n", averageTurnTime); | |
printf("--------------------------------------------------\n"); | |
// ---- | |
if (_OUTPUT_FILE_FLAG_) | |
{ | |
fprintf(fileOutput, "ROUND ROBIN >> Quantum Level: %d\n", quantumLevel); | |
fprintf(fileOutput, "ROUND ROBIN >> Max CPU Time: %d\n", timeSpent); | |
fprintf(fileOutput, "ROUND ROBIN >> Waiting Time: %d\n", totalWaitTime); | |
fprintf(fileOutput, "ROUND ROBIN >> Average Waiting Time: %Lf\n", averageWaitTime); | |
fprintf(fileOutput, "ROUND ROBIN >> Average Turn Around Time: %Lf\n", averageTurnTime); | |
fprintf(fileOutput, "--------------------------------------------------\n"); | |
} // IF: LOGGING is True | |
} // IF :: Debug | |
// Sixth: Save the results | |
timingRR[calculationKey].averageWaitingTime = averageWaitTime; | |
timingRR[calculationKey].averageTurnTime = averageTurnTime; | |
// Thrash the pointers we used in this function | |
free(processStartTime); | |
free(processTurnTime); | |
} // SchedulerRoundRobin() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment