Skip to content

Commit b1b7fd5

Browse files
committed
bpo-37146: Allow to configure the opcode cache and fix huntleaks by presetting it to 1
1 parent 78c7d52 commit b1b7fd5

File tree

7 files changed

+135
-5
lines changed

7 files changed

+135
-5
lines changed

Include/internal/pycore_pystate.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ struct _pending_calls {
4343
int last;
4444
};
4545

46+
struct _opcodecache_config {
47+
int minruns;
48+
};
49+
4650
struct _ceval_runtime_state {
4751
int recursion_limit;
4852
/* Records whether tracing is on for any thread. Counts the number
@@ -60,6 +64,7 @@ struct _ceval_runtime_state {
6064
/* Request for checking signals. */
6165
_Py_atomic_int signals_pending;
6266
struct _gil_runtime_state gil;
67+
struct _opcodecache_config opcodeconfig;
6368
};
6469

6570
/* interpreter state */
@@ -312,6 +317,10 @@ PyAPI_FUNC(void) _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime);
312317

313318
PyAPI_FUNC(void) _PyGILState_Reinit(_PyRuntimeState *runtime);
314319

320+
PyAPI_FUNC(void) _PyEval_SetOpcodeCacheMinRuns(int minruns);
321+
322+
PyAPI_FUNC(int) _PyEval_GetOpcodeCacheMinRuns();
323+
315324
#ifdef __cplusplus
316325
}
317326
#endif

Lib/test/libregrtest/runtest.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ def _test_module(the_module):
206206
def _runtest_inner2(ns, test_name):
207207
# Load the test function, run the test function, handle huntrleaks
208208
# and findleaks to detect leaks
209+
minruns = sys._getopcacheminruns()
210+
sys._setopcacheminruns(1)
209211

210212
abstest = get_abs_module(ns, test_name)
211213

@@ -243,7 +245,7 @@ def _runtest_inner2(ns, test_name):
243245
gc.garbage.clear()
244246

245247
support.reap_children()
246-
248+
sys._setopcacheminruns(1)
247249
return refleak
248250

249251

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Added ``sys._setopcacheminruns`` and ``sys._getopcacheminruns`` to allow
2+
configuring the minimum number of function executions to activate the global
3+
opcode cache.

Python/ceval.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ static long dxp[256];
103103
#endif
104104

105105
/* per opcode cache */
106-
#define OPCACHE_MIN_RUNS 1024 /* create opcache when code executed this time */
107106
#define OPCACHE_STATS 0 /* Enable stats */
108107

109108
#if OPCACHE_STATS
@@ -1152,9 +1151,10 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
11521151
f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */
11531152
f->f_executing = 1;
11541153

1155-
if (co->co_opcache_flag < OPCACHE_MIN_RUNS) {
1154+
int opcacheminruns = _PyEval_GetOpcodeCacheMinRuns();
1155+
if (co->co_opcache_flag < opcacheminruns) {
11561156
co->co_opcache_flag++;
1157-
if (co->co_opcache_flag == OPCACHE_MIN_RUNS) {
1157+
if (co->co_opcache_flag == opcacheminruns) {
11581158
if (_PyCode_InitOpcache(co) < 0) {
11591159
return NULL;
11601160
}
@@ -5632,3 +5632,15 @@ maybe_dtrace_line(PyFrameObject *frame,
56325632
}
56335633
*instr_prev = frame->f_lasti;
56345634
}
5635+
5636+
void
5637+
_PyEval_SetOpcodeCacheMinRuns(int minruns)
5638+
{
5639+
_PyRuntime.ceval.opcodeconfig.minruns = minruns;
5640+
}
5641+
5642+
int
5643+
_PyEval_GetOpcodeCacheMinRuns()
5644+
{
5645+
return _PyRuntime.ceval.opcodeconfig.minruns;
5646+
}

Python/clinic/sysmodule.c.h

Lines changed: 62 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/pylifecycle.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,9 @@ _Py_PreInitializeFromPyArgv(const PyPreConfig *src_config, const _PyArgv *args)
737737
return status;
738738
}
739739

740+
// XXX: Add this properly to the commandline config
741+
runtime->ceval.opcodeconfig.minruns = 1024;
742+
740743
runtime->pre_initialized = 1;
741744
return _PyStatus_OK();
742745
}

Python/sysmodule.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,44 @@ sys_getcheckinterval_impl(PyObject *module)
10301030
return PyLong_FromLong(interp->check_interval);
10311031
}
10321032

1033+
/*[clinic input]
1034+
sys._setopcacheminruns
1035+
1036+
minruns: int
1037+
/
1038+
1039+
Set the minimum value of runs to activate opcode cache.
1040+
[clinic start generated code]*/
1041+
1042+
static PyObject *
1043+
sys__setopcacheminruns_impl(PyObject *module, int minruns)
1044+
/*[clinic end generated code: output=e29d082b62b2aa8a input=169a982eee6595d5]*/
1045+
{
1046+
if (minruns <= 0) {
1047+
PyErr_SetString(PyExc_ValueError,
1048+
"opcache min runs must be strictly positive");
1049+
return NULL;
1050+
}
1051+
_PyEval_SetOpcodeCacheMinRuns(minruns);
1052+
Py_RETURN_NONE;
1053+
}
1054+
1055+
1056+
/*[clinic input]
1057+
sys._getopcacheminruns -> int
1058+
1059+
Return the current minimum value of runs to activate opcode cache.
1060+
[clinic start generated code]*/
1061+
1062+
static int
1063+
sys__getopcacheminruns_impl(PyObject *module)
1064+
/*[clinic end generated code: output=f25d23b7afd8512c input=93784822a3e883c9]*/
1065+
{
1066+
return _PyEval_GetOpcodeCacheMinRuns();
1067+
}
1068+
1069+
1070+
10331071
/*[clinic input]
10341072
sys.setswitchinterval
10351073
@@ -1936,6 +1974,8 @@ static PyMethodDef sys_methods[] = {
19361974
SYS_MDEBUG_METHODDEF
19371975
SYS_SETCHECKINTERVAL_METHODDEF
19381976
SYS_GETCHECKINTERVAL_METHODDEF
1977+
SYS__SETOPCACHEMINRUNS_METHODDEF
1978+
SYS__GETOPCACHEMINRUNS_METHODDEF
19391979
SYS_SETSWITCHINTERVAL_METHODDEF
19401980
SYS_GETSWITCHINTERVAL_METHODDEF
19411981
SYS_SETDLOPENFLAGS_METHODDEF

0 commit comments

Comments
 (0)