summaryrefslogtreecommitdiffstats
path: root/Python/initconfig.c
diff options
context:
space:
mode:
authormpage <mpage@cs.stanford.edu>2024-11-04 19:13:32 (GMT)
committerGitHub <noreply@github.com>2024-11-04 19:13:32 (GMT)
commit2e95c5ba3bf7e5004c7e2304afda4a8f8e2443a7 (patch)
treede32ac52ed5ffcb9460dfc062effc6b4b662ee5d /Python/initconfig.c
parente5a4b402ae55f5eeeb44d3e7bc3f3ec39b249846 (diff)
downloadcpython-2e95c5ba3bf7e5004c7e2304afda4a8f8e2443a7.zip
cpython-2e95c5ba3bf7e5004c7e2304afda4a8f8e2443a7.tar.gz
cpython-2e95c5ba3bf7e5004c7e2304afda4a8f8e2443a7.tar.bz2
gh-115999: Implement thread-local bytecode and enable specialization for `BINARY_OP` (#123926)
Each thread specializes a thread-local copy of the bytecode, created on the first RESUME, in free-threaded builds. All copies of the bytecode for a code object are stored in the co_tlbc array on the code object. Threads reserve a globally unique index identifying its copy of the bytecode in all co_tlbc arrays at thread creation and release the index at thread destruction. The first entry in every co_tlbc array always points to the "main" copy of the bytecode that is stored at the end of the code object. This ensures that no bytecode is copied for programs that do not use threads. Thread-local bytecode can be disabled at runtime by providing either -X tlbc=0 or PYTHON_TLBC=0. Disabling thread-local bytecode also disables specialization. Concurrent modifications to the bytecode made by the specializing interpreter and instrumentation use atomics, with specialization taking care not to overwrite an instruction that was instrumented concurrently.
Diffstat (limited to 'Python/initconfig.c')
-rw-r--r--Python/initconfig.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/Python/initconfig.c b/Python/initconfig.c
index c142438..438f8a5 100644
--- a/Python/initconfig.c
+++ b/Python/initconfig.c
@@ -134,6 +134,7 @@ static const PyConfigSpec PYCONFIG_SPEC[] = {
SPEC(dump_refs_file, WSTR_OPT, READ_ONLY, NO_SYS),
#ifdef Py_GIL_DISABLED
SPEC(enable_gil, INT, READ_ONLY, NO_SYS),
+ SPEC(tlbc_enabled, INT, READ_ONLY, NO_SYS),
#endif
SPEC(faulthandler, BOOL, READ_ONLY, NO_SYS),
SPEC(filesystem_encoding, WSTR, READ_ONLY, NO_SYS),
@@ -315,8 +316,13 @@ The following implementation-specific options are available:\n\
"\
-X showrefcount: output the total reference count and number of used\n\
memory blocks when the program finishes or after each statement in\n\
- the interactive interpreter; only works on debug builds\n\
--X tracemalloc[=N]: trace Python memory allocations; N sets a traceback limit\n\
+ the interactive interpreter; only works on debug builds\n"
+#ifdef Py_GIL_DISABLED
+"-X tlbc=[0|1]: enable (1) or disable (0) thread-local bytecode. Also\n\
+ PYTHON_TLBC\n"
+#endif
+"\
+-X tracemalloc[=N]: trace Python memory allocations; N sets a traceback limit\n \
of N frames (default: 1); also PYTHONTRACEMALLOC=N\n\
-X utf8[=0|1]: enable (1) or disable (0) UTF-8 mode; also PYTHONUTF8\n\
-X warn_default_encoding: enable opt-in EncodingWarning for 'encoding=None';\n\
@@ -400,6 +406,9 @@ static const char usage_envvars[] =
#ifdef Py_STATS
"PYTHONSTATS : turns on statistics gathering (-X pystats)\n"
#endif
+#ifdef Py_GIL_DISABLED
+"PYTHON_TLBC : when set to 0, disables thread-local bytecode (-X tlbc)\n"
+#endif
"PYTHONTRACEMALLOC: trace Python memory allocations (-X tracemalloc)\n"
"PYTHONUNBUFFERED: disable stdout/stderr buffering (-u)\n"
"PYTHONUTF8 : control the UTF-8 mode (-X utf8)\n"
@@ -979,6 +988,7 @@ _PyConfig_InitCompatConfig(PyConfig *config)
config->cpu_count = -1;
#ifdef Py_GIL_DISABLED
config->enable_gil = _PyConfig_GIL_DEFAULT;
+ config->tlbc_enabled = 1;
#endif
}
@@ -1863,6 +1873,36 @@ error:
}
static PyStatus
+config_init_tlbc(PyConfig *config)
+{
+#ifdef Py_GIL_DISABLED
+ const char *env = config_get_env(config, "PYTHON_TLBC");
+ if (env) {
+ int enabled;
+ if (_Py_str_to_int(env, &enabled) < 0 || (enabled < 0) || (enabled > 1)) {
+ return _PyStatus_ERR(
+ "PYTHON_TLBC=N: N is missing or invalid");
+ }
+ config->tlbc_enabled = enabled;
+ }
+
+ const wchar_t *xoption = config_get_xoption(config, L"tlbc");
+ if (xoption) {
+ int enabled;
+ const wchar_t *sep = wcschr(xoption, L'=');
+ if (!sep || (config_wstr_to_int(sep + 1, &enabled) < 0) || (enabled < 0) || (enabled > 1)) {
+ return _PyStatus_ERR(
+ "-X tlbc=n: n is missing or invalid");
+ }
+ config->tlbc_enabled = enabled;
+ }
+ return _PyStatus_OK();
+#else
+ return _PyStatus_OK();
+#endif
+}
+
+static PyStatus
config_init_perf_profiling(PyConfig *config)
{
int active = 0;
@@ -2111,6 +2151,11 @@ config_read_complex_options(PyConfig *config)
}
#endif
+ status = config_init_tlbc(config);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
+
return _PyStatus_OK();
}