Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@

## Quickstart

Include the header in one C file with `POLESITTER_IMPLEMENTATION` defined.
Include the header in one C file with `POLESITTER_IMPLEMENTATION` defined. Define `PS_MULTITHREADING` as well when using more than one thread.

```c
#define PS_MULTITHREADING
#define POLESITTER_IMPLEMENTATION
#include "polesitter.h"
```

### Basic setup

```c
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

Expand All @@ -29,7 +31,13 @@ int main(void) {
void* memory_block = malloc(MEMORY_SIZE);

// initialize the context
ps_config_t cfg = { memory_block, MEMORY_SIZE };
ps_config_t cfg = {
.buff = memory_block,
.buff_size = MEMORY_SIZE,
.max_particles = PARTICLE_CNT,
.theta = 2.0F,
.thrd_cnt = 4,
};
ps_context_t* ctx = NULL;
ps_init(&ctx, &cfg);

Expand All @@ -55,8 +63,7 @@ int main(void) {
float dt = 0.016F; // 60FPS
bool running = true;
while (running) {
// reset arena and force accumulators for the new frame
ps_arena_clear(&ctx->arena);
// reset IDs and force accumulators for the new frame
for (int i = 0; i < PARTICLE_CNT; ++i) {
ids[i] = i; // reset ids before sorting
fx[i] = 0.0F; fy[i] = 0.0F; fz[i] = 0.0F;
Expand Down Expand Up @@ -105,6 +112,7 @@ int main(void) {
}

// cleanup
ps_destroy(ctx);
free(memory_block);
return 0;
}
Expand Down
71 changes: 41 additions & 30 deletions src/polesitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ typedef void* (*ps_thrd_func_t)(void*);
#if defined(__x86_64__) || defined(__i386__) || defined(_M_X64) || \
defined(_M_IX86)

#define PS_YIELD() _mm_pause()
#ifdef _WIN32
#define PS_YIELD() YieldProcessor()
#else
#define PS_YIELD() __asm__ volatile("pause" ::: "memory")
#endif
#elif defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__)
#define PS_YIELD() __asm__ volatile("yield" ::: "memory")
#else
Expand Down Expand Up @@ -336,7 +340,6 @@ ps_result_t ps_destroy(ps_context_t* ctx);

#endif // POLESITTER_H

#define POLESITTER_IMPLEMENTATION
#ifdef POLESITTER_IMPLEMENTATION

// =====================================================================
Expand Down Expand Up @@ -432,12 +435,12 @@ typedef struct {
ps_thrd_t thrds[PS_MAX_THRDS];
uint32_t thrd_cnt;

ps_job_t queue[PS_MAX_JOBS];
volatile int hd;
volatile int tl;
volatile int cnt;
volatile int active_jobs;
volatile int shutdown_flag;
ps_job_t queue[PS_MAX_JOBS];
int hd;
int tl;
int cnt;
int active_jobs;
int shutdown_flag;

ps_spinlock_t lock;
} ps_thrd_pool_t;
Expand Down Expand Up @@ -640,18 +643,28 @@ static void ps_impl_pool_submit(ps_context_t* ctx, ps_job_t job) {
if (ctx->pool.thrd_cnt > 0) {
ps_thrd_pool_t* pool = &ctx->pool;

// block if buffer is full
while (pool->cnt == PS_MAX_JOBS && !pool->shutdown_flag) {
// Queue state is shared with workers; inspect and update it only
// while holding the spinlock. volatile does not make these accesses
// atomic or establish inter-thread ordering in C.
while (1) {
ps_spin_lock(&pool->lock);

if (pool->shutdown_flag) {
ps_spin_unlock(&pool->lock);
return;
}

if (pool->cnt < PS_MAX_JOBS) {
pool->queue[pool->tl] = job;
pool->tl = (pool->tl + 1) % PS_MAX_JOBS;
pool->cnt++;
ps_spin_unlock(&pool->lock);
return;
}

ps_spin_unlock(&pool->lock);
PS_YIELD();
}

// enqueue
ps_spin_lock(&pool->lock);
pool->queue[pool->tl] = job;
pool->tl = (pool->tl + 1) % PS_MAX_JOBS;
pool->cnt++;
ps_spin_unlock(&pool->lock);
return;
}

#endif
Expand All @@ -668,15 +681,14 @@ static void ps_impl_pool_wait(ps_context_t* ctx) {
ps_thrd_pool_t* pool = &ctx->pool;

while (1) {
if (pool->cnt == 0 && pool->active_jobs == 0) {

ps_spin_lock(&pool->lock);
int done = (pool->cnt == 0 && pool->active_jobs == 0);
ps_spin_unlock(&pool->lock);
ps_spin_lock(&pool->lock);
int done = (pool->cnt == 0 && pool->active_jobs == 0);
ps_spin_unlock(&pool->lock);

if (done)
return;
if (done) {
return;
}

PS_YIELD();
}
#endif
Expand All @@ -689,18 +701,17 @@ static PS_THRD_RET_TYPE ps_impl_worker_loop(void* arg) {
ps_thrd_pool_t* pool = w_arg->pool;

while (1) {
while (pool->cnt == 0 && !pool->shutdown_flag) {
PS_YIELD();
}

ps_spin_lock(&pool->lock);

if (pool->cnt == 0) {
int shutdown = pool->shutdown_flag;
ps_spin_unlock(&pool->lock);
if (pool->shutdown_flag) {

if (shutdown) {
break;
}

PS_YIELD();
continue;
}

Expand Down
1 change: 1 addition & 0 deletions tests/accuracy.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ static int comp_arrs(const char* phase, size_t cnt, ps_particle_arrs_t* st,
"ST(%.2f,%.2f,%.2f) MT(%.2f,%.2f,%.2f)",
phase, i, st->id[i], st->fx[i], st->fy[i], st->fz[i],
mt->fx[i], mt->fy[i], mt->fz[i]);
mismatches++;

if (mismatches >= 5) {
break;
Expand Down