Parallel Programming - Finished OpenMP
[matches/honours.git] / course / semester2 / pprog / assignment1 / openmp / nbody.c
index 1d2f369..053625b 100644 (file)
@@ -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);
-}

UCC git Repository :: git.ucc.asn.au