Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Operating Systems: CPU Schedulers [First Come First Serve, Shortest Job First, Priority, and Round Robin Quantum 4 and Quantum 8]
// =====================================================
// 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
You can’t perform that action at this time.