diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-02-07-14-38-54.bpo-46072.6ebLyN.rst b/Misc/NEWS.d/next/Core and Builtins/2022-02-07-14-38-54.bpo-46072.6ebLyN.rst new file mode 100644 index 00000000000000..288cb56cc205f2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-02-07-14-38-54.bpo-46072.6ebLyN.rst @@ -0,0 +1,2 @@ +Opcode pair stats are now gathered with ``--enable-pystats``. Defining +``DYNAMIC_EXECUTION_PROFILE`` or ``DXPAIRS`` no longer has any effect. diff --git a/Python/ceval.c b/Python/ceval.c index 3c52c5824b44a7..f7e303e82b4a48 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -115,16 +115,6 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame *frame); "cannot access free variable '%s' where it is not associated with a" \ " value in enclosing scope" -/* Dynamic execution profile */ -#ifdef DYNAMIC_EXECUTION_PROFILE -#ifdef DXPAIRS -static long dxpairs[257][256]; -#define dxp dxpairs[256] -#else -static long dxp[256]; -#endif -#endif - #ifndef NDEBUG /* Ensure that tstate is valid: sanity check for PyEval_AcquireThread() and PyEval_RestoreThread(). Detect if tstate memory was freed. It can happen @@ -1239,10 +1229,6 @@ eval_frame_handle_pending(PyThreadState *tstate) faster than the normal "switch" version, depending on the compiler and the CPU architecture. - We disable the optimization if DYNAMIC_EXECUTION_PROFILE is defined, - because it would render the measurements invalid. - - NOTE: care must be taken that the compiler doesn't try to "optimize" the indirect jumps by sharing them between all opcodes. Such optimizations can be disabled on gcc by using the -fno-gcse flag (or possibly @@ -1254,11 +1240,6 @@ eval_frame_handle_pending(PyThreadState *tstate) * We want to be sure that the compiler knows this before it generates * the CFG. */ -#ifdef LLTRACE -#define LLTRACE_INSTR() if (lltrace) { lltrace_instruction(frame, opcode, oparg); } -#else -#define LLTRACE_INSTR() ((void)0) -#endif #ifdef WITH_DTRACE #define OR_DTRACE_LINE | (PyDTrace_LINE_ENABLED() ? 255 : 0) @@ -1266,11 +1247,6 @@ eval_frame_handle_pending(PyThreadState *tstate) #define OR_DTRACE_LINE #endif -#ifdef DYNAMIC_EXECUTION_PROFILE -#undef USE_COMPUTED_GOTOS -#define USE_COMPUTED_GOTOS 0 -#endif - #ifdef HAVE_COMPUTED_GOTOS #ifndef USE_COMPUTED_GOTOS #define USE_COMPUTED_GOTOS 1 @@ -1284,7 +1260,14 @@ eval_frame_handle_pending(PyThreadState *tstate) #endif #ifdef Py_STATS -#define INSTRUCTION_START(op) frame->f_lasti = INSTR_OFFSET(); next_instr++; OPCODE_EXE_INC(op); +#define INSTRUCTION_START(op) \ + do { \ + frame->f_lasti = INSTR_OFFSET(); \ + next_instr++; \ + OPCODE_EXE_INC(op); \ + _py_stats.opcode_stats[lastopcode].pair_count[op]++; \ + lastopcode = op; \ + } while (0) #else #define INSTRUCTION_START(op) frame->f_lasti = INSTR_OFFSET(); next_instr++ #endif @@ -1297,34 +1280,12 @@ eval_frame_handle_pending(PyThreadState *tstate) #define DISPATCH_GOTO() goto dispatch_opcode #endif -/* RECORD_DXPROFILE() records the dxprofile information, if enabled. Normally a no-op */ -#ifdef DYNAMIC_EXECUTION_PROFILE -#ifdef DXPAIRS -#define RECORD_DXPROFILE() \ - do { \ - dxpairs[lastopcode][opcode]++; \ - lastopcode = opcode; \ - dxp[opcode]++; \ - } while (0) -#else - #define RECORD_DXPROFILE() \ - do { \ - dxp[opcode]++; \ - } while (0) -#endif +/* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */ +#ifdef LLTRACE +#define PRE_DISPATCH_GOTO() if (lltrace) { lltrace_instruction(frame, opcode, oparg); } #else -#define RECORD_DXPROFILE() ((void)0) -#endif - -/* PRE_DISPATCH_GOTO() does lltrace and dxprofile if either is enabled. Normally a no-op */ -#ifndef LLTRACE -#ifndef DYNAMIC_EXECUTION_PROFILE #define PRE_DISPATCH_GOTO() ((void)0) #endif -#endif -#ifndef PRE_DISPATCH_GOTO -#define PRE_DISPATCH_GOTO() do { LLTRACE_INSTR(); RECORD_DXPROFILE(); } while (0) -#endif #define NOTRACE_DISPATCH() \ { \ @@ -1404,7 +1365,7 @@ eval_frame_handle_pending(PyThreadState *tstate) #define PREDICT_ID(op) PRED_##op -#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS +#if USE_COMPUTED_GOTOS #define PREDICT(op) if (0) goto PREDICT_ID(op) #else #define PREDICT(op) \ @@ -1658,7 +1619,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr #include "opcode_targets.h" #endif -#ifdef DXPAIRS +#ifdef Py_STATS int lastopcode = 0; #endif int opcode; /* Current opcode */ @@ -7487,16 +7448,16 @@ format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int prevprevpr } } -#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef Py_STATS static PyObject * -getarray(long a[256]) +getarray(uint64_t a[256]) { int i; PyObject *l = PyList_New(256); if (l == NULL) return NULL; for (i = 0; i < 256; i++) { - PyObject *x = PyLong_FromLong(a[i]); + PyObject *x = PyLong_FromUnsignedLongLong(a[i]); if (x == NULL) { Py_DECREF(l); return NULL; @@ -7511,14 +7472,11 @@ getarray(long a[256]) PyObject * _Py_GetDXProfile(PyObject *self, PyObject *args) { -#ifndef DXPAIRS - return getarray(dxp); -#else int i; PyObject *l = PyList_New(257); if (l == NULL) return NULL; for (i = 0; i < 257; i++) { - PyObject *x = getarray(dxpairs[i]); + PyObject *x = getarray(_py_stats.opcode_stats[i].pair_count); if (x == NULL) { Py_DECREF(l); return NULL; @@ -7526,7 +7484,6 @@ _Py_GetDXProfile(PyObject *self, PyObject *args) PyList_SET_ITEM(l, i, x); } return l; -#endif } #endif diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 7597ea2ea9e495..acb03781a4f14b 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1923,7 +1923,7 @@ sys__debugmallocstats_impl(PyObject *module) extern PyObject *_Py_GetObjects(PyObject *, PyObject *); #endif -#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef Py_STATS /* Defined in ceval.c because it uses static globals in that file */ extern PyObject *_Py_GetDXProfile(PyObject *, PyObject *); #endif @@ -1992,7 +1992,7 @@ static PyMethodDef sys_methods[] = { SYS_GETDEFAULTENCODING_METHODDEF SYS_GETDLOPENFLAGS_METHODDEF SYS_GETALLOCATEDBLOCKS_METHODDEF -#ifdef DYNAMIC_EXECUTION_PROFILE +#ifdef Py_STATS {"getdxp", _Py_GetDXProfile, METH_VARARGS}, #endif SYS_GETFILESYSTEMENCODING_METHODDEF