Skip to content

bpo-46072: Add stats for FOR_ITER. #31079

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -4212,6 +4212,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PREDICTED(FOR_ITER);
/* before: [iter]; after: [iter, iter()] *or* [] */
PyObject *iter = TOP();
#ifdef Py_STATS
extern int _PySpecialization_ClassifyIterator(PyObject *);
_py_stats.opcode_stats[FOR_ITER].specialization.failure++;
_py_stats.opcode_stats[FOR_ITER].specialization.failure_kinds[_PySpecialization_ClassifyIterator(iter)]++;
#endif
PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
if (next != NULL) {
PUSH(next);
Expand Down
68 changes: 68 additions & 0 deletions Python/specialize.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,23 @@ initial_counter_value(void) {
#define SPEC_FAIL_NOT_FOLLOWED_BY_COND_JUMP 14
#define SPEC_FAIL_BIG_INT 15

/* FOR_ITER */
#define SPEC_FAIL_ITER_GENERATOR 10
#define SPEC_FAIL_ITER_COROUTINE 11
#define SPEC_FAIL_ITER_ASYNC_GENERATOR 12
#define SPEC_FAIL_ITER_LIST 13
#define SPEC_FAIL_ITER_TUPLE 14
#define SPEC_FAIL_ITER_SET 15
#define SPEC_FAIL_ITER_STRING 16
#define SPEC_FAIL_ITER_BYTES 17
#define SPEC_FAIL_ITER_RANGE 18
#define SPEC_FAIL_ITER_ITERTOOLS 19
#define SPEC_FAIL_ITER_DICT_KEYS 20
#define SPEC_FAIL_ITER_DICT_ITEMS 21
#define SPEC_FAIL_ITER_DICT_VALUES 22
#define SPEC_FAIL_ITER_ENUMERATE 23


static int
specialize_module_load_attr(
PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
Expand Down Expand Up @@ -1817,3 +1834,54 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs,
STAT_INC(COMPARE_OP, success);
adaptive->counter = initial_counter_value();
}


int
_PySpecialization_ClassifyIterator(PyObject *iter)
{
if (PyGen_CheckExact(iter)) {
return SPEC_FAIL_ITER_GENERATOR;
}
if (PyCoro_CheckExact(iter)) {
return SPEC_FAIL_ITER_COROUTINE;
}
if (PyAsyncGen_CheckExact(iter)) {
return SPEC_FAIL_ITER_ASYNC_GENERATOR;
}
PyTypeObject *t = _Py_TYPE(iter);
if (t == &PyListIter_Type) {
return SPEC_FAIL_ITER_LIST;
}
if (t == &PyTupleIter_Type) {
return SPEC_FAIL_ITER_TUPLE;
}
if (t == &PyDictIterKey_Type) {
return SPEC_FAIL_ITER_DICT_KEYS;
}
if (t == &PyDictIterValue_Type) {
return SPEC_FAIL_ITER_DICT_VALUES;
}
if (t == &PyDictIterItem_Type) {
return SPEC_FAIL_ITER_DICT_ITEMS;
}
if (t == &PySetIter_Type) {
return SPEC_FAIL_ITER_SET;
}
if (t == &PyUnicodeIter_Type) {
return SPEC_FAIL_ITER_STRING;
}
if (t == &PyBytesIter_Type) {
return SPEC_FAIL_ITER_BYTES;
}
if (t == &PyRangeIter_Type) {
return SPEC_FAIL_ITER_RANGE;
}
if (t == &PyEnum_Type) {
return SPEC_FAIL_ITER_ENUMERATE;
}

if (strncmp(t->tp_name, "itertools", 8) == 0) {
return SPEC_FAIL_ITER_ITERTOOLS;
}
return SPEC_FAIL_OTHER;
}
2 changes: 1 addition & 1 deletion Tools/scripts/summarize_stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
TOTAL = "specialization.deferred", "specialization.hit", "specialization.miss", "execution_count"

def print_specialization_stats(name, family_stats):
if "specialization.deferred" not in family_stats:
if "specialization.failure" not in family_stats:
return
total = sum(family_stats.get(kind, 0) for kind in TOTAL)
if total == 0:
Expand Down