port: advance VC6 typeobject frontier and preserve regression coverage
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
#!/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")
|
||||
Reference in New Issue
Block a user