Commit fe5fc746 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Purge the old GRWL (gil-free) code

It's time :(
parent d7be5092
...@@ -37,8 +37,6 @@ ...@@ -37,8 +37,6 @@
namespace pyston { namespace pyston {
DS_DEFINE_RWLOCK(codegen_rwlock);
FunctionMetadata::FunctionMetadata(int num_args, bool takes_varargs, bool takes_kwargs, FunctionMetadata::FunctionMetadata(int num_args, bool takes_varargs, bool takes_kwargs,
std::unique_ptr<SourceInfo> source) std::unique_ptr<SourceInfo> source)
: code_obj(NULL), : code_obj(NULL),
......
...@@ -90,8 +90,6 @@ extern GlobalState g; ...@@ -90,8 +90,6 @@ extern GlobalState g;
// in runtime_hooks.cpp: // in runtime_hooks.cpp:
void initGlobalFuncs(GlobalState& g); void initGlobalFuncs(GlobalState& g);
DS_DECLARE_RWLOCK(codegen_rwlock);
} }
#endif #endif
...@@ -341,9 +341,6 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s ...@@ -341,9 +341,6 @@ CompiledFunction* compileFunction(FunctionMetadata* f, FunctionSpecialization* s
void compileAndRunModule(AST_Module* m, BoxedModule* bm) { void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
FunctionMetadata* md; FunctionMetadata* md;
{ // scope for limiting the locked region:
LOCK_REGION(codegen_rwlock.asWrite());
Timer _t("for compileModule()"); Timer _t("for compileModule()");
const char* fn = PyModule_GetFilename(bm); const char* fn = PyModule_GetFilename(bm);
...@@ -364,7 +361,6 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) { ...@@ -364,7 +361,6 @@ void compileAndRunModule(AST_Module* m, BoxedModule* bm) {
bm->setattr(builtins_str, PyModule_GetDict(builtins_module), NULL); bm->setattr(builtins_str, PyModule_GetDict(builtins_module), NULL);
md = new FunctionMetadata(0, false, false, std::move(si)); md = new FunctionMetadata(0, false, false, std::move(si));
}
UNAVOIDABLE_STAT_TIMER(t0, "us_timer_interpreted_module_toplevel"); UNAVOIDABLE_STAT_TIMER(t0, "us_timer_interpreted_module_toplevel");
Box* r = astInterpretFunction(md, NULL, NULL, NULL, NULL, NULL, NULL, NULL); Box* r = astInterpretFunction(md, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
...@@ -395,8 +391,6 @@ Box* evalOrExec(FunctionMetadata* md, Box* globals, Box* boxedLocals) { ...@@ -395,8 +391,6 @@ Box* evalOrExec(FunctionMetadata* md, Box* globals, Box* boxedLocals) {
static FunctionMetadata* compileForEvalOrExec(AST* source, llvm::ArrayRef<AST_stmt*> body, BoxedString* fn, static FunctionMetadata* compileForEvalOrExec(AST* source, llvm::ArrayRef<AST_stmt*> body, BoxedString* fn,
PyCompilerFlags* flags) { PyCompilerFlags* flags) {
LOCK_REGION(codegen_rwlock.asWrite());
Timer _t("for evalOrExec()"); Timer _t("for evalOrExec()");
ScopingAnalysis* scoping = new ScopingAnalysis(source, false); ScopingAnalysis* scoping = new ScopingAnalysis(source, false);
...@@ -655,8 +649,6 @@ void exec(Box* boxedCode, Box* globals, Box* locals, FutureFlags caller_future_f ...@@ -655,8 +649,6 @@ void exec(Box* boxedCode, Box* globals, Box* locals, FutureFlags caller_future_f
// TODO we should have logic like this at the CLFunc level that detects that we keep // TODO we should have logic like this at the CLFunc level that detects that we keep
// on creating functions with failing speculations, and then stop speculating. // on creating functions with failing speculations, and then stop speculating.
void CompiledFunction::speculationFailed() { void CompiledFunction::speculationFailed() {
LOCK_REGION(codegen_rwlock.asWrite());
this->times_speculation_failed++; this->times_speculation_failed++;
if (this->times_speculation_failed == 4) { if (this->times_speculation_failed == 4) {
...@@ -735,8 +727,6 @@ ConcreteCompilerType* CompiledFunction::getReturnType() { ...@@ -735,8 +727,6 @@ ConcreteCompilerType* CompiledFunction::getReturnType() {
/// The cf must be an active version in its parents FunctionMetadata; the given /// The cf must be an active version in its parents FunctionMetadata; the given
/// version will be replaced by the new version, which will be returned. /// version will be replaced by the new version, which will be returned.
static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel new_effort) { static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel new_effort) {
LOCK_REGION(codegen_rwlock.asWrite());
assert(cf->md->versions.size()); assert(cf->md->versions.size());
assert(cf); assert(cf);
...@@ -773,8 +763,6 @@ static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel new_effort) ...@@ -773,8 +763,6 @@ static CompiledFunction* _doReopt(CompiledFunction* cf, EffortLevel new_effort)
static StatCounter stat_osrexits("num_osr_exits"); static StatCounter stat_osrexits("num_osr_exits");
static StatCounter stat_osr_compiles("num_osr_compiles"); static StatCounter stat_osr_compiles("num_osr_compiles");
CompiledFunction* compilePartialFuncInternal(OSRExit* exit) { CompiledFunction* compilePartialFuncInternal(OSRExit* exit) {
LOCK_REGION(codegen_rwlock.asWrite());
assert(exit); assert(exit);
stat_osrexits.log(); stat_osrexits.log();
......
...@@ -36,6 +36,8 @@ ...@@ -36,6 +36,8 @@
namespace pyston { namespace pyston {
namespace threading { namespace threading {
void _acquireGIL();
void _releaseGIL();
#ifdef WITH_THREAD #ifdef WITH_THREAD
#include "pythread.h" #include "pythread.h"
...@@ -99,14 +101,14 @@ public: ...@@ -99,14 +101,14 @@ public:
return holds_gil; return holds_gil;
} }
void takeGil() { void gilTaken() {
assert(pthread_self() == this->pthread_id); assert(pthread_self() == this->pthread_id);
assert(!holds_gil); assert(!holds_gil);
holds_gil = true; holds_gil = true;
} }
void releaseGil() { void gilReleased() {
assert(pthread_self() == this->pthread_id); assert(pthread_self() == this->pthread_id);
assert(holds_gil); assert(holds_gil);
...@@ -197,7 +199,7 @@ extern "C" PyGILState_STATE PyGILState_Ensure(void) noexcept { ...@@ -197,7 +199,7 @@ extern "C" PyGILState_STATE PyGILState_Ensure(void) noexcept {
if (current_internal_thread_state == NULL) if (current_internal_thread_state == NULL)
Py_FatalError("Couldn't create thread-state for new thread"); Py_FatalError("Couldn't create thread-state for new thread");
acquireGLRead(); _acquireGIL();
return PyGILState_UNLOCKED; return PyGILState_UNLOCKED;
} else { } else {
++cur_thread_state.gilstate_counter; ++cur_thread_state.gilstate_counter;
...@@ -246,13 +248,14 @@ static void* _thread_start(void* _arg) { ...@@ -246,13 +248,14 @@ static void* _thread_start(void* _arg) {
Box* arg3 = arg->arg3; Box* arg3 = arg->arg3;
delete arg; delete arg;
threading::GLReadRegion _glock; _acquireGIL();
registerThread(true); registerThread(true);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
void* rtn = start_func(arg1, arg2, arg3); void* rtn = start_func(arg1, arg2, arg3);
unregisterThread(); unregisterThread();
_releaseGIL();
return rtn; return rtn;
} }
...@@ -296,6 +299,8 @@ void registerMainThread() { ...@@ -296,6 +299,8 @@ void registerMainThread() {
assert(!current_internal_thread_state); assert(!current_internal_thread_state);
current_internal_thread_state = new ThreadStateInternal(pthread_self(), &cur_thread_state); current_internal_thread_state = new ThreadStateInternal(pthread_self(), &cur_thread_state);
current_threads[pthread_self()] = current_internal_thread_state; current_threads[pthread_self()] = current_internal_thread_state;
_acquireGIL();
} }
/* Wait until threading._shutdown completes, provided /* Wait until threading._shutdown completes, provided
...@@ -344,28 +349,23 @@ extern "C" void beginAllowThreads() noexcept { ...@@ -344,28 +349,23 @@ extern "C" void beginAllowThreads() noexcept {
LOCK_REGION(&threading_lock); LOCK_REGION(&threading_lock);
assert(current_internal_thread_state); assert(current_internal_thread_state);
current_internal_thread_state->releaseGil(); current_internal_thread_state->gilReleased();
} }
releaseGLRead(); _releaseGIL();
} }
extern "C" void endAllowThreads() noexcept { extern "C" void endAllowThreads() noexcept {
acquireGLRead(); _acquireGIL();
{ {
LOCK_REGION(&threading_lock); LOCK_REGION(&threading_lock);
assert(current_internal_thread_state); assert(current_internal_thread_state);
current_internal_thread_state->takeGil(); current_internal_thread_state->gilTaken();
} }
} }
#if THREADING_USE_GIL
#if THREADING_USE_GRWL
#error "Can't turn on both the GIL and the GRWL!"
#endif
static pthread_mutex_t gil = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t gil = PTHREAD_MUTEX_INITIALIZER;
std::atomic<int> threads_waiting_on_gil(0); std::atomic<int> threads_waiting_on_gil(0);
...@@ -423,7 +423,7 @@ extern "C" void PyEval_ReInitThreads() noexcept { ...@@ -423,7 +423,7 @@ extern "C" void PyEval_ReInitThreads() noexcept {
Py_DECREF(threading); Py_DECREF(threading);
} }
void acquireGLWrite() { void _acquireGIL() {
threads_waiting_on_gil++; threads_waiting_on_gil++;
pthread_mutex_lock(&gil); pthread_mutex_lock(&gil);
threads_waiting_on_gil--; threads_waiting_on_gil--;
...@@ -431,7 +431,7 @@ void acquireGLWrite() { ...@@ -431,7 +431,7 @@ void acquireGLWrite() {
pthread_cond_signal(&gil_acquired); pthread_cond_signal(&gil_acquired);
} }
void releaseGLWrite() { void _releaseGIL() {
pthread_mutex_unlock(&gil); pthread_mutex_unlock(&gil);
} }
...@@ -457,86 +457,6 @@ void _allowGLReadPreemption() { ...@@ -457,86 +457,6 @@ void _allowGLReadPreemption() {
threads_waiting_on_gil--; threads_waiting_on_gil--;
pthread_cond_signal(&gil_acquired); pthread_cond_signal(&gil_acquired);
} }
#elif THREADING_USE_GRWL
static pthread_rwlock_t grwl = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP;
enum class GRWLHeldState {
N,
R,
W,
};
static __thread GRWLHeldState grwl_state = GRWLHeldState::N;
static std::atomic<int> writers_waiting(0);
void acquireGLRead() {
assert(grwl_state == GRWLHeldState::N);
pthread_rwlock_rdlock(&grwl);
grwl_state = GRWLHeldState::R;
}
void releaseGLRead() {
assert(grwl_state == GRWLHeldState::R);
pthread_rwlock_unlock(&grwl);
grwl_state = GRWLHeldState::N;
}
void acquireGLWrite() {
assert(grwl_state == GRWLHeldState::N);
writers_waiting++;
pthread_rwlock_wrlock(&grwl);
writers_waiting--;
grwl_state = GRWLHeldState::W;
}
void releaseGLWrite() {
assert(grwl_state == GRWLHeldState::W);
pthread_rwlock_unlock(&grwl);
grwl_state = GRWLHeldState::N;
}
void promoteGL() {
Timer _t2("promoting", /*min_usec=*/10000);
// Note: this is *not* the same semantics as normal promoting, on purpose.
releaseGLRead();
acquireGLWrite();
long promote_us = _t2.end();
static thread_local StatPerThreadCounter sc_promoting_us("grwl_promoting_us");
sc_promoting_us.log(promote_us);
}
void demoteGL() {
releaseGLWrite();
acquireGLRead();
}
static __thread int gl_check_count = 0;
void allowGLReadPreemption() {
assert(grwl_state == GRWLHeldState::R);
// gl_check_count++;
// if (gl_check_count < 10)
// return;
// gl_check_count = 0;
if (__builtin_expect(!writers_waiting.load(std::memory_order_relaxed), 1))
return;
Timer _t2("preempted", /*min_usec=*/10000);
pthread_rwlock_unlock(&grwl);
// The GRWL is a writer-prefered rwlock, so this next statement will block even
// if the lock is in read mode:
pthread_rwlock_rdlock(&grwl);
long preempt_us = _t2.end();
static thread_local StatPerThreadCounter sc_preempting_us("grwl_preempt_us");
sc_preempting_us.log(preempt_us);
}
#endif
// We don't support CPython's TLS (yet?) // We don't support CPython's TLS (yet?)
extern "C" void PyThread_ReInitTLS(void) noexcept { extern "C" void PyThread_ReInitTLS(void) noexcept {
......
...@@ -47,35 +47,10 @@ void finishMainThread(); ...@@ -47,35 +47,10 @@ void finishMainThread();
bool isMainThread(); bool isMainThread();
#ifndef THREADING_USE_GIL
#define THREADING_USE_GIL 1
#define THREADING_USE_GRWL 0
#endif
#define THREADING_SAFE_DATASTRUCTURES THREADING_USE_GRWL
#if THREADING_SAFE_DATASTRUCTURES
#define DS_DEFINE_MUTEX(name) pyston::threading::PthreadFastMutex name
#define DS_DECLARE_RWLOCK(name) extern pyston::threading::PthreadRWLock name
#define DS_DEFINE_RWLOCK(name) pyston::threading::PthreadRWLock name
#define DS_DEFINE_SPINLOCK(name) pyston::threading::PthreadSpinLock name
#else
#define DS_DEFINE_MUTEX(name) pyston::threading::NopLock name
#define DS_DECLARE_RWLOCK(name) extern pyston::threading::NopLock name
#define DS_DEFINE_RWLOCK(name) pyston::threading::NopLock name
#define DS_DEFINE_SPINLOCK(name) pyston::threading::NopLock name
#endif
void acquireGLRead();
void releaseGLRead();
void acquireGLWrite();
void releaseGLWrite();
void _allowGLReadPreemption(); void _allowGLReadPreemption();
#define GIL_CHECK_INTERVAL 1000 #define GIL_CHECK_INTERVAL 1000
// Note: this doesn't need to be an atomic, since it should // Note: this doesn't need to be an atomic, since it should
// only be accessed by the thread that holds the gil: // only be accessed by the thread that holds the gil:
extern int gil_check_count; extern int gil_check_count;
...@@ -104,25 +79,7 @@ extern "C" inline void allowGLReadPreemption() { ...@@ -104,25 +79,7 @@ extern "C" inline void allowGLReadPreemption() {
_allowGLReadPreemption(); _allowGLReadPreemption();
} }
// Note: promoteGL is free to drop the lock and then reacquire
void promoteGL();
void demoteGL();
// Helper macro for creating a RAII wrapper around two functions.
#define MAKE_REGION(name, start, end) \
class name { \
public: \
name() { start(); } \
~name() { end(); } \
};
MAKE_REGION(GLReadRegion, acquireGLRead, releaseGLRead);
MAKE_REGION(GLPromoteRegion, promoteGL, demoteGL);
// MAKE_REGION(GLReadReleaseRegion, releaseGLRead, acquireGLRead);
// MAKE_REGION(GLWriteReleaseRegion, releaseGLWrite, acquireGLWrite);
#undef MAKE_REGION
extern "C" void beginAllowThreads() noexcept; extern "C" void beginAllowThreads() noexcept;
extern "C" void endAllowThreads() noexcept; extern "C" void endAllowThreads() noexcept;
...@@ -134,37 +91,6 @@ public: ...@@ -134,37 +91,6 @@ public:
}; };
#if THREADING_USE_GIL
inline void acquireGLRead() {
acquireGLWrite();
}
inline void releaseGLRead() {
releaseGLWrite();
}
inline void promoteGL() {
}
inline void demoteGL() {
}
#endif
#if !THREADING_USE_GIL && !THREADING_USE_GRWL
inline void acquireGLRead() {
}
inline void releaseGLRead() {
}
inline void acquireGLWrite() {
}
inline void releaseGLWrite() {
}
inline void promoteGL() {
}
inline void demoteGL() {
}
extern "C" inline void allowGLReadPreemption() __attribute__((visibility("default")));
extern "C" inline void allowGLReadPreemption() {
}
#endif
extern bool forgot_refs_via_fork; extern bool forgot_refs_via_fork;
} // namespace threading } // namespace threading
......
...@@ -369,7 +369,6 @@ static int main(int argc, char** argv) noexcept { ...@@ -369,7 +369,6 @@ static int main(int argc, char** argv) noexcept {
const char* fn = NULL; const char* fn = NULL;
threading::registerMainThread(); threading::registerMainThread();
threading::acquireGLRead();
Py_SetProgramName(argv[0]); Py_SetProgramName(argv[0]);
...@@ -540,11 +539,6 @@ static int main(int argc, char** argv) noexcept { ...@@ -540,11 +539,6 @@ static int main(int argc, char** argv) noexcept {
threading::finishMainThread(); threading::finishMainThread();
// Acquire the GIL to make sure we stop the other threads, since we will tear down
// data structures they are potentially running on.
// Note: we will purposefully not release the GIL on exiting.
threading::promoteGL();
_t.split("Py_Finalize"); _t.split("Py_Finalize");
Py_Finalize(); Py_Finalize();
......
...@@ -3967,8 +3967,6 @@ static StatCounter slowpath_pickversion("slowpath_pickversion"); ...@@ -3967,8 +3967,6 @@ static StatCounter slowpath_pickversion("slowpath_pickversion");
template <ExceptionStyle S> template <ExceptionStyle S>
static CompiledFunction* pickVersion(FunctionMetadata* f, int num_output_args, Box* oarg1, Box* oarg2, Box* oarg3, static CompiledFunction* pickVersion(FunctionMetadata* f, int num_output_args, Box* oarg1, Box* oarg2, Box* oarg3,
Box** oargs) { Box** oargs) {
LOCK_REGION(codegen_rwlock.asWrite());
// if always_use_version is set use it even if the exception style does not match. // if always_use_version is set use it even if the exception style does not match.
// But prefer using the correct style if both are available // But prefer using the correct style if both are available
if (f->always_use_version.get(S)) if (f->always_use_version.get(S))
......
...@@ -25,12 +25,10 @@ namespace pyston { ...@@ -25,12 +25,10 @@ namespace pyston {
class PystonTestEnvironment : public testing::Environment { class PystonTestEnvironment : public testing::Environment {
void SetUp() override { void SetUp() override {
threading::registerMainThread(); threading::registerMainThread();
threading::acquireGLRead();
} }
void TearDown() override { void TearDown() override {
threading::releaseGLRead(); // threading::releaseGLRead();
} }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment