Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
rm hooks api's, add fftw_make_planner_thread_safe() api
fftw_make_planner_thread_safe() installs a lock around the planner.
It is guaranteed to be atomic and idempotent.

I wrote an emulation of pthread mutex initializers on Windows, but I
haven't even compiled the Windows code yet.
  • Loading branch information
matteo-frigo committed May 25, 2015
1 parent 842596f commit d3442a8
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 52 deletions.
4 changes: 4 additions & 0 deletions api/api.h
Expand Up @@ -106,6 +106,10 @@ apiplan *X(mkapiplan)(int sign, unsigned flags, problem *prb);

rdft_kind *X(map_r2r_kind)(int rank, const X(r2r_kind) * kind);

typedef void (*planner_hook_t)(void);

void X(set_planner_hooks)(planner_hook_t before, planner_hook_t after);

#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
Expand Down
15 changes: 4 additions & 11 deletions api/apiplan.c
Expand Up @@ -20,25 +20,18 @@

#include "api.h"

static X(before_planner_hook_t) before_planner_hook = 0;
static X(after_planner_hook_t) after_planner_hook = 0;
static void *planner_hook_arg = 0;
static planner_hook_t before_planner_hook = 0, after_planner_hook = 0;

void X(set_planner_hooks)(X(before_planner_hook_t) before,
X(after_planner_hook_t) after,
void *arg)
void X(set_planner_hooks)(planner_hook_t before, planner_hook_t after)
{
before_planner_hook = before;
after_planner_hook = after;
planner_hook_arg = arg;
}

static plan *mkplan0(planner *plnr, unsigned flags,
const problem *prb, int hash_info,
wisdom_state_t wisdom_state)
{
plan *pln;

/* map API flags into FFTW flags */
X(mapflags)(plnr, flags);

Expand Down Expand Up @@ -102,7 +95,7 @@ apiplan *X(mkapiplan)(int sign, unsigned flags, problem *prb)
double pcost = 0;

if (before_planner_hook)
before_planner_hook(planner_hook_arg);
before_planner_hook();

plnr = X(the_planner)();

Expand Down Expand Up @@ -178,7 +171,7 @@ apiplan *X(mkapiplan)(int sign, unsigned flags, problem *prb)
#endif

if (after_planner_hook)
after_planner_hook(planner_hook_arg);
after_planner_hook();

return p;
}
Expand Down
9 changes: 1 addition & 8 deletions api/fftw3.h
Expand Up @@ -107,8 +107,6 @@ struct fftw_iodim64_do_not_use_me {

typedef void (*fftw_write_char_func_do_not_use_me)(char c, void *);
typedef int (*fftw_read_char_func_do_not_use_me)(void *);
typedef void (*fftw_before_planner_hook_do_not_use_me)(void *arg);
typedef void (*fftw_after_planner_hook_do_not_use_me)(void *arg);

/*
huge second-order macro that defines prototypes for all API
Expand All @@ -132,12 +130,6 @@ typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \
\
typedef fftw_write_char_func_do_not_use_me X(write_char_func); \
typedef fftw_read_char_func_do_not_use_me X(read_char_func); \
typedef fftw_before_planner_hook_do_not_use_me X(before_planner_hook_t); \
typedef fftw_after_planner_hook_do_not_use_me X(after_planner_hook_t); \
\
FFTW_EXTERN void X(set_planner_hooks)(X(before_planner_hook_t) before, \
X(after_planner_hook_t) after, \
void *arg); \
\
FFTW_EXTERN void X(execute)(const X(plan) p); \
\
Expand Down Expand Up @@ -326,6 +318,7 @@ FFTW_EXTERN void X(set_timelimit)(double t); \
FFTW_EXTERN void X(plan_with_nthreads)(int nthreads); \
FFTW_EXTERN int X(init_threads)(void); \
FFTW_EXTERN void X(cleanup_threads)(void); \
FFTW_EXTERN void X(make_planner_thread_safe)(void); \
\
FFTW_EXTERN int X(export_wisdom_to_filename)(const char *filename); \
FFTW_EXTERN void X(export_wisdom_to_file)(FILE *output_file); \
Expand Down
29 changes: 2 additions & 27 deletions tests/fftw-bench.c
Expand Up @@ -110,6 +110,7 @@ void rdwisdom(void)
if (threads_ok) {
BENCH_ASSERT(FFTW(init_threads)());
FFTW(plan_with_nthreads)(nthreads);
FFTW(make_planner_thread_safe)();
#ifdef _OPENMP
omp_set_num_threads(nthreads);
#endif
Expand Down Expand Up @@ -196,26 +197,12 @@ int can_do(bench_problem *p)
return 0;
}

static int before_planner_hook_called = 0;
static int after_planner_hook_called = 0;
static void before_planner_hook(void *arg)
{
before_planner_hook_called = 1;
BENCH_ASSERT(arg == &before_planner_hook_called);
}
static void after_planner_hook(void *arg)
{
after_planner_hook_called = 1;
BENCH_ASSERT(arg == &before_planner_hook_called);
}

void setup(bench_problem *p)
{
double tim;
static int setup_hooks = 0;

setup_sigfpe_handler();

if (amnesia) {
FFTW(forget_wisdom)();
havewisdom = 0;
Expand All @@ -236,25 +223,13 @@ void setup(bench_problem *p)
if (verbose > 1 && nthreads > 1) printf("NTHREADS = %d\n", nthreads);
#endif

if (setup_hooks)
FFTW(set_planner_hooks(before_planner_hook, after_planner_hook, &before_planner_hook_called));

before_planner_hook_called = 0;
after_planner_hook_called = 0;

timer_start(USER_TIMER);
the_plan = mkplan(p, preserve_input_flags(p) | the_flags);
tim = timer_stop(USER_TIMER);
if (verbose > 1) printf("planner time: %g s\n", tim);

BENCH_ASSERT(the_plan);
BENCH_ASSERT(setup_hooks == before_planner_hook_called);
BENCH_ASSERT(setup_hooks == after_planner_hook_called);

/* do something different with hooks next time */
FFTW(set_planner_hooks(0, 0, 0));
setup_hooks = 1 - setup_hooks;

{
double add, mul, nfma, cost, pcost;
FFTW(flops)(the_plan, &add, &mul, &nfma);
Expand Down
5 changes: 5 additions & 0 deletions threads/api.c
Expand Up @@ -79,3 +79,8 @@ void X(plan_with_nthreads)(int nthreads)
plnr = X(the_planner)();
plnr->nthr = X(imax)(1, nthreads);
}

void X(make_planner_thread_safe)(void)
{
X(threads_register_planner_hooks)();
}
6 changes: 6 additions & 0 deletions threads/openmp.c
Expand Up @@ -74,3 +74,9 @@ void X(spawn_loop)(int loopmax, int nthr, spawn_function proc, void *data)
void X(threads_cleanup)(void)
{
}

/* FIXME [Matteo Frigo 2015-05-25] What does "thread-safe"
mean for openmp? */
void X(threads_register_planner_hooks)(void)
{
}
62 changes: 56 additions & 6 deletions threads/threads.c
Expand Up @@ -149,6 +149,12 @@ static void os_destroy_thread(void)
pthread_exit((void *)0);
}

/* support for static mutexes */
typedef pthread_mutex_t os_static_mutex_t;
#define OS_STATIC_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
static void os_static_mutex_lock(os_static_mutex_t *s) { pthread_mutex_lock(s); }
static void os_static_mutex_unlock(os_static_mutex_t *s) { pthread_mutex_unlock(s); }

#elif defined(__WIN32__) || defined(_WIN32) || defined(_WINDOWS)
/* hack: windef.h defines INT for its own purposes and this causes
a conflict with our own INT in ifftw.h. Divert the windows
Expand Down Expand Up @@ -221,7 +227,22 @@ static void os_destroy_thread(void)
_endthreadex(0);
}


/* windows does not have statically-initialized mutexes---fake a
spinlock */
typedef volatile LONG os_static_mutex_t;
#define OS_STATIC_MUTEX_INITIALIZER 0
static void os_static_mutex_lock(os_static_mutex_t *s)
{
while (InterlockedExchange(s, 1) == 1) {
YieldProcessor();
Sleep(0);
}
}
static void os_static_mutex_unlock(os_static_mutex_t *s)
{
LONG old = InterlockedExchange(s, 0);
A(old == 1);
}
#else
#error "No threading layer defined"
#endif
Expand Down Expand Up @@ -354,14 +375,18 @@ static void kill_workforce(void)
THREAD_OFF;
}

static os_static_mutex_t initialization_mutex = OS_STATIC_MUTEX_INITIALIZER;

int X(ithreads_init)(void)
{
os_mutex_init(&queue_lock);
os_sem_init(&termination_semaphore);
os_static_mutex_lock(&initialization_mutex); {
os_mutex_init(&queue_lock);
os_sem_init(&termination_semaphore);

WITH_QUEUE_LOCK({
worker_queue = 0;
})
WITH_QUEUE_LOCK({
worker_queue = 0;
});
} os_static_mutex_unlock(&initialization_mutex);

return 0; /* no error */
}
Expand Down Expand Up @@ -437,3 +462,28 @@ void X(threads_cleanup)(void)
os_mutex_destroy(&queue_lock);
os_sem_destroy(&termination_semaphore);
}

static os_static_mutex_t install_planner_hooks_mutex = OS_STATIC_MUTEX_INITIALIZER;
static os_mutex_t planner_mutex;
static int planner_hooks_installed = 0;

static void lock_planner_mutex(void)
{
os_mutex_lock(&planner_mutex);
}

static void unlock_planner_mutex(void)
{
os_mutex_unlock(&planner_mutex);
}

void X(threads_register_planner_hooks)(void)
{
os_static_mutex_lock(&install_planner_hooks_mutex); {
if (!planner_hooks_installed) {
os_mutex_init(&planner_mutex);
X(set_planner_hooks)(lock_planner_mutex, unlock_planner_mutex);
planner_hooks_installed = 1;
}
} os_static_mutex_unlock(&install_planner_hooks_mutex);
}
2 changes: 2 additions & 0 deletions threads/threads.h
Expand Up @@ -51,4 +51,6 @@ hc2hc_solver *X(mksolver_hc2hc_threads)(size_t size, INT r, hc2hc_mkinferior mkc
void X(threads_conf_standard)(planner *p);
void X(threads_register_hooks)(void);
void X(threads_unregister_hooks)(void);
void X(threads_register_planner_hooks)(void);

#endif /* __THREADS_H__ */

0 comments on commit d3442a8

Please sign in to comment.