From 506ea765026ce7e8264b84fc2fd5e9f81ec436a8 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 14 Dec 2021 17:05:32 +0000 Subject: [PATCH 1/7] Simplify specialization stats collection macros. --- Include/internal/pycore_code.h | 15 +-------------- Modules/_opcode.c | 2 +- Python/specialize.c | 2 +- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 496d52f580f1f3..f34b25c9a7e733 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -276,22 +276,11 @@ void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); -#define PRINT_SPECIALIZATION_STATS 0 -#define PRINT_SPECIALIZATION_STATS_DETAILED 0 -#define PRINT_SPECIALIZATION_STATS_TO_FILE 0 -#ifdef Py_DEBUG -#define COLLECT_SPECIALIZATION_STATS 1 -#define COLLECT_SPECIALIZATION_STATS_DETAILED 1 -#else -#define COLLECT_SPECIALIZATION_STATS PRINT_SPECIALIZATION_STATS -#define COLLECT_SPECIALIZATION_STATS_DETAILED PRINT_SPECIALIZATION_STATS_DETAILED -#endif +#ifdef Py_STATS #define SPECIALIZATION_FAILURE_KINDS 20 -#if COLLECT_SPECIALIZATION_STATS - typedef struct _stats { uint64_t specialization_success; uint64_t specialization_failure; @@ -300,9 +289,7 @@ typedef struct _stats { uint64_t miss; uint64_t deopt; uint64_t unquickened; -#if COLLECT_SPECIALIZATION_STATS_DETAILED uint64_t specialization_failure_kinds[SPECIALIZATION_FAILURE_KINDS]; -#endif } SpecializationStats; extern SpecializationStats _specialization_stats[256]; diff --git a/Modules/_opcode.c b/Modules/_opcode.c index 39e30669559518..4812716c672718 100644 --- a/Modules/_opcode.c +++ b/Modules/_opcode.c @@ -85,7 +85,7 @@ static PyObject * _opcode_get_specialization_stats_impl(PyObject *module) /*[clinic end generated code: output=fcbc32fdfbec5c17 input=e1f60db68d8ce5f6]*/ { -#if COLLECT_SPECIALIZATION_STATS +#ifdef Py_STATS return _Py_GetSpecializationStats(); #else Py_RETURN_NONE; diff --git a/Python/specialize.c b/Python/specialize.c index 51218450081008..196a4f2bf9cc78 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -39,7 +39,7 @@ */ Py_ssize_t _Py_QuickenedCount = 0; -#if COLLECT_SPECIALIZATION_STATS +#ifdef Py_STATS SpecializationStats _specialization_stats[256] = { 0 }; #define ADD_STAT_TO_DICT(res, field) \ From d6ed66f0e342f4e0faa3440444c56ebeb6067688 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 14 Dec 2021 17:36:49 +0000 Subject: [PATCH 2/7] Add --with-pystats option to configure. --- Include/internal/pycore_code.h | 2 +- Python/ceval.c | 4 +-- Python/specialize.c | 45 ++++++++++++++++------------------ configure | 24 ++++++++++++++++++ configure.ac | 17 ++++++++++++- pyconfig.h.in | 3 +++ 6 files changed, 67 insertions(+), 28 deletions(-) diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index f34b25c9a7e733..f57ee2c10365af 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -295,7 +295,7 @@ typedef struct _stats { extern SpecializationStats _specialization_stats[256]; #define STAT_INC(opname, name) _specialization_stats[opname].name++ #define STAT_DEC(opname, name) _specialization_stats[opname].name-- -void _Py_PrintSpecializationStats(void); +void _Py_PrintSpecializationStats(int to_file); PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void); diff --git a/Python/ceval.c b/Python/ceval.c index 4f5ccf51e9cfe7..bf8c25997373d9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -347,8 +347,8 @@ PyEval_InitThreads(void) void _PyEval_Fini(void) { -#if PRINT_SPECIALIZATION_STATS - _Py_PrintSpecializationStats(); +#ifdef Py_STATS + _Py_PrintSpecializationStats(1); #endif } diff --git a/Python/specialize.c b/Python/specialize.c index 196a4f2bf9cc78..56d53d4dee3a2d 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -71,7 +71,6 @@ stats_to_dict(SpecializationStats *stats) ADD_STAT_TO_DICT(res, miss); ADD_STAT_TO_DICT(res, deopt); ADD_STAT_TO_DICT(res, unquickened); -#if COLLECT_SPECIALIZATION_STATS_DETAILED PyObject *failure_kinds = PyTuple_New(SPECIALIZATION_FAILURE_KINDS); if (failure_kinds == NULL) { Py_DECREF(res); @@ -92,7 +91,6 @@ stats_to_dict(SpecializationStats *stats) return NULL; } Py_DECREF(failure_kinds); -#endif return res; } #undef ADD_STAT_TO_DICT @@ -113,7 +111,7 @@ add_stat_dict( return err; } -#if COLLECT_SPECIALIZATION_STATS +#ifdef Py_STATS PyObject* _Py_GetSpecializationStats(void) { PyObject *stats = PyDict_New(); @@ -151,35 +149,34 @@ print_stats(FILE *out, SpecializationStats *stats, const char *name) PRINT_STAT(name, miss); PRINT_STAT(name, deopt); PRINT_STAT(name, unquickened); -#if PRINT_SPECIALIZATION_STATS_DETAILED for (int i = 0; i < SPECIALIZATION_FAILURE_KINDS; i++) { fprintf(out, " %s.specialization_failure_kinds[%d] : %" PRIu64 "\n", name, i, stats->specialization_failure_kinds[i]); } -#endif } #undef PRINT_STAT void -_Py_PrintSpecializationStats(void) +_Py_PrintSpecializationStats(int to_file) { FILE *out = stderr; -#if PRINT_SPECIALIZATION_STATS_TO_FILE - /* Write to a file instead of stderr. */ + if (to_file) { + /* Write to a file instead of stderr. */ # ifdef MS_WINDOWS - const char *dirname = "c:\\temp\\py_stats\\"; + const char *dirname = "c:\\temp\\py_stats\\"; # else - const char *dirname = "/tmp/py_stats/"; + const char *dirname = "/tmp/py_stats/"; # endif - char buf[48]; - sprintf(buf, "%s%u_%u.txt", dirname, (unsigned)clock(), (unsigned)rand()); - FILE *fout = fopen(buf, "w"); - if (fout) { - out = fout; - } -#else - fprintf(out, "Specialization stats:\n"); -#endif + char buf[48]; + sprintf(buf, "%s%u_%u.txt", dirname, (unsigned)clock(), (unsigned)rand()); + FILE *fout = fopen(buf, "w"); + if (fout) { + out = fout; + } + } + else { + fprintf(out, "Specialization stats:\n"); + } print_stats(out, &_specialization_stats[LOAD_ATTR], "load_attr"); print_stats(out, &_specialization_stats[LOAD_GLOBAL], "load_global"); print_stats(out, &_specialization_stats[LOAD_METHOD], "load_method"); @@ -194,7 +191,7 @@ _Py_PrintSpecializationStats(void) } } -#if COLLECT_SPECIALIZATION_STATS_DETAILED +#ifdef Py_STATS #define SPECIALIZATION_FAIL(opcode, kind) _specialization_stats[opcode].specialization_failure_kinds[kind]++ @@ -856,7 +853,7 @@ _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, S } -#if COLLECT_SPECIALIZATION_STATS_DETAILED +#ifdef Py_STATS static int load_method_fail_kind(DesciptorClassification kind) { @@ -1082,7 +1079,7 @@ _Py_Specialize_LoadGlobal( return 0; } -#if COLLECT_SPECIALIZATION_STATS_DETAILED +#ifdef Py_STATS static int binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub) { @@ -1306,7 +1303,7 @@ specialize_py_call( return 0; } -#if COLLECT_SPECIALIZATION_STATS_DETAILED +#ifdef Py_STATS static int builtin_call_fail_kind(int ml_flags) { @@ -1381,7 +1378,7 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, } } -#if COLLECT_SPECIALIZATION_STATS_DETAILED +#ifdef Py_STATS static int call_fail_kind(PyObject *callable) { diff --git a/configure b/configure index 583e7d1fe3b32c..91f22f9ab447d2 100755 --- a/configure +++ b/configure @@ -1006,6 +1006,7 @@ enable_shared enable_profiling with_pydebug with_trace_refs +with_pystats with_assertions enable_optimizations with_lto @@ -1753,6 +1754,7 @@ Optional Packages: --with-pydebug build with Py_DEBUG defined (default is no) --with-trace-refs enable tracing references for debugging purpose (default is no) + --with-pystats enable internal statistics gathering (default is no) --with-assertions build with C assertions enabled (default is no) --with-lto=[full|thin|no|yes] enable Link-Time-Optimization in any build (default @@ -6915,6 +6917,28 @@ $as_echo "#define Py_TRACE_REFS 1" >>confdefs.h fi +# Check for --with-pystats +# --with-trace-refs +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-pystats" >&5 +$as_echo_n "checking for --with-pystats... " >&6; } + +# Check whether --with-pystats was given. +if test "${with_pystats+set}" = set; then : + withval=$with_pystats; +else + with_pystats=no +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_pystats" >&5 +$as_echo "$with_pystats" >&6; } + +if test "$with_pystats" = "yes" +then + +$as_echo "#define Py_STATS 1" >>confdefs.h + +fi + # Check for --with-assertions. # This allows enabling assertions without Py_DEBUG. assertions='false' diff --git a/configure.ac b/configure.ac index 5256a61289e223..f67f9deedc7166 100644 --- a/configure.ac +++ b/configure.ac @@ -1387,6 +1387,21 @@ then AC_DEFINE(Py_TRACE_REFS, 1, [Define if you want to enable tracing references for debugging purpose]) fi +# Check for --with-pystats +# --with-pystats +AC_MSG_CHECKING(for --with-pystats) +AC_ARG_WITH(pystats, + AS_HELP_STRING( + [--with-pystats], + [enable internal statistics gathering (default is no)]),, + with_trace_refs=no) +AC_MSG_RESULT($with_pystats) + +if test "$with_pystats" = "yes" +then + AC_DEFINE(Py_STATS, 1, [Define if you want to enable internal statistics gathering]) +fi + # Check for --with-assertions. # This allows enabling assertions without Py_DEBUG. assertions='false' @@ -6323,7 +6338,7 @@ AC_DEFUN([PY_STDLIB_MOD], [ ]) dnl Define simple stdlib extension module -dnl Always enable unless the module is listed in py_stdlib_not_available +dnl Always enable unless the module is listed in py_stdlib_not_available dnl PY_STDLIB_MOD_SIMPLE([NAME], [CFLAGS], [LDFLAGS]) dnl cflags and ldflags are optional AC_DEFUN([PY_STDLIB_MOD_SIMPLE], [ diff --git a/pyconfig.h.in b/pyconfig.h.in index efad243d0af8aa..430a9062da8989 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1496,6 +1496,9 @@ SipHash13: 3, externally defined: 0 */ #undef Py_HASH_ALGORITHM +/* Define if you want to enable internal statistics gathering */ +#undef Py_STATS + /* Define if you want to enable tracing references for debugging purpose */ #undef Py_TRACE_REFS From c07c7594f3f151ff8d6b3cc1cabeeeb2949916f6 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 15 Dec 2021 10:37:54 +0000 Subject: [PATCH 3/7] Add news. --- Misc/NEWS.d/next/Build/2021-12-15-10-37-44.bpo-46072.GgeAU3.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Build/2021-12-15-10-37-44.bpo-46072.GgeAU3.rst diff --git a/Misc/NEWS.d/next/Build/2021-12-15-10-37-44.bpo-46072.GgeAU3.rst b/Misc/NEWS.d/next/Build/2021-12-15-10-37-44.bpo-46072.GgeAU3.rst new file mode 100644 index 00000000000000..9cc8b6c82de410 --- /dev/null +++ b/Misc/NEWS.d/next/Build/2021-12-15-10-37-44.bpo-46072.GgeAU3.rst @@ -0,0 +1,2 @@ +Add a --with-pystats configure option to turn on internal statistics +gathering. From a2639a85e9abe18ea2e73bef33a279d31b9ecb17 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 15 Dec 2021 10:44:32 +0000 Subject: [PATCH 4/7] Fix copy-and-paste error. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index f67f9deedc7166..509fb47e78fdb3 100644 --- a/configure.ac +++ b/configure.ac @@ -1394,7 +1394,7 @@ AC_ARG_WITH(pystats, AS_HELP_STRING( [--with-pystats], [enable internal statistics gathering (default is no)]),, - with_trace_refs=no) + $with_pystats=no) AC_MSG_RESULT($with_pystats) if test "$with_pystats" = "yes" From e5f396867b50214cd035bd9e600121a6070fd8c5 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 15 Dec 2021 10:46:31 +0000 Subject: [PATCH 5/7] Fix another copy-and-paste error. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 91f22f9ab447d2..63af57b9927380 100755 --- a/configure +++ b/configure @@ -6918,7 +6918,7 @@ $as_echo "#define Py_TRACE_REFS 1" >>confdefs.h fi # Check for --with-pystats -# --with-trace-refs +# --with-pystats { $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-pystats" >&5 $as_echo_n "checking for --with-pystats... " >&6; } From 03e51091d75bfb7637b233e3dc8264d2087d5bce Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 15 Dec 2021 11:15:25 +0000 Subject: [PATCH 6/7] Update specialization summary script to handle larger number of kinds --- Tools/scripts/summarize_specialization_stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/scripts/summarize_specialization_stats.py b/Tools/scripts/summarize_specialization_stats.py index cc3ef85933c026..15b1887415e44f 100644 --- a/Tools/scripts/summarize_specialization_stats.py +++ b/Tools/scripts/summarize_specialization_stats.py @@ -24,7 +24,7 @@ def print_stats(name, family_stats): for key in ("specialization_success", "specialization_failure"): print(f" {key}:{family_stats[key]:>12}") total_failures = family_stats["specialization_failure"] - failure_kinds = [ 0 ] * 20 + failure_kinds = [ 0 ] * 30 for key in family_stats: if not key.startswith("specialization_failure_kind"): continue From eabf35b3d09b1481ca15c748144db07117625360 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Wed, 15 Dec 2021 11:18:14 +0000 Subject: [PATCH 7/7] Use --enable-pystats instead of --with-pystats. --- configure | 29 +++++++++++++++-------------- configure.ac | 26 +++++++++++++------------- pyconfig.h.in | 2 +- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/configure b/configure index 63af57b9927380..1ede29989d9481 100755 --- a/configure +++ b/configure @@ -1006,7 +1006,7 @@ enable_shared enable_profiling with_pydebug with_trace_refs -with_pystats +enable_pystats with_assertions enable_optimizations with_lto @@ -1714,6 +1714,7 @@ Optional Features: no) --enable-profiling enable C-level code profiling with gprof (default is no) + --enable-pystats enable internal statistics gathering (default is no) --enable-optimizations enable expensive, stable optimizations (PGO, etc.) (default is no) --enable-loadable-sqlite-extensions @@ -1754,7 +1755,6 @@ Optional Packages: --with-pydebug build with Py_DEBUG defined (default is no) --with-trace-refs enable tracing references for debugging purpose (default is no) - --with-pystats enable internal statistics gathering (default is no) --with-assertions build with C assertions enabled (default is no) --with-lto=[full|thin|no|yes] enable Link-Time-Optimization in any build (default @@ -6917,26 +6917,27 @@ $as_echo "#define Py_TRACE_REFS 1" >>confdefs.h fi -# Check for --with-pystats -# --with-pystats -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --with-pystats" >&5 -$as_echo_n "checking for --with-pystats... " >&6; } -# Check whether --with-pystats was given. -if test "${with_pystats+set}" = set; then : - withval=$with_pystats; +# Check for --enable-pystats +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for --enable-pystats" >&5 +$as_echo_n "checking for --enable-pystats... " >&6; } +# Check whether --enable-pystats was given. +if test "${enable_pystats+set}" = set; then : + enableval=$enable_pystats; else - with_pystats=no + enable_pystats=no + fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_pystats" >&5 -$as_echo "$with_pystats" >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_pystats" >&5 +$as_echo "$enable_pystats" >&6; } + +if test "x$enable_pystats" = xyes; then : -if test "$with_pystats" = "yes" -then $as_echo "#define Py_STATS 1" >>confdefs.h + fi # Check for --with-assertions. diff --git a/configure.ac b/configure.ac index 509fb47e78fdb3..86404bcadeaba1 100644 --- a/configure.ac +++ b/configure.ac @@ -1387,20 +1387,20 @@ then AC_DEFINE(Py_TRACE_REFS, 1, [Define if you want to enable tracing references for debugging purpose]) fi -# Check for --with-pystats -# --with-pystats -AC_MSG_CHECKING(for --with-pystats) -AC_ARG_WITH(pystats, - AS_HELP_STRING( - [--with-pystats], - [enable internal statistics gathering (default is no)]),, - $with_pystats=no) -AC_MSG_RESULT($with_pystats) -if test "$with_pystats" = "yes" -then - AC_DEFINE(Py_STATS, 1, [Define if you want to enable internal statistics gathering]) -fi +# Check for --enable-pystats +AC_MSG_CHECKING([for --enable-pystats]) +AC_ARG_ENABLE([pystats], + [AS_HELP_STRING( + [--enable-pystats], + [enable internal statistics gathering (default is no)])],, + [enable_pystats=no] +) +AC_MSG_RESULT([$enable_pystats]) + +AS_VAR_IF([enable_pystats], [yes], [ + AC_DEFINE([Py_STATS], [1], [Define if you want to enable internal statistics gathering.]) +]) # Check for --with-assertions. # This allows enabling assertions without Py_DEBUG. diff --git a/pyconfig.h.in b/pyconfig.h.in index 430a9062da8989..e6e81654699d88 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -1496,7 +1496,7 @@ SipHash13: 3, externally defined: 0 */ #undef Py_HASH_ALGORITHM -/* Define if you want to enable internal statistics gathering */ +/* Define if you want to enable internal statistics gathering. */ #undef Py_STATS /* Define if you want to enable tracing references for debugging purpose */