Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Threading without using patched LLVM #14083

Merged
merged 6 commits into from
Nov 23, 2015
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
6 changes: 0 additions & 6 deletions Make.inc
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,6 @@ else
DISABLE_ASSERTIONS := -DNDEBUG
endif

# Threads
ifeq ($(JULIA_THREADS), 1)
LLVM_VER := svn
LLVM_GIT_URL_LLVM := https://github.com/JuliaLang/llvm.git -b jn/tls37
endif

# Compiler specific stuff

ifeq ($(USEMSVC), 1)
Expand Down
2 changes: 0 additions & 2 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -955,8 +955,6 @@ extern int jl_in_inference;
extern int jl_boot_file_loaded;
int jl_eval_with_compiler_p(jl_expr_t *ast, jl_expr_t *expr, int compileloops, jl_module_t *m);

JL_DEFINE_MUTEX_EXT(codegen)

static int jl_eval_inner_with_compiler(jl_expr_t *e, jl_module_t *m)
{
int i;
Expand Down
21 changes: 19 additions & 2 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2124,12 +2124,29 @@ static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **arg
}
}

static Value *emit_ptls_states()
{
#ifndef JULIA_ENABLE_THREADING
return prepare_global(jltls_states_var);
#else
return builder.CreateCall(prepare_call(jltls_states_func));
#endif
}

static Value *emit_pgcstack()
{
return prepare_global(jlpgcstack_var);
Value * addr = emit_nthptr_addr(
emit_ptls_states(),
(ssize_t)(offsetof(jl_tls_states_t, pgcstack) / sizeof(void*)));
return builder.CreateBitCast(addr, PointerType::get(T_ppjlvalue, 0),
"jl_pgcstack");
}

static Value *emit_exc_in_transit()
{
return prepare_global(jlexc_var);
Value * addr = emit_nthptr_addr(
emit_ptls_states(),
(ssize_t)(offsetof(jl_tls_states_t,
exception_in_transit) / sizeof(void*)));
return builder.CreateBitCast(addr, T_ppjlvalue, "jl_exception_in_transit");
}
48 changes: 27 additions & 21 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,8 +447,6 @@ static GlobalVariable *jlemptytuple_var;
#ifdef JL_NEED_FLOATTEMP_VAR
static GlobalVariable *jlfloattemp_var;
#endif
static GlobalVariable *jlpgcstack_var;
static GlobalVariable *jlexc_var;
static GlobalVariable *jldiverr_var;
static GlobalVariable *jlundeferr_var;
static GlobalVariable *jldomerr_var;
Expand All @@ -467,6 +465,12 @@ extern JITMemoryManager* createJITMemoryManagerWin();
extern RTDyldMemoryManager* createRTDyldMemoryManagerOSX();
#endif

#ifndef JULIA_ENABLE_THREADING
static GlobalVariable *jltls_states_var;
#else
static Function *jltls_states_func;
#endif

// important functions
static Function *jlnew_func;
static Function *jlthrow_func;
Expand Down Expand Up @@ -917,8 +921,6 @@ static void maybe_alloc_arrayvar(jl_sym_t *s, jl_codectx_t *ctx)
}
}

JL_DEFINE_MUTEX_EXT(codegen)

// Snooping on which functions are being compiled, and how long it takes
JL_STREAM *dump_compiles_stream = NULL;
uint64_t last_time = 0;
Expand Down Expand Up @@ -5574,23 +5576,6 @@ static void init_julia_llvm_env(Module *m)
"jl_array_t");
jl_parray_llvmt = PointerType::get(jl_array_llvmt,0);

#ifdef JULIA_ENABLE_THREADING
#define JL_THREAD_MODEL ,GlobalValue::GeneralDynamicTLSModel
#else
#define JL_THREAD_MODEL
#endif
jlpgcstack_var =
new GlobalVariable(*m, T_ppjlvalue,
false, GlobalVariable::ExternalLinkage,
NULL, "jl_pgcstack", NULL JL_THREAD_MODEL);
add_named_global(jlpgcstack_var, jl_dlsym(jl_dl_handle, "jl_pgcstack"));

jlexc_var =
new GlobalVariable(*m, T_pjlvalue,
false, GlobalVariable::ExternalLinkage,
NULL, "jl_exception_in_transit", NULL JL_THREAD_MODEL);
add_named_global(jlexc_var, jl_dlsym(jl_dl_handle, "jl_exception_in_transit"));

global_to_llvm("__stack_chk_guard", (void*)&__stack_chk_guard, m);
Function *jl__stack_chk_fail =
Function::Create(FunctionType::get(T_void, false),
Expand Down Expand Up @@ -5640,6 +5625,27 @@ static void init_julia_llvm_env(Module *m)
"jl_float_temp"));
#endif

#ifndef JULIA_ENABLE_THREADING
size_t tls_states_size = LLT_ALIGN(sizeof(jl_tls_states_t),
sizeof(void*)) / sizeof(void*);
jltls_states_var =
new GlobalVariable(*m, ArrayType::get(T_pint8, tls_states_size),
false, GlobalVariable::ExternalLinkage,
NULL, "jl_tls_states");
add_named_global(jltls_states_var, (void*)&jl_tls_states);
#else
jltls_states_func = Function::Create(FunctionType::get(T_ppint8, false),
Function::ExternalLinkage,
"jl_get_ptls_states", m);
jltls_states_func->setAttributes(
jltls_states_func->getAttributes()
.addAttribute(jltls_states_func->getContext(),
AttributeSet::FunctionIndex, Attribute::ReadNone)
.addAttribute(jltls_states_func->getContext(),
AttributeSet::FunctionIndex, Attribute::NoUnwind));
add_named_global(jltls_states_func, (void*)jl_get_ptls_states_getter());
#endif

std::vector<Type*> args1(0);
args1.push_back(T_pint8);
jlerror_func =
Expand Down
2 changes: 1 addition & 1 deletion src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ typedef struct {
// In the single-threaded version, they are essentially noops, but nonetheless
// serve to check that the thread context macros are being used.
#ifdef JULIA_ENABLE_THREADING
static JL_THREAD jl_thread_heap_t *jl_thread_heap;
#define jl_thread_heap (jl_get_ptls_states()->heap)
#define FOR_EACH_HEAP() \
for (jl_each_heap_index_t __current_heap_idx = {jl_n_threads, NULL}; \
--current_heap_index >= 0 && \
Expand Down
1 change: 0 additions & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,6 @@ jl_function_t *jl_method_cache_insert(jl_methtable_t *mt, jl_tupletype_t *type,
can be equal to "li" if not applicable.
*/
int jl_in_inference = 0;
JL_DEFINE_MUTEX_EXT(codegen)
void jl_type_infer(jl_lambda_info_t *li, jl_tupletype_t *argtypes, jl_lambda_info_t *def)
{
JL_LOCK(codegen);
Expand Down
4 changes: 4 additions & 0 deletions src/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,10 @@ static void jl_resolve_sysimg_location(JL_IMAGE_SEARCH rel)

void _julia_init(JL_IMAGE_SEARCH rel)
{
#ifdef JULIA_ENABLE_THREADING
// Make sure we finalize the tls callback before starting any threads.
jl_get_ptls_states_getter();
#endif
libsupport_init();
jl_io_loop = uv_default_loop(); // this loop will internal events (spawning process etc.),
// best to call this first, since it also initializes libuv
Expand Down
52 changes: 31 additions & 21 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,30 +57,19 @@ extern "C" {

// threading ------------------------------------------------------------------

// WARNING: Threading support is incomplete and experimental (and only works with llvm-svn)
// Nonetheless, we define JL_THREAD and use it to give advanced notice to maintainers
// of what eventual threading support will change.
// WARNING: Threading support is incomplete and experimental
// Nonetheless, we define JL_THREAD and use it to give advanced notice to
// maintainers of what eventual threading support will change.

// JULIA_ENABLE_THREADING is switched on in Make.inc if JULIA_THREADS is
// set (in Make.user)

#ifndef JULIA_ENABLE_THREADING
// Definition for compiling non-thread-safe Julia.
# define JL_THREAD
#elif !defined(_OS_WINDOWS_)
// Definition for compiling Julia on platforms with GCC __thread.
# define JL_THREAD __thread
#else
// Definition for compiling Julia on Windows
# define JL_THREAD __declspec(thread)
#endif

DLLEXPORT int16_t jl_threadid(void);
DLLEXPORT void *jl_threadgroup(void);
DLLEXPORT void jl_cpu_pause(void);
DLLEXPORT void jl_threading_profile(void);

#if __GNUC__
#if defined(__GNUC__)
# define JL_ATOMIC_FETCH_AND_ADD(a,b) \
__sync_fetch_and_add(&(a), (b))
# define JL_ATOMIC_COMPARE_AND_SWAP(a,b,c) \
Expand All @@ -93,7 +82,7 @@ DLLEXPORT void jl_threading_profile(void);
# define JL_ATOMIC_FETCH_AND_ADD(a,b) \
_InterlockedExchangeAdd((volatile LONG *)&(a), (b))
# define JL_ATOMIC_COMPARE_AND_SWAP(a,b,c) \
_InterlockedCompareExchange64(&(a), (c), (b))
_InterlockedCompareExchange64((volatile LONG64 *)&(a), (c), (b))
# define JL_ATOMIC_TEST_AND_SET(a) \
_InterlockedExchange64(&(a), 1)
# define JL_ATOMIC_RELEASE(a) \
Expand Down Expand Up @@ -585,7 +574,7 @@ typedef struct _jl_gcframe_t {
// jl_value_t *x=NULL, *y=NULL; JL_GC_PUSH2(&x, &y);
// x = f(); y = g(); foo(x, y)

extern DLLEXPORT JL_THREAD jl_gcframe_t *jl_pgcstack;
#define jl_pgcstack (jl_get_ptls_states()->pgcstack)

#define JL_GC_PUSH1(arg1) \
void *__gc_stkf[] = {(void*)3, jl_pgcstack, arg1}; \
Expand Down Expand Up @@ -1485,17 +1474,38 @@ typedef struct {
jl_value_t * volatile *ptask_arg_in_transit;
} jl_thread_task_state_t;

extern DLLEXPORT JL_THREAD jl_task_t * volatile jl_current_task;
extern DLLEXPORT JL_THREAD jl_task_t *jl_root_task;
extern DLLEXPORT JL_THREAD jl_value_t *jl_exception_in_transit;
extern DLLEXPORT JL_THREAD jl_value_t * volatile jl_task_arg_in_transit;
#define jl_current_task (jl_get_ptls_states()->current_task)
#define jl_root_task (jl_get_ptls_states()->root_task)
#define jl_exception_in_transit (jl_get_ptls_states()->exception_in_transit)
#define jl_task_arg_in_transit (jl_get_ptls_states()->task_arg_in_transit)

DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, size_t ssize);
DLLEXPORT jl_value_t *jl_switchto(jl_task_t *t, jl_value_t *arg);
DLLEXPORT void NORETURN jl_throw(jl_value_t *e);
DLLEXPORT void NORETURN jl_rethrow(void);
DLLEXPORT void NORETURN jl_rethrow_other(jl_value_t *e);

typedef struct _jl_tls_states_t {
jl_gcframe_t *pgcstack;
jl_value_t *exception_in_transit;
struct _jl_thread_heap_t *heap;
jl_task_t *volatile current_task;
jl_task_t *root_task;
jl_value_t *volatile task_arg_in_transit;
void *stackbase;
jl_jmp_buf *volatile jmp_target;
jl_jmp_buf base_ctx; // base context of stack
int16_t tid;
} jl_tls_states_t;
DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void);
#ifndef JULIA_ENABLE_THREADING
extern DLLEXPORT jl_tls_states_t jl_tls_states;
#define jl_get_ptls_states() (&jl_tls_states)
#else
typedef jl_tls_states_t *(*jl_get_ptls_states_func)(void);
DLLEXPORT void jl_set_ptls_states_getter(jl_get_ptls_states_func f);
#endif

STATIC_INLINE void jl_eh_restore_state(jl_handler_t *eh)
{
JL_SIGATOMIC_BEGIN();
Expand Down
7 changes: 6 additions & 1 deletion src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ void jl_init_serializer(void);

void _julia_init(JL_IMAGE_SEARCH rel);
#ifdef COPY_STACKS
extern JL_THREAD void *jl_stackbase;
#define jl_stackbase (jl_get_ptls_states()->stackbase)
#endif

void jl_set_stackbase(char *__stk);
Expand All @@ -155,6 +155,9 @@ void jl_set_base_ctx(char *__stk);
void jl_init_threading(void);
void jl_start_threads(void);
void jl_shutdown_threading(void);
#ifdef JULIA_ENABLE_THREADING
jl_get_ptls_states_func jl_get_ptls_states_getter(void);
#endif

void jl_dump_bitcode(char *fname, const char *sysimg_data, size_t sysimg_len);
void jl_dump_objfile(char *fname, int jit_model, const char *sysimg_data, size_t sysimg_len);
Expand Down Expand Up @@ -335,6 +338,8 @@ DLLEXPORT jl_value_t *jl_flipsign_int(jl_value_t *a, jl_value_t *b);
DLLEXPORT jl_value_t *jl_select_value(jl_value_t *isfalse, jl_value_t *a, jl_value_t *b);
DLLEXPORT jl_value_t *jl_arraylen(jl_value_t *a);

JL_DEFINE_MUTEX_EXT(codegen)

#ifdef __cplusplus
}
#endif
Expand Down
11 changes: 3 additions & 8 deletions src/task.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,21 +138,17 @@ static jl_sym_t *runnable_sym;

extern size_t jl_page_size;
jl_datatype_t *jl_task_type;
DLLEXPORT JL_THREAD jl_task_t * volatile jl_current_task;
JL_THREAD jl_task_t *jl_root_task;
DLLEXPORT JL_THREAD jl_value_t *jl_exception_in_transit;
DLLEXPORT JL_THREAD jl_gcframe_t *jl_pgcstack = NULL;
#define jl_root_task (jl_get_ptls_states()->root_task)

#ifdef COPY_STACKS
static JL_THREAD jl_jmp_buf * volatile jl_jmp_target;
#define jl_jmp_target (jl_get_ptls_states()->jmp_target)

#if (defined(_CPU_X86_64_) || defined(_CPU_X86_)) && !defined(_COMPILER_MICROSOFT_)
#define ASM_COPY_STACKS
#endif
JL_THREAD void *jl_stackbase;

#ifndef ASM_COPY_STACKS
static JL_THREAD jl_jmp_buf jl_base_ctx; // base context of stack
#define jl_base_ctx (jl_get_ptls_states()->base_ctx)
#endif

static void NOINLINE save_stack(jl_task_t *t)
Expand Down Expand Up @@ -359,7 +355,6 @@ static void ctx_switch(jl_task_t *t, jl_jmp_buf *where)
//JL_SIGATOMIC_END();
}

JL_THREAD jl_value_t * volatile jl_task_arg_in_transit;
extern int jl_in_gc;
DLLEXPORT jl_value_t *jl_switchto(jl_task_t *t, jl_value_t *arg)
{
Expand Down
51 changes: 50 additions & 1 deletion src/threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#ifndef _MSC_VER
#include <unistd.h>
#include <sched.h>
#else
#define sleep(x) Sleep(1000*x)
#endif

#include "julia.h"
Expand All @@ -34,8 +36,55 @@ extern "C" {
#include "threadgroup.h"
#include "threading.h"

#ifdef JULIA_ENABLE_THREADING
// fallback provided for embedding
static JL_CONST_FUNC jl_tls_states_t *jl_get_ptls_states_fallback(void)
{
# if !defined(_COMPILER_MICROSOFT_)
static __thread jl_tls_states_t tls_states;
# else
static __declspec(thread) jl_tls_states_t tls_states;
# endif
return &tls_states;
}
static jl_tls_states_t *jl_get_ptls_states_init(void);
static jl_get_ptls_states_func jl_tls_states_cb = jl_get_ptls_states_init;
static jl_tls_states_t *jl_get_ptls_states_init(void)
{
// This is clearly not thread safe but should be fine since we
// make sure the tls states callback is finalized before adding
// multiple threads
jl_tls_states_cb = jl_get_ptls_states_fallback;
return jl_get_ptls_states_fallback();
}
DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void)
{
return (*jl_tls_states_cb)();
}
DLLEXPORT void jl_set_ptls_states_getter(jl_get_ptls_states_func f)
{
// only allow setting this once
if (f && f != jl_get_ptls_states_init &&
jl_tls_states_cb == jl_get_ptls_states_init) {
jl_tls_states_cb = f;
}
}
jl_get_ptls_states_func jl_get_ptls_states_getter(void)
{
if (jl_tls_states_cb == jl_get_ptls_states_init)
jl_get_ptls_states_init();
// for codegen
return jl_tls_states_cb;
}
#else
DLLEXPORT jl_tls_states_t jl_tls_states;
DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void)
{
return &jl_tls_states;
}
#endif

// thread ID
JL_THREAD int16_t ti_tid = 0;
DLLEXPORT int jl_n_threads; // # threads we're actually using
DLLEXPORT int jl_max_threads; // # threads possible
jl_thread_task_state_t *jl_all_task_states;
Expand Down
Loading