Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7ccfadf

Browse files
committed
New PYMALLOC_DEBUG function void _PyMalloc_DebugDumpStats(void).
This displays stats about the # of arenas, pools, blocks and bytes, to stderr, both used and reserved but unused. CAUTION: Because PYMALLOC_DEBUG is on, the debug malloc routine adds 16 bytes to each request. This makes each block appear two size classes higher than it would be if PYMALLOC_DEBUG weren't on. So far, playing with this confirms the obvious: there's a lot of activity in the "small dict" size class, but nothing in the core makes any use of the 8-byte or 16-byte classes.
1 parent de14a30 commit 7ccfadf

2 files changed

Lines changed: 98 additions & 1 deletion

File tree

Include/pymem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ DL_IMPORT(void *) _PyMalloc_DebugRealloc(void *p, size_t nbytes);
102102
DL_IMPORT(void) _PyMalloc_DebugFree(void *p);
103103
DL_IMPORT(void) _PyMalloc_DebugDumpAddress(const void *p);
104104
DL_IMPORT(void) _PyMalloc_DebugCheckAddress(const void *p);
105+
DL_IMPORT(void) _PyMalloc_DebugDumpStats(void);
105106
#define _PyMalloc_MALLOC _PyMalloc_DebugMalloc
106107
#define _PyMalloc_REALLOC _PyMalloc_DebugRealloc
107108
#define _PyMalloc_FREE _PyMalloc_DebugFree

Objects/obmalloc.c

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,11 @@ _PyMalloc_DebugRealloc(void *p, size_t nbytes)
10261026
return fresh;
10271027
}
10281028

1029-
void
1029+
/* Check the forbidden bytes on both ends of the memory allocated for p.
1030+
* If anything is wrong, print info to stderr via _PyMalloc_DebugDumpAddress,
1031+
* and call Py_FatalError to kill the program.
1032+
*/
1033+
void
10301034
_PyMalloc_DebugCheckAddress(const void *p)
10311035
{
10321036
const uchar *q = (const uchar *)p;
@@ -1063,6 +1067,7 @@ _PyMalloc_DebugCheckAddress(const void *p)
10631067
Py_FatalError(msg);
10641068
}
10651069

1070+
/* Display info to stderr about the memory block at p. */
10661071
void
10671072
_PyMalloc_DebugDumpAddress(const void *p)
10681073
{
@@ -1149,4 +1154,95 @@ _PyMalloc_DebugDumpAddress(const void *p)
11491154
}
11501155
}
11511156

1157+
/* Print summary info to stderr about the state of pymalloc's structures. */
1158+
void
1159+
_PyMalloc_DebugDumpStats(void)
1160+
{
1161+
uint i;
1162+
const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT;
1163+
uint numfreepools = 0;
1164+
/* # of pools per class index */
1165+
ulong numpools[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
1166+
/* # of allocated blocks per class index */
1167+
ulong numblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
1168+
/* # of free blocks per class index */
1169+
ulong numfreeblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
1170+
ulong grandtotal; /* total # of allocated bytes */
1171+
ulong freegrandtotal; /* total # of available bytes in used blocks */
1172+
1173+
fprintf(stderr, "%u arenas * %d bytes/arena = %lu total bytes.\n",
1174+
narenas, ARENA_SIZE, narenas * (ulong)ARENA_SIZE);
1175+
fprintf(stderr, "Small block threshold = %d, in %u size classes.\n",
1176+
SMALL_REQUEST_THRESHOLD, numclasses);
1177+
fprintf(stderr, "pymalloc malloc+realloc called %lu times.\n",
1178+
serialno);
1179+
1180+
for (i = 0; i < numclasses; ++i)
1181+
numpools[i] = numblocks[i] = numfreeblocks[i] = 0;
1182+
1183+
/* Because empty pools aren't linked to from anything, it's easiest
1184+
* to march over all the arenas.
1185+
*/
1186+
for (i = 0; i < narenas; ++i) {
1187+
uint poolsinarena;
1188+
uint j;
1189+
uptr base = arenas[i];
1190+
1191+
/* round up to pool alignment */
1192+
poolsinarena = ARENA_SIZE / POOL_SIZE;
1193+
if (base & (uptr)POOL_SIZE_MASK) {
1194+
--poolsinarena;
1195+
base &= ~(uptr)POOL_SIZE_MASK;
1196+
base += POOL_SIZE;
1197+
}
1198+
1199+
if (i == narenas - 1) {
1200+
/* current arena may have raw memory at the end */
1201+
numfreepools += nfreepools;
1202+
poolsinarena -= nfreepools;
1203+
}
1204+
1205+
/* visit every pool in the arena */
1206+
for (j = 0; j < poolsinarena; ++j, base += POOL_SIZE) {
1207+
poolp p = (poolp)base;
1208+
if (p->ref.count == 0) {
1209+
/* currently unused */
1210+
++numfreepools;
1211+
continue;
1212+
}
1213+
++numpools[p->szidx];
1214+
numblocks[p->szidx] += p->ref.count;
1215+
numfreeblocks[p->szidx] += p->capacity - p->ref.count;
1216+
}
1217+
}
1218+
1219+
fputc('\n', stderr);
1220+
fprintf(stderr, "Number of unused pools: %u\n", numfreepools);
1221+
fputc('\n', stderr);
1222+
fputs("class num bytes num pools blocks in use avail blocks\n"
1223+
"----- --------- --------- ------------- ------------\n",
1224+
stderr);
1225+
1226+
grandtotal = freegrandtotal = 0;
1227+
for (i = 0; i < numclasses; ++i) {
1228+
ulong p = numpools[i];
1229+
ulong b = numblocks[i];
1230+
ulong f = numfreeblocks[i];
1231+
uint size = (i+1) << ALIGNMENT_SHIFT;
1232+
if (p == 0) {
1233+
assert(b == 0 && f == 0);
1234+
continue;
1235+
}
1236+
fprintf(stderr, "%5u %11u %11lu %15lu %13lu\n",
1237+
i, size, p, b, f);
1238+
grandtotal += b * size;
1239+
freegrandtotal += f * size;
1240+
}
1241+
fputc('\n', stderr);
1242+
fprintf(stderr, "Total bytes in allocated blocks: %lu\n",
1243+
grandtotal);
1244+
fprintf(stderr, "Total free bytes in used pools: %lu\n",
1245+
freegrandtotal);
1246+
}
1247+
11521248
#endif /* PYMALLOC_DEBUG */

0 commit comments

Comments
 (0)