X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=course%2Fsemester2%2Fpprog%2Fassignment1%2Fopenmp%2Fnbody.c;h=053625bbc513b11ee124cbaa8d7ff263da6ec1ec;hb=bb7fa31ea517a1fba064e723b37d5b8d8bd7dd72;hp=1d2f3690ddde320cba5b44c98a0bddc2a44acb75;hpb=6529f76db3022ec72ca7718d5e2bc3f176b474e9;p=matches%2Fhonours.git diff --git a/course/semester2/pprog/assignment1/openmp/nbody.c b/course/semester2/pprog/assignment1/openmp/nbody.c index 1d2f3690..053625bb 100644 --- a/course/semester2/pprog/assignment1/openmp/nbody.c +++ b/course/semester2/pprog/assignment1/openmp/nbody.c @@ -8,8 +8,10 @@ #include "../single-thread/nbody.c" // Include original code #include "graphics.h" // For Graphics_Run function only -omp_lock_t graphics_lock; -bool graphics_busy = false; + +#ifdef OVER_ENGINEERED +System * sub_system = NULL; +#endif //OVER_ENGINEERED /** * @function Simulation_Run @@ -18,138 +20,119 @@ bool graphics_busy = false; */ 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); - + { + Graphics_Run(argc, argv); + if (options.pedantic_graphics == false) + { + options.num_threads += 1; + omp_set_nested(1); + if (omp_get_nested() == 0) + { + fprintf(stderr, "Couldn't enable nested parallelism\n."); + exit(EXIT_FAILURE); + } - omp_init_lock(&graphics_lock); - #pragma omp parallel sections - { - - #pragma omp section - { - omp_set_num_threads(options.num_threads); - while (true) + #pragma omp parallel sections num_threads(2) { - - if (runstate != RUN) break; //Check whether the main thread wants to exit - - if (ExitCondition()) + #pragma omp section { - break; - } - - if (options.verbosity != 0 && universe.steps % options.verbosity == 1) + Compute(); + } + #pragma omp section { - DisplayStatistics(); + glutMainLoop(); } - - - Compute(); } - //printf("Left compute loop\n"); + return; } + } + Compute(); - #pragma omp section - { - if (options.draw_graphics) - Graphics_Run(argc, argv); - //printf("Got to bit after Graphics_Run()\n"); - } - } - omp_destroy_lock(&graphics_lock); } -/** - * @function Compute - * @purpose Compute a single step, multithreaded using OpenMP - */ -void Compute(void) + +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) + omp_set_num_threads(options.num_threads); + if (omp_get_max_threads() != options.num_threads) { - //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); + fprintf(stderr, "Couldn't use %d threads!\n", options.num_threads); + exit(EXIT_FAILURE); } - // Wait for graphics to finish drawing - - if (options.draw_graphics && options.pedantic_graphics) - { - while (graphics_busy); - } + #ifdef OVER_ENGINEERED + sub_system = Split_System(&universe, options.num_threads); // I could use omp for loops instead, but I like this way + #endif //OVER_ENGINEERED - #pragma omp parallel for - for (unsigned i = 0; i < options.num_threads; ++i) + #pragma omp parallel { - //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; + #ifdef OVER_ENGINEERED + int index = omp_get_thread_num(); + #endif //OVER_ENGINEERED + while (!ExitCondition()) + { - // Tell graphics to continue - if (options.draw_graphics && options.pedantic_graphics) - { - omp_set_lock(&graphics_lock); - graphics_busy = true; - omp_unset_lock(&graphics_lock); + #ifdef OVER_ENGINEERED + System_Forces(sub_system+index, &universe); + #pragma omp barrier // Look! An explicit barrier! + System_Positions(sub_system+index); + #pragma omp barrier + #else + #pragma omp for + for (unsigned a = 0; a < universe.N; ++a) + { + for (unsigned i = 0; i < DIMENSIONS; ++i) + (universe.body+a)->F[i] = 0; + //printf("Thread %d computes force for body %d\n", omp_get_thread_num(), a); + omp_set_num_threads(options.nested_threads); + #pragma omp parallel for + for (unsigned b = 0; b < universe.N; ++b) + { + if (b != a) + Body_Force(universe.body+a, universe.body+b); + } + } - } + #pragma omp for + for (unsigned a = 0; a < universe.N; ++a) + { + //printf("Thread %d computes position for body %d\n", omp_get_thread_num(), a); + Body_Velocity(universe.body+a); + Body_Position(universe.body+a); + } -} + #endif //OVER_ENGINEERED -/** - * @function BeforeDraw - * @purpose Called before the graphics thread draws bodies. - * If pedantic graphics are used, will wait until graphics_busy is set to true before drawing - */ -void BeforeDraw() -{ - if (options.verbosity != 0 && universe.steps % options.verbosity == 0) - DisplayStatistics(); - if (!options.pedantic_graphics) - return; - while (graphics_busy == false); + #pragma omp master + { + // The if statement has a cost, but if can be removed easily in an optimised version. + // Only the main thread is allowed to mess with glut, because glut is evil (not thread safe). + // Although this function may be nested, that will only happen if the if would be false. + // ("if the if would be false"; I am awesome at explaining code) + if (options.draw_graphics && options.pedantic_graphics) + { + glutMainLoopEvent(); + Graphics_Display(); + } + } + #pragma omp single + { + // Only one thread should execute this, and we don't care which one. + // So much easier than the pthread version! + universe.steps += 1; + if (options.verbosity != 0 && universe.steps % options.verbosity == 0) + DisplayStatistics(); + } + + } + } } -/** - * @function AfterDraw - * @purpose Called after the graphics thread draws bodies - * If pedantic graphics used, will unset graphics_busy when done drawing - */ -void AfterDraw() -{ - if (!options.pedantic_graphics) - return; - omp_set_lock(&graphics_lock); - graphics_busy = false; - omp_unset_lock(&graphics_lock); -}