Skip to content

Commit 187930f

Browse files
authored
bpo-46072: Add some frame stats. (GH-31060)
1 parent a05866c commit 187930f

File tree

7 files changed

+16
-1
lines changed

7 files changed

+16
-1
lines changed

Include/internal/pycore_code.h

+2
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ typedef struct _opcode_stats {
303303
typedef struct _call_stats {
304304
uint64_t inlined_py_calls;
305305
uint64_t pyeval_calls;
306+
uint64_t frames_pushed;
307+
uint64_t frame_objects_created;
306308
} CallStats;
307309

308310
typedef struct _object_stats {

Objects/frameobject.c

+1
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,7 @@ init_frame(InterpreterFrame *frame, PyFunctionObject *func, PyObject *locals)
794794
PyFrameObject*
795795
_PyFrame_New_NoTrack(PyCodeObject *code)
796796
{
797+
CALL_STAT_INC(frame_objects_created);
797798
int slots = code->co_nlocalsplus + code->co_stacksize;
798799
PyFrameObject *f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, slots);
799800
if (f == NULL) {

Python/ceval.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -2242,6 +2242,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
22422242
if (new_frame == NULL) {
22432243
goto error;
22442244
}
2245+
CALL_STAT_INC(frames_pushed);
22452246
_PyFrame_InitializeSpecials(new_frame, getitem,
22462247
NULL, code->co_nlocalsplus);
22472248
STACK_SHRINK(2);
@@ -4660,6 +4661,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46604661
if (new_frame == NULL) {
46614662
goto error;
46624663
}
4664+
CALL_STAT_INC(inlined_py_calls);
46634665
STACK_SHRINK(argcount);
46644666
for (int i = 0; i < argcount; i++) {
46654667
new_frame->localsplus[i] = stack_pointer[i];
@@ -4690,6 +4692,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
46904692
if (new_frame == NULL) {
46914693
goto error;
46924694
}
4695+
CALL_STAT_INC(inlined_py_calls);
46934696
STACK_SHRINK(argcount);
46944697
for (int i = 0; i < argcount; i++) {
46954698
new_frame->localsplus[i] = stack_pointer[i];
@@ -4708,7 +4711,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
47084711
_PyFrame_SetStackPointer(frame, stack_pointer);
47094712
new_frame->previous = frame;
47104713
frame = cframe.current_frame = new_frame;
4711-
CALL_STAT_INC(inlined_py_calls);
47124714
goto start_frame;
47134715
}
47144716

@@ -6078,6 +6080,7 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
60786080
{
60796081
PyCodeObject * code = (PyCodeObject *)func->func_code;
60806082
size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
6083+
CALL_STAT_INC(frames_pushed);
60816084
InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
60826085
if (frame == NULL) {
60836086
goto fail;

Python/frame.c

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
#include "Python.h"
33
#include "frameobject.h"
4+
#include "pycore_code.h" // stats
45
#include "pycore_frame.h"
56
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
67
#include "opcode.h"
@@ -113,6 +114,7 @@ _PyFrame_Push(PyThreadState *tstate, PyFunctionObject *func)
113114
{
114115
PyCodeObject *code = (PyCodeObject *)func->func_code;
115116
size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
117+
CALL_STAT_INC(frames_pushed);
116118
InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
117119
if (new_frame == NULL) {
118120
return NULL;

Python/pystate.c

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "Python.h"
55
#include "pycore_ceval.h"
6+
#include "pycore_code.h" // stats
67
#include "pycore_frame.h"
78
#include "pycore_initconfig.h"
89
#include "pycore_object.h" // _PyType_InitCache()
@@ -2219,6 +2220,7 @@ _PyThreadState_PushFrame(PyThreadState *tstate, PyFunctionObject *func, PyObject
22192220
int nlocalsplus = code->co_nlocalsplus;
22202221
size_t size = nlocalsplus + code->co_stacksize +
22212222
FRAME_SPECIALS_SIZE;
2223+
CALL_STAT_INC(frames_pushed);
22222224
InterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
22232225
if (frame == NULL) {
22242226
return NULL;

Python/specialize.c

+2
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ print_call_stats(FILE *out, CallStats *stats)
169169
{
170170
fprintf(out, "Calls to PyEval_EvalDefault: %" PRIu64 "\n", stats->pyeval_calls);
171171
fprintf(out, "Calls to Python functions inlined: %" PRIu64 "\n", stats->inlined_py_calls);
172+
fprintf(out, "Frames pushed: %" PRIu64 "\n", stats->frames_pushed);
173+
fprintf(out, "Frame objects created: %" PRIu64 "\n", stats->frame_objects_created);
172174
}
173175

174176
static void

Tools/scripts/summarize_stats.py

+3
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ def main():
106106
for key, value in stats.items():
107107
if "Calls to" in key:
108108
print(f" {key}: {value} {100*value/total:0.1f}%")
109+
for key, value in stats.items():
110+
if key.startswith("Frame"):
111+
print(f" {key}: {value} {100*value/total:0.1f}%")
109112
print("Object stats:")
110113
total = stats.get("Object new values")
111114
for key, value in stats.items():

0 commit comments

Comments
 (0)