]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-46072: Add some frame stats. (GH-31060)
authorMark Shannon <mark@hotpy.org>
Wed, 2 Feb 2022 11:01:33 +0000 (11:01 +0000)
committerGitHub <noreply@github.com>
Wed, 2 Feb 2022 11:01:33 +0000 (11:01 +0000)
Include/internal/pycore_code.h
Objects/frameobject.c
Python/ceval.c
Python/frame.c
Python/pystate.c
Python/specialize.c
Tools/scripts/summarize_stats.py

index 45c7752112b4669e836973d3324a6d571e16c7d2..3897ea0ab6a1a68c484bfea1729dfcd42b8d770b 100644 (file)
@@ -303,6 +303,8 @@ typedef struct _opcode_stats {
 typedef struct _call_stats {
     uint64_t inlined_py_calls;
     uint64_t pyeval_calls;
+    uint64_t frames_pushed;
+    uint64_t frame_objects_created;
 } CallStats;
 
 typedef struct _object_stats {
index 81ad4cc65d150c57e2d7b94402ae91e77e49308a..15da1325d1480fb9827e1f14690d76100c4adb73 100644 (file)
@@ -794,6 +794,7 @@ init_frame(InterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
 PyFrameObject*
 _PyFrame_New_NoTrack(PyCodeObject *code)
 {
+    CALL_STAT_INC(frame_objects_created);
     int slots = code->co_nlocalsplus + code->co_stacksize;
     PyFrameObject *f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, slots);
     if (f == NULL) {
index b69d5aa9d32069f51292250d720bed4cd745b73a..70748e8911f9fe30b978d4e4704b7c527b2ddbff 100644 (file)
@@ -2242,6 +2242,7 @@ handle_eval_breaker:
             if (new_frame == NULL) {
                 goto error;
             }
+            CALL_STAT_INC(frames_pushed);
             _PyFrame_InitializeSpecials(new_frame, getitem,
                                         NULL, code->co_nlocalsplus);
             STACK_SHRINK(2);
@@ -4660,6 +4661,7 @@ handle_eval_breaker:
             if (new_frame == NULL) {
                 goto error;
             }
+            CALL_STAT_INC(inlined_py_calls);
             STACK_SHRINK(argcount);
             for (int i = 0; i < argcount; i++) {
                 new_frame->localsplus[i] = stack_pointer[i];
@@ -4690,6 +4692,7 @@ handle_eval_breaker:
             if (new_frame == NULL) {
                 goto error;
             }
+            CALL_STAT_INC(inlined_py_calls);
             STACK_SHRINK(argcount);
             for (int i = 0; i < argcount; i++) {
                 new_frame->localsplus[i] = stack_pointer[i];
@@ -4708,7 +4711,6 @@ handle_eval_breaker:
             _PyFrame_SetStackPointer(frame, stack_pointer);
             new_frame->previous = frame;
             frame = cframe.current_frame = new_frame;
-            CALL_STAT_INC(inlined_py_calls);
             goto start_frame;
         }
 
@@ -6078,6 +6080,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
 {
     PyCodeObject * code = (PyCodeObject *)func->func_code;
     size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
+    CALL_STAT_INC(frames_pushed);
     InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
     if (frame == NULL) {
         goto fail;
index 771de7583be79698b9edecf66bda1440cc31462f..ca7c5f9c94e07b94cbb77b5898522ee17a4d5dea 100644 (file)
@@ -1,6 +1,7 @@
 
 #include "Python.h"
 #include "frameobject.h"
+#include "pycore_code.h"           // stats
 #include "pycore_frame.h"
 #include "pycore_object.h"        // _PyObject_GC_UNTRACK()
 #include "opcode.h"
@@ -113,6 +114,7 @@ _PyFrame_Push(PyThreadState *tstate, PyFunctionObject *func)
 {
     PyCodeObject *code = (PyCodeObject *)func->func_code;
     size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
+    CALL_STAT_INC(frames_pushed);
     InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
     if (new_frame == NULL) {
         return NULL;
index 4378d78a8b7811843760c916ce8ca3df717834a3..77467944e2afba610d06b94f18052098fb846443 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "Python.h"
 #include "pycore_ceval.h"
+#include "pycore_code.h"           // stats
 #include "pycore_frame.h"
 #include "pycore_initconfig.h"
 #include "pycore_object.h"        // _PyType_InitCache()
@@ -2219,6 +2220,7 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFunctionObject *func, PyObject
     int nlocalsplus = code->co_nlocalsplus;
     size_t size = nlocalsplus + code->co_stacksize +
         FRAME_SPECIALS_SIZE;
+    CALL_STAT_INC(frames_pushed);
     InterpreterFrame *frame  = _PyThreadState_BumpFramePointer(tstate, size);
     if (frame == NULL) {
         return NULL;
index 5771a41dcfd2ca3032c8f3f479d7d8bccb659d1e..9290fbe8239564534497f1c8b51c9180493b0b85 100644 (file)
@@ -169,6 +169,8 @@ print_call_stats(FILE *out, CallStats *stats)
 {
     fprintf(out, "Calls to PyEval_EvalDefault: %" PRIu64 "\n", stats->pyeval_calls);
     fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls);
+    fprintf(out, "Frames pushed: %" PRIu64 "\n", stats->frames_pushed);
+    fprintf(out, "Frame objects created: %" PRIu64 "\n", stats->frame_objects_created);
 }
 
 static void
index 2761dcb50985b01d8a61a1019bad2602d7ddb7e3..319b251c854a8a8ae30470dc7d5516523044733c 100644 (file)
@@ -106,6 +106,9 @@ def main():
     for key, value in stats.items():
         if "Calls to" in key:
             print(f"    {key}: {value} {100*value/total:0.1f}%")
+    for key, value in stats.items():
+        if key.startswith("Frame"):
+            print(f"    {key}: {value} {100*value/total:0.1f}%")
     print("Object stats:")
     total = stats.get("Object new values")
     for key, value in stats.items():