-
-
Notifications
You must be signed in to change notification settings - Fork 7.4k
Add round-robin CPU scheduling algorithm #2193
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
803d707
feat: create round-robin CPU scheduling algorithm
Daemon19 4885fac
test: create self-test implementation for round-robin cpu scheduling
Daemon19 b4d8109
doc: add doxygen documentation to round_robin_scheduling.cpp
Daemon19 e48f29a
chore: processes don't need to be sorted
Daemon19 26210ba
doc: add documentation so the code more understandable
Daemon19 be91e2f
doc: add include documentation
Daemon19 cca92aa
Merge branch 'master' into round-robin-scheduling
Daemon19 2ae3379
Merge branch 'master' into round-robin-scheduling
Panquesito7 6c0d6d8
Update cpu_scheduling_algorithms/round_robin_scheduling.cpp
Daemon19 3586fb0
doc: add doc for structs member variable
Daemon19 8f81761
Update cpu_scheduling_algorithms/round_robin_scheduling.cpp
Daemon19 6a63dcd
fix: missing algorithm header file
Daemon19 cb43edc
Update cpu_scheduling_algorithms/round_robin_scheduling.cpp
Daemon19 b6ff48c
fix: formatting errors
Daemon19 6d00a6b
updating DIRECTORY.md
Panquesito7 ee2b2e9
clang-format and clang-tidy fixes for b6ff48cf
Panquesito7 825bcd5
Merge branch 'master' into round-robin-scheduling
Daemon19 ba74e24
clang-format and clang-tidy fixes for 825bcd54
Panquesito7 d08022c
doc: update include doc in cpu_scheduling_algorithms/round_robin_sche…
Daemon19 c5a915c
doc: update include doc in cpu_scheduling_algorithms/round_robin_sche…
Daemon19 e1071fe
doc: added Wikipedia link
Daemon19 75745a0
doc: remove Test function prototype
Daemon19 dfef854
fix: missing newline character
Daemon19 5f752df
Merge branch 'master' into round-robin-scheduling
Daemon19 72e4f59
clang-format and clang-tidy fixes for 5f752df9
Panquesito7 baaae54
Merge branch 'master' into round-robin-scheduling
Panquesito7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
/** | ||
* @file | ||
* @brief Implementation of [Round Robin CPU | ||
* scheduling](https://en.wikipedia.org/wiki/Round-robin_scheduling) algorithm | ||
* @details | ||
* Round-robin is a preemptive CPU scheduling algorithm where each | ||
* ready task runs turn by turn only in a cyclic queue for a limited | ||
* time slice. This algorithm also offers starvation free execution | ||
* of processes. | ||
* @author [Daemon19](https://github.com/Daemon19) | ||
*/ | ||
|
||
#include <algorithm> /// For std::sort | ||
#include <cassert> /// For testing the round-robin algorithm | ||
#include <iomanip> /// For formatting process results output | ||
#include <iostream> /// For outputting process execution results | ||
#include <queue> /// Container for process execution turn | ||
#include <set> /// Container for processes that have arrived | ||
#include <string> /// For converting int type to string | ||
#include <utility> /// For std::pair | ||
#include <vector> /// Container for processes that will be executed | ||
|
||
/** | ||
* @brief Represent a process to be executed. | ||
*/ | ||
struct Process { | ||
uint32_t id; ///< Used to distinguish processes | ||
uint32_t arrival_time; ///< The time at which the process arrives | ||
uint32_t burst_time; ///< Time required to complete process execution | ||
}; | ||
|
||
/** | ||
* @brief Represent the result of a process execution. | ||
*/ | ||
struct ProcessResult : public Process { | ||
uint32_t completion_time; ///< The time at which the process execution is | ||
///< finished | ||
uint32_t turn_around_time; ///< The turn around time required for the | ||
///< process to complete | ||
uint32_t waiting_time; ///< Process waiting time before execution | ||
|
||
/** | ||
* @brief Constructor that calculate member variables based on a | ||
* process and completion time. | ||
* | ||
* \param process A process that have been executed | ||
* \param completion_time The process execution finish time | ||
*/ | ||
ProcessResult(const Process& process, uint32_t completion_time) | ||
: Process(process), completion_time(completion_time) { | ||
turn_around_time = completion_time - arrival_time; | ||
waiting_time = turn_around_time - burst_time; | ||
} | ||
|
||
/** | ||
* @brief Compare each member variable. | ||
* | ||
* \param p ProcessResult to be compared with | ||
* \return true if the processes IS equal | ||
* \return false if the processes IS NOT equal | ||
*/ | ||
bool operator==(const ProcessResult& p) const { | ||
return id == p.id && arrival_time == p.arrival_time && | ||
burst_time == p.burst_time && | ||
completion_time == p.completion_time && | ||
turn_around_time == p.turn_around_time && | ||
waiting_time == p.waiting_time; | ||
} | ||
}; | ||
|
||
/** | ||
* Represent remaining burst time of a process. | ||
*/ | ||
using BTLeft = uint32_t; | ||
|
||
/** | ||
* @brief Execute processes based on Round-robin algorithm. | ||
* | ||
* \param processes Processes to be executed | ||
* \param time_slice Time slice for processes execution | ||
* \return Results of each process execution | ||
*/ | ||
std::vector<ProcessResult> RRExecute(const std::vector<Process>& processes, | ||
uint32_t time_slice); | ||
|
||
/** | ||
* @brief Print a table containing process results data. | ||
* | ||
* \return ostream inputted ostream | ||
*/ | ||
std::ostream& operator<<(std::ostream& ostream, | ||
const std::vector<ProcessResult>& results); | ||
|
||
/** | ||
* @brief Comparator function for sorting processes. | ||
* | ||
* \param p1 Process to be compared | ||
* \param p2 Process to be compared | ||
* \return | ||
*/ | ||
bool CompareAT(const Process& p1, const Process& p2) { | ||
return p1.arrival_time < p2.arrival_time; | ||
} | ||
|
||
/** | ||
* @brief Check processes that arrive after the given time_elapsed. | ||
* | ||
* If a process arrive after the give time_elapsed, then the process | ||
* will be pushed into the schedule queue and inserted into the | ||
* arrived_process set. | ||
* | ||
* \param processes Processes that will be checked for arrival | ||
* \param arrived_process A set containing processes that has arrived | ||
* \param schedule Queue containing pair of process and its remaining burst time | ||
* \param time_elapsed Time that has elapsed after processes execution | ||
*/ | ||
void CheckArriveProcess(const std::vector<Process>& processes, | ||
std::set<uint32_t>* arrived_process, | ||
std::queue<std::pair<Process, BTLeft>>* schedule, | ||
uint32_t time_elapsed); | ||
|
||
/** | ||
* @brief Self-test implementations | ||
* @returns void | ||
*/ | ||
static void Test() { | ||
std::vector<Process> processes{ | ||
{0, 70, 3}, {1, 9, 2}, {2, 3, 39}, {3, 5, 29}, {4, 30, 90}}; | ||
const uint32_t kTimeSlice{3}; | ||
std::vector<ProcessResult> results = RRExecute(processes, kTimeSlice); | ||
|
||
std::vector<uint32_t> correct_completion_times({80, 14, 100, 82, 166}); | ||
std::vector<ProcessResult> correct_results; | ||
// Generate correct process results based on correct completion times | ||
for (size_t i = 0; i < processes.size(); i++) { | ||
correct_results.emplace_back(processes[i], correct_completion_times[i]); | ||
} | ||
|
||
// Sort the results and correct results so they're exactly the same | ||
std::sort(results.begin(), results.end(), CompareAT); | ||
std::sort(correct_results.begin(), correct_results.end(), CompareAT); | ||
|
||
std::cout << results; | ||
assert(results == correct_results); | ||
std::cout << "All test passed.\n"; | ||
} | ||
|
||
/** | ||
* @brief Entry point of the program. | ||
* | ||
* \return 0 on exit | ||
*/ | ||
int main() { | ||
Test(); | ||
return 0; | ||
} | ||
|
||
std::vector<ProcessResult> RRExecute(const std::vector<Process>& processes, | ||
Daemon19 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
uint32_t time_slice) { | ||
std::queue<std::pair<Process, BTLeft>> schedule; | ||
std::set<uint32_t> arrived_processes; | ||
|
||
std::vector<ProcessResult> results; | ||
results.reserve(processes.size()); | ||
|
||
// The time of the first process execution will be the lowest process AT | ||
uint32_t time_elapsed = | ||
std::min_element(processes.begin(), processes.end(), CompareAT) | ||
->arrival_time; | ||
|
||
CheckArriveProcess(processes, &arrived_processes, &schedule, time_elapsed); | ||
|
||
while (!schedule.empty()) { | ||
std::pair<Process, BTLeft> current = schedule.front(); | ||
schedule.pop(); | ||
|
||
// If process burst time < time slice, then the process will be | ||
// executed for the burst time amount of time, not the time | ||
// quantum/slice | ||
uint32_t elapsed = | ||
(current.second > time_slice) ? time_slice : current.second; | ||
current.second -= elapsed; | ||
time_elapsed += elapsed; | ||
|
||
CheckArriveProcess(processes, &arrived_processes, &schedule, | ||
time_elapsed); | ||
|
||
if (current.second > 0) { | ||
schedule.push(current); | ||
continue; | ||
} | ||
// Generate process result based on the completion time (time | ||
// that has elapsed) | ||
results.emplace_back(current.first, time_elapsed); | ||
} | ||
|
||
return results; | ||
} | ||
|
||
std::ostream& operator<<(std::ostream& ostream, | ||
const std::vector<ProcessResult>& results) { | ||
auto PrintCell = [&](const std::string& str) { | ||
ostream << std::setw(17) << std::left << str; | ||
}; | ||
|
||
std::vector<ProcessResult> sorted = results; | ||
std::sort(sorted.begin(), sorted.end(), CompareAT); | ||
|
||
PrintCell("Process ID"); | ||
PrintCell("Arrival Time"); | ||
PrintCell("Burst Time"); | ||
PrintCell("Completion Time"); | ||
PrintCell("Turnaround Time"); | ||
PrintCell("Waiting Time"); | ||
ostream << std::endl; | ||
|
||
for (auto& p : sorted) { | ||
PrintCell(std::to_string(p.id)); | ||
PrintCell(std::to_string(p.arrival_time)); | ||
PrintCell(std::to_string(p.burst_time)); | ||
PrintCell(std::to_string(p.completion_time)); | ||
PrintCell(std::to_string(p.turn_around_time)); | ||
PrintCell(std::to_string(p.waiting_time)); | ||
ostream << "\n"; | ||
} | ||
|
||
return ostream; | ||
} | ||
|
||
void CheckArriveProcess(const std::vector<Process>& processes, | ||
std::set<uint32_t>* arrived_process, | ||
std::queue<std::pair<Process, BTLeft>>* schedule, | ||
uint32_t time_elapsed) { | ||
for (auto& p : processes) { | ||
if (p.arrival_time > time_elapsed || | ||
arrived_process->find(p.id) != arrived_process->end()) { | ||
continue; | ||
} | ||
schedule->emplace(p, p.burst_time); | ||
arrived_process->insert(p.id); | ||
} | ||
} |
This file contains hidden or 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
This file contains hidden or 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
This file contains hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Best to initialize the variables to avoid issues.