GH-132554: Add stats for GET_ITER (GH-132592)

* Add stats for GET_ITER

* Look for common iterable types, not iterator types

* Add stats for self iter and fix naming in summary
This commit is contained in:
Mark Shannon 2025-04-29 09:00:14 +01:00 committed by GitHub
parent 01f11a0e4e
commit 622300bdfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 64 additions and 1 deletions

View file

@ -317,6 +317,7 @@ extern void _Py_Specialize_ForIter(_PyStackRef iter, _Py_CODEUNIT *instr, int op
extern void _Py_Specialize_Send(_PyStackRef receiver, _Py_CODEUNIT *instr);
extern void _Py_Specialize_ToBool(_PyStackRef value, _Py_CODEUNIT *instr);
extern void _Py_Specialize_ContainsOp(_PyStackRef value, _Py_CODEUNIT *instr);
extern void _Py_GatherStats_GetIter(_PyStackRef iterable);
// Utility functions for reading/writing 32/64-bit values in the inline caches.
// Great care should be taken to ensure that these functions remain correct and

View file

@ -3029,6 +3029,9 @@ dummy_func(
}
inst(GET_ITER, (iterable -- iter)) {
#ifdef Py_STATS
_Py_GatherStats_GetIter(iterable);
#endif
/* before: [obj]; after [getiter(obj)] */
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
PyStackRef_CLOSE(iterable);

View file

@ -4075,6 +4075,11 @@
_PyStackRef iterable;
_PyStackRef iter;
iterable = stack_pointer[-1];
#ifdef Py_STATS
_PyFrame_SetStackPointer(frame, stack_pointer);
_Py_GatherStats_GetIter(iterable);
stack_pointer = _PyFrame_GetStackPointer(frame);
#endif
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
stack_pointer = _PyFrame_GetStackPointer(frame);

View file

@ -5995,6 +5995,11 @@
_PyStackRef iterable;
_PyStackRef iter;
iterable = stack_pointer[-1];
#ifdef Py_STATS
_PyFrame_SetStackPointer(frame, stack_pointer);
_Py_GatherStats_GetIter(iterable);
stack_pointer = _PyFrame_GetStackPointer(frame);
#endif
_PyFrame_SetStackPointer(frame, stack_pointer);
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
stack_pointer = _PyFrame_GetStackPointer(frame);

View file

@ -146,6 +146,7 @@ print_spec_stats(FILE *out, OpcodeStats *stats)
* even though we don't specialize them yet. */
fprintf(out, "opcode[BINARY_SLICE].specializable : 1\n");
fprintf(out, "opcode[STORE_SLICE].specializable : 1\n");
fprintf(out, "opcode[GET_ITER].specializable : 1\n");
for (int i = 0; i < 256; i++) {
if (_PyOpcode_Caches[i]) {
/* Ignore jumps as they cannot be specialized */
@ -668,6 +669,7 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters
#define SPEC_FAIL_ITER_CALLABLE 28
#define SPEC_FAIL_ITER_ASCII_STRING 29
#define SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND 30
#define SPEC_FAIL_ITER_SELF 31
// UNPACK_SEQUENCE
@ -3115,6 +3117,53 @@ _Py_Specialize_ContainsOp(_PyStackRef value_st, _Py_CODEUNIT *instr)
return;
}
#ifdef Py_STATS
void
_Py_GatherStats_GetIter(_PyStackRef iterable)
{
PyTypeObject *tp = PyStackRef_TYPE(iterable);
int kind = SPEC_FAIL_OTHER;
if (tp == &PyTuple_Type) {
kind = SPEC_FAIL_ITER_TUPLE;
}
else if (tp == &PyList_Type) {
kind = SPEC_FAIL_ITER_LIST;
}
else if (tp == &PyDict_Type) {
kind = SPEC_FAIL_ITER_DICT_KEYS;
}
else if (tp == &PySet_Type) {
kind = SPEC_FAIL_ITER_SET;
}
else if (tp == &PyBytes_Type) {
kind = SPEC_FAIL_ITER_BYTES;
}
else if (tp == &PyEnum_Type) {
kind = SPEC_FAIL_ITER_ENUMERATE;
}
else if (tp == &PyUnicode_Type) {
kind = SPEC_FAIL_ITER_STRING;
}
else if (tp == &PyGen_Type) {
kind = SPEC_FAIL_ITER_GENERATOR;
}
else if (tp == &PyCoro_Type) {
kind = SPEC_FAIL_ITER_COROUTINE;
}
else if (tp == &PyAsyncGen_Type) {
kind = SPEC_FAIL_ITER_ASYNC_GENERATOR;
}
else if (tp == &_PyAsyncGenASend_Type) {
kind = SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND;
}
else if (tp->tp_iter == PyObject_SelfIter) {
kind = SPEC_FAIL_ITER_SELF;
}
SPECIALIZATION_FAIL(GET_ITER, kind);
}
#endif
/* Code init cleanup.
* CALL_ALLOC_AND_ENTER_INIT will set up
* the frame to execute the EXIT_INIT_CHECK

View file

@ -288,7 +288,7 @@ class OpcodeStats:
opcode = "SUPER"
elif opcode.endswith("ATTR"):
opcode = "ATTR"
elif opcode in ("FOR_ITER", "SEND"):
elif opcode in ("FOR_ITER", "GET_ITER", "SEND"):
opcode = "ITER"
elif opcode.endswith("SUBSCR"):
opcode = "SUBSCR"