diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index 0fc65b60a905..29bf3715184a 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -52,6 +52,8 @@ #include "utils/memutils.h" #include "utils/gp_alloc.h" +#include "utils/hsearch.h" + #include "miscadmin.h" /* Define this to detail debug alloc information */ @@ -180,6 +182,10 @@ typedef struct AllocSetContext Size currentAllocated; Size peakAllocated; + +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG + HTAB *chunkTable; +#endif } AllocSetContext; typedef AllocSetContext *AllocSet; @@ -266,6 +272,20 @@ typedef struct AllocChunkData #define ALLOCCHUNK_RAWSIZE (SIZEOF_SIZE_T + SIZEOF_VOID_P) #endif /* MEMORY_CONTEXT_CHECKING */ +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG + /* + * extra information about callee, file, and line number of each + * allocation + */ + MemoryContextChunkInfo info; + +#define ALLOCCHUNK_RAWSIZE_EXTRA ALLOCCHUNK_RAWSIZE +#undef ALLOCCHUNK_RAWSIZE + +#define ALLOCCHUNK_RAWSIZE \ + (ALLOCCHUNK_RAWSIZE_EXTRA + MEMORYCONTEXTCHUNKINFO_RAWSIZE) +#endif + /* ensure proper alignment by adding padding if needed */ #if (ALLOCCHUNK_RAWSIZE % MAXIMUM_ALIGNOF) != 0 char padding[MAXIMUM_ALIGNOF - ALLOCCHUNK_RAWSIZE % MAXIMUM_ALIGNOF]; @@ -275,6 +295,7 @@ typedef struct AllocChunkData void *aset; /* there must not be any padding to reach a MAXALIGN boundary here! */ + /* FIXME: these are obsolete */ #ifdef CDB_PALLOC_TAGS const char *alloc_tag; int alloc_n; @@ -425,6 +446,26 @@ static const unsigned char LogTable256[256] = #define AllocAllocInfo(_cxt, _chunk) #endif +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG +HTAB * +AllocSetTakeChunkTable(MemoryContext context) +{ + Assert(AllocSetIsValid(context)); + Assert(IsA(context, AllocSetContext)); + + HTAB *table = ((AllocSet) context)->chunkTable; + ((AllocSet) context)->chunkTable = NULL; + + return table; +} + +MemoryContextChunkInfo * +AllocPointerGetChunkInfo(void *ptr) +{ + return &AllocPointerGetChunk(ptr)->info; +} +#endif + /* ---------- * AllocSetFreeIndex - * @@ -669,6 +710,10 @@ AllocSetContextCreateInternal(MemoryContext parent, set->currentAllocated = 0; set->peakAllocated = 0; +#if defined EXTRA_DYNAMIC_MEMORY_DEBUG + set->chunkTable = NULL; +#endif + ((MemoryContext) set)->mem_allocated = firstBlockSize; return (MemoryContext) set; @@ -1571,6 +1616,10 @@ AllocSetIsEmpty(MemoryContext context) return false; } +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG +#include "aset_memory_debug.c" +#endif + /* * AllocSetStats * Compute stats about memory consumption of an allocset. @@ -1632,6 +1681,10 @@ AllocSetStats(MemoryContext context, totals->totalspace += totalspace; totals->freespace += freespace; } + +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG + AllocSetUpdateAllocatedChunkStats(set); +#endif } static void diff --git a/src/backend/utils/mmgr/aset_memory_debug.c b/src/backend/utils/mmgr/aset_memory_debug.c new file mode 100644 index 000000000000..1f51e3db554d --- /dev/null +++ b/src/backend/utils/mmgr/aset_memory_debug.c @@ -0,0 +1,109 @@ +/* This file should be included into aset.c. */ + +#include "postgres.h" + +#include "utils/palloc_memory_debug.h" +#include "access/hash.h" +#include "utils/hsearch.h" + +/* Update individual chunk stats. */ +static void +AllocChunkUpdateStats(HTAB *chunk_table, AllocChunk chunk) +{ + bool found = false; + MemoryContextChunkTableEntry *r = NULL; + + r = hash_search(chunk_table, &chunk->info.key, HASH_ENTER, &found); + Assert(r != NULL); + + if (found) + { + r->stat.count++; + r->stat.bytes += chunk->size; + } + else + { + r->info = chunk->info; + r->stat.bytes = chunk->size; + r->stat.count = 1; + } +} + +static uint32 +MemoryContextChunkStatKeyHash(const void *key, Size keysize) +{ + Assert(keysize == sizeof(MemoryContextChunkStatKey)); + return DatumGetUInt32(hash_any((const unsigned char *) key, + keysize)); +} + +static int +MemoryContextChunkStatKeyCompare(const void *a, const void *b, + Size keysize) +{ + Assert(keysize == sizeof(MemoryContextChunkStatKey)); + + MemoryContextChunkStatKey *lhs = (MemoryContextChunkStatKey *) a; + MemoryContextChunkStatKey *rhs = (MemoryContextChunkStatKey *) b; + + return !(strcmp(lhs->parent_func, rhs->parent_func) == 0 && + lhs->line == rhs->line); +} + +static bool +AllocSetChunkIsFree(AllocChunk chunk, AllocSet set) +{ + if (chunk->size > set->allocChunkLimit) + return false; + + AllocChunk free_chunk = set->freelist[AllocSetFreeIndex(chunk->size)]; + + while (free_chunk != NULL) + { + if (free_chunk == chunk) + return true; + + free_chunk = (AllocChunk) free_chunk->aset; + } + + return false; +} + +/* Update every chunk's stats table inside an AllocSet. */ +static void +AllocSetUpdateAllocatedChunkStats(AllocSet set) +{ + if (set->chunkTable == NULL) + { + HASHCTL hash_ctl = + { + .keysize = sizeof(MemoryContextChunkStatKey), + .entrysize = sizeof(MemoryContextChunkTableEntry), + .hash = MemoryContextChunkStatKeyHash, + .match = MemoryContextChunkStatKeyCompare, + }; + + set->chunkTable = hash_create("AllocSetUpdateAllocatedChunkStats", + DYN_MEM_HTABLE_SIZE, &hash_ctl, + HASH_FUNCTION | HASH_ELEM | HASH_COMPARE); + } + + for (AllocBlock block = set->blocks; block != NULL; block = block->next) + { + AllocChunk chunk; + + for (chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ); + (char *) chunk < (char *) block->freeptr; + chunk = (AllocChunk) ((char *) chunk + chunk->size + ALLOC_CHUNKHDRSZ)) + { + if (AllocSetChunkIsFree(chunk, set) || + chunk->info.init != EXTRA_DYNAMIC_MEMORY_DEBUG_INIT_MAGIC) + continue; + if (!chunk->info.key.parent_func || !chunk->info.key.line || + !chunk->info.filename || !chunk->info.func) + continue; + + AllocChunkUpdateStats(set->chunkTable, chunk); + } + } +} diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c index be19a72e9b17..4e18a527a9bf 100644 --- a/src/backend/utils/mmgr/mcxt.c +++ b/src/backend/utils/mmgr/mcxt.c @@ -45,6 +45,10 @@ #error "If CDB_PALLOC_TAGS is defined, CDB_PALLOC_CALLER_ID must be defined too" #endif +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG +#include "utils/palloc_memory_debug_undef.h" +#endif + /***************************************************************************** * GLOBAL MEMORY * *****************************************************************************/ @@ -714,6 +718,10 @@ MemoryContextStatsDetail(MemoryContext context, int max_children, grand_totals.totalspace - grand_totals.freespace))); } +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG +#include "mcxt_memory_debug.c" +#endif + /* * MemoryContextStatsInternal * One recursion level for MemoryContextStats @@ -739,6 +747,10 @@ MemoryContextStatsInternal(MemoryContext context, int level, (void *) &level, totals, print_to_stderr); +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG + MemoryContextDumpChunkStats(context, max_children, print_to_stderr); +#endif + /* * Examine children. If there are more than max_children of them, we do * not print the rest explicitly, but just summarize them. diff --git a/src/backend/utils/mmgr/mcxt_memory_debug.c b/src/backend/utils/mmgr/mcxt_memory_debug.c new file mode 100644 index 000000000000..81a30ee16e30 --- /dev/null +++ b/src/backend/utils/mmgr/mcxt_memory_debug.c @@ -0,0 +1,263 @@ +/* This file should be included into mcxt.c. */ + +/* + * `func` is the function which performed an allocation, `parent_func` is the + * callee of `func`. + */ +#define MEMORY_CONTEXT_INFO_PARAMS \ + const char *parent_func, const char *filename, int line + +#define MEMORY_CONTEXT_INFO_ARGS parent_func, filename, line +static void + +/* Write info about an allocation to the AllocChunk's header. */ +MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_PARAMS, void *ptr, + const char *func) +{ + MemoryContextChunkInfo *info = AllocPointerGetChunkInfo(ptr); + + info->key.parent_func = parent_func; + info->key.line = line; + + info->func = func; + info->filename = filename; + info->init = EXTRA_DYNAMIC_MEMORY_DEBUG_INIT_MAGIC; +} + +/* Overriden allocation functions. */ + +#define MEMORY_CONTEXT_ALLOC_FUNC(f) \ + void *_##f(MEMORY_CONTEXT_INFO_PARAMS, MemoryContext context, Size size) \ + { \ + void *chunk = f(context, size); \ + if (chunk != NULL) \ + MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_ARGS, chunk, \ + #f); \ + return chunk; \ + } + +#define MEMORY_CONTEXT_PALLOC_FUNC(f) \ + void *_##f(MEMORY_CONTEXT_INFO_PARAMS, Size size) \ + { \ + void *chunk = f(size); \ + if (chunk != NULL) \ + MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_ARGS, chunk, \ + #f); \ + return chunk; \ + } + +#define MEMORY_CONTEXT_REPALLOC_FUNC(f) \ + void *_##f(MEMORY_CONTEXT_INFO_PARAMS, void *pointer, Size size) \ + { \ + void *chunk = f(pointer, size); \ + if (chunk != NULL) \ + MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_ARGS, chunk, \ + #f); \ + return chunk; \ + } + +MEMORY_CONTEXT_ALLOC_FUNC(MemoryContextAlloc) +MEMORY_CONTEXT_ALLOC_FUNC(MemoryContextAllocZero) +MEMORY_CONTEXT_ALLOC_FUNC(MemoryContextAllocZeroAligned) +MEMORY_CONTEXT_ALLOC_FUNC(MemoryContextAllocHuge) + +MEMORY_CONTEXT_PALLOC_FUNC(palloc) +MEMORY_CONTEXT_PALLOC_FUNC(palloc0) + +MEMORY_CONTEXT_REPALLOC_FUNC(repalloc) +MEMORY_CONTEXT_REPALLOC_FUNC(repalloc_huge) + +void * +_palloc_extended(MEMORY_CONTEXT_INFO_PARAMS, Size size, int flags) +{ + void *chunk = palloc_extended(size, flags); + if (chunk != NULL) + MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_ARGS, chunk, + "palloc_extended"); + return chunk; +} + +void * +_MemoryContextAllocExtended(MEMORY_CONTEXT_INFO_PARAMS, MemoryContext context, + Size size, int flags) +{ + void *chunk = MemoryContextAllocExtended(context, size, flags); + if (chunk != NULL) + MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_ARGS, chunk, + "MemoryContextAllocExtended"); + return chunk; +} + +char * +_MemoryContextStrdup(MEMORY_CONTEXT_INFO_PARAMS, MemoryContext context, + const char *string) +{ + void *nstr = MemoryContextStrdup(context, string); + if (nstr != NULL) + MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_ARGS, nstr, + "MemoryContextStrdup"); + return nstr; +} + +char * +_pstrdup(MEMORY_CONTEXT_INFO_PARAMS, const char *in) +{ + char *nstr = pstrdup(in); + if (nstr != NULL) + MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_ARGS, nstr, + "pstrdup"); + return nstr; +} + +char * +_pnstrdup(MEMORY_CONTEXT_INFO_PARAMS, const char *in, Size len) +{ + void *nstr = pnstrdup(in, len); + if (nstr != NULL) + MemoryContextChunkCollectInfo(MEMORY_CONTEXT_INFO_ARGS, nstr, + "pnstrdup"); + return nstr; +} + +/* This should mirror psprintf(), except for the _palloc() call. */ +char * +_psprintf(MEMORY_CONTEXT_INFO_PARAMS, const char *fmt, ...) +{ + int save_errno = errno; + size_t len = 128; /* initial assumption about buffer size */ + + for (;;) + { + char *result; + va_list args; + size_t newlen; + + /* + * Allocate result buffer. Note that in frontend this maps to malloc + * with exit-on-error. + */ + result = (char *) _palloc(MEMORY_CONTEXT_INFO_ARGS, len); + + /* Try to format the data. */ + errno = save_errno; + va_start(args, fmt); + newlen = pvsnprintf(result, len, fmt, args); + va_end(args); + + if (newlen < len) + return result; /* success */ + + /* Release buffer and loop around to try again with larger len. */ + pfree(result); + len = newlen; + } +} + +/* Helper functions. */ + +static int +MemoryContextChunkTableCompare(const void *a, const void *b) +{ + const MemoryContextChunkTableEntry *lhs = + *(MemoryContextChunkTableEntry **) a; + const MemoryContextChunkTableEntry *rhs = + *(MemoryContextChunkTableEntry **) b; + + return rhs->stat.bytes - lhs->stat.bytes; +} + +/* + * Dump info about collected allocation stats. This will be called recursively + * by MemoryContextStatsDetail(). + */ +static void +MemoryContextDumpChunkStats(MemoryContext context, int max_children, + bool print_to_stderr) +{ + HTAB *chunk_table = AllocSetTakeChunkTable(context); + + if (chunk_table == NULL) + return; + + Size chunk_count = hash_get_num_entries(chunk_table); + + if (chunk_count <= 0) + { + hash_destroy(chunk_table); + return; + } + + MemoryContext chunk_stat_ctx = AllocSetContextCreate( + TopMemoryContext, "MemoryContextDumpTopChunkStatsCtx", + ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + MemoryContext oldcontext = MemoryContextSwitchTo(chunk_stat_ctx); + + MemoryContextChunkTableEntry **chunks = + palloc(chunk_count * sizeof(MemoryContextChunkTableEntry *)); + + Size idx = 0; + Size summary_bytes = 0; + MemoryContextChunkTableEntry *entry = NULL; + + HASH_SEQ_STATUS hash_seq; + hash_seq_init(&hash_seq, chunk_table); + + while ((entry = hash_seq_search(&hash_seq)) != NULL) + { + chunks[idx++] = entry; + summary_bytes += entry->stat.bytes; + } + + Size show_count = + (chunk_count < max_children) ? chunk_count : max_children; + + qsort(chunks, chunk_count, sizeof(MemoryContextChunkTableEntry *), + MemoryContextChunkTableCompare); + + if (print_to_stderr) + { + fprintf( + stderr, + "\tList of top %zu (all %zu) the biggest allocations (summary %zu bytes)\n", + show_count, chunk_count, summary_bytes); + } + else + { + ereport( + LOG_SERVER_ONLY, + (errhidestmt(true), errhidecontext(true), + errmsg_internal( + "\tList of top %zu (all %zu) the biggest allocations (summary %zu bytes)\n", + show_count, chunk_count, summary_bytes))); + } + + for (Size i = 0; i < show_count; i++) + { + if (print_to_stderr) + { + fprintf( + stderr, + "\t%s:%zu, in %s(): %s() was called %zu times, for %zu bytes total\n", + chunks[i]->info.filename, chunks[i]->info.key.line, + chunks[i]->info.key.parent_func, chunks[i]->info.func, + chunks[i]->stat.count, chunks[i]->stat.bytes); + } + else + { + ereport( + LOG_SERVER_ONLY, + (errhidestmt(true), errhidecontext(true), + errmsg_internal( + "\t%s:%zu, in %s(): %s() was called %zu times, for %zu bytes total\n", + chunks[i]->info.filename, chunks[i]->info.key.line, + chunks[i]->info.key.parent_func, chunks[i]->info.func, + chunks[i]->stat.count, chunks[i]->stat.bytes))); + } + } + + MemoryContextSwitchTo(oldcontext); + + MemoryContextDelete(chunk_stat_ctx); + hash_destroy(chunk_table); +} diff --git a/src/bin/pg_upgrade/greenplum/pg_upgrade_greenplum.h b/src/bin/pg_upgrade/greenplum/pg_upgrade_greenplum.h index 26e1d52e7e72..01b1519af784 100644 --- a/src/bin/pg_upgrade/greenplum/pg_upgrade_greenplum.h +++ b/src/bin/pg_upgrade/greenplum/pg_upgrade_greenplum.h @@ -9,7 +9,7 @@ #include "pg_upgrade.h" - +#include "utils/palloc_memory_debug_undef.h" #define PG_OPTIONS_UTILITY_MODE_VERSION(major_version) \ ( (GET_MAJOR_VERSION(major_version)) < 1200 ? \ diff --git a/src/common/psprintf.c b/src/common/psprintf.c index e8a7e44554c1..00b284bb41e3 100644 --- a/src/common/psprintf.c +++ b/src/common/psprintf.c @@ -29,6 +29,11 @@ #endif +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG + +#include "utils/palloc_memory_debug_undef.h" + +#endif /* * psprintf @@ -149,3 +154,4 @@ pvsnprintf(char *buf, size_t len, const char *fmt, va_list args) return nprinted + 1; } + diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h index 73ed37b2cd6a..de5e73760ea5 100644 --- a/src/include/access/xlogreader.h +++ b/src/include/access/xlogreader.h @@ -26,6 +26,8 @@ #define XLOGREADER_H #include "access/xlogrecord.h" +#include "utils/palloc.h" +#include "utils/memutils.h" typedef struct XLogReaderState XLogReaderState; diff --git a/src/include/common/fe_memutils.h b/src/include/common/fe_memutils.h index a1e5940d3120..833166d75853 100644 --- a/src/include/common/fe_memutils.h +++ b/src/include/common/fe_memutils.h @@ -29,6 +29,10 @@ extern void *pg_malloc_extended(size_t size, int flags); extern void *pg_realloc(void *pointer, size_t size); extern void pg_free(void *pointer); +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG +#include "utils/palloc_memory_debug_undef.h" +#endif + /* Equivalent functions, deliberately named the same as backend functions */ extern char *pstrdup(const char *in); extern void *palloc(Size size); diff --git a/src/include/postgres_fe.h b/src/include/postgres_fe.h index f55cebd7b41b..81f5d854f271 100644 --- a/src/include/postgres_fe.h +++ b/src/include/postgres_fe.h @@ -26,4 +26,6 @@ #include "common/fe_memutils.h" +#include "utils/palloc_memory_debug_undef.h" + #endif /* POSTGRES_FE_H */ diff --git a/src/include/utils/memutils.h b/src/include/utils/memutils.h index 40be202ec1a5..6e6c61ebcbcc 100644 --- a/src/include/utils/memutils.h +++ b/src/include/utils/memutils.h @@ -20,7 +20,7 @@ #define MEMUTILS_H #include "nodes/memnodes.h" - +#include "utils/hsearch.h" /* * MaxAllocSize, MaxAllocHugeSize @@ -48,6 +48,9 @@ #define AllocHugeSizeIsValid(size) ((Size) (size) <= MaxAllocHugeSize) /* + * FIXME: The comment below and the structure is obsolete. AllocChunkData may + * be used instead. + * * All chunks allocated by any memory context manager are required to be * preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE. * A currently-allocated chunk must contain a backpointer to its owning @@ -64,7 +67,6 @@ typedef struct StandardChunkHeader /* when debugging memory usage, also store actual requested size */ Size requested_size; #endif - #ifdef CDB_PALLOC_TAGS const char *alloc_tag; int alloc_n; @@ -75,7 +77,6 @@ typedef struct StandardChunkHeader #define STANDARDCHUNKHEADERSIZE MAXALIGN(sizeof(StandardChunkHeader)) - /* * Standard top-level memory contexts. * @@ -223,6 +224,11 @@ extern MemoryContext AllocSetContextCreateInternal(MemoryContext parent, AllocSetContextCreateInternal #endif +#ifdef EXTRA_DYNAMIC_MEMORY_DEBUG +extern HTAB *AllocSetTakeChunkTable(MemoryContext context); +extern MemoryContextChunkInfo *AllocPointerGetChunkInfo(void *ptr); +#endif + extern bool AllocSetContains(MemoryContext context, void *pointer); /* slab.c */ diff --git a/src/include/utils/palloc.h b/src/include/utils/palloc.h index 8bd1aa9d3816..2d33358c9a4c 100644 --- a/src/include/utils/palloc.h +++ b/src/include/utils/palloc.h @@ -33,6 +33,9 @@ /* * Optional #defines for debugging... * + * Important: CDB_PALLOC_CALLER_ID is obsolete. EXTRA_DYNAMIC_MEMORY_DEBUG can + * be used instead. + * * If CDB_PALLOC_CALLER_ID is defined, MemoryContext error and warning * messages (such as "out of memory" and "invalid memory alloc request * size") will include the caller's source file name and line number. @@ -53,6 +56,15 @@ #define CDB_PALLOC_CALLER_ID */ +/* + * To enable collection of additional allocation data (function, file, and line + * where the allocation occurred), add -DEXTRA_DYNAMIC_MEMORY_DEBUG to CFLAGS + * during ./configure. + * Use MemoryContextStats(TopMemoryContext) to print the top allocations for + * each MemoryContext into the logs, following the summary counters for each + * context. + */ + /* * GPDB_93_MERGE_FIXME: This mechanism got broken. If this is resurrected and * and made working the --enable-testutils invocations should be readded to @@ -236,4 +248,12 @@ extern void MemoryContextStats(MemoryContext context); }\ } -#endif /* PALLOC_H */ +#if defined EXTRA_DYNAMIC_MEMORY_DEBUG +#include "utils/palloc_memory_debug.h" +#endif + +#if defined FRONTEND +#include "utils/palloc_memory_debug_undef.h" +#endif + +#endif /* PALLOC_H */ diff --git a/src/include/utils/palloc_memory_debug.h b/src/include/utils/palloc_memory_debug.h new file mode 100644 index 000000000000..29849d16af88 --- /dev/null +++ b/src/include/utils/palloc_memory_debug.h @@ -0,0 +1,97 @@ +#ifndef PALLOC_OVERRIDE_H +#define PALLOC_OVERRIDE_H + +#ifndef DYN_MEM_HTABLE_SIZE +#define DYN_MEM_HTABLE_SIZE 32 +#endif + +#define EXTRA_DYNAMIC_MEMORY_DEBUG_INIT_MAGIC 0x12345678 + +typedef struct +{ + Size count; + Size bytes; +} MemoryContextChunkStat; + +typedef struct +{ + const char *parent_func; + Size line; +} MemoryContextChunkStatKey; + +typedef struct +{ + MemoryContextChunkStatKey key; + + int32_t init; + const char *filename; + const char *func; +} MemoryContextChunkInfo; + +#define MEMORYCONTEXTCHUNKINFO_RAWSIZE 40 + +typedef struct +{ + MemoryContextChunkInfo info; + MemoryContextChunkStat stat; +} MemoryContextChunkTableEntry; + +#define MEMORY_CONTEXT_INFO_PARAMS \ + const char *parent_func, const char *filename, int line + +void *_MemoryContextAlloc(MEMORY_CONTEXT_INFO_PARAMS, MemoryContext context, + Size size); +void *_MemoryContextAllocZero(MEMORY_CONTEXT_INFO_PARAMS, MemoryContext context, + Size size); +void *_MemoryContextAllocZeroAligned(MEMORY_CONTEXT_INFO_PARAMS, + MemoryContext context, Size size); +void *_MemoryContextAllocExtended(MEMORY_CONTEXT_INFO_PARAMS, + MemoryContext context, Size size, int flags); +void *_MemoryContextAllocHuge(MEMORY_CONTEXT_INFO_PARAMS, MemoryContext context, + Size size); + +void *_palloc(MEMORY_CONTEXT_INFO_PARAMS, Size size); +void *_palloc0(MEMORY_CONTEXT_INFO_PARAMS, Size size); +void *_palloc_extended(MEMORY_CONTEXT_INFO_PARAMS, Size size, int flags); + +void *_repalloc(MEMORY_CONTEXT_INFO_PARAMS, void *pointer, Size size); +void *_repalloc_huge(MEMORY_CONTEXT_INFO_PARAMS, void *pointer, Size size); + +char *_MemoryContextStrdup(MEMORY_CONTEXT_INFO_PARAMS, MemoryContext context, + const char *string); +char *_pstrdup(MEMORY_CONTEXT_INFO_PARAMS, const char *in); +char *_pnstrdup(MEMORY_CONTEXT_INFO_PARAMS, const char *in, Size len); + +char *_psprintf(MEMORY_CONTEXT_INFO_PARAMS, const char *fmt, ...) + __attribute__((format(PG_PRINTF_ATTRIBUTE, 4, 5))); + +#define MEMORY_CONTEXT_INFO_MACROS __func__, __FILE__, __LINE__ + +#define MemoryContextAlloc(...) \ + _MemoryContextAlloc(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define MemoryContextAllocZero(...) \ + _MemoryContextAllocZero(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define MemoryContextAllocZeroAligned(...) \ + _MemoryContextAllocZeroAligned(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define MemoryContextAllocExtended(...) \ + _MemoryContextAllocExtended(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define MemoryContextAllocHuge(...) \ + _MemoryContextAllocHuge(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) + +#define palloc(...) _palloc(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define palloc0(...) _palloc0(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define palloc_extended(...) \ + _palloc_extended(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) + +#define repalloc(...) _repalloc(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define repalloc_huge(...) \ + _repalloc_huge(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) + +#define MemoryContextStrdup(...) \ + _MemoryContextStrdup(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define pstrdup(...) _pstrdup(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) +#define pnstrdup(...) _pnstrdup(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) + +#define psprintf(...) _psprintf(MEMORY_CONTEXT_INFO_MACROS, __VA_ARGS__) + +#endif diff --git a/src/include/utils/palloc_memory_debug_undef.h b/src/include/utils/palloc_memory_debug_undef.h new file mode 100644 index 000000000000..76a2282b5b94 --- /dev/null +++ b/src/include/utils/palloc_memory_debug_undef.h @@ -0,0 +1,46 @@ +#ifdef MemoryContextAlloc +#undef MemoryContextAlloc +#endif +#ifdef MemoryContextAllocZero +#undef MemoryContextAllocZero +#endif +#ifdef MemoryContextAllocZeroAligned +#undef MemoryContextAllocZeroAligned +#endif +#ifdef MemoryContextAllocExtended +#undef MemoryContextAllocExtended +#endif +#ifdef MemoryContextAllocHuge +#undef MemoryContextAllocHuge +#endif + +#ifdef palloc +#undef palloc +#endif +#ifdef palloc0 +#undef palloc0 +#endif +#ifdef palloc_extended +#undef palloc_extended +#endif + +#ifdef repalloc +#undef repalloc +#endif +#ifdef repalloc_huge +#undef repalloc_huge +#endif + +#ifdef MemoryContextStrdup +#undef MemoryContextStrdup +#endif +#ifdef pstrdup +#undef pstrdup +#endif +#ifdef pnstrdup +#undef pnstrdup +#endif + +#ifdef psprintf +#undef psprintf +#endif