added first parallel version
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 30 Oct 2020 02:57:57 +0000 (21:57 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 30 Oct 2020 02:57:57 +0000 (21:57 -0500)
Makefile
src/sim.cpp

index 75ee0aee54f55e2610d7be81cda5135e562727ff..edeb4e3ede9be654f572193b308e398ccec57370 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ LIB_FILES=\
 
 CC=g++
 INCLUDES=-I./include
-LIBS=-lGL -lglfw -lm
+LIBS=-lGL -lglfw -lm -lpthread
 TARGET=./sim
 
 ifeq ($(RELEASE), 1)
index 5103e7252221e1914a85804351a8d16347fa3755..00b4f1a39202f3152da290bfcb5c57908077fbf5 100644 (file)
@@ -7,6 +7,7 @@
 #include <unistd.h>
 #include <math.h>
 #include <time.h>
+#include <pthread.h>
 
 #include <GLES3/gl3.h>
 #include <GLFW/glfw3.h>
 #define WINDOW_TITLE           "N-Body Simulation"
 
 // :ArbitraryConstant
-#define PARTICLE_COUNT 2500
+#define PARTICLE_COUNT 3000
+
+// :ArbitraryConstant
+#define NUM_THREADS 2
 
 // TODO(Brendan): Maybe this can be removed because it isn't really necessary?
 internal void
@@ -127,6 +131,51 @@ struct SimState
     Camera camera;
 };
 
+internal void
+update_bodies_partial(SimState *state, i32 index)
+{
+    i32 low  = index * (PARTICLE_COUNT / NUM_THREADS);
+    i32 high = (index + 1) * (PARTICLE_COUNT / NUM_THREADS);
+
+    persist const f64 step = 0.01;
+
+    foreach (i, low, high)
+    {
+        body_accumulate_move(&state->bodies[i], &state->qt_bodies, step);
+    }
+
+    foreach (i, low, high)
+    {
+        body_apply_move(&state->bodies[i], step);
+    }
+}
+
+internal pthread_barrier_t thread_sync_barrier;
+internal pthread_t threads[NUM_THREADS - 1];
+
+struct ThreadData
+{
+    i32 id;
+    SimState* state;
+};
+
+internal void*
+thread_start(void* data)
+{
+    i32 thread_id = ((ThreadData *) data)->id;
+    SimState* state = ((ThreadData *) data)->state;
+
+    while (true)
+    {
+        pthread_barrier_wait(&thread_sync_barrier);
+        update_bodies_partial(state, thread_id + 1);
+        pthread_barrier_wait(&thread_sync_barrier);
+        pthread_barrier_wait(&thread_sync_barrier);
+    }
+
+    return NULL;
+}
+
 internal void
 sim_state_init(SimState* state)
 {
@@ -146,8 +195,17 @@ sim_state_init(SimState* state)
 
     state->qt_body_allocator.init(PARTICLE_COUNT);
 
-    state->camera.offset = V2f { 0, 0 };
     state->camera.scale = 1.0f;
+
+    pthread_barrier_init(&thread_sync_barrier, NULL, NUM_THREADS);
+
+    foreach (i, 0, NUM_THREADS - 1)
+    {
+        auto td = alloc<ThreadData>(1); // LEAK
+        td->id = i;
+        td->state = state;
+        pthread_create(&threads[i], NULL, thread_start, (void *) td);
+    }
 }
 
 // NOTE(Brendan): dt is expected to be in units of "per second".
@@ -164,14 +222,13 @@ update(SimState* state, f64 dt)
     if (glfwGetKey(window, GLFW_KEY_Q))     state->camera.scale *= 1.01f;
     if (glfwGetKey(window, GLFW_KEY_A))     state->camera.scale /= 1.01f;
 
-    persist const f64 step = 0.01;
-
     state->qt_bodies.init(AABB { -2000, -2000, 4000, 4000 });
     state->qt_body_allocator.reset();
     For (state->bodies) state->qt_bodies.insert(&it, &state->qt_body_allocator);
+    pthread_barrier_wait(&thread_sync_barrier);
 
-    For (state->bodies) body_accumulate_move(&it, &state->qt_bodies, step);
-    For (state->bodies) body_apply_move(&it, step);
+    update_bodies_partial(state, 0);
+    pthread_barrier_wait(&thread_sync_barrier);
 }
 
 // NOTE CLEANUP(Brendan): Bunch of graphics state that should go elsewhere.
@@ -219,6 +276,7 @@ draw(SimState* state)
 
     // NOTE(Brendan): Present the changes to the screen.
     glfwSwapBuffers(window);
+    pthread_barrier_wait(&thread_sync_barrier);
 }
 
 internal void