LCOV - code coverage report
Current view: top level - src/include/utils - memutils.h (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 25 41 61.0 %
Date: 2025-04-24 12:15:10 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * memutils.h
       4             :  *    This file contains declarations for memory allocation utility
       5             :  *    functions.  These are functions that are not quite widely used
       6             :  *    enough to justify going in utils/palloc.h, but are still part
       7             :  *    of the API of the memory management subsystem.
       8             :  *
       9             :  *
      10             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
      11             :  * Portions Copyright (c) 1994, Regents of the University of California
      12             :  *
      13             :  * src/include/utils/memutils.h
      14             :  *
      15             :  *-------------------------------------------------------------------------
      16             :  */
      17             : #ifndef MEMUTILS_H
      18             : #define MEMUTILS_H
      19             : 
      20             : #include "nodes/memnodes.h"
      21             : #include "storage/condition_variable.h"
      22             : #include "storage/lmgr.h"
      23             : #include "utils/dsa.h"
      24             : 
      25             : 
      26             : /*
      27             :  * MaxAllocSize, MaxAllocHugeSize
      28             :  *      Quasi-arbitrary limits on size of allocations.
      29             :  *
      30             :  * Note:
      31             :  *      There is no guarantee that smaller allocations will succeed, but
      32             :  *      larger requests will be summarily denied.
      33             :  *
      34             :  * palloc() enforces MaxAllocSize, chosen to correspond to the limiting size
      35             :  * of varlena objects under TOAST.  See VARSIZE_4B() and related macros in
      36             :  * postgres.h.  Many datatypes assume that any allocatable size can be
      37             :  * represented in a varlena header.  This limit also permits a caller to use
      38             :  * an "int" variable for an index into or length of an allocation.  Callers
      39             :  * careful to avoid these hazards can access the higher limit with
      40             :  * MemoryContextAllocHuge().  Both limits permit code to assume that it may
      41             :  * compute twice an allocation's size without overflow.
      42             :  */
      43             : #define MaxAllocSize    ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
      44             : 
      45             : #define AllocSizeIsValid(size)  ((Size) (size) <= MaxAllocSize)
      46             : 
      47             : /* Must be less than SIZE_MAX */
      48             : #define MaxAllocHugeSize    (SIZE_MAX / 2)
      49             : 
      50             : #define InvalidAllocSize    SIZE_MAX
      51             : 
      52             : #define AllocHugeSizeIsValid(size)  ((Size) (size) <= MaxAllocHugeSize)
      53             : 
      54             : /*
      55             :  * Memory Context reporting size limits.
      56             :  */
      57             : 
      58             : /* Max length of context name and ident */
      59             : #define MEMORY_CONTEXT_IDENT_SHMEM_SIZE 64
      60             : /* Maximum size (in bytes) of DSA area per process */
      61             : #define MEMORY_CONTEXT_REPORT_MAX_PER_BACKEND  ((size_t) (1 * 1024 * 1024))
      62             : 
      63             : /*
      64             :  * Maximum size per context. Actual size may be lower as this assumes the worst
      65             :  * case of deepest path and longest identifiers (name and ident, thus the
      66             :  * multiplication by 2). The path depth is limited to 100 like for memory
      67             :  * context logging.
      68             :  */
      69             : #define MAX_MEMORY_CONTEXT_STATS_SIZE (sizeof(MemoryStatsEntry) + \
      70             :     (100 * sizeof(int)) + (2 * MEMORY_CONTEXT_IDENT_SHMEM_SIZE))
      71             : 
      72             : /*
      73             :  * Standard top-level memory contexts.
      74             :  *
      75             :  * Only TopMemoryContext and ErrorContext are initialized by
      76             :  * MemoryContextInit() itself.
      77             :  */
      78             : extern PGDLLIMPORT MemoryContext TopMemoryContext;
      79             : extern PGDLLIMPORT MemoryContext ErrorContext;
      80             : extern PGDLLIMPORT MemoryContext PostmasterContext;
      81             : extern PGDLLIMPORT MemoryContext CacheMemoryContext;
      82             : extern PGDLLIMPORT MemoryContext MessageContext;
      83             : extern PGDLLIMPORT MemoryContext TopTransactionContext;
      84             : extern PGDLLIMPORT MemoryContext CurTransactionContext;
      85             : 
      86             : /* This is a transient link to the active portal's memory context: */
      87             : extern PGDLLIMPORT MemoryContext PortalContext;
      88             : 
      89             : 
      90             : /*
      91             :  * Memory-context-type-independent functions in mcxt.c
      92             :  */
      93             : extern void MemoryContextInit(void);
      94             : extern void MemoryContextReset(MemoryContext context);
      95             : extern void MemoryContextDelete(MemoryContext context);
      96             : extern void MemoryContextResetOnly(MemoryContext context);
      97             : extern void MemoryContextResetChildren(MemoryContext context);
      98             : extern void MemoryContextDeleteChildren(MemoryContext context);
      99             : extern void MemoryContextSetIdentifier(MemoryContext context, const char *id);
     100             : extern void MemoryContextSetParent(MemoryContext context,
     101             :                                    MemoryContext new_parent);
     102             : extern MemoryContext GetMemoryChunkContext(void *pointer);
     103             : extern Size GetMemoryChunkSpace(void *pointer);
     104             : extern MemoryContext MemoryContextGetParent(MemoryContext context);
     105             : extern bool MemoryContextIsEmpty(MemoryContext context);
     106             : extern Size MemoryContextMemAllocated(MemoryContext context, bool recurse);
     107             : extern void MemoryContextMemConsumed(MemoryContext context,
     108             :                                      MemoryContextCounters *consumed);
     109             : extern void MemoryContextStats(MemoryContext context);
     110             : extern void MemoryContextStatsDetail(MemoryContext context,
     111             :                                      int max_level, int max_children,
     112             :                                      bool print_to_stderr);
     113             : extern void MemoryContextAllowInCriticalSection(MemoryContext context,
     114             :                                                 bool allow);
     115             : 
     116             : #ifdef MEMORY_CONTEXT_CHECKING
     117             : extern void MemoryContextCheck(MemoryContext context);
     118             : #endif
     119             : 
     120             : /* Handy macro for copying and assigning context ID ... but note double eval */
     121             : #define MemoryContextCopyAndSetIdentifier(cxt, id) \
     122             :     MemoryContextSetIdentifier(cxt, MemoryContextStrdup(cxt, id))
     123             : 
     124             : extern void HandleLogMemoryContextInterrupt(void);
     125             : extern void ProcessLogMemoryContextInterrupt(void);
     126             : 
     127             : /*
     128             :  * Memory-context-type-specific functions
     129             :  */
     130             : 
     131             : /* aset.c */
     132             : extern MemoryContext AllocSetContextCreateInternal(MemoryContext parent,
     133             :                                                    const char *name,
     134             :                                                    Size minContextSize,
     135             :                                                    Size initBlockSize,
     136             :                                                    Size maxBlockSize);
     137             : 
     138             : /*
     139             :  * This wrapper macro exists to check for non-constant strings used as context
     140             :  * names; that's no longer supported.  (Use MemoryContextSetIdentifier if you
     141             :  * want to provide a variable identifier.)
     142             :  */
     143             : #ifdef HAVE__BUILTIN_CONSTANT_P
     144             : #define AllocSetContextCreate(parent, name, ...) \
     145             :     (StaticAssertExpr(__builtin_constant_p(name), \
     146             :                       "memory context names must be constant strings"), \
     147             :      AllocSetContextCreateInternal(parent, name, __VA_ARGS__))
     148             : #else
     149             : #define AllocSetContextCreate \
     150             :     AllocSetContextCreateInternal
     151             : #endif
     152             : 
     153             : /* slab.c */
     154             : extern MemoryContext SlabContextCreate(MemoryContext parent,
     155             :                                        const char *name,
     156             :                                        Size blockSize,
     157             :                                        Size chunkSize);
     158             : 
     159             : /* generation.c */
     160             : extern MemoryContext GenerationContextCreate(MemoryContext parent,
     161             :                                              const char *name,
     162             :                                              Size minContextSize,
     163             :                                              Size initBlockSize,
     164             :                                              Size maxBlockSize);
     165             : 
     166             : /* bump.c */
     167             : extern MemoryContext BumpContextCreate(MemoryContext parent,
     168             :                                        const char *name,
     169             :                                        Size minContextSize,
     170             :                                        Size initBlockSize,
     171             :                                        Size maxBlockSize);
     172             : 
     173             : /*
     174             :  * Recommended default alloc parameters, suitable for "ordinary" contexts
     175             :  * that might hold quite a lot of data.
     176             :  */
     177             : #define ALLOCSET_DEFAULT_MINSIZE   0
     178             : #define ALLOCSET_DEFAULT_INITSIZE  (8 * 1024)
     179             : #define ALLOCSET_DEFAULT_MAXSIZE   (8 * 1024 * 1024)
     180             : #define ALLOCSET_DEFAULT_SIZES \
     181             :     ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
     182             : 
     183             : /*
     184             :  * Recommended alloc parameters for "small" contexts that are never expected
     185             :  * to contain much data (for example, a context to contain a query plan).
     186             :  */
     187             : #define ALLOCSET_SMALL_MINSIZE   0
     188             : #define ALLOCSET_SMALL_INITSIZE  (1 * 1024)
     189             : #define ALLOCSET_SMALL_MAXSIZE   (8 * 1024)
     190             : #define ALLOCSET_SMALL_SIZES \
     191             :     ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE
     192             : 
     193             : /*
     194             :  * Recommended alloc parameters for contexts that should start out small,
     195             :  * but might sometimes grow big.
     196             :  */
     197             : #define ALLOCSET_START_SMALL_SIZES \
     198             :     ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
     199             : 
     200             : 
     201             : /*
     202             :  * Threshold above which a request in an AllocSet context is certain to be
     203             :  * allocated separately (and thereby have constant allocation overhead).
     204             :  * Few callers should be interested in this, but tuplesort/tuplestore need
     205             :  * to know it.
     206             :  */
     207             : #define ALLOCSET_SEPARATE_THRESHOLD  8192
     208             : 
     209             : #define SLAB_DEFAULT_BLOCK_SIZE     (8 * 1024)
     210             : #define SLAB_LARGE_BLOCK_SIZE       (8 * 1024 * 1024)
     211             : 
     212             : /*
     213             :  * pg_memory_is_all_zeros
     214             :  *
     215             :  * Test if a memory region starting at "ptr" and of size "len" is full of
     216             :  * zeroes.
     217             :  *
     218             :  * The test is divided into multiple cases for safety reason and multiple
     219             :  * phases for efficiency.
     220             :  *
     221             :  * Case 1: len < sizeof(size_t) bytes, then byte-by-byte comparison.
     222             :  * Case 2: len < (sizeof(size_t) * 8 - 1) bytes:
     223             :  *       - Phase 1: byte-by-byte comparison, until the pointer is aligned.
     224             :  *       - Phase 2: size_t comparisons, with aligned pointers, up to the last
     225             :  *                  location possible.
     226             :  *       - Phase 3: byte-by-byte comparison, until the end location.
     227             :  * Case 3: len >= (sizeof(size_t) * 8) bytes, same as case 2 except that an
     228             :  *         additional phase is placed between Phase 1 and Phase 2, with
     229             :  *         (8 * sizeof(size_t)) comparisons using bitwise OR to encourage
     230             :  *         compilers to use SIMD instructions if available, up to the last
     231             :  *         aligned location possible.
     232             :  *
     233             :  * Case 1 and Case 2 are mandatory to ensure that we won't read beyond the
     234             :  * memory area.  This is portable for 32-bit and 64-bit architectures.
     235             :  *
     236             :  * Caller must ensure that "ptr" is not NULL.
     237             :  */
     238             : static inline bool
     239     1780338 : pg_memory_is_all_zeros(const void *ptr, size_t len)
     240             : {
     241     1780338 :     const unsigned char *p = (const unsigned char *) ptr;
     242     1780338 :     const unsigned char *end = &p[len];
     243     1780338 :     const unsigned char *aligned_end = (const unsigned char *)
     244     1780338 :         ((uintptr_t) end & (~(sizeof(size_t) - 1)));
     245             : 
     246     1780338 :     if (len < sizeof(size_t))
     247             :     {
     248           0 :         while (p < end)
     249             :         {
     250           0 :             if (*p++ != 0)
     251           0 :                 return false;
     252             :         }
     253           0 :         return true;
     254             :     }
     255             : 
     256             :     /* "len" in the [sizeof(size_t), sizeof(size_t) * 8 - 1] range */
     257     1780338 :     if (len < sizeof(size_t) * 8)
     258             :     {
     259             :         /* Compare bytes until the pointer "p" is aligned */
     260       20588 :         while (((uintptr_t) p & (sizeof(size_t) - 1)) != 0)
     261             :         {
     262           0 :             if (p == end)
     263           0 :                 return true;
     264           0 :             if (*p++ != 0)
     265           0 :                 return false;
     266             :         }
     267             : 
     268             :         /*
     269             :          * Compare remaining size_t-aligned chunks.
     270             :          *
     271             :          * There is no risk to read beyond the memory area, as "aligned_end"
     272             :          * cannot be higher than "end".
     273             :          */
     274       74708 :         for (; p < aligned_end; p += sizeof(size_t))
     275             :         {
     276       65426 :             if (*(size_t *) p != 0)
     277       11306 :                 return false;
     278             :         }
     279             : 
     280             :         /* Compare remaining bytes until the end */
     281        9282 :         while (p < end)
     282             :         {
     283           0 :             if (*p++ != 0)
     284           0 :                 return false;
     285             :         }
     286        9282 :         return true;
     287             :     }
     288             : 
     289             :     /* "len" in the [sizeof(size_t) * 8, inf) range */
     290             : 
     291             :     /* Compare bytes until the pointer "p" is aligned */
     292     1759750 :     while (((uintptr_t) p & (sizeof(size_t) - 1)) != 0)
     293             :     {
     294           0 :         if (p == end)
     295           0 :             return true;
     296             : 
     297           0 :         if (*p++ != 0)
     298           0 :             return false;
     299             :     }
     300             : 
     301             :     /*
     302             :      * Compare 8 * sizeof(size_t) chunks at once.
     303             :      *
     304             :      * For performance reasons, we manually unroll this loop and purposefully
     305             :      * use bitwise-ORs to combine each comparison.  This prevents boolean
     306             :      * short-circuiting and lets the compiler know that it's safe to access
     307             :      * all 8 elements regardless of the result of the other comparisons.  This
     308             :      * seems to be enough to coax a few compilers into using SIMD
     309             :      * instructions.
     310             :      */
     311     3599560 :     for (; p < aligned_end - (sizeof(size_t) * 7); p += sizeof(size_t) * 8)
     312             :     {
     313     2858540 :         if ((((size_t *) p)[0] != 0) | (((size_t *) p)[1] != 0) |
     314     2858540 :             (((size_t *) p)[2] != 0) | (((size_t *) p)[3] != 0) |
     315     2858540 :             (((size_t *) p)[4] != 0) | (((size_t *) p)[5] != 0) |
     316     2858540 :             (((size_t *) p)[6] != 0) | (((size_t *) p)[7] != 0))
     317     1018730 :             return false;
     318             :     }
     319             : 
     320             :     /*
     321             :      * Compare remaining size_t-aligned chunks.
     322             :      *
     323             :      * There is no risk to read beyond the memory area, as "aligned_end"
     324             :      * cannot be higher than "end".
     325             :      */
     326     3597396 :     for (; p < aligned_end; p += sizeof(size_t))
     327             :     {
     328     3557026 :         if (*(size_t *) p != 0)
     329      700650 :             return false;
     330             :     }
     331             : 
     332             :     /* Compare remaining bytes until the end */
     333       40370 :     while (p < end)
     334             :     {
     335           0 :         if (*p++ != 0)
     336           0 :             return false;
     337             :     }
     338             : 
     339       40370 :     return true;
     340             : }
     341             : 
     342             : /* Dynamic shared memory state for statistics per context */
     343             : typedef struct MemoryStatsEntry
     344             : {
     345             :     dsa_pointer name;
     346             :     dsa_pointer ident;
     347             :     dsa_pointer path;
     348             :     NodeTag     type;
     349             :     int         path_length;
     350             :     int         levels;
     351             :     int64       totalspace;
     352             :     int64       nblocks;
     353             :     int64       freespace;
     354             :     int64       freechunks;
     355             :     int         num_agg_stats;
     356             : } MemoryStatsEntry;
     357             : 
     358             : /*
     359             :  * Static shared memory state representing the DSA area created for memory
     360             :  * context statistics reporting.  A single DSA area is created and used by all
     361             :  * the processes, each having its specific DSA allocations for sharing memory
     362             :  * statistics, tracked by per backend static shared memory state.
     363             :  */
     364             : typedef struct MemoryStatsCtl
     365             : {
     366             :     dsa_handle  memstats_dsa_handle;
     367             :     LWLock      lw_lock;
     368             : } MemoryStatsCtl;
     369             : 
     370             : /*
     371             :  * Per backend static shared memory state for memory context statistics
     372             :  * reporting.
     373             :  */
     374             : typedef struct MemoryStatsBackendState
     375             : {
     376             :     ConditionVariable memcxt_cv;
     377             :     LWLock      lw_lock;
     378             :     int         proc_id;
     379             :     int         total_stats;
     380             :     bool        summary;
     381             :     dsa_pointer memstats_dsa_pointer;
     382             :     TimestampTz stats_timestamp;
     383             : } MemoryStatsBackendState;
     384             : 
     385             : 
     386             : /*
     387             :  * Used for storage of transient identifiers for pg_get_backend_memory_contexts
     388             :  */
     389             : typedef struct MemoryStatsContextId
     390             : {
     391             :     MemoryContext context;
     392             :     int         context_id;
     393             : } MemoryStatsContextId;
     394             : 
     395             : extern PGDLLIMPORT MemoryStatsBackendState *memCxtState;
     396             : extern PGDLLIMPORT MemoryStatsCtl *memCxtArea;
     397             : extern PGDLLIMPORT dsa_area *MemoryStatsDsaArea;
     398             : extern void ProcessGetMemoryContextInterrupt(void);
     399             : extern const char *ContextTypeToString(NodeTag type);
     400             : extern void HandleGetMemoryContextInterrupt(void);
     401             : extern Size MemoryContextReportingShmemSize(void);
     402             : extern void MemoryContextReportingShmemInit(void);
     403             : extern void AtProcExit_memstats_cleanup(int code, Datum arg);
     404             : #endif                          /* MEMUTILS_H */

Generated by: LCOV version 1.14