summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_code.h17
-rw-r--r--Misc/NEWS.d/next/Build/2021-12-15-10-37-44.bpo-46072.GgeAU3.rst2
-rw-r--r--Modules/_opcode.c2
-rw-r--r--Python/ceval.c4
-rw-r--r--Python/specialize.c47
-rw-r--r--Tools/scripts/summarize_specialization_stats.py2
-rwxr-xr-xconfigure25
-rw-r--r--configure.ac17
-rw-r--r--pyconfig.h.in3
9 files changed, 74 insertions, 45 deletions
diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index b0463e3617..e9b1ad4064 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 30
-#if COLLECT_SPECIALIZATION_STATS
-
typedef struct _stats {
uint64_t specialization_success;
uint64_t specialization_failure;
@@ -300,15 +289,13 @@ 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];
#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/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 0000000000..9cc8b6c82d
--- /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.
diff --git a/Modules/_opcode.c b/Modules/_opcode.c
index 39e3066955..4812716c67 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/ceval.c b/Python/ceval.c
index b9444b2213..87d6a2288e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -349,8 +349,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 5cf327df47..7d4387b163 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) \
@@ -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]++
@@ -860,7 +857,7 @@ success:
}
-#if COLLECT_SPECIALIZATION_STATS_DETAILED
+#ifdef Py_STATS
static int
load_method_fail_kind(DesciptorClassification kind)
{
@@ -1086,7 +1083,7 @@ success:
return 0;
}
-#if COLLECT_SPECIALIZATION_STATS_DETAILED
+#ifdef Py_STATS
static int
binary_subscr_fail_kind(PyTypeObject *container_type, PyObject *sub)
{
@@ -1380,7 +1377,7 @@ specialize_py_call(
return 0;
}
-#if COLLECT_SPECIALIZATION_STATS_DETAILED
+#ifdef Py_STATS
static int
builtin_call_fail_kind(int ml_flags)
{
@@ -1459,7 +1456,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/Tools/scripts/summarize_specialization_stats.py b/Tools/scripts/summarize_specialization_stats.py
index cc3ef85933..15b1887415 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
diff --git a/configure b/configure
index 583e7d1fe3..1ede29989d 100755
--- a/configure
+++ b/configure
@@ -1006,6 +1006,7 @@ enable_shared
enable_profiling
with_pydebug
with_trace_refs
+enable_pystats
with_assertions
enable_optimizations
with_lto
@@ -1713,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
@@ -6915,6 +6917,29 @@ $as_echo "#define Py_TRACE_REFS 1" >>confdefs.h
fi
+
+# 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
+ enable_pystats=no
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_pystats" >&5
+$as_echo "$enable_pystats" >&6; }
+
+if test "x$enable_pystats" = xyes; 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 5256a61289..86404bcade 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 --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.
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 efad243d0a..e6e8165469 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