bpo-46072: Add --with-pystats configure option to simplify gathering of VM stats (GH-30116)

* Simplify specialization stats collection macros.

* Add --enable-pystats option to configure.

* Update specialization summary script to handle larger number of kinds
This commit is contained in:
Mark Shannon 2021-12-15 15:32:32 +00:00 committed by GitHub
parent 3a60bfef49
commit 342b93f9f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 73 additions and 44 deletions

View file

@ -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);

View file

@ -0,0 +1,2 @@
Add a --with-pystats configure option to turn on internal statistics
gathering.

View file

@ -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;

View file

@ -349,8 +349,8 @@ PyEval_InitThreads(void)
void
_PyEval_Fini(void)
{
#if PRINT_SPECIALIZATION_STATS
_Py_PrintSpecializationStats();
#ifdef Py_STATS
_Py_PrintSpecializationStats(1);
#endif
}

View file

@ -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;
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");
}
#else
fprintf(out, "Specialization stats:\n");
#endif
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 @@ _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)
{
@ -1086,7 +1083,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)
{
@ -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)
{

View file

@ -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

25
configure vendored
View file

@ -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
@ -6913,6 +6915,29 @@ then
$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.

View file

@ -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], [

View file

@ -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