[Python-checkins] Add option to write specialization stats to files and script to summarize. (GH-27575)

markshannon webhook-mailer at python.org
Wed Aug 4 06:39:57 EDT 2021


https://github.com/python/cpython/commit/c83919bd635f4433f1c6ae8504996a9fe3c215e5
commit: c83919bd635f4433f1c6ae8504996a9fe3c215e5
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2021-08-04T11:39:52+01:00
summary:

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.

files:
A Tools/scripts/summarize_specialization_stats.py
M Include/internal/pycore_code.h
M Python/ceval.c
M Python/specialize.c

diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index 2a50a0700feaa1..312939ee1d26e6 100644
--- a/Include/internal/pycore_code.h
+++ b/Include/internal/pycore_code.h
@@ -302,6 +302,7 @@ int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT
 
 #define SPECIALIZATION_STATS 0
 #define SPECIALIZATION_STATS_DETAILED 0
+#define SPECIALIZATION_STATS_TO_FILE 0
 
 #if SPECIALIZATION_STATS
 
diff --git a/Python/ceval.c b/Python/ceval.c
index 4f7edb84fc3696..e3658b81388321 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4408,6 +4408,7 @@ opname ## _miss: \
             cache_backoff(cache); \
         } \
         oparg = cache->original_oparg; \
+        STAT_DEC(opname, unquickened); \
         JUMP_TO_INSTRUCTION(opname); \
     }
 
@@ -4423,6 +4424,7 @@ opname ## _miss: \
             next_instr[-1] = _Py_MAKECODEUNIT(opname ## _ADAPTIVE, oparg); \
             STAT_INC(opname, deopt); \
         } \
+        STAT_DEC(opname, unquickened); \
         JUMP_TO_INSTRUCTION(opname); \
     }
 
diff --git a/Python/specialize.c b/Python/specialize.c
index 680ffb428e4441..1ca49d244a87b0 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -117,10 +117,10 @@ _Py_GetSpecializationStats(void) {
 #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
-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_failure);
@@ -133,18 +133,18 @@ print_stats(SpecializationStats *stats, const char *name)
     if (stats->miss_types == NULL) {
         return;
     }
-    fprintf(stderr, "    %s.fails:\n", name);
+    fprintf(out, "    %s.fails:\n", name);
     PyObject *key, *count;
     Py_ssize_t pos = 0;
     while (PyDict_Next(stats->miss_types, &pos, &key, &count)) {
         PyObject *type = PyTuple_GetItem(key, 0);
         PyObject *name = PyTuple_GetItem(key, 1);
         PyObject *kind = PyTuple_GetItem(key, 2);
-        fprintf(stderr, "        %s.", ((PyTypeObject *)type)->tp_name);
-        PyObject_Print(name, stderr, Py_PRINT_RAW);
-        fprintf(stderr, " (");
-        PyObject_Print(kind, stderr, Py_PRINT_RAW);
-        fprintf(stderr, "): %ld\n", PyLong_AsLong(count));
+        fprintf(out, "        %s.", ((PyTypeObject *)type)->tp_name);
+        PyObject_Print(name, out, Py_PRINT_RAW);
+        fprintf(out, " (");
+        PyObject_Print(kind, out, Py_PRINT_RAW);
+        fprintf(out, "): %ld\n", PyLong_AsLong(count));
     }
 #endif
 }
@@ -153,10 +153,29 @@ print_stats(SpecializationStats *stats, const char *name)
 void
 _Py_PrintSpecializationStats(void)
 {
-    printf("Specialization stats:\n");
-    print_stats(&_specialization_stats[LOAD_ATTR], "load_attr");
-    print_stats(&_specialization_stats[LOAD_GLOBAL], "load_global");
-    print_stats(&_specialization_stats[BINARY_SUBSCR], "binary_subscr");
+    FILE *out = stderr;
+#if SPECIALIZATION_STATS_TO_FILE
+    /* Write to a file instead of stderr. */
+# 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
diff --git a/Tools/scripts/summarize_specialization_stats.py b/Tools/scripts/summarize_specialization_stats.py
new file mode 100644
index 00000000000000..1a13ae8cb6ce5a
--- /dev/null
+++ b/Tools/scripts/summarize_specialization_stats.py
@@ -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()



More information about the Python-checkins mailing list