Skip to content

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
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
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 Oct 9, 2022
4885fac
test: create self-test implementation for round-robin cpu scheduling
Daemon19 Oct 9, 2022
b4d8109
doc: add doxygen documentation to round_robin_scheduling.cpp
Daemon19 Oct 9, 2022
e48f29a
chore: processes don't need to be sorted
Daemon19 Oct 9, 2022
26210ba
doc: add documentation so the code more understandable
Daemon19 Oct 9, 2022
be91e2f
doc: add include documentation
Daemon19 Oct 10, 2022
cca92aa
Merge branch 'master' into round-robin-scheduling
Daemon19 Oct 15, 2022
2ae3379
Merge branch 'master' into round-robin-scheduling
Panquesito7 Oct 18, 2022
6c0d6d8
Update cpu_scheduling_algorithms/round_robin_scheduling.cpp
Daemon19 Oct 18, 2022
3586fb0
doc: add doc for structs member variable
Daemon19 Oct 18, 2022
8f81761
Update cpu_scheduling_algorithms/round_robin_scheduling.cpp
Daemon19 Oct 18, 2022
6a63dcd
fix: missing algorithm header file
Daemon19 Oct 18, 2022
cb43edc
Update cpu_scheduling_algorithms/round_robin_scheduling.cpp
Daemon19 Oct 18, 2022
b6ff48c
fix: formatting errors
Daemon19 Oct 18, 2022
6d00a6b
updating DIRECTORY.md
Panquesito7 Oct 18, 2022
ee2b2e9
clang-format and clang-tidy fixes for b6ff48cf
Panquesito7 Oct 18, 2022
825bcd5
Merge branch 'master' into round-robin-scheduling
Daemon19 Oct 19, 2022
ba74e24
clang-format and clang-tidy fixes for 825bcd54
Panquesito7 Oct 19, 2022
d08022c
doc: update include doc in cpu_scheduling_algorithms/round_robin_sche…
Daemon19 Oct 20, 2022
c5a915c
doc: update include doc in cpu_scheduling_algorithms/round_robin_sche…
Daemon19 Oct 21, 2022
e1071fe
doc: added Wikipedia link
Daemon19 Oct 21, 2022
75745a0
doc: remove Test function prototype
Daemon19 Oct 21, 2022
dfef854
fix: missing newline character
Daemon19 Oct 21, 2022
5f752df
Merge branch 'master' into round-robin-scheduling
Daemon19 Oct 30, 2022
72e4f59
clang-format and clang-tidy fixes for 5f752df9
Panquesito7 Oct 30, 2022
baaae54
Merge branch 'master' into round-robin-scheduling
Panquesito7 Jan 1, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
242 changes: 242 additions & 0 deletions cpu_scheduling_algorithms/round_robin_scheduling.cpp
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
Comment on lines +27 to +29
Copy link
Member

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.

Suggested change
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
uint32_t id = 0; ///< Used to distinguish processes
uint32_t arrival_time = 0; ///< The time at which the process arrives
uint32_t burst_time = 0; ///< 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,
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);
}
}
15 changes: 8 additions & 7 deletions dynamic_programming/0_1_knapsack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ namespace dynamic_programming {
namespace knapsack {
/**
* @brief Picking up all those items whose combined weight is below
* the given capacity and calculating the value of those picked items. Trying all
* possible combinations will yield the maximum knapsack value.
* the given capacity and calculating the value of those picked items. Trying
* all possible combinations will yield the maximum knapsack value.
* @tparam n size of the weight and value array
* @param capacity capacity of the carrying bag
* @param weight array representing the weight of items
Expand All @@ -62,9 +62,9 @@ int maxKnapsackValue(const int capacity, const std::array<int, n> &weight,
// will be zero
maxValue[i][j] = 0;
} else if (weight[i - 1] <= j) {
// if the ith item's weight(in the actual array it will be at i-1)
// is less than or equal to the allowed weight i.e. j then we
// can pick that item for our knapsack. maxValue will be the
// if the ith item's weight(in the actual array it will be at
// i-1) is less than or equal to the allowed weight i.e. j then
// we can pick that item for our knapsack. maxValue will be the
// obtained either by picking the current item or by not picking
// current item

Expand All @@ -76,8 +76,9 @@ int maxKnapsackValue(const int capacity, const std::array<int, n> &weight,

maxValue[i][j] = std::max(profit1, profit2);
} else {
// as the weight of the current item is greater than the allowed weight, so
// maxProfit will be profit obtained by excluding the current item.
// as the weight of the current item is greater than the allowed
// weight, so maxProfit will be profit obtained by excluding the
// current item.
maxValue[i][j] = maxValue[i - 1][j];
}
}
Expand Down
32 changes: 22 additions & 10 deletions physics/ground_to_ground_projectile_motion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ double degrees_to_radians(double radian, double PI = 3.14) {
*/
template <typename T>
T time_of_flight(T initial_velocity, T angle, double gravity = 9.81) {
double Viy = initial_velocity * (std::sin(degrees_to_radians(angle))); // calculate y component of the initial velocity
double Viy = initial_velocity *
(std::sin(degrees_to_radians(
angle))); // calculate y component of the initial velocity
return 2.0 * Viy / gravity;
}

Expand All @@ -55,7 +57,9 @@ T time_of_flight(T initial_velocity, T angle, double gravity = 9.81) {
*/
template <typename T>
T horizontal_range(T initial_velocity, T angle, T time) {
double Vix = initial_velocity * (std::cos(degrees_to_radians(angle))); // calculate x component of the initial velocity
double Vix = initial_velocity *
(std::cos(degrees_to_radians(
angle))); // calculate x component of the initial velocity
return Vix * time;
}

Expand All @@ -68,7 +72,9 @@ T horizontal_range(T initial_velocity, T angle, T time) {
*/
template <typename T>
T max_height(T initial_velocity, T angle, double gravity = 9.81) {
double Viy = initial_velocity * (std::sin(degrees_to_radians(angle))); // calculate y component of the initial velocity
double Viy = initial_velocity *
(std::sin(degrees_to_radians(
angle))); // calculate y component of the initial velocity
return (std::pow(Viy, 2) / (2.0 * gravity));
}
} // namespace ground_to_ground_projectile_motion
Expand All @@ -86,7 +92,9 @@ static void test() {
// 1st test
double expected_time_of_flight = 0.655; // expected time output
double flight_time_output =
std::round(physics::ground_to_ground_projectile_motion::time_of_flight(initial_velocity, angle) * 1000.0) /
std::round(physics::ground_to_ground_projectile_motion::time_of_flight(
initial_velocity, angle) *
1000.0) /
1000.0; // round output to 3 decimal places

std::cout << "Projectile Flight Time (double)" << std::endl;
Expand All @@ -98,11 +106,13 @@ static void test() {
std::cout << "TEST PASSED" << std::endl << std::endl;

// 2nd test
double expected_horizontal_range = 2.51; // expected range output
double expected_horizontal_range = 2.51; // expected range output
double horizontal_range_output =
std::round(physics::ground_to_ground_projectile_motion::horizontal_range(initial_velocity, angle,
flight_time_output) *
100.0) /
std::round(
physics::ground_to_ground_projectile_motion::horizontal_range(
initial_velocity, angle,
flight_time_output) *
100.0) /
100.0; // round output to 2 decimal places

std::cout << "Projectile Horizontal Range (double)" << std::endl;
Expand All @@ -115,9 +125,11 @@ static void test() {
std::cout << "TEST PASSED" << std::endl << std::endl;

// 3rd test
double expected_max_height = 0.526; // expected height output
double expected_max_height = 0.526; // expected height output
double max_height_output =
std::round(physics::ground_to_ground_projectile_motion::max_height(initial_velocity, angle) * 1000.0) /
std::round(physics::ground_to_ground_projectile_motion::max_height(
initial_velocity, angle) *
1000.0) /
1000.0; // round output to 3 decimal places

std::cout << "Projectile Max Height (double)" << std::endl;
Expand Down
4 changes: 2 additions & 2 deletions sorting/merge_sort.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
* @param r - end index or right index of second half array
*/
void merge(int *arr, int l, int m, int r) {
int i, j, k;
int i = 0, j = 0, k = 0;
int n1 = m - l + 1;
int n2 = r - m;

Expand Down Expand Up @@ -88,7 +88,7 @@ void show(int *arr, int size) {

/** Main function */
int main() {
int size;
int size = 0;
std::cout << "Enter the number of elements : ";
std::cin >> size;
int *arr = new int[size];
Expand Down