Parallel Programming - Stuff happened
[matches/honours.git] / course / semester2 / pprog / assignment1 / openmp / nbody.c
1 /**
2  * @file nbody.c
3  * @purpose OpenMP version of N-Body simulator, implementation
4  * @author Sam Moore (20503628) - 2012
5  */
6
7 #include "nbody.h"
8 #include "../single-thread/nbody.c" // Include original code
9 #include "graphics.h" // For Graphics_Run function only
10
11 omp_lock_t graphics_lock;
12 bool graphics_busy = false;
13
14 /**
15  * @function Simulation_Run
16  * @purpose Start the simulation
17  * @param argc, argv - Passed to Graphics_Run if needed, otherwise unused
18  */
19 void Simulation_Run(int argc, char ** argv)
20 {       
21         omp_set_nested(1);
22         if (omp_get_nested() != 1)
23         {
24                 fprintf(stderr, "Couldn't set nested parallelism, I kind of need that\n");
25                 exit(EXIT_FAILURE);
26         }       
27                 
28
29         if (options.num_threads == 0)
30                 options.num_threads = omp_get_max_threads();
31
32         if (options.draw_graphics)
33                 omp_set_num_threads(2);
34         else
35                 omp_set_num_threads(1);
36
37
38         omp_init_lock(&graphics_lock);
39
40         #pragma omp parallel sections
41         {
42                 
43                 #pragma omp section
44                 {
45                         omp_set_num_threads(options.num_threads);
46                         while (true)
47                         {
48                                 
49                                 if (runstate != RUN) break; //Check whether the main thread wants to exit
50                                 
51                                 if (ExitCondition())
52                                 {
53                                         break;
54                                 }                               
55
56                                 if (options.verbosity != 0 && universe.steps % options.verbosity == 1)
57                                 {
58                                         DisplayStatistics();
59                                 }
60                                 
61                                                 
62                                 Compute();
63                         }
64                         //printf("Left compute loop\n");
65                 }
66
67                 #pragma omp section
68                 {
69                         if (options.draw_graphics)
70                                 Graphics_Run(argc, argv);
71                         //printf("Got to bit after Graphics_Run()\n");
72                 }
73
74         }
75
76         omp_destroy_lock(&graphics_lock);
77 }
78
79 /**
80  * @function Compute
81  * @purpose Compute a single step, multithreaded using OpenMP
82  */
83 void Compute(void)
84 {
85         //printf("There are %d threads working and %d available\n", omp_get_num_threads(), omp_get_max_threads());
86         //return;
87         unsigned n_per_thread = (universe.N) / options.num_threads;
88         unsigned remainder = (universe.N) % options.num_threads;
89         #pragma omp parallel for
90         for (unsigned i = 0; i < options.num_threads; ++i)
91         {
92                 //printf("Thread %d executes iteration %u\n", omp_get_thread_num(), i);
93                 System s;
94                 s.body = universe.body + (i * n_per_thread);
95                 s.N = (i == options.num_threads - 1) ? n_per_thread : n_per_thread + remainder;
96                 System_Forces(&s, &universe);
97         }
98
99         // Wait for graphics to finish drawing
100
101         if (options.draw_graphics && options.pedantic_graphics)
102         {
103                 while (graphics_busy);
104         }       
105
106         #pragma omp parallel for
107         for (unsigned i = 0; i < options.num_threads; ++i)
108         {
109                 //printf("Thread %d executes iteration %u\n", omp_get_thread_num(), i);
110                 System s;
111                 s.body = universe.body + (i * n_per_thread);
112                 s.N = (i == options.num_threads - 1) ? n_per_thread : n_per_thread + remainder;
113                 System_Positions(&s);
114         }
115
116         universe.steps += 1;
117
118         // Tell graphics to continue
119         if (options.draw_graphics && options.pedantic_graphics)
120         {
121                 omp_set_lock(&graphics_lock);
122                 graphics_busy = true;
123                 omp_unset_lock(&graphics_lock);
124                 
125         }
126
127 }
128
129 /**
130  * @function BeforeDraw
131  * @purpose Called before the graphics thread draws bodies. 
132  *      If pedantic graphics are used, will wait until graphics_busy is set to true before drawing
133  */
134 void BeforeDraw()
135 {
136         if (options.verbosity != 0 && universe.steps % options.verbosity == 0)
137                 DisplayStatistics();
138         if (!options.pedantic_graphics)
139                 return;
140         while (graphics_busy == false);
141 }
142
143 /**
144  * @function AfterDraw
145  * @purpose Called after the graphics thread draws bodies
146  *      If pedantic graphics used, will unset graphics_busy when done drawing
147  */
148 void AfterDraw()
149 {
150         if (!options.pedantic_graphics)
151                 return;
152         omp_set_lock(&graphics_lock);
153         graphics_busy = false;
154         omp_unset_lock(&graphics_lock);
155 }

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