mirror of
https://github.com/python/cpython
synced 2024-09-05 00:05:39 +00:00
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:
parent
3a60bfef49
commit
342b93f9f2
|
@ -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);
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Add a --with-pystats configure option to turn on internal statistics
|
||||
gathering.
|
|
@ -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;
|
||||
|
|
|
@ -349,8 +349,8 @@ PyEval_InitThreads(void)
|
|||
void
|
||||
_PyEval_Fini(void)
|
||||
{
|
||||
#if PRINT_SPECIALIZATION_STATS
|
||||
_Py_PrintSpecializationStats();
|
||||
#ifdef Py_STATS
|
||||
_Py_PrintSpecializationStats(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
25
configure
vendored
|
@ -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.
|
||||
|
|
17
configure.ac
17
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], [
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue