mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +00:00
Add option to write specialization stats to files and script to summarize. (GH-27575)
* Add option to write stats to random file in a directory. * Add script to summarize stats.
This commit is contained in:
parent
ac811f9b5a
commit
c83919bd63
4 changed files with 75 additions and 12 deletions
|
@ -302,6 +302,7 @@ int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT
|
||||||
|
|
||||||
#define SPECIALIZATION_STATS 0
|
#define SPECIALIZATION_STATS 0
|
||||||
#define SPECIALIZATION_STATS_DETAILED 0
|
#define SPECIALIZATION_STATS_DETAILED 0
|
||||||
|
#define SPECIALIZATION_STATS_TO_FILE 0
|
||||||
|
|
||||||
#if SPECIALIZATION_STATS
|
#if SPECIALIZATION_STATS
|
||||||
|
|
||||||
|
|
|
@ -4408,6 +4408,7 @@ opname ## _miss: \
|
||||||
cache_backoff(cache); \
|
cache_backoff(cache); \
|
||||||
} \
|
} \
|
||||||
oparg = cache->original_oparg; \
|
oparg = cache->original_oparg; \
|
||||||
|
STAT_DEC(opname, unquickened); \
|
||||||
JUMP_TO_INSTRUCTION(opname); \
|
JUMP_TO_INSTRUCTION(opname); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4423,6 +4424,7 @@ opname ## _miss: \
|
||||||
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
|
next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
|
||||||
STAT_INC(opname, deopt); \
|
STAT_INC(opname, deopt); \
|
||||||
} \
|
} \
|
||||||
|
STAT_DEC(opname, unquickened); \
|
||||||
JUMP_TO_INSTRUCTION(opname); \
|
JUMP_TO_INSTRUCTION(opname); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,10 +117,10 @@ _Py_GetSpecializationStats(void) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define PRINT_STAT(name, field) fprintf(stderr, " %s." #field " : %" PRIu64 "\n", name, stats->field);
|
#define PRINT_STAT(name, field) fprintf(out, " %s." #field " : %" PRIu64 "\n", name, stats->field);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
print_stats(SpecializationStats *stats, const char *name)
|
print_stats(FILE *out, SpecializationStats *stats, const char *name)
|
||||||
{
|
{
|
||||||
PRINT_STAT(name, specialization_success);
|
PRINT_STAT(name, specialization_success);
|
||||||
PRINT_STAT(name, specialization_failure);
|
PRINT_STAT(name, specialization_failure);
|
||||||
|
@ -133,18 +133,18 @@ print_stats(SpecializationStats *stats, const char *name)
|
||||||
if (stats->miss_types == NULL) {
|
if (stats->miss_types == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fprintf(stderr, " %s.fails:\n", name);
|
fprintf(out, " %s.fails:\n", name);
|
||||||
PyObject *key, *count;
|
PyObject *key, *count;
|
||||||
Py_ssize_t pos = 0;
|
Py_ssize_t pos = 0;
|
||||||
while (PyDict_Next(stats->miss_types, &pos, &key, &count)) {
|
while (PyDict_Next(stats->miss_types, &pos, &key, &count)) {
|
||||||
PyObject *type = PyTuple_GetItem(key, 0);
|
PyObject *type = PyTuple_GetItem(key, 0);
|
||||||
PyObject *name = PyTuple_GetItem(key, 1);
|
PyObject *name = PyTuple_GetItem(key, 1);
|
||||||
PyObject *kind = PyTuple_GetItem(key, 2);
|
PyObject *kind = PyTuple_GetItem(key, 2);
|
||||||
fprintf(stderr, " %s.", ((PyTypeObject *)type)->tp_name);
|
fprintf(out, " %s.", ((PyTypeObject *)type)->tp_name);
|
||||||
PyObject_Print(name, stderr, Py_PRINT_RAW);
|
PyObject_Print(name, out, Py_PRINT_RAW);
|
||||||
fprintf(stderr, " (");
|
fprintf(out, " (");
|
||||||
PyObject_Print(kind, stderr, Py_PRINT_RAW);
|
PyObject_Print(kind, out, Py_PRINT_RAW);
|
||||||
fprintf(stderr, "): %ld\n", PyLong_AsLong(count));
|
fprintf(out, "): %ld\n", PyLong_AsLong(count));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -153,10 +153,29 @@ print_stats(SpecializationStats *stats, const char *name)
|
||||||
void
|
void
|
||||||
_Py_PrintSpecializationStats(void)
|
_Py_PrintSpecializationStats(void)
|
||||||
{
|
{
|
||||||
printf("Specialization stats:\n");
|
FILE *out = stderr;
|
||||||
print_stats(&_specialization_stats[LOAD_ATTR], "load_attr");
|
#if SPECIALIZATION_STATS_TO_FILE
|
||||||
print_stats(&_specialization_stats[LOAD_GLOBAL], "load_global");
|
/* Write to a file instead of stderr. */
|
||||||
print_stats(&_specialization_stats[BINARY_SUBSCR], "binary_subscr");
|
# ifdef MS_WINDOWS
|
||||||
|
const char *dirname = "c:\\temp\\py_stats\\";
|
||||||
|
# else
|
||||||
|
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
|
||||||
|
print_stats(out, &_specialization_stats[LOAD_ATTR], "load_attr");
|
||||||
|
print_stats(out, &_specialization_stats[LOAD_GLOBAL], "load_global");
|
||||||
|
print_stats(out, &_specialization_stats[BINARY_SUBSCR], "binary_subscr");
|
||||||
|
if (out != stderr) {
|
||||||
|
fclose(out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SPECIALIZATION_STATS_DETAILED
|
#if SPECIALIZATION_STATS_DETAILED
|
||||||
|
|
41
Tools/scripts/summarize_specialization_stats.py
Normal file
41
Tools/scripts/summarize_specialization_stats.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
"""Print a summary of specialization stats for all files in the
|
||||||
|
default stats folders.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import collections
|
||||||
|
import os.path
|
||||||
|
|
||||||
|
if os.name == "nt":
|
||||||
|
DEFAULT_DIR = "c:\\temp\\py_stats\\"
|
||||||
|
else:
|
||||||
|
DEFAULT_DIR = "/tmp/py_stats/"
|
||||||
|
|
||||||
|
|
||||||
|
TOTAL = "deferred", "hit", "miss", "unquickened"
|
||||||
|
|
||||||
|
def print_stats(name, family_stats):
|
||||||
|
total = sum(family_stats[kind] for kind in TOTAL)
|
||||||
|
if total == 0:
|
||||||
|
return
|
||||||
|
print(name+":")
|
||||||
|
for key in sorted(family_stats):
|
||||||
|
if not key.startswith("specialization"):
|
||||||
|
print(f"{key:>12}:{family_stats[key]:>12} {100*family_stats[key]/total:0.1f}%")
|
||||||
|
for key in ("specialization_success", "specialization_failure"):
|
||||||
|
print(f" {key}:{family_stats[key]:>12}")
|
||||||
|
|
||||||
|
def main():
|
||||||
|
stats = collections.defaultdict(collections.Counter)
|
||||||
|
for filename in os.listdir(DEFAULT_DIR):
|
||||||
|
for line in open(os.path.join(DEFAULT_DIR, filename)):
|
||||||
|
key, value = line.split(":")
|
||||||
|
key = key.strip()
|
||||||
|
family, stat = key.split(".")
|
||||||
|
value = int(value.strip())
|
||||||
|
stats[family][stat] += value
|
||||||
|
|
||||||
|
for name in sorted(stats):
|
||||||
|
print_stats(name, stats[name])
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Add table
Add a link
Reference in a new issue