Age Owner Branch data TLA 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 : :
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
309 michael@paquier.xyz 219 :CBC 809504 : pg_memory_is_all_zeros(const void *ptr, size_t len)
220 : : {
292 221 : 809504 : const unsigned char *p = (const unsigned char *) ptr;
222 : 809504 : const unsigned char *end = &p[len];
223 : 809504 : const unsigned char *aligned_end = (const unsigned char *)
224 : 809504 : ((uintptr_t) end & (~(sizeof(size_t) - 1)));
225 : :
226 [ - + ]: 809504 : if (len < sizeof(size_t))
227 : : {
292 michael@paquier.xyz 228 [ # # ]:UBC 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 */
292 michael@paquier.xyz 237 [ + + ]:CBC 809504 : if (len < sizeof(size_t) * 8)
238 : : {
239 : : /* Compare bytes until the pointer "p" is aligned */
240 [ - + ]: 11160 : while (((uintptr_t) p & (sizeof(size_t) - 1)) != 0)
241 : : {
292 michael@paquier.xyz 242 [ # # ]:UBC 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 : : */
292 michael@paquier.xyz 254 [ + + ]:CBC 35628 : for (; p < aligned_end; p += sizeof(size_t))
255 : : {
256 [ + + ]: 32237 : if (*(size_t *) p != 0)
257 : 7769 : return false;
258 : : }
259 : :
260 : : /* Compare remaining bytes until the end */
261 [ - + ]: 3391 : while (p < end)
262 : : {
292 michael@paquier.xyz 263 [ # # ]:UBC 0 : if (*p++ != 0)
264 : 0 : return false;
265 : : }
292 michael@paquier.xyz 266 :CBC 3391 : 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 [ - + ]: 798344 : while (((uintptr_t) p & (sizeof(size_t) - 1)) != 0)
273 : : {
292 michael@paquier.xyz 274 [ # # ]:UBC 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 : : */
292 michael@paquier.xyz 291 [ + + ]:CBC 1610702 : for (; p < aligned_end - (sizeof(size_t) * 7); p += sizeof(size_t) * 8)
292 : : {
293 : 1321607 : if ((((size_t *) p)[0] != 0) | (((size_t *) p)[1] != 0) |
294 : 1321607 : (((size_t *) p)[2] != 0) | (((size_t *) p)[3] != 0) |
295 : 1321607 : (((size_t *) p)[4] != 0) | (((size_t *) p)[5] != 0) |
296 [ + + ]: 1321607 : (((size_t *) p)[6] != 0) | (((size_t *) p)[7] != 0))
297 : 509249 : 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 [ + + ]: 1395273 : for (; p < aligned_end; p += sizeof(size_t))
307 : : {
308 [ + + ]: 1375890 : if (*(size_t *) p != 0)
309 309 : 269712 : return false;
310 : : }
311 : :
312 : : /* Compare remaining bytes until the end */
292 313 [ - + ]: 19383 : while (p < end)
314 : : {
292 michael@paquier.xyz 315 [ # # ]:UBC 0 : if (*p++ != 0)
316 : 0 : return false;
317 : : }
318 : :
309 michael@paquier.xyz 319 :CBC 19383 : return true;
320 : : }
321 : :
322 : : #endif /* MEMUTILS_H */
|