45#define BOGUS_MCTX(id) \
46 [id].free_p = BogusFree, \
47 [id].realloc = BogusRealloc, \
48 [id].get_chunk_context = BogusGetChunkContext, \
49 [id].get_chunk_space = BogusGetChunkSpace
62#ifdef MEMORY_CONTEXT_CHECKING
76#ifdef MEMORY_CONTEXT_CHECKING
90#ifdef MEMORY_CONTEXT_CHECKING
104#ifdef MEMORY_CONTEXT_CHECKING
118#ifdef MEMORY_CONTEXT_CHECKING
180 int max_level,
int max_children,
185 const char *stats_string,
186 bool print_to_stderr);
206#define AssertNotInCriticalSection(context) \
207 Assert(CritSectionCount == 0 || (context)->allowInCritSection)
213#define MCXT_METHOD(pointer, method) \
214 mcxt_methods[GetMemoryChunkMethodID(pointer)].method
236 header = *((
const uint64 *) ((
const char *) pointer -
sizeof(
uint64)));
258 header = *((
const uint64 *) ((
const char *) pointer -
sizeof(
uint64)));
319 elog(
ERROR,
"pfree called with invalid pointer %p (header 0x%016" PRIx64
")",
326 elog(
ERROR,
"repalloc called with invalid pointer %p (header 0x%016" PRIx64
")",
334 elog(
ERROR,
"GetMemoryChunkContext called with invalid pointer %p (header 0x%016" PRIx64
")",
342 elog(
ERROR,
"GetMemoryChunkSpace called with invalid pointer %p (header 0x%016" PRIx64
")",
557 context->
ident = NULL;
625 while ((cb = context->
reset_cbs) != NULL)
671 Assert(context != new_parent);
674 if (new_parent == context->
parent)
698 context->
parent = new_parent;
740 return MCXT_METHOD(pointer, get_chunk_context) (pointer);
754 return MCXT_METHOD(pointer, get_chunk_space) (pointer);
805 total += curr->mem_allocated;
822 memset(consumed, 0,
sizeof(*consumed));
825 context->
methods->
stats(context, NULL, NULL, consumed,
false);
832 curr->methods->stats(curr, NULL, NULL, consumed,
false);
861 int max_level,
int max_children,
862 bool print_to_stderr)
868 memset(&grand_totals, 0,
sizeof(grand_totals));
877 &grand_totals, print_location, &num_contexts);
881 "Grand total: %zu bytes in %zu blocks; %zu free (%zu chunks); %zu used\n",
900 errmsg_internal(
"Grand total: %zu bytes in %zu blocks; %zu free (%zu chunks); %zu used",
917 int max_level,
int max_children,
927 switch (print_location)
959 *num_contexts = *num_contexts + 1;
973 for (; child != NULL && ichild < max_children;
977 max_level, max_children,
979 print_location, num_contexts);
988 memset(&local_totals, 0,
sizeof(local_totals));
991 while (child != NULL)
993 child->
methods->
stats(child, NULL, NULL, &local_totals,
false);
1002 *num_contexts = *num_contexts + ichild;
1006 for (
int i = 0;
i <= level;
i++)
1009 "%d more child contexts containing %zu total in %zu blocks; %zu free (%zu chunks); %zu used\n",
1021 errmsg_internal(
"level: %d; %d more child contexts containing %zu total in %zu blocks; %zu free (%zu chunks); %zu used",
1049 const char *stats_string,
1050 bool print_to_stderr)
1052 int level = *(
int *) passthru;
1055 char truncated_ident[110];
1063 if (
ident && strcmp(
name,
"dynahash") == 0)
1069 truncated_ident[0] =
'\0';
1079 int idlen = strlen(
ident);
1080 bool truncated =
false;
1082 strcpy(truncated_ident,
": ");
1083 i = strlen(truncated_ident);
1093 unsigned char c = *
ident++;
1097 truncated_ident[
i++] =
c;
1099 truncated_ident[
i] =
'\0';
1102 strcat(truncated_ident,
"...");
1105 if (print_to_stderr)
1107 for (
i = 0;
i < level;
i++)
1109 fprintf(stderr,
"%s: %s%s\n",
name, stats_string, truncated_ident);
1116 level,
name, stats_string, truncated_ident)));
1125#ifdef MEMORY_CONTEXT_CHECKING
1130 context->
methods->check(context);
1137 curr->methods->check(curr);
1229 (
errcode(ERRCODE_OUT_OF_MEMORY),
1231 errdetail(
"Failed on request of size %zu in memory context \"%s\".",
1232 size, context->
name)));
1245 elog(
ERROR,
"invalid memory alloc request size %zu", size);
1322 elog(
ERROR,
"invalid memory alloc request size %zu", size);
1436 HTAB *context_id_lookup;
1439 bool summary =
false;
1442 int stats_count = 0;
1445 int num_individual_stats = 0;
1457 context_id_lookup =
hash_create(
"pg_get_remote_backend_memory_contexts",
1486 stats_num =
Min(stats_count, max_stats);
1576 cxt_id = cxt_id + 1;
1587 int num_contexts = 0;
1591 memset(&grand_totals, 0,
sizeof(grand_totals));
1629 (*
cur->methods->stats) (
cur, NULL, NULL, &
stat,
true);
1632 if (context_id < (max_stats - 1) || stats_count <= max_stats)
1654 if (stats_count > max_stats && context_id == (max_stats - 2))
1657 int namelen = strlen(
"Remaining Totals");
1659 num_individual_stats = context_id + 1;
1662 strncpy(nameptr,
"Remaining Totals", namelen);
1665 meminfo[max_stats - 1].
type = 0;
1674 if (stats_count <= max_stats)
1682 num_individual_stats;
1722 for (cur_context =
c; cur_context != NULL; cur_context = cur_context->
parent)
1729 elog(
ERROR,
"hash table corrupted, can't construct path value");
1743 int *stats_count,
bool summary)
1803 if (context->
ident && strncmp(context->
name,
"dynahash", 8) == 0)
1811 int namelen = strlen(
name);
1828 int idlen = strlen(context->
ident);
1865 memcxt_info[curr_id].
type = context->type;
1887 for (
int i = 0;
i < total_stats;
i++)
2036 Size size,
Size alignto,
int flags)
2044 Assert(alignto < (128 * 1024 * 1024));
2047 Assert((alignto & (alignto - 1)) == 0);
2053 if (
unlikely(alignto <= MAXIMUM_ALIGNOF))
2075#ifdef MEMORY_CONTEXT_CHECKING
2084 aligned = (
void *)
TYPEALIGN(alignto, (
char *) unaligned +
2105#ifdef MEMORY_CONTEXT_CHECKING
2106 alignedchunk->requested_size = size;
2108 set_sentinel(aligned, size);
2113 (
char *) alignedchunk - (
char *) unaligned);
2172#if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
2210#if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
2251 elog(
ERROR,
"invalid repalloc0 call: oldsize %zu, new size %zu",
2255 memset((
char *) ret + oldsize, 0, (size - oldsize));
2312 Size len = strlen(
string) + 1;
2316 memcpy(nstr,
string,
len);
2340 memcpy(out, in,
len);
2355 while (n > 0 && in[n - 1] ==
'\n')
Datum idx(PG_FUNCTION_ARGS)
MemoryContext AlignedAllocGetChunkContext(void *pointer)
void * AlignedAllocRealloc(void *pointer, Size size, int flags)
Size AlignedAllocGetChunkSpace(void *pointer)
void AlignedAllocFree(void *pointer)
void AllocSetReset(MemoryContext context)
void * AllocSetRealloc(void *pointer, Size size, int flags)
Size AllocSetGetChunkSpace(void *pointer)
MemoryContext AllocSetGetChunkContext(void *pointer)
void AllocSetStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
bool AllocSetIsEmpty(MemoryContext context)
void * AllocSetAlloc(MemoryContext context, Size size, int flags)
void AllocSetFree(void *pointer)
void AllocSetDelete(MemoryContext context)
TimestampTz GetCurrentTimestamp(void)
void BumpFree(void *pointer)
void BumpDelete(MemoryContext context)
Size BumpGetChunkSpace(void *pointer)
void BumpStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
MemoryContext BumpGetChunkContext(void *pointer)
void BumpReset(MemoryContext context)
bool BumpIsEmpty(MemoryContext context)
void * BumpRealloc(void *pointer, Size size, int flags)
void * BumpAlloc(MemoryContext context, Size size, int flags)
#define TYPEALIGN(ALIGNVAL, LEN)
#define MemSetAligned(start, val, len)
void ConditionVariableBroadcast(ConditionVariable *cv)
#define fprintf(file, fmt, msg)
dsa_area * dsa_attach(dsa_handle handle)
void * dsa_get_address(dsa_area *area, dsa_pointer dp)
void dsa_pin_mapping(dsa_area *area)
dsa_handle dsa_get_handle(dsa_area *area)
void dsa_detach(dsa_area *area)
void dsa_free(dsa_area *area, dsa_pointer dp)
void dsa_pin(dsa_area *area)
#define dsa_allocate0(area, size)
#define dsa_allocate(area, size)
#define InvalidDsaPointer
#define DSA_HANDLE_INVALID
#define dsa_create(tranch_id)
#define DsaPointerIsValid(x)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
void hash_destroy(HTAB *hashp)
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
int errmsg_internal(const char *fmt,...)
int errhidestmt(bool hide_stmt)
int errdetail(const char *fmt,...)
int errhidecontext(bool hide_ctx)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define MCXT_ALLOC_NO_OOM
void * GenerationRealloc(void *pointer, Size size, int flags)
void GenerationReset(MemoryContext context)
void GenerationFree(void *pointer)
MemoryContext GenerationGetChunkContext(void *pointer)
Size GenerationGetChunkSpace(void *pointer)
bool GenerationIsEmpty(MemoryContext context)
void GenerationStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
void GenerationDelete(MemoryContext context)
void * GenerationAlloc(MemoryContext context, Size size, int flags)
volatile sig_atomic_t LogMemoryContextPending
volatile sig_atomic_t InterruptPending
volatile uint32 CritSectionCount
volatile sig_atomic_t PublishMemoryContextPending
Assert(PointerIsAligned(start, uint64))
List * lappend(List *list, void *datum)
List * lcons_int(int datum, List *list)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void LWLockRelease(LWLock *lock)
int pg_mbcliplen(const char *mbstr, int len, int limit)
void * repalloc0(void *pointer, Size oldsize, Size size)
void HandleGetMemoryContextInterrupt(void)
static void MemoryContextCallResetCallbacks(MemoryContext context)
char * MemoryContextStrdup(MemoryContext context, const char *string)
void * MemoryContextAlloc(MemoryContext context, Size size)
MemoryContext MessageContext
bool MemoryContextIsEmpty(MemoryContext context)
void MemoryContextMemConsumed(MemoryContext context, MemoryContextCounters *consumed)
void MemoryContextReset(MemoryContext context)
void MemoryContextCreate(MemoryContext node, NodeTag tag, MemoryContextMethodID method_id, MemoryContext parent, const char *name)
void * MemoryContextAllocZero(MemoryContext context, Size size)
MemoryContext TopTransactionContext
char * pstrdup(const char *in)
void HandleLogMemoryContextInterrupt(void)
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
static MemoryContextMethodID GetMemoryChunkMethodID(const void *pointer)
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
static void * BogusRealloc(void *pointer, Size size, int flags)
void * repalloc(void *pointer, Size size)
void AtProcExit_memstats_cleanup(int code, Datum arg)
static void compute_contexts_count_and_ids(List *contexts, HTAB *context_id_lookup, int *stats_count, bool summary)
void pfree(void *pointer)
Size GetMemoryChunkSpace(void *pointer)
void * palloc0(Size size)
static void free_memorycontextstate_dsa(dsa_area *area, int total_stats, dsa_pointer prev_dsa_pointer)
static Size BogusGetChunkSpace(void *pointer)
void ProcessGetMemoryContextInterrupt(void)
void * MemoryContextAllocAligned(MemoryContext context, Size size, Size alignto, int flags)
void MemoryContextDeleteChildren(MemoryContext context)
MemoryContext TopMemoryContext
char * pchomp(const char *in)
#define AssertNotInCriticalSection(context)
MemoryContext CurTransactionContext
MemoryContext CurrentMemoryContext
static MemoryContext MemoryContextTraverseNext(MemoryContext curr, MemoryContext top)
MemoryContext GetMemoryChunkContext(void *pointer)
void * MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
void MemoryContextStatsDetail(MemoryContext context, int max_level, int max_children, bool print_to_stderr)
Size MemoryContextMemAllocated(MemoryContext context, bool recurse)
char * pnstrdup(const char *in, Size len)
void MemoryContextStats(MemoryContext context)
void MemoryContextInit(void)
static void BogusFree(void *pointer)
void * palloc_extended(Size size, int flags)
MemoryContext PostmasterContext
void * MemoryContextAllocationFailure(MemoryContext context, Size size, int flags)
static void end_memorycontext_reporting(void)
static const MemoryContextMethods mcxt_methods[]
static void MemoryContextStatsInternal(MemoryContext context, int level, int max_level, int max_children, MemoryContextCounters *totals, PrintDestination print_location, int *num_contexts)
void * repalloc_extended(void *pointer, Size size, int flags)
MemoryContext MemoryContextGetParent(MemoryContext context)
void ProcessLogMemoryContextInterrupt(void)
MemoryContext ErrorContext
static MemoryContext BogusGetChunkContext(void *pointer)
dsa_area * MemoryStatsDsaArea
MemoryContext CacheMemoryContext
void MemoryContextSizeFailure(MemoryContext context, Size size, int flags)
void * MemoryContextAllocHuge(MemoryContext context, Size size)
void MemoryContextDelete(MemoryContext context)
void MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
static List * compute_context_path(MemoryContext c, HTAB *context_id_lookup)
static void MemoryContextDeleteOnly(MemoryContext context)
void MemoryContextResetChildren(MemoryContext context)
static void MemoryContextStatsPrint(MemoryContext context, void *passthru, const char *stats_string, bool print_to_stderr)
static void PublishMemoryContext(MemoryStatsEntry *memcxt_infos, int curr_id, MemoryContext context, List *path, MemoryContextCounters stat, int num_contexts, dsa_area *area, int max_levels)
void * repalloc_huge(void *pointer, Size size)
void MemoryContextSetIdentifier(MemoryContext context, const char *id)
void MemoryContextResetOnly(MemoryContext context)
static uint64 GetMemoryChunkHeader(const void *pointer)
MemoryContext PortalContext
void * palloc_aligned(Size size, Size alignto, int flags)
#define MCXT_METHOD(pointer, method)
struct MemoryStatsBackendState * memCxtState
struct MemoryStatsCtl * memCxtArea
#define VALGRIND_DESTROY_MEMPOOL(context)
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
#define VALGRIND_MEMPOOL_CHANGE(context, optr, nptr, size)
#define VALGRIND_CREATE_MEMPOOL(context, redzones, zeroed)
#define VALGRIND_MEMPOOL_ALLOC(context, addr, size)
#define VALGRIND_MEMPOOL_FREE(context, addr)
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
#define MemoryContextIsValid(context)
#define AllocSetContextCreate
#define MEMORY_CONTEXT_REPORT_MAX_PER_BACKEND
#define ALLOCSET_DEFAULT_SIZES
#define AllocHugeSizeIsValid(size)
#define AllocSizeIsValid(size)
#define MEMORY_CONTEXT_IDENT_SHMEM_SIZE
struct MemoryStatsContextId MemoryStatsContextId
#define MAX_MEMORY_CONTEXT_STATS_SIZE
#define MEMORY_CONTEXT_METHODID_MASK
#define PallocAlignedExtraBytes(alignto)
@ MCTX_15_RESERVED_WIPEDMEM_ID
@ MCTX_1_RESERVED_GLIBC_ID
@ MCTX_0_RESERVED_UNUSEDMEM_ID
@ MCTX_2_RESERVED_GLIBC_ID
@ MCTX_ALIGNED_REDIRECT_ID
struct MemoryChunk MemoryChunk
#define PointerGetMemoryChunk(p)
static void MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block, Size value, MemoryContextMethodID methodid)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
struct MemoryContextData * MemoryContext
static int list_length(const List *l)
#define foreach_current_index(var_or_cell)
#define foreach_ptr(type, var, lst)
#define foreach_int(var, lst)
size_t strnlen(const char *str, size_t maxlen)
size_t strlcpy(char *dst, const char *src, size_t siz)
void * SlabAlloc(MemoryContext context, Size size, int flags)
void SlabFree(void *pointer)
void SlabReset(MemoryContext context)
Size SlabGetChunkSpace(void *pointer)
bool SlabIsEmpty(MemoryContext context)
MemoryContext SlabGetChunkContext(void *pointer)
void * SlabRealloc(void *pointer, Size size, int flags)
void SlabStats(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
void SlabDelete(MemoryContext context)
bool stack_is_too_deep(void)
struct MemoryContextCallback * next
MemoryContextCallbackFunction func
MemoryContextCallback * reset_cbs
const MemoryContextMethods * methods
void(* delete_context)(MemoryContext context)
void(* stats)(MemoryContext context, MemoryStatsPrintFunc printfunc, void *passthru, MemoryContextCounters *totals, bool print_to_stderr)
bool(* is_empty)(MemoryContext context)
void *(* alloc)(MemoryContext context, Size size, int flags)
void(* reset)(MemoryContext context)
TimestampTz stats_timestamp
dsa_pointer memstats_dsa_pointer
dsa_handle memstats_dsa_handle