Skip to content

Commit

Permalink
Only allow enabling/disabling tlbc
Browse files Browse the repository at this point in the history
  • Loading branch information
mpage committed Sep 13, 2024
1 parent 1bbbbbc commit e63e403
Show file tree
Hide file tree
Showing 16 changed files with 83 additions and 234 deletions.
2 changes: 1 addition & 1 deletion Include/cpython/initconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ typedef struct PyConfig {
int cpu_count;
#ifdef Py_GIL_DISABLED
int enable_gil;
int tlbc_limit;
int tlbc_enabled;
#endif

/* --- Path configuration inputs ------------ */
Expand Down
15 changes: 15 additions & 0 deletions Include/internal/pycore_ceval.h
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ _PyEval_IsGILEnabled(PyThreadState *tstate)
extern int _PyEval_EnableGILTransient(PyThreadState *tstate);
extern int _PyEval_EnableGILPermanent(PyThreadState *tstate);
extern int _PyEval_DisableGIL(PyThreadState *state);


static inline _Py_CODEUNIT *
_PyEval_GetExecutableCode(PyCodeObject *co)
{
_Py_CODEUNIT *bc = _PyCode_GetTLBCFast(co);
if (bc != NULL) {
return bc;
}
if (!_PyInterpreterState_GET()->config.tlbc_enabled) {
return _PyCode_CODE(co);
}
return _PyCode_GetTLBC(co);
}

#endif

extern void _PyEval_DeactivateOpCache(void);
Expand Down
48 changes: 7 additions & 41 deletions Include/internal/pycore_code.h
Original file line number Diff line number Diff line change
Expand Up @@ -633,24 +633,6 @@ PyAPI_DATA(const struct _PyCode8) _Py_InitCleanup;

#ifdef Py_GIL_DISABLED

typedef enum {
// No limit on the amount of memory consumed by thread-local bytecode.
// Terminal state.
_PY_TLBC_UNLIMITED = 0,

// The total amount of memory consumed by thread-local bytecode must be
// <= PyInterpreterState::tlbc_limit. State transitions to
// _PY_TLBC_DISABLED
// when the limit is reached.
_PY_TLBC_LIMITED = 1,

// New thread-local bytecode is disabled. Previously allocated copies
// may still be used. Terminal state.
_PY_TLBC_DISABLED = 2,
} _Py_TLBC_State;

extern void _PyCode_InitState(PyInterpreterState *interp);

// Return a pointer to the thread-local bytecode for the current thread, if it
// exists.
static inline _Py_CODEUNIT *
Expand All @@ -665,31 +647,15 @@ _PyCode_GetTLBCFast(PyCodeObject *co)
return NULL;
}

// Return a pointer to the thread-local bytecode for the current thread, creating
// it if it doesn't exist.
//
// On error, NULL is returned, new thread-local bytecode is disabled, and
// specialization is disabled for the "main" copy of the bytecode (the bytecode
// embedded in the code object) for all code objects.
extern _Py_CODEUNIT *_PyCode_GetTLBCSlow(PyCodeObject *co);

// Return the bytecode that should be executed by the current thread, creating
// a copy if necessary.
static inline _Py_CODEUNIT *
_PyCode_GetExecutableCode(PyCodeObject *co)
{
_Py_CODEUNIT *res = _PyCode_GetTLBCFast(co);
if (res != NULL) {
return res;
}
res = _PyCode_GetTLBCSlow(co);
if (res != NULL) {
return res;
}
return _PyCode_CODE(co);
}
// Return a pointer to the thread-local bytecode for the current thread,
// creating it if necessary.
extern _Py_CODEUNIT *_PyCode_GetTLBC(PyCodeObject *co);

// Reserve an index for the current thread into thread-local bytecode
// arrays
extern int _Py_ReserveTLBCIndex(PyInterpreterState *interp);

// Release the current thread's index into thread-local bytecode arrays
extern void _Py_ClearTLBCIndex(_PyThreadStateImpl *tstate);
#endif

Expand Down
5 changes: 0 additions & 5 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,6 @@ struct _is {
struct _Py_type_id_pool type_ids;
PyMutex weakref_locks[NUM_WEAKREF_LIST_LOCKS];
_PyIndexPool tlbc_indices;
// Number of bytes available for thread-local bytecode, counts down to
// zero.
Py_ssize_t tlbc_avail;
PyMutex tlbc_avail_mutex;
_Py_TLBC_State tlbc_state;
#endif

// Per-interpreter state for the obmalloc allocator. For the main
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_capi/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def test_config_get(self):
options.append(("run_presite", str | None, None))
if sysconfig.get_config_var('Py_GIL_DISABLED'):
options.append(("enable_gil", int, None))
options.append(("tlbc_limit", int, None))
options.append(("tlbc_enabled", int, None))
if support.MS_WINDOWS:
options.extend((
("legacy_windows_stdio", bool, None),
Expand Down
34 changes: 20 additions & 14 deletions Lib/test/test_cmd_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -1070,32 +1070,38 @@ def res2int(self, res):
return tuple(int(i) for i in out.split())

@unittest.skipUnless(support.Py_GIL_DISABLED,
"PYTHON_TLBC_LIMIT and -X tlbc_limit"
"PYTHON_TLBC and -X tlbc"
" only supported in Py_GIL_DISABLED builds")
@threading_helper.requires_working_threading()
def test_set_thread_local_bytecode_limit(self):
def test_disable_thread_local_bytecode(self):
code = """if 1:
import threading
def test(x, y):
return x + y
t = threading.Thread(target=test, args=(1,2))
t.start()
t.join()"""
rc, out, err = assert_python_ok("-W", "always", "-X", "tlbc_limit=1", "-c", code)
self.assertIn(b"Reached memory limit for thread-local bytecode", err)
rc, out, err = assert_python_ok("-W", "always", "-c", code, PYTHON_TLBC_LIMIT="1")
self.assertIn(b"Reached memory limit for thread-local bytecode", err)
assert_python_ok("-W", "always", "-X", "tlbc=0", "-c", code)
assert_python_ok("-W", "always", "-c", code, PYTHON_TLBC="0")

@unittest.skipUnless(support.Py_GIL_DISABLED,
"PYTHON_TLBC_LIMIT and -X tlbc_limit"
"PYTHON_TLBC and -X tlbc"
" only supported in Py_GIL_DISABLED builds")
def test_invalid_thread_local_bytecode_limit(self):
rc, out, err = assert_python_failure("-X", "tlbc_limit")
self.assertIn(b"tlbc_limit=n: n is missing or invalid", err)
rc, out, err = assert_python_failure("-X", "tlbc_limit=foo")
self.assertIn(b"tlbc_limit=n: n is missing or invalid", err)
rc, out, err = assert_python_failure(PYTHON_TLBC_LIMIT="foo")
self.assertIn(b"PYTHON_TLBC_LIMIT=N: N is missing or invalid", err)
def test_invalid_thread_local_bytecode(self):
rc, out, err = assert_python_failure("-X", "tlbc")
self.assertIn(b"tlbc=n: n is missing or invalid", err)
rc, out, err = assert_python_failure("-X", "tlbc=foo")
self.assertIn(b"tlbc=n: n is missing or invalid", err)
rc, out, err = assert_python_failure("-X", "tlbc=-1")
self.assertIn(b"tlbc=n: n is missing or invalid", err)
rc, out, err = assert_python_failure("-X", "tlbc=2")
self.assertIn(b"tlbc=n: n is missing or invalid", err)
rc, out, err = assert_python_failure(PYTHON_TLBC="foo")
self.assertIn(b"PYTHON_TLBC=N: N is missing or invalid", err)
rc, out, err = assert_python_failure(PYTHON_TLBC="-1")
self.assertIn(b"PYTHON_TLBC=N: N is missing or invalid", err)
rc, out, err = assert_python_failure(PYTHON_TLBC="2")
self.assertIn(b"PYTHON_TLBC=N: N is missing or invalid", err)


@unittest.skipIf(interpreter_requires_environment(),
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_embed.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ class InitConfigTests(EmbeddingTestsMixin, unittest.TestCase):
CONFIG_COMPAT['run_presite'] = None
if support.Py_GIL_DISABLED:
CONFIG_COMPAT['enable_gil'] = -1
CONFIG_COMPAT['tlbc_limit'] = GET_DEFAULT_CONFIG
CONFIG_COMPAT['tlbc_enabled'] = GET_DEFAULT_CONFIG
if MS_WINDOWS:
CONFIG_COMPAT.update({
'legacy_windows_stdio': False,
Expand Down
12 changes: 6 additions & 6 deletions Lib/test/test_tlbc.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def f(a, b, q=None):
assert "BINARY_OP_ADD_INT" in all_opnames(get_tlbc(f))
assert "BINARY_OP_ADD_INT" not in all_opnames(q.get())
""")
assert_python_ok("-X", "tlbc_limit=-1", "-c", code)
assert_python_ok("-X", "tlbc=1", "-c", code)

@requires_specialization_of("BINARY_OP")
def test_threads_specialize_independently(self):
Expand Down Expand Up @@ -82,7 +82,7 @@ def g(a, b, q=None):
assert "BINARY_OP_ADD_INT" not in t_opnames
assert "BINARY_OP_ADD_UNICODE" in t_opnames
""")
assert_python_ok("-X", "tlbc_limit=-1", "-c", code)
assert_python_ok("-X", "tlbc=1", "-c", code)

def test_reuse_tlbc_across_threads_different_lifetimes(self):
code = textwrap.dedent("""
Expand All @@ -107,7 +107,7 @@ def f(a, b, q=None):
assert tlbc_ids[0] == tlbc_ids[1]
assert tlbc_ids[1] == tlbc_ids[2]
""")
assert_python_ok("-X", "tlbc_limit=-1", "-c", code)
assert_python_ok("-X", "tlbc=1", "-c", code)

def test_no_tlbc_if_tlbc_disabled(self):
code = textwrap.dedent("""
Expand Down Expand Up @@ -138,7 +138,7 @@ def f(a, b, q=None):
assert tlbcs[1] is None
assert tlbcs[2] is None
""")
assert_python_ok("-X", "tlbc_limit=0", "-c", code)
assert_python_ok("-X", "tlbc=0", "-c", code)

def test_no_specialization_if_tlbc_disabled(self):
code = textwrap.dedent("""
Expand All @@ -160,7 +160,7 @@ def f(a, b):
assert "BINARY_OP_ADD_INT" not in all_opnames(f)
""")
assert_python_ok("-X", "tlbc_limit=0", "-c", code)
assert_python_ok("-X", "tlbc=0", "-c", code)

def test_generator_throw(self):
code = textwrap.dedent("""
Expand Down Expand Up @@ -190,7 +190,7 @@ def f(q):
main_id = gen.throw(ValueError)
assert main_id != q.get()
""")
assert_python_ok("-X", "tlbc_limit=-1", "-c", code)
assert_python_ok("-X", "tlbc=1", "-c", code)


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit e63e403

Please sign in to comment.