Merge branch 'master' of git.ucc.asn.au:/matches/honours
authorSam Moore <sam@daedalus.(none)>
Tue, 11 Sep 2012 13:37:39 +0000 (21:37 +0800)
committerSam Moore <sam@daedalus.(none)>
Tue, 11 Sep 2012 13:37:39 +0000 (21:37 +0800)
course/semester2/pprog/assignment1/Makefile [new file with mode: 0644]
course/semester2/pprog/assignment1/get_data.py
course/semester2/pprog/assignment1/mthread/nbody-slow [new file with mode: 0755]
course/semester2/pprog/assignment1/mthread/nbody.c
course/semester2/pprog/assignment1/mthread/nbody.h
course/semester2/pprog/assignment1/openmp/nbody.c
course/semester2/pprog/assignment1/openmp/nbody.h
course/semester2/pprog/assignment1/single-thread/graphics.c
course/semester2/pprog/assignment1/single-thread/main.c
course/semester2/pprog/assignment1/single-thread/nbody.c
course/semester2/pprog/assignment1/single-thread/nbody.h

diff --git a/course/semester2/pprog/assignment1/Makefile b/course/semester2/pprog/assignment1/Makefile
new file mode 100644 (file)
index 0000000..c66787e
--- /dev/null
@@ -0,0 +1,18 @@
+# Makefile to build all programs
+
+all : single-thread/nbody mthread/nbody openmp/nbody
+
+single-thread/nbody :
+       make -C single-thread
+
+mthread/nbody :
+       make -C mthread
+
+openmp/nbody : 
+       make -C openmp
+
+clean :
+       make -C single-thread clean_full
+       make -C mthread clean_full
+       make -C openmp clean_full
+       rm *~
index 8ef8241..04ad2be 100755 (executable)
@@ -12,10 +12,13 @@ import Gnuplot, Gnuplot.funcutils
 plot = Gnuplot.Gnuplot(persist=0)
 
 programs = {
-       "single-thread" : "./single-thread/nbody -g -v 5"
+       "single-thread" : "./single-thread/nbody -v 5"
 }
-for n in range(1, 5):
-       programs.update({"mthread"+str(n) : "./mthread/nbody -g -v 5 -n "+str(n)})
+for n in range(2, 6):
+       programs.update({"mthread"+str(n) : "./mthread/nbody -v 5 --pedantic-graphics -n "+str(n)})
+       programs.update({"mthread"+str(n) : "./mthread/nbody -v 5 -n "+str(n)})
+       #programs.update({"slow-mthread"+str(n) : "./mthread/nbody-slow --pedantic-graphics -v 5 -n "+str(n)})
+       #programs.update({"openmp"+str(n) : "./openmp/nbody -v 5 --pedantic-graphics -n " +str(n)})
 
 
 
@@ -29,8 +32,8 @@ def RunProgram(string):
 
 def RunForSteps(program, field, steps):
        results = []
-       #print(str(program) + " -s "+str(steps) + " " + str(field))
-       results.append(RunProgram(str(program) + " -s "+str(steps) + " " + str(field)))
+       print(str(program) + " -s "+str(steps) + " " + str(field))
+       results = RunProgram(str(program) + " -s "+str(steps) + " " + str(field))
        return results
 
 def VaryField(program, steps, fields):
@@ -56,12 +59,18 @@ def main(argv):
        fields = map(int, os.listdir("fields"))
        fields.sort(key = lambda e : e)
        
+       ignore = [10, 100]
        for n in fields:
+               if n in ignore:
+                       continue
                for p in data.keys():
-                       data[p] = [RunForSteps(programs[p], "fields/"+str(n), 200), n]
+                       data[p] = RunForSteps(programs[p], "fields/"+str(n), 200)
                        #print(str(data[p]))
-                       if (len(data[p]) > 0):
-                               plot.replot(Gnuplot.Data(data[p][0], title=str(p)+":"+str(n), with_="lp linecolor "+str(fields.index(n))))
+
+               #print(str(data.items()));
+               for d in sorted(data.items(), key = lambda e : e[1][len(e[1])-1][1]):
+                       if (len(d[1]) > 0):
+                               plot.replot(Gnuplot.Data(d[1], title=str(d[0])+":"+str(n), with_="lp")) #linecolor "+str(fields.index(n))))
 
        #print(str(data.items()))
        # Score the programs
diff --git a/course/semester2/pprog/assignment1/mthread/nbody-slow b/course/semester2/pprog/assignment1/mthread/nbody-slow
new file mode 100755 (executable)
index 0000000..9680b55
Binary files /dev/null and b/course/semester2/pprog/assignment1/mthread/nbody-slow differ
index 4acf28f..301cd8b 100644 (file)
@@ -15,12 +15,17 @@ pthread_t compute_thread; // The thread responsible for computations; it spawns
        
 pthread_t * worker_thread = NULL; //Array of worker threads responsible for Force and Position updates
 System * sub_system = NULL; //Array of Systems used to divide up the main "universe" System for worker threads
-pthread_mutex_t mutex_workers; // Mutex used for the barrier between Force and Position updates
-pthread_cond_t workers_done_cv; // Conditional used for the barrier between Force and Position updates
-unsigned workers_busy; // Number of workers currently doing something
 
 pthread_mutex_t mutex_runstate; // Mutex around the runstate
 
+#ifdef PERSISTENT_THREADS
+Barrier force_barrier; // I laughed at this variable name. A bit sad really.
+Barrier position_barrier;
+#else
+Barrier worker_barrier;
+#endif //PERSISTENT_THREADS
+
+Barrier graphics_barrier;
 
 
 /**
@@ -48,6 +53,10 @@ void * Compute_Thread(void * arg)
                options.num_threads = s->N;
        }
        
+       pthread_attr_t attr; //thread attribute for the workers. 
+       pthread_attr_init(&attr);
+       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //Needs to be detached, so that memory can be reused.
+       
        if (options.num_threads > 1) // Allocate worker threads and sub systems, as long as there would be more than 1
        {
                worker_thread = (pthread_t*)(calloc(options.num_threads, sizeof(pthread_t)));
@@ -76,14 +85,39 @@ void * Compute_Thread(void * arg)
                        if (i == options.num_threads - 1)
                                sub_system[i].N += remainder; // The last thread gets the remainder
 
+                       #ifdef PERSISTENT_THREADS
+                       if (pthread_create(worker_thread+i, & attr, Worker_Thread, (void*)(sub_system+i)) != 0)
+                       {
+                               perror("In compute thread, couldn't create worker thread");
+                               QuitProgram(true);
+                               pthread_exit(NULL);
+                       }
+                       #endif //PERSISTENT_THREADS
+       
                }
-       }
 
+               
+       }
+       #ifdef PERSISTENT_THREADS
+       else
+       {
+               while (!ExitCondition())
+               {
+                       if (options.verbosity != 0 && universe.steps % options.verbosity == 1)
+                       {
+                               DisplayStatistics();
+                       }
 
-       pthread_attr_t attr; //thread attribute for the workers. 
-       pthread_attr_init(&attr);
-       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //Needs to be detached, so that memory can be reused.
+                       // Just do everything in this thread 
+                       System_Forces(s, s);
+                       System_Positions(s);
+                       continue;
+               }
+               QuitProgram(false);
+               pthread_exit(NULL);
+       }
 
+       #else
        // The main computation loop
        while (true)
        {
@@ -94,8 +128,7 @@ void * Compute_Thread(void * arg)
                        pthread_exit(NULL);
                }
 
-               if (options.draw_graphics == false && options.verbosity != 0 
-                       && universe.steps % options.verbosity == 1)
+               if (options.verbosity != 0 && universe.steps % options.verbosity == 1)
                {
                        DisplayStatistics();
                }
@@ -111,9 +144,6 @@ void * Compute_Thread(void * arg)
 
                
 
-               
-               workers_busy = options.num_threads; //All threads working
-
                //Compute forces
                for (unsigned i = 0; i < options.num_threads; ++i)
                {
@@ -123,19 +153,19 @@ void * Compute_Thread(void * arg)
                                QuitProgram(true);
                                pthread_exit(NULL);
                        }       
+                       
                }
 
 
-
-               //Barrier - Wait for forces to be computed
-               pthread_mutex_lock(&mutex_workers);
-               while (workers_busy > 0)
-                       pthread_cond_wait(&workers_done_cv, &mutex_workers);
-               pthread_mutex_unlock(&mutex_workers);
+               Barrier_Wait(&worker_barrier);
 
                //All the forces are now computed
-               
-               workers_busy = options.num_threads; //All threads working
+
+               if (options.draw_graphics && options.pedantic_graphics)
+               {
+                       Barrier_Wait(&graphics_barrier);
+                       Barrier_Enter(&graphics_barrier);
+               }
 
                //Compute positions
                for (unsigned i = 0; i < options.num_threads; ++i)
@@ -149,19 +179,104 @@ void * Compute_Thread(void * arg)
                }
 
                //Wait for positions to be computed
-               pthread_mutex_lock(&mutex_workers);
-               while (workers_busy > 0)
-                       pthread_cond_wait(&workers_done_cv, &mutex_workers);
-               pthread_mutex_unlock(&mutex_workers);
+               Barrier_Wait(&worker_barrier);
+
 
                //Update number of steps computed
                universe.steps += 1;
 
+               if (options.draw_graphics && options.pedantic_graphics)
+                       Barrier_Leave(&graphics_barrier);
+
+               
 
 
        }
+       #endif //PERSISTENT_THREADS
+       
+       return NULL;
 }
 
+/**
+ * @function BeforeDraw
+ * @purpose Called in graphics thread before the draw loop
+ *     When --pedantic-graphics enabled, will wait for position computations to finish before drawing
+ *     Otherwise does nothing
+ */
+void BeforeDraw()
+{
+       if (options.verbosity != 0 && universe.steps % options.verbosity == 0)
+               DisplayStatistics();
+       //printf("BEFORE DRAW\n");
+       if (!options.pedantic_graphics)
+               return;
+       #ifdef PERSISTENT_THREADS
+       Barrier_Wait(&position_barrier);
+       
+       #else
+       Barrier_Wait(&graphics_barrier);
+       #endif //PERSISTENT_THREADS
+
+       Barrier_Enter(&graphics_barrier);       
+}
+
+/**
+ * @function AfterDraw
+ * @purpose Called in graphics thread after the draw loop
+ *     When --pedantic-graphics is supplied, will signal computation thread that drawing is finished
+ *             So that positions can be safely altered
+ *     Otherwise does nothing
+ */
+void AfterDraw()
+{
+       universe.steps += 1;
+       if (!options.pedantic_graphics)
+               return;
+       Barrier_Leave(&graphics_barrier);
+       
+}
+
+#ifdef PERSISTENT_THREADS
+
+/**
+ * @function Worker_Thread
+ * @purpose Thread - Calculate stuff
+ */
+void * Worker_Thread(void * arg)
+{
+       System * s = (System*)(arg);
+       while (!ExitCondition())
+       {
+               
+               Barrier_Enter(&force_barrier);
+
+               System_Forces(s, &universe);
+               
+               Barrier_Leave(&force_barrier);
+
+               //printf("Computed forces for %p\n", arg);
+               Barrier_Wait(&force_barrier);
+               //printf("Computed ALL forces\n");
+
+               if (options.draw_graphics && options.pedantic_graphics)
+                       Barrier_Wait(&graphics_barrier);
+
+               Barrier_Enter(&position_barrier);
+               
+               System_Positions(s);
+
+               Barrier_Leave(&position_barrier);
+               //printf("Computed positions for %p\n", arg);
+               Barrier_Wait(&position_barrier);
+               //printf("Computed ALL positions\n");
+       }
+       QuitProgram(false);
+       pthread_exit(NULL);
+}
+
+
+#else
+
 /**
  * @function Force_Thread
  * @purpose Thread - Calculates the forces on objects in a System
@@ -169,16 +284,12 @@ void * Compute_Thread(void * arg)
  */
 void * Force_Thread(void * s)
 {
-       
+       Barrier_Enter(&worker_barrier);
+
        System_Forces((System*)s, &universe); //Simple wrapper
 
-       pthread_mutex_lock(&mutex_workers);
-       workers_busy -= 1;      // Count this thread as done
-       if (workers_busy == 0)
-       {
-               pthread_cond_signal(&workers_done_cv); // All threads done; wake up the compute_thread
-       }
-       pthread_mutex_unlock(&mutex_workers);
+       Barrier_Leave(&worker_barrier);
+
        return NULL;
 }
 
@@ -189,19 +300,14 @@ void * Force_Thread(void * s)
  */
 void * Position_Thread(void * s)
 {
-       
+       Barrier_Enter(&worker_barrier);
        System_Positions((System*)s); // Simple wrapper
-
-       pthread_mutex_lock(&mutex_workers);
-       workers_busy -= 1; // Count this thread as done
-       if (workers_busy == 0)
-       {
-               pthread_cond_signal(&workers_done_cv); //All threads done; wake up the compute_thread
-       }
-       pthread_mutex_unlock(&mutex_workers);
+       Barrier_Leave(&worker_barrier);
        return NULL;
 }      
 
+#endif //PERSISTENT_THREADS
+
 /**
  * @function QuitProgram
  * @purpose This function can either be called by the main thread in order to signal other threads
@@ -249,17 +355,66 @@ void Simulation_Run(int argc, char ** argv)
 {
        atexit(Thread_Cleanup);
 
+       #ifdef PERSISTENT_THREADS
+       Barrier_Init(&force_barrier);
+       Barrier_Init(&position_barrier);
+       #else
+       Barrier_Init(&worker_barrier);
+       #endif //PERSISTENT_THREADS
+       Barrier_Init(&graphics_barrier);
+
+       
        if (options.draw_graphics)
        {
                // The graphics are enabled, so create a thread to do computations
                // Graphics are done in the main loop
+               //printf("Graphics are enabled\n");
+               #ifdef PERSISTENT_THREADS
+               Compute_Thread((void*)(&universe));
+               #else
                if (pthread_create(&compute_thread, NULL, Compute_Thread, (void*)&universe) != 0)
                {
                        perror("Error creating compute thread");
                        exit(EXIT_FAILURE);
                }
+               #endif //PERSISTENT_THREADS
+               //printf("Run compute thread\n");
                Graphics_Run(argc, argv);
        }
        else
+       
                Compute_Thread((void*)(&universe)); // Graphics are disabled, so do computations in the main thread
 }
+
+
+
+void Barrier_Init(Barrier * b)
+{
+       b->threads_busy = 0;
+}      
+
+void Barrier_Enter(Barrier * b)
+{
+       pthread_mutex_lock(&(b->mutex));
+       b->threads_busy += 1;
+       pthread_mutex_unlock(&(b->mutex));
+}
+
+void Barrier_Leave(Barrier * b)
+{
+       pthread_mutex_lock(&(b->mutex));
+       b->threads_busy -= 1;
+       if (b->threads_busy == 0)
+       {
+               pthread_cond_signal(&(b->threads_done_cv));
+       }
+       pthread_mutex_unlock(&(b->mutex));
+}
+
+void Barrier_Wait(Barrier * b)
+{
+       pthread_mutex_lock(&(b->mutex));
+       while (b->threads_busy > 0)
+               pthread_cond_wait(&(b->threads_done_cv), &(b->mutex));
+       pthread_mutex_unlock(&(b->mutex));
+}
index 0b3208a..7abe525 100644 (file)
 
 #define DEFAULT_WORKING_THREADS 2 
 
+//#define PERSISTENT_THREADS //If defined, threads will not be continually destroyed and then respawned
+
+
+
 //Undefine default macros, replace with functions
 #undef Simulation_Run
 void Simulation_Run(int argc, char ** argv);
 #undef QuitProgram
 void QuitProgram(bool error);
 
+#undef BeforeDraw
+void BeforeDraw();
+#undef AfterDraw
+void AfterDraw();
+
 
 void * Compute_Thread(void * system); //Thread - Continuously perform computations for a System of bodies. May spawn additional worker threads.
 
+#ifdef PERSISTENT_THREADS
+void * Worker_Thread(void * arg);
+#else
 void * Force_Thread(void * system); //Thread - Compute forces for all objects in a system
 void * Position_Thread(void * system); //Thread - Compute positions for all objects in a system
-
-
+#endif //PERSISTENT_THREADS
 
 void Thread_Cleanup(void); //Called at program exit to safely join computation thread
 
-extern pthread_t compute_thread; // ID of the thread that runs Compute_Thread. 
-extern pthread_mutex_t mutex_runstate; //Mutex around the "runstate" variable
-
-extern pthread_t * worker_thread; //Array of worker threads responsible for Force and Position updates
-extern System * sub_system; //Array of Systems used to divide up the main "universe" System for worker threads
-extern pthread_mutex_t mutex_workers;
-extern pthread_cond_t workers_done_cv;
-extern unsigned workers_busy;
+typedef struct
+{
+       pthread_mutex_t mutex;
+       unsigned threads_busy; // Counter of threads which are busy
+       pthread_cond_t threads_done_cv;
+} Barrier;
+
+void Barrier_Init(Barrier * b);
+void Barrier_Enter(Barrier * b);
+void Barrier_Leave(Barrier * b);
+void Barrier_Wait(Barrier * b);
 
 #endif //_NBODY_MTHREAD_H
index 6eb9ed4..1d2f369 100644 (file)
@@ -8,6 +8,9 @@
 #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;
+
 /**
  * @function Simulation_Run
  * @purpose Start the simulation
@@ -32,7 +35,7 @@ void Simulation_Run(int argc, char ** argv)
                omp_set_num_threads(1);
 
 
-               
+       omp_init_lock(&graphics_lock);
 
        #pragma omp parallel sections
        {
@@ -50,9 +53,7 @@ void Simulation_Run(int argc, char ** argv)
                                        break;
                                }                               
 
-
-                               if (options.draw_graphics == false && options.verbosity != 0 
-                                       && universe.steps % options.verbosity == 1)
+                               if (options.verbosity != 0 && universe.steps % options.verbosity == 1)
                                {
                                        DisplayStatistics();
                                }
@@ -71,6 +72,8 @@ void Simulation_Run(int argc, char ** argv)
                }
 
        }
+
+       omp_destroy_lock(&graphics_lock);
 }
 
 /**
@@ -93,6 +96,13 @@ void Compute(void)
                System_Forces(&s, &universe);
        }
 
+       // Wait for graphics to finish drawing
+
+       if (options.draw_graphics && options.pedantic_graphics)
+       {
+               while (graphics_busy);
+       }       
+
        #pragma omp parallel for
        for (unsigned i = 0; i < options.num_threads; ++i)
        {
@@ -105,4 +115,41 @@ void Compute(void)
 
        universe.steps += 1;
 
+       // Tell graphics to continue
+       if (options.draw_graphics && options.pedantic_graphics)
+       {
+               omp_set_lock(&graphics_lock);
+               graphics_busy = true;
+               omp_unset_lock(&graphics_lock);
+               
+       }
+
+}
+
+/**
+ * @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);
+}
+
+/**
+ * @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);
 }
index b7d0b41..91c4bf4 100644 (file)
@@ -20,6 +20,11 @@ void Simulation_Run(int argc, char ** argv);
 //#undef QuitProgram
 //void QuitProgram(bool error); 
 
+#undef BeforeDraw
+void BeforeDraw();
+#undef AfterDraw
+void AfterDraw();
+
 void Compute(); //Compute a single step
 
 #endif //_NBODY_OPENMP_H
index 7a7d213..864ff91 100644 (file)
@@ -33,10 +33,9 @@ void Graphics_Run(int argc, char ** argv)
 {
        if (options.draw_graphics == false)
        {
-               while (true)
-                       Graphics_Display();
-                       
-               return;
+               // This message is left here for when I inevitably accidentally call the function
+               fprintf(stderr, "Graphics_Run should not be called if graphics are disabled!\n");
+               exit(EXIT_FAILURE);
        }       
 
        glutInit(&argc, argv);  
@@ -107,23 +106,20 @@ void Graphics_Run(int argc, char ** argv)
  */
 void Graphics_Display() 
 {
-       //Check whether the program should quit due to steps being computed, or a timeout
-       if (ExitCondition())
+
+       if (options.draw_graphics == false)
        {
-               //printf("Leave graphics loop\n");
-               glutLeaveMainLoop();    
-               return;
+               // This message is left here for when I inevitably accidentally call the function
+               fprintf(stderr, "Graphics_Display should not be called if graphics are disabled!\n");
+               exit(EXIT_FAILURE);
        }
 
-       #ifdef SINGLE_THREADED
-               if (options.verbosity != 0 && universe.steps % options.verbosity == 1)
-                       DisplayStatistics();
-               System_Compute(&universe);
-       #endif
-
-       if (options.draw_graphics == false)
+       //Check whether the graphics thread should exit for any reason
+       if (ExitCondition())
+       {
+               glutLeaveMainLoop();    // original glut does not have this, which makes "nicely" exiting a bit annoying
                return;
-       
+       }
 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
@@ -131,6 +127,11 @@ void Graphics_Display()
        gluLookAt(eyeRho * sin(eyePhi) * sin(eyeTheta), eyeRho * cos(eyePhi),
                eyeRho * sin(eyePhi) * cos(eyeTheta),look[0], look[1], look[2], 0, upY, 0);
 
+       BeforeDraw(); // Stuff to do before graphics is allowed to draw
+                       // Single-thread - perform a computation step, obviously! It's not done anywhere else
+                       // Multiple threads - ensure that all body positions are updated (ie: not halfway through step).
+                       //      (We don't care about the force and velocity variables though)
+
        for (int i = 0; i < universe.N; ++i) 
        {
                Body * b = universe.body+i;
@@ -141,6 +142,11 @@ void Graphics_Display()
                glPopMatrix(); // restore the previous matrix
        }
        glFlush();
+
+       AfterDraw(); // Stuff to do after graphics is done drawing
+                       // Single-thread - Nothing at all
+                       // Multiple threads - signal threads it is safe to change position variables
+
 }
 
 /**
index 4b0c48a..e9ccb41 100644 (file)
@@ -9,6 +9,7 @@
 #include <stdio.h>
 #include <time.h>
 #include <signal.h>
+#include <string.h> // For parsing arguments
 
 #include "nbody.h"
 #include "graphics.h"
@@ -20,7 +21,7 @@ Options options; // global variable declared in "nbody.h" - Options passed to pr
 
 // --- Function forward declarations --- //
 void HandleArguments(int argc, char ** argv); //Interprets program arguments and sets up the "options" variable
-void UnsignedArgument(unsigned * i, int argc, char ** argv, unsigned * store); //Helper function to get switch value for unsigned
+unsigned UnsignedArgument(unsigned * i, int argc, char ** argv, unsigned * store, unsigned * store2); //Helper function to get switch value for unsigned
 void FloatArgument(unsigned * i, int argc, char ** argv, float * store); //Helper function to get switch value for float
 void DisplayStatistics(); //Called on exit of program, displays information about computation time, steps computed, etc
 void Interrupt(int dummy); // Interrupt handler function, called when SIGINT (Ctrl-C) is sent to program
@@ -41,9 +42,11 @@ int main(int argc, char** argv)
        options.input = NULL;
        options.output = NULL;
        options.num_threads = 0;
+       options.nested_threads = 0;
        options.num_steps = 0;
        options.timeout = 0;
        options.draw_graphics = true;
+       options.pedantic_graphics = false;
        options.print_positions = false;
        options.verbosity = 0;
 
@@ -82,7 +85,7 @@ int main(int argc, char** argv)
        options.start_clock = clock(); //Get CPU cycles executed before simulation starts
        Simulation_Run(argc, argv); // Start the simulation
        
-       printf("Got here!\n");
+       //printf("Got here!\n");
        exit(EXIT_FAILURE); //Should never get to this line
 }
 
@@ -116,25 +119,49 @@ void HandleArguments(int argc, char ** argv)
                switch (argv[i][1]) //The argument is a switch if we get here
                {
                        case 'n': //Number of threads switch
-                               UnsignedArgument(&i, argc, argv, &(options.num_threads));
+                               UnsignedArgument(&i, argc, argv, &(options.num_threads), &(options.nested_threads));
                                #ifdef SINGLE_THREADED
                                fprintf(stderr, "Warning: -%c switch has no effect in the single-threaded program.\n", argv[i][1]);
-                               options.num_threads = 1;
+                               
                                #endif //SINGLE_THREADED
                                break;
                        case 's': //Number of steps switch
-                               UnsignedArgument(&i, argc, argv, &(options.num_steps));
+                               UnsignedArgument(&i, argc, argv, &(options.num_steps), NULL);
                                break;
                        case 't': //Timeout switch (in seconds)
-                               UnsignedArgument(&i, argc, argv, &(options.timeout));
+                               UnsignedArgument(&i, argc, argv, &(options.timeout), NULL);
                                break;
                        case 'g': //Graphics switch
                                options.draw_graphics = !options.draw_graphics;
                                break;
                        case 'v': //Verbosity switch
-                               UnsignedArgument(&i, argc, argv, &(options.verbosity));
+                               UnsignedArgument(&i, argc, argv, &(options.verbosity), NULL);
                                break;
 
+                       case '-':
+                               if (strcmp(argv[i]+1, "pedantic-graphics"))
+                               {
+                                       options.pedantic_graphics = true;
+                                       #ifdef SINGLE_THREADED
+                                       fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]);
+                                       #endif //SINGLE_THREADED
+                               }
+                               else if (strcmp(argv[i]+1, "fast-graphics"))
+                               {
+                                       options.pedantic_graphics = false;
+                                       #ifdef SINGLE_THREADED
+                                       fprintf(stderr, "Warning: %s switch has no effect in the single threaded program.\n", argv[i]);
+                                       #endif //SINGLE_THREADED
+
+                               }
+                               else
+                               {
+                                       fprintf(stderr, "Unrecognised switch -%s\n", argv[i]);
+                                       exit(EXIT_FAILURE);
+                               }
+                               break;
+
+
                        default:
                                fprintf(stderr, "Unrecognised switch -%c\n", argv[i][1]);
                                exit(EXIT_FAILURE);
@@ -151,22 +178,46 @@ void HandleArguments(int argc, char ** argv)
  * @param argc - number of arguments
  * @param argv - argument strings
  * @param store - pointer to unsigned to store result in
+ * @param store2 - pointer to second unsigned
+ * @returns 1 if store was filled, 2 if both store1 and store2 were filled
  */
-void UnsignedArgument(unsigned * i, int argc, char ** argv, unsigned * store)
+unsigned UnsignedArgument(unsigned * i, int argc, char ** argv, unsigned * store, unsigned * store2)
 {
        if (*i >= argc-1)
        {
                fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
                exit(EXIT_FAILURE);
        }
+
+       char * seperator = strstr(argv[*i+1], ":");
+       if (seperator != NULL)
+       {
+               if (store2 == NULL)
+               {
+                       fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
+                       exit(EXIT_FAILURE);     
+               }
+               int val = atoi(seperator+1);
+               if (val <= 0)
+               {
+                       fprintf(stderr,"Supply a positive integer for the -%c switch.\n", argv[*i][1]);
+                       exit(EXIT_FAILURE);     
+               }       
+               *store2 = (unsigned)val;
+
+               *seperator = '\0';
+       }
+       
        int val = atoi(argv[*i+1]);
        if (val <= 0)
        {
                fprintf(stderr,"Supply a positive integer for the -%c switch. %s is invalid.\n", argv[*i][1], argv[*i+1]);
                exit(EXIT_FAILURE);
        }
-       *store = val;
+       *store = (unsigned)val;
        *i += 1;
+
+       return (seperator == NULL) ? 1 : 2;
 }
 /**
  * @function FloatArgument
index c54661f..67afd0f 100644 (file)
@@ -101,6 +101,7 @@ void System_Compute(System * s)
  * @param s1, s2 - The two systems
  * NOTE: In single threaded version, called with s1 == s2 == &universe
  *      In multi threaded version, called with s2 == &universe, but s1 is constructed for each thread
+ *             In nested multi-threaded version, s2 is constructed for the nested threads as well
  */
 void System_Forces(System * s1, System * s2) 
 {
index fc19d05..4d53f9d 100644 (file)
 
 #define SINGLE_THREADED
 
-//These macros will be undefined by the multithreaded versions
-#define Simulation_Run(argc, argv) (Graphics_Run(argc, argv)) //Sets up the simulation; in multithreaded versions, will spawn threads
+// --- The below macros will be undefined by the multithreaded versions, and replaced with functions --- //
+
+//Sets up the simulation; in multithreaded versions, will spawn threads
+#define Simulation_Run(argc, argv) \
+if (options.draw_graphics) \
+       Graphics_Run(argc, argv); \
+else \
+{ \
+       while (ExitCondition() == false) \
+       { BeforeDraw(); AfterDraw(); } \
+}
+
 #define QuitProgram(error) (runstate = (error == true) ? QUIT : QUIT_ERROR) //Prepares to exit program, is thread safe in multithreaded versions
 
+//Macro to be overwritten in multithreaded versions, called before the graphics is allowed to draw anything
+#define BeforeDraw() \
+if (options.verbosity != 0 && universe.steps % options.verbosity == 0) \
+       DisplayStatistics(); \
+System_Compute(&universe);
+
+
+
+//Macro to be overwritten in multithreaded versions, called after the graphics has finished drawing.
+#define AfterDraw()    
+
+// --- Constants and other Macros --- //       
+
 #define M_PI        3.14159265358979323846264338327950288   /* pi */
 #define G 6.67428E-11
 #define DELTA_T 0.05
@@ -71,9 +94,11 @@ typedef struct
        const char * output; // file to write final positions / velocities of bodies to
        const char * program; // program name
        unsigned num_threads; // number of worker threads to spawn (must be greater than 1 for any to be spawned)
+       unsigned nested_threads; // number of threads to nest computations with (must be greater than 1 for any to be spawned)
        unsigned num_steps; // number of steps to run before stopping (run indefinately if equal to zero)
        unsigned timeout; // number of seconds to run before stopping (run indefinately if equal to zero)
        bool draw_graphics; // whether or not to actually draw graphics
+       bool pedantic_graphics; // whether the graphics thread will synchronise with the computation thread (true) or just draw as fast as possible (false)
        bool print_positions; // print positions of bodies to stdout on every step
        unsigned verbosity; // print statistics every number of steps indicated by this variable
        clock_t start_clock;  // clock cycles done when simulation starts

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