summaryrefslogtreecommitdiff
path: root/src/include
diff options
context:
space:
mode:
authorDavid Rowley2024-04-07 11:32:00 +0000
committerDavid Rowley2024-04-07 11:32:00 +0000
commit0ba8b75e7ea6b7b3090c81239ebcb866772a624b (patch)
tree3015678f6979d3f4fff6dedf80fb0ff938ee273c /src/include
parentc4ab7da60617f020e8d75b1584d0754005d71830 (diff)
Enlarge bit-space for MemoryContextMethodID
Reserve 4 bits for MemoryContextMethodID rather than 3. 3 bits did technically allow a maximum of 8 memory context types, however, we've opted to reserve some bit patterns which left us with only 4 slots, all of which were used. Here we add another bit which frees up 8 slots for future memory context types. In passing, adjust the enum names in MemoryContextMethodID to make it more clear which ones can be used and which ones are reserved. Author: Matthias van de Meent, David Rowley Discussion: https://postgr.es/m/CAApHDvqGSpCU95TmM=Bp=6xjL_nLys4zdZOpfNyWBk97Xrdj2w@mail.gmail.com
Diffstat (limited to 'src/include')
-rw-r--r--src/include/utils/memutils_internal.h18
-rw-r--r--src/include/utils/memutils_memorychunk.h32
2 files changed, 37 insertions, 13 deletions
diff --git a/src/include/utils/memutils_internal.h b/src/include/utils/memutils_internal.h
index ad1048fd829..2d032611556 100644
--- a/src/include/utils/memutils_internal.h
+++ b/src/include/utils/memutils_internal.h
@@ -104,21 +104,29 @@ extern Size AlignedAllocGetChunkSpace(void *pointer);
*/
typedef enum MemoryContextMethodID
{
- MCTX_UNUSED1_ID, /* 000 occurs in never-used memory */
- MCTX_UNUSED2_ID, /* glibc malloc'd chunks usually match 001 */
- MCTX_UNUSED3_ID, /* glibc malloc'd chunks > 128kB match 010 */
+ MCTX_0_RESERVED_UNUSEDMEM_ID, /* 0000 occurs in never-used memory */
+ MCTX_1_RESERVED_GLIBC_ID, /* glibc malloc'd chunks usually match 0001 */
+ MCTX_2_RESERVED_GLIBC_ID, /* glibc malloc'd chunks > 128kB match 0010 */
MCTX_ASET_ID,
MCTX_GENERATION_ID,
MCTX_SLAB_ID,
MCTX_ALIGNED_REDIRECT_ID,
- MCTX_UNUSED4_ID, /* 111 occurs in wipe_mem'd memory */
+ MCTX_7_UNUSED_ID,
+ MCTX_8_UNUSED_ID,
+ MCTX_9_UNUSED_ID,
+ MCTX_10_UNUSED_ID,
+ MCTX_11_UNUSED_ID,
+ MCTX_12_UNUSED_ID,
+ MCTX_13_UNUSED_ID,
+ MCTX_14_UNUSED_ID,
+ MCTX_15_RESERVED_WIPEDMEM_ID /* 1111 occurs in wipe_mem'd memory */
} MemoryContextMethodID;
/*
* The number of bits that 8-byte memory chunk headers can use to encode the
* MemoryContextMethodID.
*/
-#define MEMORY_CONTEXT_METHODID_BITS 3
+#define MEMORY_CONTEXT_METHODID_BITS 4
#define MEMORY_CONTEXT_METHODID_MASK \
((((uint64) 1) << MEMORY_CONTEXT_METHODID_BITS) - 1)
diff --git a/src/include/utils/memutils_memorychunk.h b/src/include/utils/memutils_memorychunk.h
index 38296abe1bd..56c49d604c3 100644
--- a/src/include/utils/memutils_memorychunk.h
+++ b/src/include/utils/memutils_memorychunk.h
@@ -12,7 +12,7 @@
* Although MemoryChunks are used by each of our MemoryContexts, future
* implementations may choose to implement their own method for storing chunk
* headers. The only requirement is that the header ends with an 8-byte value
- * which the least significant 3-bits of are set to the MemoryContextMethodID
+ * which the least significant 4-bits of are set to the MemoryContextMethodID
* of the given context.
*
* By default, a MemoryChunk is 8 bytes in size, however, when
@@ -25,15 +25,23 @@
* used to encode 4 separate pieces of information. Starting with the least
* significant bits of 'hdrmask', the bit space is reserved as follows:
*
- * 1. 3-bits to indicate the MemoryContextMethodID as defined by
+ * 1. 4-bits to indicate the MemoryContextMethodID as defined by
* MEMORY_CONTEXT_METHODID_MASK
* 2. 1-bit to denote an "external" chunk (see below)
* 3. 30-bits reserved for the MemoryContext to use for anything it
- * requires. Most MemoryContext likely want to store the size of the
+ * requires. Most MemoryContexts likely want to store the size of the
* chunk here.
* 4. 30-bits for the number of bytes that must be subtracted from the chunk
* to obtain the address of the block that the chunk is stored on.
*
+ * If you're paying close attention, you'll notice this adds up to 65 bits
+ * rather than 64 bits. This is because the highest-order bit of #3 is the
+ * same bit as the lowest-order bit of #4. We can do this as we insist that
+ * the chunk and block pointers are both MAXALIGNed, therefore the relative
+ * offset between those will always be a MAXALIGNed value which means the
+ * lowest order bit is always 0. When fetching the chunk to block offset we
+ * mask out the lowest-order bit to ensure it's still zero.
+ *
* In some cases, for example when memory allocations become large, it's
* possible fields 3 and 4 above are not large enough to store the values
* required for the chunk. In this case, the MemoryContext can choose to mark
@@ -93,10 +101,16 @@
*/
#define MEMORYCHUNK_MAX_BLOCKOFFSET UINT64CONST(0x3FFFFFFF)
+/*
+ * As above, but mask out the lowest-order (always zero) bit as this is shared
+ * with the MemoryChunkGetValue field.
+ */
+#define MEMORYCHUNK_BLOCKOFFSET_MASK UINT64CONST(0x3FFFFFFE)
+
/* define the least significant base-0 bit of each portion of the hdrmask */
#define MEMORYCHUNK_EXTERNAL_BASEBIT MEMORY_CONTEXT_METHODID_BITS
#define MEMORYCHUNK_VALUE_BASEBIT (MEMORYCHUNK_EXTERNAL_BASEBIT + 1)
-#define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 30)
+#define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 29)
/*
* A magic number for storing in the free bits of an external chunk. This
@@ -131,11 +145,11 @@ typedef struct MemoryChunk
(((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT) & MEMORYCHUNK_MAX_VALUE)
/*
- * We should have used up all the bits here, so the compiler is likely to
- * optimize out the & MEMORYCHUNK_MAX_BLOCKOFFSET.
+ * Shift the block offset down to the 0th bit position and mask off the single
+ * bit that's shared with the MemoryChunkGetValue field.
*/
#define HdrMaskBlockOffset(hdrmask) \
- (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_MAX_BLOCKOFFSET)
+ (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_BLOCKOFFSET_MASK)
/* For external chunks only, check the magic number matches */
#define HdrMaskCheckMagic(hdrmask) \
@@ -149,6 +163,7 @@ typedef struct MemoryChunk
* The number of bytes between 'block' and 'chunk' must be <=
* MEMORYCHUNK_MAX_BLOCKOFFSET.
* 'value' must be <= MEMORYCHUNK_MAX_VALUE.
+ * Both 'chunk' and 'block' must be MAXALIGNed pointers.
*/
static inline void
MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block,
@@ -157,7 +172,7 @@ MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block,
Size blockoffset = (char *) chunk - (char *) block;
Assert((char *) chunk >= (char *) block);
- Assert(blockoffset <= MEMORYCHUNK_MAX_BLOCKOFFSET);
+ Assert((blockoffset & MEMORYCHUNK_BLOCKOFFSET_MASK) == blockoffset);
Assert(value <= MEMORYCHUNK_MAX_VALUE);
Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
@@ -225,6 +240,7 @@ MemoryChunkGetBlock(MemoryChunk *chunk)
}
/* cleanup all internal definitions */
+#undef MEMORYCHUNK_BLOCKOFFSET_MASK
#undef MEMORYCHUNK_EXTERNAL_BASEBIT
#undef MEMORYCHUNK_VALUE_BASEBIT
#undef MEMORYCHUNK_BLOCKOFFSET_BASEBIT