parent
9db000e864
commit
ae9efca41b
@ -1,3 +1,5 @@
|
||||
obj/
|
||||
fcmp-*
|
||||
test/
|
||||
perf.*
|
||||
flamegraph.svg
|
||||
|
@ -0,0 +1,25 @@
|
||||
#ifndef _FCMP_H
|
||||
#define _FCMP_H
|
||||
|
||||
#ifdef DEBUG
|
||||
#define _FORCE_INLINE static inline __attribute__((gnu_inline))
|
||||
#else
|
||||
#define _FORCE_INLINE extern inline __attribute__((gnu_inline))
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define __name(d) #d
|
||||
#define dprintf(fmt, ...) printf("[dbg @" __FILE__ "->%s:%d] " fmt "\n", __func__, __LINE__ __VA_OPT__(,) __VA_ARGS__)
|
||||
#else
|
||||
#define dprintf(fmt, ...)
|
||||
#endif
|
||||
|
||||
/// Enabled threaded scheduling
|
||||
// Set to 1 to FORCE threaded scheduling, 0 to use when opportune.
|
||||
//
|
||||
//#define _RUN_THREADED 0
|
||||
|
||||
|
||||
extern const char* _prog_name;
|
||||
|
||||
#endif /* _FCMP_H */
|
@ -0,0 +1,22 @@
|
||||
#ifndef _SCHED_H
|
||||
#define _SCHED_H
|
||||
|
||||
#include <vector.h>
|
||||
#include <fcmp.h>
|
||||
|
||||
typedef struct tasklist {
|
||||
size_t argc;
|
||||
struct taskarg* argv;
|
||||
pthread_t* tasks;
|
||||
|
||||
} tasklist_t;
|
||||
|
||||
typedef void (*sched_cb)(vec_t* restrict tasklist);
|
||||
|
||||
#ifdef _RUN_THREADED
|
||||
bool sched_spawn(vec_t full, sched_cb callback, struct tasklist *restrict t_list);
|
||||
void sched_wait(struct tasklist* restrict t_list);
|
||||
bool sched_should(size_t ntasks);
|
||||
#endif
|
||||
|
||||
#endif /* _SHCED_H */
|
@ -0,0 +1,84 @@
|
||||
// Scheduler
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <vector.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef _RUN_THREADED
|
||||
inline static size_t num_cpus() {
|
||||
return sysconf( _SC_NPROCESSORS_ONLN );
|
||||
}
|
||||
|
||||
struct taskarg {
|
||||
vec_t li;
|
||||
sched_cb cb;
|
||||
};
|
||||
|
||||
static void* _spawn(void* _arg)
|
||||
{
|
||||
struct taskarg* restrict arg = _arg;
|
||||
if(arg->li.len>0)
|
||||
arg->cb(&arg->li);
|
||||
vec_free(arg->li);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool sched_should(size_t ntasks)
|
||||
{
|
||||
register size_t num = num_cpus();
|
||||
return (num > 1 && ntasks > 1);
|
||||
}
|
||||
|
||||
bool sched_spawn(vec_t full, sched_cb callback, struct tasklist *restrict t_list)
|
||||
{
|
||||
register size_t spn = num_cpus() + 1;
|
||||
|
||||
if (spn > full.len) spn = full.len;
|
||||
|
||||
dprintf("Spawning %lu worker threads", spn);
|
||||
// Split tasks
|
||||
*t_list = (struct tasklist){
|
||||
.argc = spn,
|
||||
.argv = calloc(sizeof(struct taskarg), spn),
|
||||
.tasks = calloc(sizeof(pthread_t), spn),
|
||||
};
|
||||
struct taskarg* tasklist = t_list->argv;
|
||||
|
||||
for(register int i=0;i<spn;i++) tasklist[i] = (struct taskarg){.li = vec_new_with_cap(full.element, full.len), .cb = callback };
|
||||
|
||||
for (register int i=0;i<full.len;i++)
|
||||
{
|
||||
vec_push(&tasklist[i%spn].li, vec_index(&full, i));
|
||||
}
|
||||
|
||||
for(register int i=0;i<spn;i++)
|
||||
{
|
||||
if(pthread_create(&t_list->tasks[i], NULL, &_spawn, &tasklist[i]))
|
||||
{
|
||||
perror("Failed to spawn thread");
|
||||
return false;
|
||||
}
|
||||
dprintf("Worker thead %d of %lu OK", i, spn);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void sched_wait(struct tasklist* restrict t_list)
|
||||
{
|
||||
dprintf("Waiting on %lu worker threads", t_list->argc);
|
||||
for (size_t i=0;i<t_list->argc;i++) {
|
||||
if(pthread_join(t_list->tasks[i], NULL)) {
|
||||
perror("Failed to join thread");
|
||||
continue;
|
||||
}
|
||||
dprintf("Joined thread %lu of %lu okay", i, t_list->argc);
|
||||
}
|
||||
free(t_list->tasks);
|
||||
free(t_list->argv);
|
||||
dprintf("Freed args and thread handles okay");
|
||||
}
|
||||
#endif
|
Loading…
Reference in new issue