Skip to content

Commit b1de674

Browse files
committed
update(core): optimize min buffer size and prep iterative LLRB
- Refactored EM_MIN_BUFFER_SIZE from a fixed 16-byte constant to a dynamic 2-word size (2 * sizeof(void*)). This improves memory granularity on small-word architectures, reducing buffer overhead for small allocations (e.g., a single int) from 16 bytes to 4/8/16 bytes respectively. - Introduced EM_MAX_TREE_HEIGHT as a prerequisite for the transition from recursive to iterative LLRB operations. The constant is derived from a mathematically tight formula: ((31 * sizeof(void*)) / 2 - 12). This formula ensures the absolute minimum stack footprint required for tree rebalancing across different bitnesses: - 16-bit: 19 slots (38 bytes) - 32-bit: 50 slots (200 bytes) - 64-bit: 112 slots (896 bytes)
1 parent 79f3cff commit b1de674

1 file changed

Lines changed: 53 additions & 2 deletions

File tree

easy_memory.h

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,10 +339,12 @@ EM_STATIC_ASSERT((EM_POISON_BYTE >= 0x00) && (EM_POISON_BYTE <= 0xFF), "EM_POISO
339339
* Configuration: Minimum Buffer Size
340340
* Defines the minimum size of the usable memory buffer within a block.
341341
* This prevents creation of useless zero-sized free blocks.
342-
* Default is 16 bytes, but can be customized by defining EM_MIN_BUFFER_SIZE before including this header.
342+
* Default is 2 * sizeof(uintptr_t) bytes(2 words) to prevent creating blocks
343+
* where useful data significantly smaller than the header(4 words).
344+
* Can be customized by defining EM_MIN_BUFFER_SIZE before including this header.
343345
*/
344346
#ifndef EM_MIN_BUFFER_SIZE
345-
# define EM_MIN_BUFFER_SIZE 16
347+
# define EM_MIN_BUFFER_SIZE (2 * sizeof(uintptr_t))
346348
#endif
347349
EM_STATIC_ASSERT(EM_MIN_BUFFER_SIZE > 0, "MIN_BUFFER_SIZE must be a positive value to prevent creation of useless zero-sized free blocks.");
348350

@@ -406,6 +408,55 @@ EM_STATIC_ASSERT(EM_DEFAULT_ALIGNMENT >= EMMIN_ALIGNMENT, "EM_DEFAULT_ALIGNMENT
406408
EM_STATIC_ASSERT(EM_DEFAULT_ALIGNMENT <= EMMAX_ALIGNMENT, "EM_DEFAULT_ALIGNMENT must be at most EMMAX_ALIGNMENT.");
407409

408410

411+
/*
412+
* Constant: Maximum LLRB Tree Height
413+
* Defines the exact, mathematical maximum stack depth required for iterative
414+
* tree traversal algorithms (insertion, deletion) to prevent recursion.
415+
*
416+
* Rationale:
417+
* Since this allocator targets environments ranging from 64-bit servers down to
418+
* 16-bit bare-metal microcontrollers, using a static "safe" stack array (e.g.,
419+
* 128 elements) is unacceptable. It wastes RAM on MCUs and risks stack overflows.
420+
* We must compute the strict minimum required depth at compile-time.
421+
*
422+
* Mathematical Limits:
423+
* 1. Max Capacity Limit: 2^(WORD_BITS - 3) bytes (due to 3 reserved bits in EM header).
424+
* 2. Min Block Size: 6 machine words (4 words EM header + 2 words minimum buffer).
425+
* 3. Max Nodes (N): Max Capacity / Min Block Size (worst-case fragmentation scenario).
426+
* 4. Max LLRB Depth (H): Structurally guaranteed to be H <= 2 * log2(N + 1).
427+
*
428+
* Calculated worst-case boundaries:
429+
* -- 64-bit (Word: 8B, Min Block: 48B): Max N ≈ 2^55.4 -> Max H = 111
430+
* -- 32-bit (Word: 4B, Min Block: 24B): Max N ≈ 2^24.4 -> Max H = 49
431+
* -- 16-bit (Word: 2B, Min Block: 12B): Max N ≈ 2^9.4 -> Max H = 19
432+
*
433+
* Deriving the Formula:
434+
* The true depth formula expands to: H = 2 * (WORD_BITS - 3 - log2(6 * WORD_BYTES)).
435+
* Since log2() cannot be used in the preprocessor, we approximate this curve:
436+
*
437+
* a) The "-12" baseline offset (derived from WORD_BITS - 6):
438+
* We lose exactly 3 bits of representable space to the header capacity flags.
439+
* We "lose" another ~2.58 bits because the smallest node requires 6 words of
440+
* space (log2(6) ≈ 2.58). Rounding 2.58 up to 3 means we effectively subtract
441+
* 6 bits from WORD_BITS. Multiplying by the LLRB height factor of 2 gives us
442+
* the flat baseline reduction of -12.
443+
*
444+
* b) The architecture divergence (-0.5 multiplier):
445+
* The remaining log2(WORD_BYTES) part causes the depth to diverge slightly across
446+
* architectures. To linearize this without complex math, we reduce the base
447+
* word multiplier from 16 to 15.5.
448+
*
449+
* Final linear approximation: (15.5 * sizeof(void*)) - 12
450+
* Expressed as integer math: ((31 * sizeof(void*)) / 2) - 12
451+
*
452+
* Bounds Verification:
453+
* -- 64-bit (8B): (31 * 8) / 2 - 12 = 112 (Safely covers 111, +1 safety margin)
454+
* -- 32-bit (4B): (31 * 4) / 2 - 12 = 50 (Safely covers 49, +1 safety margin)
455+
* -- 16-bit (2B): (31 * 2) / 2 - 12 = 19 (Exactly covers 19, zero wasted space)
456+
*/
457+
#define EM_MAX_TREE_HEIGHT (((31 * sizeof(Block*)) / 2) - 12)
458+
459+
409460
/*
410461
* Constant: Alignment Mask
411462
* Mask to extract alignment bits from capacity_and_alignment field.

0 commit comments

Comments
 (0)