diff --git a/makefile b/makefile index 595fb14fc858c7d2de1f0ee97480c3f579206a97..f9954558ada25cb91cc498533e162e843427cd02 100644 --- a/makefile +++ b/makefile @@ -11,7 +11,7 @@ EXE = mpiexec CFLAGS = -Wall -Wpedantic -std=c99 -g TARGET = main.out LIBRARIES = -pthread -DEPENDENCIES = src/main.c src/structs.c src/simulate_loads.c src/terminal_commands.c +DEPENDENCIES = src/main.c src/load_balance_general.c src/load_balance_schemes.c src/structs.c src/terminal_commands.c CORES := $(shell nproc) # ARGS = `arg="$(filter-out $@,$(MAKECMDGOALS))" && echo $${arg:-${1}}` ARGS = $(filter-out $@,$(MAKECMDGOALS)) diff --git a/src/load_balance_general.c b/src/load_balance_general.c new file mode 100644 index 0000000000000000000000000000000000000000..1ab6b8b5c3f91024f2e58a783bead8f1369e7a98 --- /dev/null +++ b/src/load_balance_general.c @@ -0,0 +1,168 @@ +/** + * File for general "Load Balancing" logic. + */ + + +// User Import Headers. +#ifndef user_headers + #define user_headers + #include "load_balance_general.h" + #include "structs.h" + #include "terminal_commands.h" +#endif + + +/** + * Displays provided worker data through master process. + */ +void main_display_status(thread_struct* thread_args_ptr, int process_num, int process_load_status, int init_run) { + int index; + + // Travel to desired terminal row. Skip if first loop through thread displaying. + if (init_run == 0) { + for (index = 0; index < (thread_args_ptr->total_processors - process_num); index ++) { + terminal_line_up(); + } + } + // Clear row. + terminal_line_erase(); + terminal_line_start(); + + // Display message. + printf("Thread %5i: %5i / %5i Loads Remaining\n", process_num, process_load_status, thread_args_ptr->total_loads); + + // Travel back to original terminal location. Skip if first loop through thread displaying. + if (init_run == 0) { + for (index = 0; index < (thread_args_ptr->total_processors - process_num); index ++) { + terminal_line_down(); + } + terminal_line_start(); + } +} + + +/** + * Sends message to all worker processes that all work has been completed, and it's okay to terminate now. + */ +void main_terminate_workers(thread_struct* thread_args_ptr) { + int program_end_tag = 1; + int index; + MPI_Request request_var; // What is this for?? Why is it required? + + for (index = 1; index < thread_args_ptr->total_processors; index++) { + MPI_Isend(&program_end_tag, 1, MPI_INT, index, program_end_tag, MPI_COMM_WORLD, &request_var); + // printf("Sending termination message to process %i.\n", index); + // MPI_Send(&program_end_tag, 1, MPI_INT, index, program_end_tag, MPI_COMM_WORLD); + // printf("Process %i received termination message.\n", index); + } + +} + + +/** + * Sends worker load status and rank to master process. + */ +void worker_send_status(int process_rank, int process_load_status) { + int* send_array = calloc(2, sizeof(int)); + send_array[0] = process_rank; + send_array[1] = process_load_status; + MPI_Send(send_array, 2, MPI_INT, 0, 0, MPI_COMM_WORLD); + free(send_array); +} + + +/** + * Checks status of program runtime for worker to eventually get the okay to terminate. + * + * :return: 0 if received okay from main process to end. Otherwise 1 to continue working. + */ +int worker_check_status() { + int msg_status_flag = 0; + int temp = 0; + int main_process = 0; + int program_end_tag = 1; + + // Check for pending message from main process. + // Should only ocurr if main is telling child process that all work has completed. + MPI_Iprobe(main_process, program_end_tag, MPI_COMM_WORLD, &msg_status_flag, MPI_STATUS_IGNORE); + if (msg_status_flag == 1) { + // Message present. Officially grab message so master can unblock. + MPI_Recv(&temp, 1, MPI_INT, main_process, program_end_tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + return 0; + } + return 1; +} + + +/** + * Attempts to receive work from given "possible donor" process (donor is determined by load balancing schema). + * + * Does so by sending message to "possible donor" process, to initiate request. + * Once it gets around to message checking, donor will then send back a message of: + * * -1 indicating donor does not have work to give. + * * Positive integer of work being passed back to begging process. + */ +int worker_send_request(thread_struct* thread_args_ptr, int possible_donor) { + int donor_response = 0; + + // Initialilze interaction by sending a "begging message" for work. + MPI_Send(&donor_response, 1, MPI_INT, possible_donor, 0, MPI_COMM_WORLD); + + // If got this far, then we have unblocked. Means that "possible donor" process is sending a response. + MPI_Recv(&donor_response, 1, MPI_INT, possible_donor, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Check what response was and handle accoringly. + if (donor_response > 0) { + // Donor sent workload to process. + thread_args_ptr->remaining_loads = donor_response; + return 1; + } else { + // Donor sent reject message. + return 0; + } +} + + +/** + * Checks if worker has any pending work requests from other processes. + * On any pending request, checks if request exists on all processes. + * + * To handle request, either splits current work load in half (asking process gets the smaller portion if odd number) + * or returns negative number if no work to send. + */ +void worker_handle_request(thread_struct* thread_args_ptr) { + int msg_status_flag = 0; + int work_send_value = 0; + int temp = 0; + int index; + + MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &msg_status_flag, MPI_STATUS_IGNORE); + if (msg_status_flag == 1) { + + // One or more messages present. Loop through and check for message from all processors. + for (index = 1; index < thread_args_ptr->total_processors; index++) { + msg_status_flag = 0; + MPI_Iprobe(index, MPI_ANY_TAG, MPI_COMM_WORLD, &msg_status_flag, MPI_STATUS_IGNORE); + if (msg_status_flag == 1) { + // Message present from processor at corresponding index. Handle. + + // First, properly "receive" pending message, so asking worker can unblock. + MPI_Recv(&temp, 1, MPI_INT, index, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Check if donating worker has work to split and send. + if (thread_args_ptr->remaining_loads > 1) { + // Worker has at least one load to split and send. Do so. + work_send_value = thread_args_ptr->remaining_loads / 2; + thread_args_ptr->remaining_loads = work_send_value + (thread_args_ptr->remaining_loads % 2); + MPI_Send(&work_send_value, 1, MPI_INT, index, 0, MPI_COMM_WORLD); + } else { + // Worker has exactly 0 or 1 loads. Not enough to send. Reject request instead. + work_send_value = -1; + MPI_Send(&work_send_value, 1, MPI_INT, index, 0, MPI_COMM_WORLD); + } + + } + } + + } +} diff --git a/src/load_balance_general.h b/src/load_balance_general.h new file mode 100644 index 0000000000000000000000000000000000000000..426296583ce20aa49a53dbbe11d9b4604ad9eaa8 --- /dev/null +++ b/src/load_balance_general.h @@ -0,0 +1,21 @@ +/** + * Header file for general "Load Balancing" logic. + */ + + +// System Import Headers. +#include <ctype.h> +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +// Function Prototypes. +void main_display_status(); +void main_terminate_workers(); +void worker_send_status(); +int worker_check_status(); +int worker_send_request(); +void worker_handle_request(); diff --git a/src/load_balance_schemes.c b/src/load_balance_schemes.c new file mode 100644 index 0000000000000000000000000000000000000000..f4b0572d4605f64a15ffcd67712f172386f8d225 --- /dev/null +++ b/src/load_balance_schemes.c @@ -0,0 +1,256 @@ +/** + * File for general "Load Balancing" logic. + */ + + +// User Import Headers. +#ifndef user_headers + #define user_headers + #include "load_balance_schemes.h" + #include "load_balance_general.h" + #include "structs.h" + #include "terminal_commands.h" +#endif + + +/** + * Entrypoint for logic to run "Asynchronous Round Robin" load scheme. + */ +void arr_run(thread_struct* thread_args_ptr) { + int process_rank = thread_args_ptr->thread_num; + + if (process_rank == 0) { + printf("Starting ARR load scheme.\n"); + printf("\n"); + } + + // Wait for all processes to synchronize. + // Also sleep for a second to allow time for console output to process. + MPI_Barrier(MPI_COMM_WORLD); + sleep(1); + + // Handle based on process number. + if (process_rank > 0) { + // Child process. Handles all the work. + arr_worker(thread_args_ptr); + } else { + // Main process. Handles communication to terminal. + arr_main(thread_args_ptr); + } + + // Wait for all processes to synchronize. + // Also sleep for a second to allow time for console output to process. + MPI_Barrier(MPI_COMM_WORLD); + sleep(1); + + if (process_rank == 0) { + printf("\n"); + printf("ARR load scheme. Finished.\n"); + } +} + + +/** + * Main processor logic for "Asynchronous Round Robin" load scheme. + */ +void arr_main(thread_struct* thread_args_ptr) { + int index; + int main_loop_bool = 1; + int init_run = 1; + int msg_status_flag; + int msg_recieved = 0; + int* recv_array; + + // Initialize console display. + for (index = 1; index < thread_args_ptr->total_processors; index++) { + recv_array = calloc(3, sizeof(int)); + MPI_Recv(recv_array, 2, MPI_INT, index, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + main_display_status(thread_args_ptr, recv_array[0], recv_array[1], init_run); + free(recv_array); + } + + // Continually grab messages from all worker processors until done. + // For each loop, it checks all worker processes for a message about work being done. + // If no messages are found for two consecutive loops in a row, then assumes all work is complete and terminates. + index = 1; + init_run = 0; + while (main_loop_bool == 1) { + msg_status_flag = 0; + + // Check if message present from respective process. + MPI_Iprobe(index, MPI_ANY_TAG, MPI_COMM_WORLD, &msg_status_flag, MPI_STATUS_IGNORE); + if (msg_status_flag == 1) { + msg_recieved = 1; + + // Message present. Retrieve and handle. + recv_array = calloc(3, sizeof(int)); + MPI_Recv(recv_array, 2, MPI_INT, index, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + main_display_status(thread_args_ptr, recv_array[0], recv_array[1], init_run); + free(recv_array); + } + + // Increment for next thread. + index = (index + 1) % thread_args_ptr->total_processors; + + // Check if past last processor. + if (index == 0) { + index += 1; + + // Check if messages were recieved this run. + if (msg_recieved == 0) { + // No messages recieved. Run one last loop to double check. + msg_recieved = -1; + sleep(2); + } else if (msg_recieved == -1) { + // No messages recieved for two loops in a row. Terminate. + main_terminate_workers(thread_args_ptr); + main_loop_bool = 0; + } else { + // One or more messages recieved this loop. Reset value. + msg_recieved = 0; + } + + // Sleep number of seconds provided by user terminal. + // Meant to simulate "work", as it forces each worker process to block for this amount of time each load, + // before continuing on. In a real program, the worker would be doing something useful in this time, + // instead of just blocking. + sleep(thread_args_ptr->seconds_per_load); + } + + } +} + + +/** + * Worker processor logic for "Asynchronous Round Robin" load scheme. + */ +void arr_worker(thread_struct* thread_args_ptr) { + int process_rank = thread_args_ptr->thread_num; + int arr_counter = thread_args_ptr->thread_num; + int main_loop_bool = 1; + int index; + int msg_status_flag; + + // Initialize process "1" to have full loads. All others start with none. + if (process_rank == 1) { + thread_args_ptr->remaining_loads = thread_args_ptr->total_loads; + } else { + thread_args_ptr->remaining_loads = 0; + } + + // Main loop bool. Continues until main process says all work is done. + while (main_loop_bool == 1) { + + // Loop all worker processes until load count message of "0" has been sent. + while (thread_args_ptr->remaining_loads >= 0) { + + // Send message for current load. + worker_send_status(process_rank, thread_args_ptr->remaining_loads); + + // Check for message requests from other processes. + worker_handle_request(thread_args_ptr); + + // Decriment load number. + thread_args_ptr->remaining_loads -= 1; + } + + // If we made it this far, then worker no longer has work. First beg fellow worker for work. + + // Then check if program as a whole is done running. + main_loop_bool = worker_check_status(); + } +} + + +/** + * Entrypoint for logic to run "Global Round Robin" load scheme. + */ +void grr_run(int total_processors) { + printf("Starting GRR load scheme."); + printf("\n"); + + // pthread_t* thread_pool = NULL; + + printf("\n"); + printf("GRR load scheme. Finished."); +} + + +/** + * Main processor logic for "Global Round Robin" load scheme. + */ +void grr_main(thread_struct* thread_args_ptr) { + +} + + +/** + * Worker processor logic for "Global Round Robin" load scheme. + */ +void grr_worker(thread_struct* thread_args_ptr) { + + +} + + +/** + * Entrypoint for logic to run "Random Poling" load scheme. + */ +void rp_run(int total_processors) { + printf("Starting RP load scheme."); + printf("\n"); + + // pthread_t* thread_pool = NULL; + + printf("\n"); + printf("RP load scheme. Finished."); +} + + +/** + * Main processor logic for "Random Poling" load scheme. + */ +void rp_main(thread_struct* thread_args_ptr) { + +} + + +/** + * Worker processor logic for "Random Poling" load scheme. + */ +void rp_worker(thread_struct* thread_args_ptr) { + +} + + + +/** + * Entrypoint for logic to run "Nearest Neighbor" load scheme. + */ +void nn_run(int total_processors) { + printf("Starting NN load scheme."); + printf("\n"); + + // pthread_t* thread_pool = NULL; + + printf("\n"); + printf("NN load scheme. Finished."); +} + + +/** + * Main processor logic for "Nearest Neighbor" load scheme. + */ +void nn_main(thread_struct* thread_args_ptr) { + +} + + + +/** + * Worker processor logic for "Nearest Neighbor" load scheme. + */ +void nn_worker(thread_struct* thread_args_ptr) { + + +} diff --git a/src/load_balance_schemes.h b/src/load_balance_schemes.h new file mode 100644 index 0000000000000000000000000000000000000000..a1c62bfe224b51cc82f5d5d67df4b69489a2b505 --- /dev/null +++ b/src/load_balance_schemes.h @@ -0,0 +1,30 @@ +/** + * Header file for specifc scheme "Load Balancing" logic. + */ + + +// System Import Headers. +#include <ctype.h> +#include <mpi.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +// Function Prototypes. +void arr_run(); // Encapsulated logic for "Asynchronous Round Robin" load scheme. +void arr_main(); // Main process logic for "Asynchronous Round Robin" load scheme. +void arr_worker(); // Worker process logic for "Asynchronous Round Robin" load scheme. + +void grr_run(); // Encapsulated logic for "Global Round Robin" load scheme. +void grr_main(); // Main process logic for "Global Round Robin" load scheme. +void grr_worker(); // Worker process logic for "Global Round Robin" load scheme. + +void rp_run(); // Encapsulated logic for "Random Polling" load scheme. +void rp_main(); // Main process logic for "Random Polling" load scheme. +void rp_worker(); // Worker process logic for "Random Polling" load scheme. + +void nn_run(); // Encapsulated logic for "Nearest Neighbor" load scheme. +void nn_main(); // Main process logic for "Nearest Neighbor" load scheme. +void nn_worker(); // Worker process logic for "Nearest Neighbor" load scheme. diff --git a/src/main.c b/src/main.c index e0df9b81dc7b816259c47a6f82f8a01838c817ea..558457013c77a1884c302df32b351b80459d18c4 100644 --- a/src/main.c +++ b/src/main.c @@ -17,7 +17,7 @@ // User Import Headers. #ifndef user_headers #define user_headers - #include "simulate_loads.h" + #include "load_balance_schemes.h" #include "structs.h" #include "terminal_commands.h" #endif @@ -179,7 +179,7 @@ void run_program() { total_processors, seconds_per_load, total_loads, process_rank ); - run_arr(thread_args_ptr); + arr_run(thread_args_ptr); free_thread_struct(thread_args_ptr); diff --git a/src/simulate_loads.c b/src/simulate_loads.c deleted file mode 100644 index 7597f75a4dfe1796b7daaedf95e157c00f13b537..0000000000000000000000000000000000000000 --- a/src/simulate_loads.c +++ /dev/null @@ -1,440 +0,0 @@ -/** - * File for load simulation logic. - */ - - -// User Import Headers. -#ifndef user_headers - #define user_headers - #include "simulate_loads.h" - #include "structs.h" - #include "terminal_commands.h" -#endif - - -/** - * Displays provided worker data through master process. - */ -void main_display_status(thread_struct* thread_args_ptr, int process_num, int process_load_status, int init_run) { - int index; - - // Travel to desired terminal row. Skip if first loop through thread displaying. - if (init_run == 0) { - for (index = 0; index < (thread_args_ptr->total_processors - process_num); index ++) { - terminal_line_up(); - } - } - // Clear row. - terminal_line_erase(); - terminal_line_start(); - - // Display message. - printf("Thread %5i: %5i / %5i Loads Remaining\n", process_num, process_load_status, thread_args_ptr->total_loads); - - // Travel back to original terminal location. Skip if first loop through thread displaying. - if (init_run == 0) { - for (index = 0; index < (thread_args_ptr->total_processors - process_num); index ++) { - terminal_line_down(); - } - terminal_line_start(); - } -} - - -/** - * Sends message to all worker processes that all work has been completed, and it's okay to terminate now. - */ -void main_terminate_workers(thread_struct* thread_args_ptr) { - int program_end_tag = 1; - int index; - MPI_Request request_var; // What is this for?? Why is it required? - - for (index = 1; index < thread_args_ptr->total_processors; index++) { - MPI_Isend(&program_end_tag, 1, MPI_INT, index, program_end_tag, MPI_COMM_WORLD, &request_var); - // printf("Sending termination message to process %i.\n", index); - // MPI_Send(&program_end_tag, 1, MPI_INT, index, program_end_tag, MPI_COMM_WORLD); - // printf("Process %i received termination message.\n", index); - } - -} - - -/** - * Sends worker load status and rank to master process. - */ -void worker_send_status(int process_rank, int process_load_status) { - int* send_array = calloc(2, sizeof(int)); - send_array[0] = process_rank; - send_array[1] = process_load_status; - MPI_Send(send_array, 2, MPI_INT, 0, 0, MPI_COMM_WORLD); - free(send_array); -} - - -/** - * Checks status of program runtime for worker to eventually get the okay to terminate. - * - * :return: 0 if received okay from main process to end. Otherwise 1 to continue working. - */ -int worker_check_status() { - int msg_status_flag = 0; - int temp = 0; - int main_process = 0; - int program_end_tag = 1; - - // Check for pending message from main process. - // Should only ocurr if main is telling child process that all work has completed. - MPI_Iprobe(main_process, program_end_tag, MPI_COMM_WORLD, &msg_status_flag, MPI_STATUS_IGNORE); - if (msg_status_flag == 1) { - // Message present. Officially grab message so master can unblock. - MPI_Recv(&temp, 1, MPI_INT, main_process, program_end_tag, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - return 0; - } - return 1; -} - - -/** - * Attempts to receive work from given "possible donor" process (donor is determined by load balancing schema). - * - * Does so by sending message to "possible donor" process, to initiate request. - * Once it gets around to message checking, donor will then send back a message of: - * * -1 indicating donor does not have work to give. - * * Positive integer of work being passed back to begging process. - */ -int worker_send_request(thread_struct* thread_args_ptr, int possible_donor) { - int donor_response = 0; - - // Initialilze interaction by sending a "begging message" for work. - MPI_Send(&donor_response, 1, MPI_INT, possible_donor, 0, MPI_COMM_WORLD); - - // If got this far, then we have unblocked. Means that "possible donor" process is sending a response. - MPI_Recv(&donor_response, 1, MPI_INT, possible_donor, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - // Check what response was and handle accoringly. - if (donor_response > 0) { - // Donor sent workload to process. - thread_args_ptr->remaining_loads = donor_response; - return 1; - } else { - // Donor sent reject message. - return 0; - } -} - - -/** - * Checks if worker has any pending work requests from other processes. - * On any pending request, checks if request exists on all processes. - * - * To handle request, either splits current work load in half (asking process gets the smaller portion if odd number) - * or returns negative number if no work to send. - */ -void worker_handle_request(thread_struct* thread_args_ptr) { - int msg_status_flag = 0; - int work_send_value = 0; - int temp = 0; - int index; - - MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &msg_status_flag, MPI_STATUS_IGNORE); - if (msg_status_flag == 1) { - - // One or more messages present. Loop through and check for message from all processors. - for (index = 1; index < thread_args_ptr->total_processors; index++) { - msg_status_flag = 0; - MPI_Iprobe(index, MPI_ANY_TAG, MPI_COMM_WORLD, &msg_status_flag, MPI_STATUS_IGNORE); - if (msg_status_flag == 1) { - // Message present from processor at corresponding index. Handle. - - // First, properly "receive" pending message, so asking worker can unblock. - MPI_Recv(&temp, 1, MPI_INT, index, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - // Check if donating worker has work to split and send. - if (thread_args_ptr->remaining_loads > 1) { - // Worker has at least one load to split and send. Do so. - work_send_value = thread_args_ptr->remaining_loads / 2; - thread_args_ptr->remaining_loads = work_send_value + (thread_args_ptr->remaining_loads % 2); - MPI_Send(&work_send_value, 1, MPI_INT, index, 0, MPI_COMM_WORLD); - } else { - // Worker has exactly 0 or 1 loads. Not enough to send. Reject request instead. - work_send_value = -1; - MPI_Send(&work_send_value, 1, MPI_INT, index, 0, MPI_COMM_WORLD); - } - - } - } - - } -} - - -/** - * Logic to run "Asynchronous Round Robin" load scheme. - */ -void run_arr(thread_struct* thread_args_ptr) { - int process_rank = thread_args_ptr->thread_num; - - if (process_rank == 0) { - printf("Starting ARR load scheme.\n"); - printf("\n"); - } - - // Wait for all processes to synchronize. - // Also sleep for a second to allow time for console output to process. - MPI_Barrier(MPI_COMM_WORLD); - sleep(1); - - // Handle based on process number. - if (process_rank > 0) { - // Child process. Handles all the work. - worker_arr(thread_args_ptr); - } else { - // Main process. Handles communication to terminal. - main_arr(thread_args_ptr); - } - - // Wait for all processes to synchronize. - // Also sleep for a second to allow time for console output to process. - MPI_Barrier(MPI_COMM_WORLD); - sleep(1); - - if (process_rank == 0) { - printf("\n"); - printf("ARR load scheme. Finished.\n"); - } -} - - -/** - * Main processor logic for "Asynchronous Round Robin" load scheme. - */ -void main_arr(thread_struct* thread_args_ptr) { - int index; - int main_loop_bool = 1; - int init_run = 1; - int msg_status_flag; - int msg_recieved = 0; - int* recv_array; - - // Initialize console display. - for (index = 1; index < thread_args_ptr->total_processors; index++) { - recv_array = calloc(3, sizeof(int)); - MPI_Recv(recv_array, 2, MPI_INT, index, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - main_display_status(thread_args_ptr, recv_array[0], recv_array[1], init_run); - free(recv_array); - } - - // Continually grab messages from all worker processors until done. - // For each loop, it checks all worker processes for a message about work being done. - // If no messages are found for two consecutive loops in a row, then assumes all work is complete and terminates. - index = 1; - init_run = 0; - while (main_loop_bool == 1) { - msg_status_flag = 0; - - // Check if message present from respective process. - MPI_Iprobe(index, MPI_ANY_TAG, MPI_COMM_WORLD, &msg_status_flag, MPI_STATUS_IGNORE); - if (msg_status_flag == 1) { - msg_recieved = 1; - - // Message present. Retrieve and handle. - recv_array = calloc(3, sizeof(int)); - MPI_Recv(recv_array, 2, MPI_INT, index, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - main_display_status(thread_args_ptr, recv_array[0], recv_array[1], init_run); - free(recv_array); - } - - // Increment for next thread. - index = (index + 1) % thread_args_ptr->total_processors; - - // Check if past last processor. - if (index == 0) { - index += 1; - - // Check if messages were recieved this run. - if (msg_recieved == 0) { - // No messages recieved. Run one last loop to double check. - msg_recieved = -1; - sleep(2); - } else if (msg_recieved == -1) { - // No messages recieved for two loops in a row. Terminate. - main_terminate_workers(thread_args_ptr); - main_loop_bool = 0; - } else { - // One or more messages recieved this loop. Reset value. - msg_recieved = 0; - } - - // Sleep number of seconds provided by user terminal. - // Meant to simulate "work", as it forces each worker process to block for this amount of time each load, - // before continuing on. In a real program, the worker would be doing something useful in this time, - // instead of just blocking. - sleep(thread_args_ptr->seconds_per_load); - } - - } -} - - -/** - * Worker processor logic for "Asynchronous Round Robin" load scheme. - */ -void worker_arr(thread_struct* thread_args_ptr) { - int process_rank = thread_args_ptr->thread_num; - int arr_counter = thread_args_ptr->thread_num; - int main_loop_bool = 1; - int index; - int msg_status_flag; - - // Initialize process "1" to have full loads. All others start with none. - if (process_rank == 1) { - thread_args_ptr->remaining_loads = thread_args_ptr->total_loads; - } else { - thread_args_ptr->remaining_loads = 0; - } - - // Main loop bool. Continues until main process says all work is done. - while (main_loop_bool == 1) { - - // Loop all worker processes until load count message of "0" has been sent. - while (thread_args_ptr->remaining_loads >= 0) { - - // Send message for current load. - worker_send_status(process_rank, thread_args_ptr->remaining_loads); - - // Check for message requests from other processes. - worker_handle_request(thread_args_ptr); - - // Decriment load number. - thread_args_ptr->remaining_loads -= 1; - } - - // If we made it this far, then worker no longer has work. First beg fellow worker for work. - - // Then check if program as a whole is done running. - main_loop_bool = worker_check_status(); - } -} - - -/** - * Logic to run "Global Round Robin" load scheme. - */ -void run_grr(int total_processors) { - printf("Starting GRR load scheme."); - printf("\n"); - - // pthread_t* thread_pool = NULL; - - printf("\n"); - printf("GRR load scheme. Finished."); -} - - -/** - * Logic to run "Random Poling" load scheme. - */ -void run_rp(int total_processors) { - printf("Starting RP load scheme."); - printf("\n"); - - // pthread_t* thread_pool = NULL; - - printf("\n"); - printf("RP load scheme. Finished."); -} - - - -/** - * Logic to run "Nearest Neighbor" load scheme. - */ -void run_nn(int total_processors) { - printf("Starting NN load scheme."); - printf("\n"); - - // pthread_t* thread_pool = NULL; - - printf("\n"); - printf("NN load scheme. Finished."); -} - - -// /** -// * Function to simulate working on a load. -// */ -// void simulate_load(char* thread_name) { -// printf("Simulating load processing on thread \"%s\".\n", thread_name); - -// int load_counter = 0; -// int index = 0; - -// // Iterate through loads. Each load has indexes to simulate "work". -// while (load_counter < total_loads) { - -// // Increment load num. -// load_counter += 1; -// printf("Simulating load %i on thread \"%s\".\n", load_counter, thread_name); - -// // Simulate running the load. -// index = 0; -// while (index < indexes_per_load) { - -// // Print out index value. -// if ((index % 10) == 0) { -// printf("load %i / %i index %i / %i\n", load_counter, total_loads, index, indexes_per_load); -// } - -// // Wait 1 second to simulate work. -// sleep(1); - -// // Increment index. -// index += 1; -// } - -// } - -// } - - -/** - * Function to simulate working on an ARR load. - */ -// void* simulate_arr_load(thread_struct* thread_struct_ptr) { -// printf("Simulating load processing on thread \"%i\".\n", thread_struct_ptr->thread_num); - -// // Send message back to main thread. -// // char* message = "Thread %i checking in!\n"; -// // MPI_Send(message, sizeof(message) + 1, MPI_CHAR, 0, 0,) - -// // int load_counter = 0; -// // int index = 0; - -// // // Iterate through loads. Each load has indexes to simulate "work". -// // while (load_counter < total_loads) { - -// // // Increment load num. -// // load_counter += 1; -// // printf("Simulating load %i on thread \"%s\".\n", load_counter, thread_name); - -// // // Simulate running the load. -// // index = 0; -// // while (index < indexes_per_load) { - -// // // Print out index value. -// // if ((index % 10) == 0) { -// // printf("load %i / %i index %i / %i\n", load_counter, total_loads, index, indexes_per_load); -// // } - -// // // Wait 1 second to simulate work. -// // sleep(1); - -// // // Increment index. -// // index += 1; -// // } - -// // } - -// free(thread_struct_ptr); -// } - diff --git a/src/simulate_loads.h b/src/simulate_loads.h deleted file mode 100644 index 3d08d5ef27ca4e18fbfe4422ac5d3b966b548aa0..0000000000000000000000000000000000000000 --- a/src/simulate_loads.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Header file for load simulation logic. - */ - - -// System Import Headers. -#include <ctype.h> -#include <mpi.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - -// Function Prototypes. -void main_display_status(); -void main_terminate_workers(); -void worker_send_status(); -int worker_check_status(); -int worker_send_request(); -void worker_handle_request(); -void run_arr(); // Encapsulated logic for "Asynchronous Round Robin" load scheme. -void main_arr(); -void worker_arr(); -void run_grr(); // Encapsulated logic for "Global Round Robin" load scheme. -void run_rp(); // Encapsulated logic for "Random Poling" load scheme. -void run_nn(); // Encapsulated logic for "Nearest Neighbor" load scheme. -void simulate_load(); // Simulates running one load. -void* simulate_arr_load(); // Thread entrypoint for an "Asynchronous Round Robin" load. -void* simulate_grr_load(); // Thread entrypoint for a "Global Round Robin" load. -void* simulate_rp_load(); // Thread entrypoint for a "Random Polling" load. -void* simulate_nn_load(); // Thread entrypoint for a "Nearest Neigher" load. diff --git a/src/structs.c b/src/structs.c index c1a05520f01324fec34e6a9d5adb53e917143ad1..88244988f4e504ad12add7d69a8a3f09e7680666 100644 --- a/src/structs.c +++ b/src/structs.c @@ -6,7 +6,6 @@ // User Import Headers. #ifndef user_headers #define user_headers - #include "simulate_loads.h" #include "structs.h" #endif diff --git a/src/terminal_commands.c b/src/terminal_commands.c index a44a46ba4289c4e7b896ea27b503ce749087651c..33d9876a78634a13bd008a3bad930085bc3433ff 100644 --- a/src/terminal_commands.c +++ b/src/terminal_commands.c @@ -7,8 +7,6 @@ // User Import Headers. #ifndef user_headers #define user_headers - #include "simulate_loads.h" - #include "structs.h" #include "terminal_commands.h" #endif