tail = q + nbytes; fprintf(stderr, " The %d pad bytes at tail=%p are ", SST, tail); ok = 1; for (i = 0; i < SST; ++i) { if (tail[i] != FORBIDDENBYTE) { ok = 0; break; } } if (ok) fputs("FORBIDDENBYTE, as expected.\n", stderr); else { fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", FORBIDDENBYTE); for (i = 0; i < SST; ++i) { const uchar byte = tail[i]; fprintf(stderr, " at tail+%d: 0x%02x", i, byte); if (byte != FORBIDDENBYTE) fputs(" *** OUCH", stderr); fputc('\n', stderr); } } serial = read_size_t(tail + SST); fprintf(stderr, " The block was made by call #%" PY_FORMAT_SIZE_T "u to debug malloc/realloc.\n", serial); if (nbytes > 0) { i = 0; fputs(" Data at p:", stderr); /* print up to 8 bytes at the start */ while (q < tail && i < 8) { fprintf(stderr, " %02x", *q); ++i; ++q; } /* and up to 8 at the end */ if (q < tail) { if (tail - q > 8) { fputs(" ...", stderr); q = tail - 8; } while (q < tail) { fprintf(stderr, " %02x", *q); ++q; } } fputc('\n', stderr); }} static size_tprintone(const char* msg, size_t value){ int i, k; char buf[100]; size_t origvalue = value; fputs(msg, stderr); for (i = (int)strlen(msg); i < 35; ++i) fputc(' ', stderr); fputc('=', stderr); /* Write the value with commas. */ i = 22; buf[i--] = '\0'; buf[i--] = '\n'; k = 3; do { size_t nextvalue = value / 10; uint digit = (uint)(value - nextvalue * 10); value = nextvalue; buf[i--] = (char)(digit + '0'); --k; if (k == 0 && value && i >= 0) { k = 3; buf[i--] = ','; } } while (value && i >= 0); while (i >= 0) buf[i--] = ' '; fputs(buf, stderr); return origvalue;} /* Print summary info to stderr about the state of pymalloc's structures. * In Py_DEBUG mode, also perform some expensive internal consistency * checks. */void_PyObject_DebugMallocStats(void){ uint i; const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT; /* # of pools, allocated blocks, and free blocks per class index */ size_t numpools[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; size_t numblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; size_t numfreeblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; /* total # of allocated bytes in used and full pools */ size_t allocated_bytes = 0; /* total # of available bytes in used pools */ size_t available_bytes = 0; /* # of free pools + pools not yet carved out of current arena */ uint numfreepools = 0; /* # of bytes for arena alignment padding */ size_t arena_alignment = 0; /* # of bytes in used and full pools used for pool_headers */ size_t pool_header_bytes = 0; /* # of bytes in used and full pools wasted due to quantization, * i.e. the necessarily leftover space at the ends of used and * full pools. */ size_t quantization = 0; /* # of arenas actually allocated. */ size_t narenas = 0; /* running total -- should equal narenas * ARENA_SIZE */ size_t total; char buf[128]; fprintf(stderr, "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; /* Because full pools aren't linked to from anything, it's easiest * to march over all the arenas. If we're lucky, most of the memory * will be living in full pools -- would be a shame to miss them. */ for (i = 0; i < maxarenas; ++i) { uint poolsinarena; uint j; uptr base = arenas[i].address; /* Skip arenas which are not allocated. */ if (arenas[i].address == (uptr)NULL) continue; narenas += 1; poolsinarena = arenas[i].ntotalpools; numfreepools += arenas[i].nfreepools; /* round up to pool alignment */ if (base & (uptr)POOL_SIZE_MASK) { arena_alignment += POOL_SIZE; base &= ~(uptr)POOL_SIZE_MASK; base += POOL_SIZE; } /* visit every pool in the arena */ assert(base <= (uptr) arenas[i].pool_address); for (j = 0; base < (uptr) arenas[i].pool_address; ++j, base += POOL_SIZE) { poolp p = (poolp)base; const uint sz = p->szidx; uint freeblocks; if (p->ref.count == 0) { /* currently unused */ assert(pool_is_in_list(p, arenas[i].freepools)); 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', stderr); fputs("class size num pools blocks in use avail blocks\n" "----- ---- --------- ------------- ------------\n", stderr); 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(stderr, "%5u %6u " "%11" PY_FORMAT_SIZE_T "u " "%15" PY_FORMAT_SIZE_T "u " "%13" PY_FORMAT_SIZE_T "u\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', stderr); (void)printone("# times object malloc called", serialno); (void)printone("# arenas allocated total", ntimes_arena_allocated); (void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas); (void)printone("# arenas highwater mark", narenas_highwater); (void)printone("# arenas allocated current", narenas); PyOS_snprintf(buf, sizeof(buf), "%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena", narenas, ARENA_SIZE); (void)printone(buf, narenas * ARENA_SIZE); fputc('\n', stderr); total = printone("# bytes in allocated blocks", allocated_bytes); total += printone("# bytes in available blocks", available_bytes); PyOS_snprintf(buf, sizeof(buf), "%u unused pools * %d bytes", numfreepools, POOL_SIZE); total += printone(buf, (size_t)numfreepools * POOL_SIZE); total += printone("# bytes lost to pool headers", pool_header_bytes); total += printone("# bytes lost to quantization", quantization); total += printone("# bytes lost to arena alignment", arena_alignment); (void)printone("Total", total);} #endif /* PYMALLOC_DEBUG */ #ifdef Py_USING_MEMORY_DEBUGGER/* Make this function last so gcc won't inline it since the definition is * after the reference. */intPy_ADDRESS_IN_RANGE(void *P, poolp pool){ return pool->arenaindex < maxarenas && (uptr)P - arenas[pool->arenaindex].address < (uptr)ARENA_SIZE && arenas[pool->arenaindex].address != 0;}#endifLines 1501–1745 of 1745. Previous lines
tail = q + nbytes; fprintf(stderr, " The %d pad bytes at tail=%p are ", SST, tail); ok = 1; for (i = 0; i < SST; ++i) { if (tail[i] != FORBIDDENBYTE) { ok = 0; break; } } if (ok) fputs("FORBIDDENBYTE, as expected.\n", stderr); else { fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", FORBIDDENBYTE); for (i = 0; i < SST; ++i) { const uchar byte = tail[i]; fprintf(stderr, " at tail+%d: 0x%02x", i, byte); if (byte != FORBIDDENBYTE) fputs(" *** OUCH", stderr); fputc('\n', stderr); } } serial = read_size_t(tail + SST); fprintf(stderr, " The block was made by call #%" PY_FORMAT_SIZE_T "u to debug malloc/realloc.\n", serial); if (nbytes > 0) { i = 0; fputs(" Data at p:", stderr); /* print up to 8 bytes at the start */ while (q < tail && i < 8) { fprintf(stderr, " %02x", *q); ++i; ++q; } /* and up to 8 at the end */ if (q < tail) { if (tail - q > 8) { fputs(" ...", stderr); q = tail - 8; } while (q < tail) { fprintf(stderr, " %02x", *q); ++q; } } fputc('\n', stderr); } } static size_t printone(const char* msg, size_t value) { int i, k; char buf[100]; size_t origvalue = value; fputs(msg, stderr); for (i = (int)strlen(msg); i < 35; ++i) fputc(' ', stderr); fputc('=', stderr); /* Write the value with commas. */ i = 22; buf[i--] = '\0'; buf[i--] = '\n'; k = 3; do { size_t nextvalue = value / 10; uint digit = (uint)(value - nextvalue * 10); value = nextvalue; buf[i--] = (char)(digit + '0'); --k; if (k == 0 && value && i >= 0) { k = 3; buf[i--] = ','; } } while (value && i >= 0); while (i >= 0) buf[i--] = ' '; fputs(buf, stderr); return origvalue; } /* Print summary info to stderr about the state of pymalloc's structures. * In Py_DEBUG mode, also perform some expensive internal consistency * checks. */ void _PyObject_DebugMallocStats(void) { uint i; const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT; /* # of pools, allocated blocks, and free blocks per class index */ size_t numpools[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; size_t numblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; size_t numfreeblocks[SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT]; /* total # of allocated bytes in used and full pools */ size_t allocated_bytes = 0; /* total # of available bytes in used pools */ size_t available_bytes = 0; /* # of free pools + pools not yet carved out of current arena */ uint numfreepools = 0; /* # of bytes for arena alignment padding */ size_t arena_alignment = 0; /* # of bytes in used and full pools used for pool_headers */ size_t pool_header_bytes = 0; /* # of bytes in used and full pools wasted due to quantization, * i.e. the necessarily leftover space at the ends of used and * full pools. */ size_t quantization = 0; /* # of arenas actually allocated. */ size_t narenas = 0; /* running total -- should equal narenas * ARENA_SIZE */ size_t total; char buf[128]; fprintf(stderr, "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; /* Because full pools aren't linked to from anything, it's easiest * to march over all the arenas. If we're lucky, most of the memory * will be living in full pools -- would be a shame to miss them. */ for (i = 0; i < maxarenas; ++i) { uint poolsinarena; uint j; uptr base = arenas[i].address; /* Skip arenas which are not allocated. */ if (arenas[i].address == (uptr)NULL) continue; narenas += 1; poolsinarena = arenas[i].ntotalpools; numfreepools += arenas[i].nfreepools; /* round up to pool alignment */ if (base & (uptr)POOL_SIZE_MASK) { arena_alignment += POOL_SIZE; base &= ~(uptr)POOL_SIZE_MASK; base += POOL_SIZE; } /* visit every pool in the arena */ assert(base <= (uptr) arenas[i].pool_address); for (j = 0; base < (uptr) arenas[i].pool_address; ++j, base += POOL_SIZE) { poolp p = (poolp)base; const uint sz = p->szidx; uint freeblocks; if (p->ref.count == 0) { /* currently unused */ assert(pool_is_in_list(p, arenas[i].freepools)); 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', stderr); fputs("class size num pools blocks in use avail blocks\n" "----- ---- --------- ------------- ------------\n", stderr); 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(stderr, "%5u %6u " "%11" PY_FORMAT_SIZE_T "u " "%15" PY_FORMAT_SIZE_T "u " "%13" PY_FORMAT_SIZE_T "u\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', stderr); (void)printone("# times object malloc called", serialno); (void)printone("# arenas allocated total", ntimes_arena_allocated); (void)printone("# arenas reclaimed", ntimes_arena_allocated - narenas); (void)printone("# arenas highwater mark", narenas_highwater); (void)printone("# arenas allocated current", narenas); PyOS_snprintf(buf, sizeof(buf), "%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena", narenas, ARENA_SIZE); (void)printone(buf, narenas * ARENA_SIZE); fputc('\n', stderr); total = printone("# bytes in allocated blocks", allocated_bytes); total += printone("# bytes in available blocks", available_bytes); PyOS_snprintf(buf, sizeof(buf), "%u unused pools * %d bytes", numfreepools, POOL_SIZE); total += printone(buf, (size_t)numfreepools * POOL_SIZE); total += printone("# bytes lost to pool headers", pool_header_bytes); total += printone("# bytes lost to quantization", quantization); total += printone("# bytes lost to arena alignment", arena_alignment); (void)printone("Total", total); } #endif /* PYMALLOC_DEBUG */ #ifdef Py_USING_MEMORY_DEBUGGER /* Make this function last so gcc won't inline it since the definition is * after the reference. */ int Py_ADDRESS_IN_RANGE(void *P, poolp pool) { return pool->arenaindex < maxarenas && (uptr)P - arenas[pool->arenaindex].address < (uptr)ARENA_SIZE && arenas[pool->arenaindex].address != 0; } #endif