Skip to content

Commit ff81eb2

Browse files
Count total tuples
1 parent 3b80c93 commit ff81eb2

File tree

3 files changed

+52
-0
lines changed

3 files changed

+52
-0
lines changed

Include/internal/pycore_interp_structs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,9 @@ struct gc_generation_stats {
193193
/* total number of uncollectable objects (put into gc.garbage) */
194194
Py_ssize_t uncollectable;
195195
Py_ssize_t untracked_tuples;
196+
Py_ssize_t total_untracked_tuples;
197+
Py_ssize_t total_tuples;
198+
Py_ssize_t tuples_by_size[33];
196199
};
197200

198201
enum _GCPhase {

Objects/tupleobject.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,44 @@ class tuple "PyTupleObject *" "&PyTuple_Type"
2222

2323
static inline int maybe_freelist_push(PyTupleObject *);
2424

25+
static uint8_t
26+
_log2_int(Py_ssize_t size)
27+
{
28+
if (size == 0) {
29+
return 0;
30+
}
31+
32+
const uint64_t b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000, 0xFFFFFFFF00000000};
33+
const uint64_t S[] = {1, 2, 4, 8, 16, 32};
34+
35+
int64_t v = size;
36+
uint8_t r = 0; // result of log2(v) will go here
37+
for (int i = 5; i >= 0; i--) // unroll for speed...
38+
{
39+
if (v & b[i])
40+
{
41+
v >>= S[i];
42+
r |= S[i];
43+
}
44+
}
45+
46+
#ifdef Py_DEBUG
47+
uint8_t x = (uint8_t)log2((double)size);
48+
assert(x == r);
49+
#endif
50+
51+
return r + 1;
52+
}
53+
54+
static void
55+
_count_tuple(Py_ssize_t size)
56+
{
57+
PyInterpreterState *interp = _PyInterpreterState_GET();
58+
interp->gc.generation_stats[0].total_tuples += 1;
59+
uint8_t size_index = _log2_int(size);
60+
interp->gc.generation_stats[0].tuples_by_size[size_index] += 1;
61+
}
62+
2563

2664
/* Allocate an uninitialized tuple object. Before making it public, following
2765
steps must be done:
@@ -46,6 +84,7 @@ tuple_alloc(Py_ssize_t size)
4684
PyTupleObject *op = _Py_FREELIST_POP(PyTupleObject, tuples[index]);
4785
if (op != NULL) {
4886
_PyTuple_RESET_HASH_CACHE(op);
87+
_count_tuple(size);
4988
return op;
5089
}
5190
}
@@ -57,6 +96,7 @@ tuple_alloc(Py_ssize_t size)
5796
PyTupleObject *result = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size);
5897
if (result != NULL) {
5998
_PyTuple_RESET_HASH_CACHE(result);
99+
_count_tuple(size);
60100
}
61101
return result;
62102
}
@@ -68,6 +108,7 @@ tuple_alloc(Py_ssize_t size)
68108
static inline PyObject *
69109
tuple_get_empty(void)
70110
{
111+
_count_tuple(0);
71112
return (PyObject *)&_Py_SINGLETON(tuple_empty);
72113
}
73114

Python/gc.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2101,6 +2101,7 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
21012101
Py_UNREACHABLE();
21022102
}
21032103
gcstate->generation_stats[generation].untracked_tuples += stats.untracked_tuples;
2104+
gcstate->generation_stats[0].total_untracked_tuples += stats.untracked_tuples;
21042105
if (PyDTrace_GC_DONE_ENABLED()) {
21052106
PyDTrace_GC_DONE(stats.uncollectable + stats.collected);
21062107
}
@@ -2109,6 +2110,13 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
21092110
}
21102111
else {
21112112
FILE *out = stderr;
2113+
2114+
fprintf(out, "GC[%d] total tuples : %zd\n", 0, gcstate->generation_stats[0].total_tuples);
2115+
fprintf(out, "GC[%d] total untracked_tuples : %zd\n", 0, gcstate->generation_stats[0].total_untracked_tuples);
2116+
for (int i = 0; i < 33; i++) {
2117+
fprintf(out, "GC[%d] by size %d : %zd\n", 0, i, gcstate->generation_stats[0].tuples_by_size[i]);
2118+
}
2119+
21122120
for (int i = 0; i < NUM_GENERATIONS; i++) {
21132121
fprintf(out, "GC[%d] collections : %zd\n", i, gcstate->generation_stats[i].collections);
21142122
fprintf(out, "GC[%d] collected : %zd\n", i, gcstate->generation_stats[i].collected);

0 commit comments

Comments
 (0)