From 9c979d7afd839abbb080028bdfeb73727e5cf633 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 7 Feb 2022 16:51:43 +0000 Subject: [PATCH] bpo-46072: Merge dxpairs into py_stats. (GH-31197) --- .../2022-02-07-14-38-54.bpo-46072.6ebLyN.rst | 2 + Python/ceval.c | 77 ++++--------------- Python/sysmodule.c | 4 +- 3 files changed, 21 insertions(+), 62 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-02-07-14-38-54.bpo-46072.6ebLyN.rst 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 00000000000..288cb56cc20 --- /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 31b41b84848..52dbd6e7b07 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -114,16 +114,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 @@ -1238,10 +1228,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 @@ -1253,11 +1239,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) @@ -1265,11 +1246,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 @@ -1283,7 +1259,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 @@ -1296,34 +1279,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) +/* 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() \ - do { \ - dxp[opcode]++; \ - } while (0) -#endif -#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() \ { \ @@ -1403,7 +1364,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) \ @@ -1653,7 +1614,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 */ @@ -7489,16 +7450,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; @@ -7513,14 +7474,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; @@ -7528,7 +7486,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 7597ea2ea9e..acb03781a4f 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