Skip to content

Commit 0d05da1

Browse files
authored
Add specialization stats for FOR_ITER. (GH-31079)
1 parent f66c857 commit 0d05da1

File tree

3 files changed

+74
-1
lines changed

3 files changed

+74
-1
lines changed

Python/ceval.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4212,6 +4212,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
42124212
PREDICTED(FOR_ITER);
42134213
/* before: [iter]; after: [iter, iter()] *or* [] */
42144214
PyObject *iter = TOP();
4215+
#ifdef Py_STATS
4216+
extern int _PySpecialization_ClassifyIterator(PyObject *);
4217+
_py_stats.opcode_stats[FOR_ITER].specialization.failure++;
4218+
_py_stats.opcode_stats[FOR_ITER].specialization.failure_kinds[_PySpecialization_ClassifyIterator(iter)]++;
4219+
#endif
42154220
PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
42164221
if (next != NULL) {
42174222
PUSH(next);

Python/specialize.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,23 @@ initial_counter_value(void) {
548548
#define SPEC_FAIL_NOT_FOLLOWED_BY_COND_JUMP 14
549549
#define SPEC_FAIL_BIG_INT 15
550550

551+
/* FOR_ITER */
552+
#define SPEC_FAIL_ITER_GENERATOR 10
553+
#define SPEC_FAIL_ITER_COROUTINE 11
554+
#define SPEC_FAIL_ITER_ASYNC_GENERATOR 12
555+
#define SPEC_FAIL_ITER_LIST 13
556+
#define SPEC_FAIL_ITER_TUPLE 14
557+
#define SPEC_FAIL_ITER_SET 15
558+
#define SPEC_FAIL_ITER_STRING 16
559+
#define SPEC_FAIL_ITER_BYTES 17
560+
#define SPEC_FAIL_ITER_RANGE 18
561+
#define SPEC_FAIL_ITER_ITERTOOLS 19
562+
#define SPEC_FAIL_ITER_DICT_KEYS 20
563+
#define SPEC_FAIL_ITER_DICT_ITEMS 21
564+
#define SPEC_FAIL_ITER_DICT_VALUES 22
565+
#define SPEC_FAIL_ITER_ENUMERATE 23
566+
567+
551568
static int
552569
specialize_module_load_attr(
553570
PyObject *owner, _Py_CODEUNIT *instr, PyObject *name,
@@ -1817,3 +1834,54 @@ _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs,
18171834
STAT_INC(COMPARE_OP, success);
18181835
adaptive->counter = initial_counter_value();
18191836
}
1837+
1838+
1839+
int
1840+
_PySpecialization_ClassifyIterator(PyObject *iter)
1841+
{
1842+
if (PyGen_CheckExact(iter)) {
1843+
return SPEC_FAIL_ITER_GENERATOR;
1844+
}
1845+
if (PyCoro_CheckExact(iter)) {
1846+
return SPEC_FAIL_ITER_COROUTINE;
1847+
}
1848+
if (PyAsyncGen_CheckExact(iter)) {
1849+
return SPEC_FAIL_ITER_ASYNC_GENERATOR;
1850+
}
1851+
PyTypeObject *t = _Py_TYPE(iter);
1852+
if (t == &PyListIter_Type) {
1853+
return SPEC_FAIL_ITER_LIST;
1854+
}
1855+
if (t == &PyTupleIter_Type) {
1856+
return SPEC_FAIL_ITER_TUPLE;
1857+
}
1858+
if (t == &PyDictIterKey_Type) {
1859+
return SPEC_FAIL_ITER_DICT_KEYS;
1860+
}
1861+
if (t == &PyDictIterValue_Type) {
1862+
return SPEC_FAIL_ITER_DICT_VALUES;
1863+
}
1864+
if (t == &PyDictIterItem_Type) {
1865+
return SPEC_FAIL_ITER_DICT_ITEMS;
1866+
}
1867+
if (t == &PySetIter_Type) {
1868+
return SPEC_FAIL_ITER_SET;
1869+
}
1870+
if (t == &PyUnicodeIter_Type) {
1871+
return SPEC_FAIL_ITER_STRING;
1872+
}
1873+
if (t == &PyBytesIter_Type) {
1874+
return SPEC_FAIL_ITER_BYTES;
1875+
}
1876+
if (t == &PyRangeIter_Type) {
1877+
return SPEC_FAIL_ITER_RANGE;
1878+
}
1879+
if (t == &PyEnum_Type) {
1880+
return SPEC_FAIL_ITER_ENUMERATE;
1881+
}
1882+
1883+
if (strncmp(t->tp_name, "itertools", 8) == 0) {
1884+
return SPEC_FAIL_ITER_ITERTOOLS;
1885+
}
1886+
return SPEC_FAIL_OTHER;
1887+
}

Tools/scripts/summarize_stats.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
TOTAL = "specialization.deferred", "specialization.hit", "specialization.miss", "execution_count"
2727

2828
def print_specialization_stats(name, family_stats):
29-
if "specialization.deferred" not in family_stats:
29+
if "specialization.failure" not in family_stats:
3030
return
3131
total = sum(family_stats.get(kind, 0) for kind in TOTAL)
3232
if total == 0:

0 commit comments

Comments
 (0)