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: 2024-11-21 08:14:44 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-2024, 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             : 
      22             : 
      23             : /*
      24             :  * MaxAllocSize, MaxAllocHugeSize
      25             :  *      Quasi-arbitrary limits on size of allocations.
      26             :  *
      27             :  * Note:
      28             :  *      There is no guarantee that smaller allocations will succeed, but
      29             :  *      larger requests will be summarily denied.
      30             :  *
      31             :  * palloc() enforces MaxAllocSize, chosen to correspond to the limiting size
      32             :  * of varlena objects under TOAST.  See VARSIZE_4B() and related macros in
      33             :  * postgres.h.  Many datatypes assume that any allocatable size can be
      34             :  * represented in a varlena header.  This limit also permits a caller to use
      35             :  * an "int" variable for an index into or length of an allocation.  Callers
      36             :  * careful to avoid these hazards can access the higher limit with
      37             :  * MemoryContextAllocHuge().  Both limits permit code to assume that it may
      38             :  * compute twice an allocation's size without overflow.
      39             :  */
      40             : #define MaxAllocSize    ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
      41             : 
      42             : #define AllocSizeIsValid(size)  ((Size) (size) <= MaxAllocSize)
      43             : 
      44             : /* Must be less than SIZE_MAX */
      45             : #define MaxAllocHugeSize    (SIZE_MAX / 2)
      46             : 
      47             : #define InvalidAllocSize    SIZE_MAX
      48             : 
      49             : #define AllocHugeSizeIsValid(size)  ((Size) (size) <= MaxAllocHugeSize)
      50             : 
      51             : 
      52             : /*
      53             :  * Standard top-level memory contexts.
      54             :  *
      55             :  * Only TopMemoryContext and ErrorContext are initialized by
      56             :  * MemoryContextInit() itself.
      57             :  */
      58             : extern PGDLLIMPORT MemoryContext TopMemoryContext;
      59             : extern PGDLLIMPORT MemoryContext ErrorContext;
      60             : extern PGDLLIMPORT MemoryContext PostmasterContext;
      61             : extern PGDLLIMPORT MemoryContext CacheMemoryContext;
      62             : extern PGDLLIMPORT MemoryContext MessageContext;
      63             : extern PGDLLIMPORT MemoryContext TopTransactionContext;
      64             : extern PGDLLIMPORT MemoryContext CurTransactionContext;
      65             : 
      66             : /* This is a transient link to the active portal's memory context: */
      67             : extern PGDLLIMPORT MemoryContext PortalContext;
      68             : 
      69             : 
      70             : /*
      71             :  * Memory-context-type-independent functions in mcxt.c
      72             :  */
      73             : extern void MemoryContextInit(void);
      74             : extern void MemoryContextReset(MemoryContext context);
      75             : extern void MemoryContextDelete(MemoryContext context);
      76             : extern void MemoryContextResetOnly(MemoryContext context);
      77             : extern void MemoryContextResetChildren(MemoryContext context);
      78             : extern void MemoryContextDeleteChildren(MemoryContext context);
      79             : extern void MemoryContextSetIdentifier(MemoryContext context, const char *id);
      80             : extern void MemoryContextSetParent(MemoryContext context,
      81             :                                    MemoryContext new_parent);
      82             : extern MemoryContext GetMemoryChunkContext(void *pointer);
      83             : extern Size GetMemoryChunkSpace(void *pointer);
      84             : extern MemoryContext MemoryContextGetParent(MemoryContext context);
      85             : extern bool MemoryContextIsEmpty(MemoryContext context);
      86             : extern Size MemoryContextMemAllocated(MemoryContext context, bool recurse);
      87             : extern void MemoryContextMemConsumed(MemoryContext context,
      88             :                                      MemoryContextCounters *consumed);
      89             : extern void MemoryContextStats(MemoryContext context);
      90             : extern void MemoryContextStatsDetail(MemoryContext context,
      91             :                                      int max_level, int max_children,
      92             :                                      bool print_to_stderr);
      93             : extern void MemoryContextAllowInCriticalSection(MemoryContext context,
      94             :                                                 bool allow);
      95             : 
      96             : #ifdef MEMORY_CONTEXT_CHECKING
      97             : extern void MemoryContextCheck(MemoryContext context);
      98             : #endif
      99             : 
     100             : /* Handy macro for copying and assigning context ID ... but note double eval */
     101             : #define MemoryContextCopyAndSetIdentifier(cxt, id) \
     102             :     MemoryContextSetIdentifier(cxt, MemoryContextStrdup(cxt, id))
     103             : 
     104             : extern void HandleLogMemoryContextInterrupt(void);
     105             : extern void ProcessLogMemoryContextInterrupt(void);
     106             : 
     107             : /*
     108             :  * Memory-context-type-specific functions
     109             :  */
     110             : 
     111             : /* aset.c */
     112             : extern MemoryContext AllocSetContextCreateInternal(MemoryContext parent,
     113             :                                                    const char *name,
     114             :                                                    Size minContextSize,
     115             :                                                    Size initBlockSize,
     116             :                                                    Size maxBlockSize);
     117             : 
     118             : /*
     119             :  * This wrapper macro exists to check for non-constant strings used as context
     120             :  * names; that's no longer supported.  (Use MemoryContextSetIdentifier if you
     121             :  * want to provide a variable identifier.)
     122             :  */
     123             : #ifdef HAVE__BUILTIN_CONSTANT_P
     124             : #define AllocSetContextCreate(parent, name, ...) \
     125             :     (StaticAssertExpr(__builtin_constant_p(name), \
     126             :                       "memory context names must be constant strings"), \
     127             :      AllocSetContextCreateInternal(parent, name, __VA_ARGS__))
     128             : #else
     129             : #define AllocSetContextCreate \
     130             :     AllocSetContextCreateInternal
     131             : #endif
     132             : 
     133             : /* slab.c */
     134             : extern MemoryContext SlabContextCreate(MemoryContext parent,
     135             :                                        const char *name,
     136             :                                        Size blockSize,
     137             :                                        Size chunkSize);
     138             : 
     139             : /* generation.c */
     140             : extern MemoryContext GenerationContextCreate(MemoryContext parent,
     141             :                                              const char *name,
     142             :                                              Size minContextSize,
     143             :                                              Size initBlockSize,
     144             :                                              Size maxBlockSize);
     145             : 
     146             : /* bump.c */
     147             : extern MemoryContext BumpContextCreate(MemoryContext parent,
     148             :                                        const char *name,
     149             :                                        Size minContextSize,
     150             :                                        Size initBlockSize,
     151             :                                        Size maxBlockSize);
     152             : 
     153             : /*
     154             :  * Recommended default alloc parameters, suitable for "ordinary" contexts
     155             :  * that might hold quite a lot of data.
     156             :  */
     157             : #define ALLOCSET_DEFAULT_MINSIZE   0
     158             : #define ALLOCSET_DEFAULT_INITSIZE  (8 * 1024)
     159             : #define ALLOCSET_DEFAULT_MAXSIZE   (8 * 1024 * 1024)
     160             : #define ALLOCSET_DEFAULT_SIZES \
     161             :     ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
     162             : 
     163             : /*
     164             :  * Recommended alloc parameters for "small" contexts that are never expected
     165             :  * to contain much data (for example, a context to contain a query plan).
     166             :  */
     167             : #define ALLOCSET_SMALL_MINSIZE   0
     168             : #define ALLOCSET_SMALL_INITSIZE  (1 * 1024)
     169             : #define ALLOCSET_SMALL_MAXSIZE   (8 * 1024)
     170             : #define ALLOCSET_SMALL_SIZES \
     171             :     ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE
     172             : 
     173             : /*
     174             :  * Recommended alloc parameters for contexts that should start out small,
     175             :  * but might sometimes grow big.
     176             :  */
     177             : #define ALLOCSET_START_SMALL_SIZES \
     178             :     ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
     179             : 
     180             : 
     181             : /*
     182             :  * Threshold above which a request in an AllocSet context is certain to be
     183             :  * allocated separately (and thereby have constant allocation overhead).
     184             :  * Few callers should be interested in this, but tuplesort/tuplestore need
     185             :  * to know it.
     186             :  */
     187             : #define ALLOCSET_SEPARATE_THRESHOLD  8192
     188             : 
     189             : #define SLAB_DEFAULT_BLOCK_SIZE     (8 * 1024)
     190             : #define SLAB_LARGE_BLOCK_SIZE       (8 * 1024 * 1024)
     191             : 
     192             : /*
     193             :  * pg_memory_is_all_zeros
     194             :  *
     195             :  * Test if a memory region starting at "ptr" and of size "len" is full of
     196             :  * zeroes.
     197             :  *
     198             :  * The test is divided into multiple cases for safety reason and multiple
     199             :  * phases for efficiency.
     200             :  *
     201             :  * Case 1: len < sizeof(size_t) bytes, then byte-by-byte comparison.
     202             :  * Case 2: len < (sizeof(size_t) * 8 - 1) bytes:
     203             :  *       - Phase 1: byte-by-byte comparison, until the pointer is aligned.
     204             :  *       - Phase 2: size_t comparisons, with aligned pointers, up to the last
     205             :  *                  location possible.
     206             :  *       - Phase 3: byte-by-byte comparison, until the end location.
     207             :  * Case 3: len >= (sizeof(size_t) * 8) bytes, same as case 2 except that an
     208             :  *         additional phase is placed between Phase 1 and Phase 2, with
     209             :  *         (8 * sizeof(size_t)) comparisons using bitwise OR to encourage
     210             :  *         compilers to use SIMD instructions if available, up to the last
     211             :  *         aligned location possible.
     212             :  *
     213             :  * Case 1 and Case 2 are mandatory to ensure that we won't read beyond the
     214             :  * memory area.  This is portable for 32-bit and 64-bit architectures.
     215             :  *
     216             :  * Caller must ensure that "ptr" is not NULL.
     217             :  */
     218             : static inline bool
     219     1629920 : pg_memory_is_all_zeros(const void *ptr, size_t len)
     220             : {
     221     1629920 :     const unsigned char *p = (const unsigned char *) ptr;
     222     1629920 :     const unsigned char *end = &p[len];
     223     1629920 :     const unsigned char *aligned_end = (const unsigned char *)
     224     1629920 :         ((uintptr_t) end & (~(sizeof(size_t) - 1)));
     225             : 
     226     1629920 :     if (len < sizeof(size_t))
     227             :     {
     228           0 :         while (p < end)
     229             :         {
     230           0 :             if (*p++ != 0)
     231           0 :                 return false;
     232             :         }
     233           0 :         return true;
     234             :     }
     235             : 
     236             :     /* "len" in the [sizeof(size_t), sizeof(size_t) * 8 - 1] range */
     237     1629920 :     if (len < sizeof(size_t) * 8)
     238             :     {
     239             :         /* Compare bytes until the pointer "p" is aligned */
     240       17426 :         while (((uintptr_t) p & (sizeof(size_t) - 1)) != 0)
     241             :         {
     242           0 :             if (p == end)
     243           0 :                 return true;
     244           0 :             if (*p++ != 0)
     245           0 :                 return false;
     246             :         }
     247             : 
     248             :         /*
     249             :          * Compare remaining size_t-aligned chunks.
     250             :          *
     251             :          * There is no risk to read beyond the memory area, as "aligned_end"
     252             :          * cannot be higher than "end".
     253             :          */
     254       62322 :         for (; p < aligned_end; p += sizeof(size_t))
     255             :         {
     256       54746 :             if (*(size_t *) p != 0)
     257        9850 :                 return false;
     258             :         }
     259             : 
     260             :         /* Compare remaining bytes until the end */
     261        7576 :         while (p < end)
     262             :         {
     263           0 :             if (*p++ != 0)
     264           0 :                 return false;
     265             :         }
     266        7576 :         return true;
     267             :     }
     268             : 
     269             :     /* "len" in the [sizeof(size_t) * 8, inf) range */
     270             : 
     271             :     /* Compare bytes until the pointer "p" is aligned */
     272     1612494 :     while (((uintptr_t) p & (sizeof(size_t) - 1)) != 0)
     273             :     {
     274           0 :         if (p == end)
     275           0 :             return true;
     276             : 
     277           0 :         if (*p++ != 0)
     278           0 :             return false;
     279             :     }
     280             : 
     281             :     /*
     282             :      * Compare 8 * sizeof(size_t) chunks at once.
     283             :      *
     284             :      * For performance reasons, we manually unroll this loop and purposefully
     285             :      * use bitwise-ORs to combine each comparison.  This prevents boolean
     286             :      * short-circuiting and lets the compiler know that it's safe to access
     287             :      * all 8 elements regardless of the result of the other comparisons.  This
     288             :      * seems to be enough to coax a few compilers into using SIMD
     289             :      * instructions.
     290             :      */
     291     3201680 :     for (; p < aligned_end - (sizeof(size_t) * 7); p += sizeof(size_t) * 8)
     292             :     {
     293     2545944 :         if ((((size_t *) p)[0] != 0) | (((size_t *) p)[1] != 0) |
     294     2545944 :             (((size_t *) p)[2] != 0) | (((size_t *) p)[3] != 0) |
     295     2545944 :             (((size_t *) p)[4] != 0) | (((size_t *) p)[5] != 0) |
     296     2545944 :             (((size_t *) p)[6] != 0) | (((size_t *) p)[7] != 0))
     297      956758 :             return false;
     298             :     }
     299             : 
     300             :     /*
     301             :      * Compare remaining size_t-aligned chunks.
     302             :      *
     303             :      * There is no risk to read beyond the memory area, as "aligned_end"
     304             :      * cannot be higher than "end".
     305             :      */
     306     3221942 :     for (; p < aligned_end; p += sizeof(size_t))
     307             :     {
     308     3199470 :         if (*(size_t *) p != 0)
     309      633264 :             return false;
     310             :     }
     311             : 
     312             :     /* Compare remaining bytes until the end */
     313       22472 :     while (p < end)
     314             :     {
     315           0 :         if (*p++ != 0)
     316           0 :             return false;
     317             :     }
     318             : 
     319       22472 :     return true;
     320             : }
     321             : 
     322             : #endif                          /* MEMUTILS_H */

Generated by: LCOV version 1.14