From f012817dee17e24eee2e8951d138dab40b808ad3 Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Sun, 9 Sep 2012 18:53:14 +0800 Subject: [PATCH] Parallel Programming - Start OpenMP Version Almost finished --- .../pprog/assignment1/mthread/nbody.c | 49 ++++---- .../pprog/assignment1/mthread/nbody.h | 2 +- .../pprog/assignment1/openmp/Makefile | 1 + .../pprog/assignment1/openmp/graphics.c | 1 + .../pprog/assignment1/openmp/graphics.h | 1 + .../semester2/pprog/assignment1/openmp/main.c | 1 + .../pprog/assignment1/openmp/nbody.c | 107 ++++++++++++++++++ .../pprog/assignment1/openmp/nbody.h | 27 +++++ .../pprog/assignment1/single-thread/Makefile | 2 +- .../assignment1/single-thread/graphics.c | 33 +++--- .../assignment1/single-thread/graphics.h | 2 +- .../pprog/assignment1/single-thread/main.c | 6 +- .../pprog/assignment1/single-thread/nbody.c | 13 ++- .../pprog/assignment1/single-thread/nbody.h | 5 +- 14 files changed, 198 insertions(+), 52 deletions(-) create mode 120000 course/semester2/pprog/assignment1/openmp/Makefile create mode 120000 course/semester2/pprog/assignment1/openmp/graphics.c create mode 120000 course/semester2/pprog/assignment1/openmp/graphics.h create mode 120000 course/semester2/pprog/assignment1/openmp/main.c create mode 100644 course/semester2/pprog/assignment1/openmp/nbody.c create mode 100644 course/semester2/pprog/assignment1/openmp/nbody.h diff --git a/course/semester2/pprog/assignment1/mthread/nbody.c b/course/semester2/pprog/assignment1/mthread/nbody.c index afd1d607..42b97cf4 100644 --- a/course/semester2/pprog/assignment1/mthread/nbody.c +++ b/course/semester2/pprog/assignment1/mthread/nbody.c @@ -7,6 +7,8 @@ #include "nbody.h" // Declarations #include "../single-thread/nbody.c" // Include all functions from the single threaded version +#include "graphics.h" // For declaration of Graphics_Run only + // --- Variable declarations --- // pthread_t compute_thread; // The thread responsible for computations; it spawns worker threads @@ -86,19 +88,16 @@ void * Compute_Thread(void * arg) while (true) { - if (runstate != RUN) pthread_exit(NULL); //Check whether the main thread wants to exit + if (runstate != RUN) pthread_exit(NULL); //Check whether the thread needs to exit //Check whether the program should quit due to steps being computed, or a timeout - if (options.timeout > 0.0) + if (ExitCondition()) { - if ((unsigned)(time(NULL) - options.start_time.tv_sec) >= options.timeout) - QuitProgram(false); - } - - if (options.num_steps > 0 && universe.steps > options.num_steps) QuitProgram(false); + continue; // The check at the start of the next loop will stop the thread + } if (options.draw_graphics == false && options.verbosity != 0 && universe.steps % options.verbosity == 1) @@ -217,7 +216,8 @@ void * Position_Thread(void * s) */ void QuitProgram(bool error) { - + if (runstate == QUIT || runstate == QUIT_ERROR) + return; //Don't do anything if already quitting pthread_mutex_lock(&mutex_runstate); // aquire mutex if (error) // set the runstate runstate = QUIT_ERROR; @@ -247,29 +247,24 @@ void Thread_Cleanup(void) * @function Simulation_Run * @purpose Initialise and start the simulation. Will be called in the main thread. * Replaces the single-threaded macro that does nothing, and sets up the compute thread + * @param argc - Number of arguments - Passed to Graphics_Run if needed + * @param argv - Argument strings - Passed to Graphics_Run if needed */ -void Simulation_Run() +void Simulation_Run(int argc, char ** argv) { atexit(Thread_Cleanup); - if (options.draw_graphics == false) - { - Compute_Thread((void*)(&universe)); - - // If there are no graphics, run the computation loop in the main thread - // The call to pthread_exit(NULL) in the computation loop ends the main thread - - // This means the main function never calls the Graphics_Run function - // Without this condition here, Graphics_Display would essentially be running a busy loop in the main thread - - fprintf(stderr,"Should not see this\n"); - exit(EXIT_FAILURE); - } - - // Create a thread to handle computation loop - if (pthread_create(&compute_thread, NULL, Compute_Thread, (void*)&universe) != 0) + if (options.draw_graphics) { - perror("Error creating compute thread"); - exit(EXIT_FAILURE); + // The graphics are enabled, so create a thread to do computations + // Graphics are done in the main loop + if (pthread_create(&compute_thread, NULL, Compute_Thread, (void*)&universe) != 0) + { + perror("Error creating compute thread"); + exit(EXIT_FAILURE); + } + Graphics_Run(argc, argv); } + else + Compute_Thread((void*)(&universe)); // Graphics are disabled, so do computations in the main thread } diff --git a/course/semester2/pprog/assignment1/mthread/nbody.h b/course/semester2/pprog/assignment1/mthread/nbody.h index 9b76bc75..0b3208a9 100644 --- a/course/semester2/pprog/assignment1/mthread/nbody.h +++ b/course/semester2/pprog/assignment1/mthread/nbody.h @@ -12,7 +12,7 @@ //Undefine default macros, replace with functions #undef Simulation_Run -void Simulation_Run(void); +void Simulation_Run(int argc, char ** argv); #undef QuitProgram void QuitProgram(bool error); diff --git a/course/semester2/pprog/assignment1/openmp/Makefile b/course/semester2/pprog/assignment1/openmp/Makefile new file mode 120000 index 00000000..b0d614da --- /dev/null +++ b/course/semester2/pprog/assignment1/openmp/Makefile @@ -0,0 +1 @@ +../single-thread/Makefile \ No newline at end of file diff --git a/course/semester2/pprog/assignment1/openmp/graphics.c b/course/semester2/pprog/assignment1/openmp/graphics.c new file mode 120000 index 00000000..6fc2284c --- /dev/null +++ b/course/semester2/pprog/assignment1/openmp/graphics.c @@ -0,0 +1 @@ +../single-thread/graphics.c \ No newline at end of file diff --git a/course/semester2/pprog/assignment1/openmp/graphics.h b/course/semester2/pprog/assignment1/openmp/graphics.h new file mode 120000 index 00000000..aebee138 --- /dev/null +++ b/course/semester2/pprog/assignment1/openmp/graphics.h @@ -0,0 +1 @@ +../single-thread/graphics.h \ No newline at end of file diff --git a/course/semester2/pprog/assignment1/openmp/main.c b/course/semester2/pprog/assignment1/openmp/main.c new file mode 120000 index 00000000..37e59853 --- /dev/null +++ b/course/semester2/pprog/assignment1/openmp/main.c @@ -0,0 +1 @@ +../single-thread/main.c \ No newline at end of file diff --git a/course/semester2/pprog/assignment1/openmp/nbody.c b/course/semester2/pprog/assignment1/openmp/nbody.c new file mode 100644 index 00000000..69988922 --- /dev/null +++ b/course/semester2/pprog/assignment1/openmp/nbody.c @@ -0,0 +1,107 @@ +/** + * @file nbody.c + * @purpose OpenMP version of N-Body simulator, implementation + * @author Sam Moore (20503628) - 2012 + */ + +#include "nbody.h" +#include "../single-thread/nbody.c" // Include original code +#include "graphics.h" // For Graphics_Run function only + +/** + * @function Simulation_Run + * @purpose Start the simulation + * @param argc, argv - Passed to Graphics_Run if needed, otherwise unused + */ +void Simulation_Run(int argc, char ** argv) +{ + omp_set_nested(1); + if (omp_get_nested() != 1) + { + fprintf(stderr, "Couldn't set nested parallelism, I kind of need that\n"); + exit(EXIT_FAILURE); + } + + + if (options.num_threads == 0) + options.num_threads = omp_get_max_threads(); + + if (options.draw_graphics) + omp_set_num_threads(2); + else + omp_set_num_threads(1); + + + + + #pragma omp parallel sections + { + + #pragma omp section + { + omp_set_num_threads(options.num_threads); + while (true) + { + + if (runstate != RUN) break; //Check whether the main thread wants to exit + + if (ExitCondition()) + { + break; + } + + + if (options.draw_graphics == false && options.verbosity != 0 + && universe.steps % options.verbosity == 1) + { + DisplayStatistics(); + } + + + Compute(); + } + } + + #pragma omp section + { + if (options.draw_graphics) + Graphics_Run(argc, argv); + printf("Got to bit after Graphics_Run()\n"); + } + + } +} + +/** + * @function Compute + * @purpose Compute a single step, multithreaded using OpenMP + */ +void Compute(void) +{ + //printf("There are %d threads working and %d available\n", omp_get_num_threads(), omp_get_max_threads()); + //return; + unsigned n_per_thread = (universe.N) / options.num_threads; + unsigned remainder = (universe.N) % options.num_threads; + #pragma omp parallel for + for (unsigned i = 0; i < options.num_threads; ++i) + { + //printf("Thread %d executes iteration %u\n", omp_get_thread_num(), i); + System s; + s.body = universe.body + (i * n_per_thread); + s.N = (i == options.num_threads - 1) ? n_per_thread : n_per_thread + remainder; + System_Forces(&s, &universe); + } + + #pragma omp parallel for + for (unsigned i = 0; i < options.num_threads; ++i) + { + //printf("Thread %d executes iteration %u\n", omp_get_thread_num(), i); + System s; + s.body = universe.body + (i * n_per_thread); + s.N = (i == options.num_threads - 1) ? n_per_thread : n_per_thread + remainder; + System_Positions(&s); + } + + universe.steps += 1; + +} diff --git a/course/semester2/pprog/assignment1/openmp/nbody.h b/course/semester2/pprog/assignment1/openmp/nbody.h new file mode 100644 index 00000000..b7d0b417 --- /dev/null +++ b/course/semester2/pprog/assignment1/openmp/nbody.h @@ -0,0 +1,27 @@ +#ifndef _NBODY_OPENMP_H +#define _NBODY_OPENMP_H + +/** + * @file nbody.h + * @purpose OpenMP version of N-Body simulator, declarations + * @author Sam Moore (20503628) - 2012 + */ + +#include "../single-thread/nbody.h" //Include original code +#include + + +#undef SINGLE_THREADED +#define OMP_THREADED + +// Replace default macros with thread-safe functions +#undef Simulation_Run +void Simulation_Run(int argc, char ** argv); +//#undef QuitProgram +//void QuitProgram(bool error); + +void Compute(); //Compute a single step + +#endif //_NBODY_OPENMP_H + +//EOF diff --git a/course/semester2/pprog/assignment1/single-thread/Makefile b/course/semester2/pprog/assignment1/single-thread/Makefile index f34eab2a..b1640378 100644 --- a/course/semester2/pprog/assignment1/single-thread/Makefile +++ b/course/semester2/pprog/assignment1/single-thread/Makefile @@ -11,7 +11,7 @@ LINK_OBJ = main.o nbody.o graphics.o BIN = nbody $(BIN) : $(LINK_OBJ) - $(CXX) -o $(BIN) $(LINK_OBJ) $(LIBRARIES) + $(CXX) -o $(BIN) $(LINK_OBJ) $(PREPROCESSOR_FLAGS) $(LIBRARIES) nbody : diff --git a/course/semester2/pprog/assignment1/single-thread/graphics.c b/course/semester2/pprog/assignment1/single-thread/graphics.c index e3722e9c..1b4fcb31 100644 --- a/course/semester2/pprog/assignment1/single-thread/graphics.c +++ b/course/semester2/pprog/assignment1/single-thread/graphics.c @@ -14,6 +14,7 @@ #include "graphics.h" //Function declarations #include "nbody.h" //The simulation +#include // --- Variable definitions --- // double previousTime, eyeTheta, eyePhi, eyeRho; @@ -106,37 +107,34 @@ void Graphics_Run(int argc, char ** argv) */ void Graphics_Display() { + //Check whether the program should quit due to steps being computed, or a timeout + if (ExitCondition()) + { + glutLeaveMainLoop(); + return; + } - if (options.verbosity != 0 && universe.steps % options.verbosity == 1) - DisplayStatistics(); - #ifdef SINGLE_THREADED + if (options.verbosity != 0 && universe.steps % options.verbosity == 1) + DisplayStatistics(); System_Compute(&universe); - - //Check whether the program should quit due to steps being computed, or a timeout - if (options.timeout > 0.0) - { - if ((unsigned)(time(NULL) - options.start_time.tv_sec) >= options.timeout) - exit(EXIT_SUCCESS); - } - if (options.num_steps > 0 && universe.steps > options.num_steps) - exit(EXIT_SUCCESS); - - #endif + //Check whether the runstate has been set to quit the program switch (runstate) { case RUN: break; case QUIT: - exit(EXIT_SUCCESS); + glutLeaveMainLoop(); + return; break; case QUIT_ERROR: - exit(EXIT_FAILURE); + glutLeaveMainLoop(); + return; break; } @@ -172,7 +170,8 @@ void Graphics_Keyboard(unsigned char theKey, int mouseX, int mouseY) { if (theKey == 'x' || theKey == 'X') { - exit(EXIT_SUCCESS); + glutLeaveMainLoop(); + return; } if (theKey == 'i' || theKey == 'I') { diff --git a/course/semester2/pprog/assignment1/single-thread/graphics.h b/course/semester2/pprog/assignment1/single-thread/graphics.h index 2fbc0a6a..c2b99f38 100644 --- a/course/semester2/pprog/assignment1/single-thread/graphics.h +++ b/course/semester2/pprog/assignment1/single-thread/graphics.h @@ -28,7 +28,7 @@ #define WORLD_FAR 1000000 #define BALL_SIZE 0.5 #define REFRESH_RATE 0.001 -#define LINE_SIZE 1000 + void Graphics_Run(int argc, char ** argv); void Graphics_Display(void); diff --git a/course/semester2/pprog/assignment1/single-thread/main.c b/course/semester2/pprog/assignment1/single-thread/main.c index f9f3b529..4b0c48ac 100644 --- a/course/semester2/pprog/assignment1/single-thread/main.c +++ b/course/semester2/pprog/assignment1/single-thread/main.c @@ -80,9 +80,9 @@ int main(int argc, char** argv) } options.start_clock = clock(); //Get CPU cycles executed before simulation starts - Simulation_Run(); // Start the simulation - Graphics_Run(argc, argv); //Start the graphics loop - + Simulation_Run(argc, argv); // Start the simulation + + printf("Got here!\n"); exit(EXIT_FAILURE); //Should never get to this line } diff --git a/course/semester2/pprog/assignment1/single-thread/nbody.c b/course/semester2/pprog/assignment1/single-thread/nbody.c index 47820d17..67c36d3b 100644 --- a/course/semester2/pprog/assignment1/single-thread/nbody.c +++ b/course/semester2/pprog/assignment1/single-thread/nbody.c @@ -136,7 +136,6 @@ void System_Positions(System * s) * @param s - The System * @param fileName - The input file */ -#define LINE_SIZE BUFSIZ void System_Init(System * s, const char *fileName) { char line[LINE_SIZE]; @@ -226,3 +225,15 @@ void DisplayStatistics() printf("%u\t%f\t%u\t%f\n", universe.steps, runtime, (unsigned)(end - options.start_clock), clock_time); } + +/** + * @function ExitCondition + * @purpose Helper to check whether the program is supposed to exit + * Does not check for user triggered quit + * Checks for either a timeout, or computation of the required number of steps + */ +bool ExitCondition(void) +{ + return ((options.timeout > 0.00 && ((unsigned)(time(NULL) - options.start_time.tv_sec) >= options.timeout)) + || (options.num_steps > 0 && universe.steps > options.num_steps)); +} diff --git a/course/semester2/pprog/assignment1/single-thread/nbody.h b/course/semester2/pprog/assignment1/single-thread/nbody.h index b8c98135..fc19d059 100644 --- a/course/semester2/pprog/assignment1/single-thread/nbody.h +++ b/course/semester2/pprog/assignment1/single-thread/nbody.h @@ -18,13 +18,14 @@ #define SINGLE_THREADED //These macros will be undefined by the multithreaded versions -#define Simulation_Run() //Sets up the simulation; in multithreaded versions, will spawn threads +#define Simulation_Run(argc, argv) (Graphics_Run(argc, argv)) //Sets up the simulation; in multithreaded versions, will spawn threads #define QuitProgram(error) (runstate = (error == true) ? QUIT : QUIT_ERROR) //Prepares to exit program, is thread safe in multithreaded versions #define M_PI 3.14159265358979323846264338327950288 /* pi */ #define G 6.67428E-11 #define DELTA_T 0.05 #define DIMENSIONS 3 +#define LINE_SIZE 1000 #define square(x) ((x)*(x)) @@ -95,6 +96,8 @@ void Universe_Cleanup(); //Cleanup universe and write bodies to file void DisplayStatistics(); // Print information about steps computed, total (real) runtime, and CPU cycles +bool ExitCondition(void); //Checks whether the program is supposed to exit automatically yet (ie: other than the user pressing "quit") + typedef enum {RUN, QUIT, QUIT_ERROR} RUNSTATE; extern RUNSTATE runstate; // Set runstate to QUIT or QUIT_ERROR and the simulation will stop on the next step. -- 2.20.1