3 * @purpose OpenMP version of N-Body simulator, implementation
4 * @author Sam Moore (20503628) - 2012
8 #include "../single-thread/nbody.c" // Include original code
9 #include "graphics.h" // For Graphics_Run function only
12 #ifdef OVER_ENGINEERED
13 System * sub_system = NULL;
14 #endif //OVER_ENGINEERED
16 omp_lock_t runstate_lock;
19 * @function Simulation_Run
20 * @purpose Start the simulation
21 * @param argc, argv - Passed to Graphics_Run if needed, otherwise unused
23 void Simulation_Run(int argc, char ** argv)
25 omp_init_lock(&runstate_lock);
26 if (options.num_threads == 0)
27 options.num_threads = omp_get_max_threads();
29 if (options.draw_graphics)
31 Graphics_Run(argc, argv);
32 if (options.pedantic_graphics == false)
34 options.num_threads += 1;
36 if (omp_get_nested() == 0)
38 fprintf(stderr, "Couldn't enable nested parallelism\n.");
43 #pragma omp parallel num_threads(2)
45 // This can't be done with sections!
46 // Because glut is useless, and can only be dealt with in the main thread
47 // I just hope that thread "0" is always the main thread!
48 if (omp_get_thread_num() == 0) // #pragma omp section
50 //printf("Thread %d gets graphics\n", omp_get_thread_num());
52 QuitProgram(false); // Program gets to here if the window is quit
54 else // #pragma omp section
56 //printf("Thread %d gets computations\n", omp_get_thread_num());
66 omp_destroy_lock(&runstate_lock);
72 omp_set_num_threads(options.num_threads);
73 if (omp_get_max_threads() != options.num_threads)
75 fprintf(stderr, "Couldn't use %d threads!\n", options.num_threads);
79 #ifdef OVER_ENGINEERED
80 sub_system = Split_System(&universe, options.num_threads); // I could use omp for loops instead, but I like this way
81 #endif //OVER_ENGINEERED
85 #ifdef OVER_ENGINEERED
86 int index = omp_get_thread_num();
87 #endif //OVER_ENGINEERED
88 while (!ExitCondition())
91 #ifdef OVER_ENGINEERED
92 System_Forces(sub_system+index, &universe);
93 #pragma omp barrier // Look! An explicit barrier!
94 System_Positions(sub_system+index);
98 for (unsigned a = 0; a < universe.N; ++a)
100 for (unsigned i = 0; i < DIMENSIONS; ++i)
101 (universe.body+a)->F[i] = 0;
102 //printf("Thread %d computes force for body %d\n", omp_get_thread_num(), a);
103 omp_set_num_threads(options.nested_threads);
104 #pragma omp parallel for
105 for (unsigned b = 0; b < universe.N; ++b)
108 Body_Force(universe.body+a, universe.body+b);
113 for (unsigned a = 0; a < universe.N; ++a)
115 //printf("Thread %d computes position for body %d\n", omp_get_thread_num(), a);
116 Body_Velocity(universe.body+a);
117 Body_Position(universe.body+a);
120 #endif //OVER_ENGINEERED
124 // The if statement has a cost, but if can be removed easily in an optimised version.
125 // Only the main thread is allowed to mess with glut, because glut is evil (not thread safe).
126 // Although this function may be nested, that will only happen if the if would be false.
127 // ("if the if would be false"; I am awesome at explaining code)
128 if (options.draw_graphics && options.pedantic_graphics)
136 // Only one thread should execute this, and we don't care which one.
137 // So much easier than the pthread version!
139 if (options.verbosity != 0 && universe.steps % options.verbosity == 0)
148 void QuitProgram(bool error)
150 if (runstate == QUIT || runstate == QUIT_ERROR)
152 omp_set_lock(&runstate_lock);
153 runstate = (error) ? QUIT_ERROR : QUIT;
154 omp_unset_lock(&runstate_lock);