Skip to content

Commit af64dc8

Browse files
committed
Experimental visit stats by type
1 parent bfc1d25 commit af64dc8

File tree

4 files changed

+46
-4
lines changed

4 files changed

+46
-4
lines changed

Include/cpython/pystats.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ typedef struct _object_stats {
9191
uint64_t type_cache_dunder_hits;
9292
uint64_t type_cache_dunder_misses;
9393
uint64_t type_cache_collisions;
94+
uint64_t dict_visits;
95+
uint64_t list_visits;
96+
uint64_t tuple_visits;
97+
uint64_t immortal_object_visits;
98+
uint64_t gc_object_visits;
99+
uint64_t non_gc_object_visits;
94100
/* Temporary value used during GC */
95101
uint64_t object_visits;
96102
} ObjectStats;

Include/internal/pycore_code.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,13 +389,17 @@ extern void _Py_Specialize_ContainsOp(_PyStackRef value, _Py_CODEUNIT *instr);
389389
// Export for '_opcode' shared extension
390390
PyAPI_FUNC(PyObject*) _Py_GetSpecializationStats(void);
391391

392+
extern void _PyStats_ObjectVisit(PyObject *op);
393+
#define OBJECT_VISIT(op) _PyStats_ObjectVisit(op)
394+
392395
#else
393396
#define STAT_INC(opname, name) ((void)0)
394397
#define STAT_DEC(opname, name) ((void)0)
395398
#define OPCODE_EXE_INC(opname) ((void)0)
396399
#define CALL_STAT_INC(name) ((void)0)
397400
#define OBJECT_STAT_INC(name) ((void)0)
398401
#define OBJECT_STAT_INC_COND(name, cond) ((void)0)
402+
#define OBJECT_VISIT(op) ((void)0)
399403
#define EVAL_CALL_STAT_INC(name) ((void)0)
400404
#define EVAL_CALL_STAT_INC_IF_FUNCTION(name, callable) ((void)0)
401405
#define GC_STAT_ADD(gen, name, n) ((void)0)

Python/gc.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,36 @@ update_refs(PyGC_Head *containers)
514514
}
515515
}
516516

517+
#ifdef Py_STATS
518+
void _PyStats_ObjectVisit(PyObject *op)
519+
{
520+
OBJECT_STAT_INC(object_visits);
521+
if (_Py_IsImmortal(op)) {
522+
OBJECT_STAT_INC(immortal_object_visits);
523+
}
524+
else if (PyDict_CheckExact(op)) {
525+
OBJECT_STAT_INC(dict_visits);
526+
}
527+
else if (PyList_CheckExact(op)) {
528+
OBJECT_STAT_INC(list_visits);
529+
}
530+
else if (PyTuple_CheckExact(op)) {
531+
OBJECT_STAT_INC(tuple_visits);
532+
}
533+
else if (_PyObject_IS_GC(op)) {
534+
OBJECT_STAT_INC(gc_object_visits);
535+
}
536+
else {
537+
OBJECT_STAT_INC(non_gc_object_visits);
538+
}
539+
}
540+
#endif
541+
517542
/* A traversal callback for subtract_refs. */
518543
static int
519544
visit_decref(PyObject *op, void *parent)
520545
{
521-
OBJECT_STAT_INC(object_visits);
546+
OBJECT_VISIT(op);
522547
_PyObject_ASSERT(_PyObject_CAST(parent), !_PyObject_IsFreed(op));
523548

524549
if (_PyObject_IS_GC(op)) {
@@ -576,7 +601,7 @@ static int
576601
visit_reachable(PyObject *op, void *arg)
577602
{
578603
PyGC_Head *reachable = arg;
579-
OBJECT_STAT_INC(object_visits);
604+
OBJECT_VISIT(op);
580605
if (!_PyObject_IS_GC(op)) {
581606
return 0;
582607
}
@@ -816,7 +841,7 @@ static int
816841
visit_move(PyObject *op, void *arg)
817842
{
818843
PyGC_Head *tolist = arg;
819-
OBJECT_STAT_INC(object_visits);
844+
OBJECT_VISIT(op);
820845
if (_PyObject_IS_GC(op)) {
821846
PyGC_Head *gc = AS_GC(op);
822847
if (gc_is_collecting(gc)) {
@@ -1367,7 +1392,7 @@ struct container_and_flag {
13671392
static int
13681393
visit_add_to_container(PyObject *op, void *arg)
13691394
{
1370-
OBJECT_STAT_INC(object_visits);
1395+
OBJECT_VISIT(op);
13711396
struct container_and_flag *cf = (struct container_and_flag *)arg;
13721397
int visited = cf->visited_space;
13731398
assert(visited == get_gc_state()->visited_space);

Python/specialize.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,13 @@ print_object_stats(FILE *out, ObjectStats *stats)
222222
fprintf(out, "Object method cache collisions: %" PRIu64 "\n", stats->type_cache_collisions);
223223
fprintf(out, "Object method cache dunder hits: %" PRIu64 "\n", stats->type_cache_dunder_hits);
224224
fprintf(out, "Object method cache dunder misses: %" PRIu64 "\n", stats->type_cache_dunder_misses);
225+
fprintf(out, "Object tuple visits: %" PRIu64 "\n", stats->tuple_visits);
226+
fprintf(out, "Object dict visits: %" PRIu64 "\n", stats->dict_visits);
227+
fprintf(out, "Object list visits: %" PRIu64 "\n", stats->list_visits);
228+
fprintf(out, "Object tuple visits: %" PRIu64 "\n", stats->tuple_visits);
229+
fprintf(out, "Object immortal object visits: %" PRIu64 "\n", stats->immortal_object_visits);
230+
fprintf(out, "Object GC object visits: %" PRIu64 "\n", stats->gc_object_visits);
231+
fprintf(out, "Object non-GC object visits: %" PRIu64 "\n", stats->non_gc_object_visits);
225232
}
226233

227234
static void

0 commit comments

Comments
 (0)