#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
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)
*/
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;
* @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
}
//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);
--- /dev/null
+../single-thread/Makefile
\ No newline at end of file
--- /dev/null
+../single-thread/graphics.c
\ No newline at end of file
--- /dev/null
+../single-thread/graphics.h
\ No newline at end of file
--- /dev/null
+../single-thread/main.c
\ No newline at end of file
--- /dev/null
+/**
+ * @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;
+
+}
--- /dev/null
+#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 <omp.h>
+
+
+#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
BIN = nbody
$(BIN) : $(LINK_OBJ)
- $(CXX) -o $(BIN) $(LINK_OBJ) $(LIBRARIES)
+ $(CXX) -o $(BIN) $(LINK_OBJ) $(PREPROCESSOR_FLAGS) $(LIBRARIES)
nbody :
#include "graphics.h" //Function declarations
#include "nbody.h" //The simulation
+#include <GL/freeglut.h>
// --- Variable definitions --- //
double previousTime, eyeTheta, eyePhi, eyeRho;
*/
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;
}
{
if (theKey == 'x' || theKey == 'X')
{
- exit(EXIT_SUCCESS);
+ glutLeaveMainLoop();
+ return;
}
if (theKey == 'i' || theKey == 'I') {
#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);
}
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
}
* @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];
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));
+}
#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))
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.