Files
Python3-Win9x/scripts/vc6-obmalloc-debugmallocstats-c89.test.py
T

176 lines
5.8 KiB
Python

#!/usr/bin/env python3
"""Guard _PyObject_DebugMallocStats C89 declarations and evaluation order."""
import re
import sys
from pathlib import Path
source = Path(sys.argv[1]).read_text()
match = re.search(
r"\n_PyObject_DebugMallocStats\(FILE \*out\)\s*\{(.*?)\n\}",
source, re.S,
)
assert match, "_PyObject_DebugMallocStats definition not found"
body = re.sub(r"/\*.*?\*/", "", match.group(1), flags=re.S)
declarations = r"""
uint i;
uint numclasses;
size_t numpools[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
size_t numblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
size_t numfreeblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT];
size_t allocated_bytes;
size_t available_bytes;
uint numfreepools;
size_t arena_alignment;
size_t pool_header_bytes;
size_t quantization;
size_t narenas;
size_t total;
char buf[128];
"""
assert body.split()[:len(declarations.split())] == declarations.split(), (
"_PyObject_DebugMallocStats must hoist only uninitialized declarations "
"before the pymalloc guard, preserving array extents"
)
# Freeze the guard before all scalar assignments, their original order, and
# the entire remaining body, including array zeroing and conditional paths.
expected = declarations + r"""
if (!_PyMem_PymallocEnabled()) {
return 0;
}
numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT;
allocated_bytes = 0;
available_bytes = 0;
numfreepools = 0;
arena_alignment = 0;
pool_header_bytes = 0;
quantization = 0;
narenas = 0;
fprintf(out, "Small block threshold = %d, in %u size classes.\n",
SMALL_REQUEST_THRESHOLD, numclasses);
for (i = 0; i < numclasses; ++i)
numpools[i] = numblocks[i] = numfreeblocks[i] = 0;
for (i = 0; i < maxarenas; ++i) {
uintptr_t base = arenas[i].address;
if (arenas[i].address == (uintptr_t)NULL)
continue;
narenas += 1;
numfreepools += arenas[i].nfreepools;
if (base & (uintptr_t)POOL_SIZE_MASK) {
arena_alignment += POOL_SIZE;
base &= ~(uintptr_t)POOL_SIZE_MASK;
base += POOL_SIZE;
}
assert(base <= (uintptr_t) arenas[i].pool_address);
for (; base < (uintptr_t) arenas[i].pool_address; base += POOL_SIZE) {
poolp p = (poolp)base;
const uint sz = p->szidx;
uint freeblocks;
if (p->ref.count == 0) {
#ifdef Py_DEBUG
assert(pool_is_in_list(p, arenas[i].freepools));
#endif
continue;
}
++numpools[sz];
numblocks[sz] += p->ref.count;
freeblocks = NUMBLOCKS(sz) - p->ref.count;
numfreeblocks[sz] += freeblocks;
#ifdef Py_DEBUG
if (freeblocks > 0)
assert(pool_is_in_list(p, usedpools[sz + sz]));
#endif
}
}
assert(narenas == narenas_currently_allocated);
fputc('\n', out);
fputs("class size num pools blocks in use avail blocks\n"
"----- ---- --------- ------------- ------------\n",
out);
for (i = 0; i < numclasses; ++i) {
size_t p = numpools[i];
size_t b = numblocks[i];
size_t f = numfreeblocks[i];
uint size = INDEX2SIZE(i);
if (p == 0) {
assert(b == 0 && f == 0);
continue;
}
fprintf(out, "%5u %6u %11zu %15zu %13zu\n",
i, size, p, b, f);
allocated_bytes += b * size;
available_bytes += f * size;
pool_header_bytes += p * POOL_OVERHEAD;
quantization += p * ((POOL_SIZE - POOL_OVERHEAD) % size);
}
fputc('\n', out);
#ifdef PYMEM_DEBUG_SERIALNO
if (_PyMem_DebugEnabled()) {
(void)printone(out, "# times object malloc called", serialno);
}
#endif
(void)printone(out, "# arenas allocated total", ntimes_arena_allocated);
(void)printone(out, "# arenas reclaimed", ntimes_arena_allocated - narenas);
(void)printone(out, "# arenas highwater mark", narenas_highwater);
(void)printone(out, "# arenas allocated current", narenas);
PyOS_snprintf(buf, sizeof(buf),
"%zu arenas * %d bytes/arena",
narenas, ARENA_SIZE);
(void)printone(out, buf, narenas * ARENA_SIZE);
fputc('\n', out);
total = printone(out, "# bytes in allocated blocks", allocated_bytes);
total += printone(out, "# bytes in available blocks", available_bytes);
PyOS_snprintf(buf, sizeof(buf),
"%u unused pools * %d bytes", numfreepools, POOL_SIZE);
total += printone(out, buf, (size_t)numfreepools * POOL_SIZE);
total += printone(out, "# bytes lost to pool headers", pool_header_bytes);
total += printone(out, "# bytes lost to quantization", quantization);
total += printone(out, "# bytes lost to arena alignment", arena_alignment);
(void)printone(out, "Total", total);
assert(narenas * ARENA_SIZE == total);
#if WITH_PYMALLOC_RADIX_TREE
fputs("\narena map counts\n", out);
#ifdef USE_INTERIOR_NODES
(void)printone(out, "# arena map mid nodes", arena_map_mid_count);
(void)printone(out, "# arena map bot nodes", arena_map_bot_count);
fputc('\n', out);
#endif
total = printone(out, "# bytes lost to arena map root", sizeof(arena_map_root));
#ifdef USE_INTERIOR_NODES
total += printone(out, "# bytes lost to arena map mid",
sizeof(arena_map_mid_t) * arena_map_mid_count);
total += printone(out, "# bytes lost to arena map bot",
sizeof(arena_map_bot_t) * arena_map_bot_count);
(void)printone(out, "Total", total);
#endif
#endif
return 1;"""
assert body.split() == expected.split(), (
"preserve _PyObject_DebugMallocStats early return, initialization/evaluation "
"points, array contents, and complete operation order"
)
print("obmalloc _PyObject_DebugMallocStats C89 declarations and operation order: PASS")