Skip to content

Commit 57e12b5

Browse files
mjp41Copilot
andcommitted
Remove buddy allocators
LargeBuddyRange, SmallBuddyRange and their shared buddy.h are no longer reachable now that SmallArenaRange owns the metadata path and BackendArenaRange owns the large-range path. Delete them (-848 lines) and clean up stale references in comments, README, AddressSpace.md, and the MIN_HEAP_SIZE_FOR_THREAD_LOCAL_BUDDY constant (renamed ..._CACHE since the per-thread cache it gates is no longer specifically a buddy). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent fd9352f commit 57e12b5

8 files changed

Lines changed: 26 additions & 881 deletions

File tree

docs/AddressSpace.md

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ For simplicity, we gloss over much of the "lazy initialization" that would actua
2626
Because the two exercise similar bits of machinery, we now track them in parallel in prose despite their sequential nature.
2727

2828
4. The `BackendAllocator` has a chain of "range" types that it uses to manage address space.
29-
By default (and in the case we are considering), that chain begins with a per-thread "small buddy allocator range".
29+
By default (and in the case we are considering), that chain begins with a per-thread *small arena range*.
3030

3131
1. For the metadata allocation, the size is (well) below `MIN_CHUNK_SIZE` and so this allocator, which by supposition is empty, attempts to `refill` itself from its parent.
3232
This results in a request for a `MIN_CHUNK_SIZE` chunk from the parent allocator.
3333

3434
2. For the chunk allocation, the size is `MIN_CHUNK_SIZE` or larger, so this allocator immediately forwards the request to its parent.
3535

36-
5. The next range allocator in the chain is a per-thread *large* buddy allocator that refills in 2 MiB granules.
36+
5. The next range allocator in the chain is a per-thread `LargeArenaRange` that refills in 2 MiB granules.
3737
(2 MiB chosen because it is a typical superpage size.)
3838
At this point, both requests are for at least one and no more than a few times `MIN_CHUNK_SIZE` bytes.
3939

@@ -48,7 +48,7 @@ For simplicity, we gloss over much of the "lazy initialization" that would actua
4848
8. The next entry in the chain is a `StatsRange` which serves to accumulate statistics.
4949
We ignore this stage and continue onwards.
5050

51-
9. The next entry in the chain is another *large* buddy allocator which refills at 16 MiB but can hold regions
51+
9. The next entry in the chain is another `LargeArenaRange` which refills at 16 MiB but can hold regions
5252
of any size up to the entire address space.
5353
The first request triggers a `refill`, continuing along the chain as a 16 MiB request.
5454
(Recall that the second allocation will be handled at an earlier point on the chain.)
@@ -61,15 +61,15 @@ For simplicity, we gloss over much of the "lazy initialization" that would actua
6161
12. Having wound the chain onto our stack, we now unwind!
6262
The `PagemapRegisterRange` ensures that the Pagemap entries for allocations passing through it are mapped and returns the allocation unaltered.
6363

64-
13. The global large buddy allocator splits the 16 MiB refill into 8, 4, and 2 MiB regions it retains as well as returning the remaining 2 MiB back along the chain.
64+
13. The global `LargeArenaRange` carves the request out of its 16 MiB refill and keeps the unused remainder as a single free block in its internal red-black trees of free ranges, returning the carved portion back along the chain.
6565

6666
14. The `StatsRange` makes its observations, the `GlobalRange` now unlocks the global component of the chain, and the `CommitRange` ensures that the allocation is mapped.
6767
Aside from these side effects, these propagate the allocation along the chain unaltered.
6868

69-
15. We now arrive back at the thread-local large buddy allocator, which takes its 2 MiB refill and breaks it down into powers of two down to the requested `MIN_CHUNK_SIZE`.
70-
The second allocation (of the chunk), will either return or again break down one of these intermediate chunks.
69+
15. We now arrive back at the thread-local `LargeArenaRange`, which takes its 2 MiB refill and carves out the requested chunk(s); the unused remainder stays in its free-range trees.
70+
The second allocation (of the chunk) will either be satisfied from this leftover or trigger another carve.
7171

72-
16. For the first (metadata) allocation, the thread-local *small* allocator breaks the `MIN_CHUNK_SIZE` allocation down into powers of two down to `PAGEMAP_METADATA_STRUCT_SIZE` and returns one of that size.
72+
16. For the first (metadata) allocation, the thread-local *small arena range* takes its `MIN_CHUNK_SIZE` refill, hands back a sub-chunk fragment large enough for `PAGEMAP_METADATA_STRUCT_SIZE`, and tracks the remainder as free sub-chunk space using tree nodes stored inside the free fragments themselves.
7373
The second allocation will have been forwarded and so is not additionally handled here.
7474

7575
Exciting, no?
@@ -98,26 +98,19 @@ For chunks owned by the *frontend* (`REMOTE_BACKEND_MARKER` not asserted),
9898

9999
2. A bit (`META_BOUNDARY_BIT`) that serves to limit chunk coalescing on platforms where that may not be possible, such as CHERI.
100100

101-
See `src/backend/metatypes.h` and `src/mem/metaslab.h`.
101+
See `src/snmalloc/mem/metadata.h`.
102102

103103
For chunks owned by a *backend* (`REMOTE_BACKEND_MARKER` asserted), there are again multiple possibilities.
104104

105-
For chunks owned by a *small buddy allocator*, the remainder of the `MetaEntry` is zero.
105+
For chunks owned by a *small arena range* (`SmallArenaRange`), the remainder of the `MetaEntry` is zero.
106106
That is, it appears to have small sizeclass 0 and an implausible `RemoteAllocator*`.
107+
The free-fragment tree itself is stored in-band, inside the free space of the chunk, rather than in the pagemap (see `InplaceRep` in `src/snmalloc/backend_helpers/inplacerep.h`).
107108

108-
For chunks owned by a *large buddy allocator*, the `MetaEntry` is instead a node in a red-black tree of all such chunks.
109-
Its contents can be decoded as follows:
109+
For chunks owned by a `LargeArenaRange`, the `MetaEntry` is instead a node in the red-black trees of free ranges.
110+
A free block of *N* units consumes the `MetaEntry`s of its first *min(N, 3)* unit-aligned addresses; their words encode the bin-tree node (unit 0), the range-tree node (unit 1, for blocks of two or more units), and the large-chunk count (unit 2, for blocks of three or more units).
111+
The pagemap reserves the low `MetaEntryBase::BACKEND_LAYOUT_FIRST_FREE_BIT` bits of each word for the meta-entry layout itself; the tree-node encoding (left/right pointers, red bit, variant tag, large-size count) lives at or above that bit.
110112

111-
1. The `meta` field's `META_BOUNDARY_BIT` is preserved, with the same meaning as in the frontend case, above.
112-
113-
2. `meta` (resp. `remote_and_sizeclass`) includes a pointer to the left (resp. right) *chunk* of address space.
114-
(The corresponding child *node* in this tree is found by taking the *address* of this chunk and looking up the `MetaEntry` in the Pagemap.
115-
This trick of pointing at the child's chunk rather than at the child `MetaEntry` is particularly useful on CHERI:
116-
it allows us to capture the authority to the chunk without needing another pointer and costs just a shift and add.)
117-
118-
3. The `meta` field's `LargeBuddyRep::RED_BIT` is used to carry the red/black color of this node.
119-
120-
See `src/backend/largebuddyrange.h`.
113+
See `PagemapRep` in `src/snmalloc/backend_helpers/largearenarange.h`.
121114

122115
### Encoding a MetaEntry
123116

@@ -131,18 +124,20 @@ The following cases apply:
131124
* has "small" sizeclass 0, which has size 0.
132125
* has no associated metadata structure.
133126

134-
2. The address is part of a free chunk in a backend's Large Buddy Allocator:
127+
2. The address is part of a free chunk in a backend `LargeArenaRange`:
135128
The `MetaEntry`...
136129
* has `REMOTE_BACKEND_MARKER` asserted in `remote_and_sizeclass`.
137130
* has "small" sizeclass 0, which has size 0.
138-
* the remainder of its `MetaEntry` structure will be a Large Buddy Allocator rbtree node.
131+
* the remainder of its `MetaEntry` structure (and those of the next one or two unit-aligned `MetaEntry`s if the free block spans them) carries the `Arena`'s red-black-tree node encoding.
139132
* has no associated metadata structure.
140133

141-
3. The address is part of a free chunk inside a backend's Small Buddy Allocator:
134+
3. The address is part of a free fragment inside a backend `SmallArenaRange`:
142135
Here, the `MetaEntry` is zero aside from the asserted `REMOTE_BACKEND_MARKER` bit, and so it...
143136
* has "small" sizeclass 0, which has size 0.
144137
* has no associated metadata structure.
145138

139+
The tree of free sub-chunk fragments for this chunk is stored inside the free fragments themselves (`InplaceRep`), not in the pagemap.
140+
146141
4. The address is part of a live large allocation (spanning one or more 16KiB chunks):
147142
Here, the `MetaEntry`...
148143
* has `REMOTE_BACKEND_MARKER` clear in `remote_and_sizeclass`.

src/snmalloc/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ These are arranged in a hierarchy such that each of the directories may include
2020
- `mem/` provides the core allocator abstractions.
2121
The code here is templated over a back-end, which defines a particular embedding of snmalloc.
2222
- `backend_helpers/` provides helper classes for use in defining a back end.
23-
This includes data structures such as pagemap implementations (efficient maps from a chunk address to associated metadata) and buddy allocators for managing address-space ranges.
23+
This includes data structures such as pagemap implementations (efficient maps from a chunk address to associated metadata) and range allocators for managing address-space ranges.
2424
- `backend/` provides some example implementations for snmalloc embeddings that provide a global memory allocator for an address space.
2525
Users may ignore this entirely and use the types in `mem/` with a custom back end to expose an snmalloc instance with specific behaviour.
2626
Layers above this can be used with a custom configuration by defining `SNMALLOC_PROVIDE_OWN_CONFIG` and exporting a type as `snmalloc::Config` that defines the configuration.

src/snmalloc/backend/fixedglobalconfig.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ namespace snmalloc
9393
Pagemap::concretePagemap.init(base, length);
9494

9595
// Make this a alloc_config constant.
96-
if (length < MIN_HEAP_SIZE_FOR_THREAD_LOCAL_BUDDY)
96+
if (length < MIN_HEAP_SIZE_FOR_THREAD_LOCAL_CACHE)
9797
{
9898
LocalState::set_small_heap();
9999
}

src/snmalloc/backend_helpers/backend_helpers.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,19 @@
33
#include "../mem/mem.h"
44
#include "authmap.h"
55
#include "backend_arena_range.h"
6-
#include "buddy.h"
76
#include "commitrange.h"
87
#include "commonconfig.h"
98
#include "defaultpagemapentry.h"
109
#include "empty_range.h"
1110
#include "globalrange.h"
1211
#include "indirectrange.h"
13-
#include "largebuddyrange.h"
1412
#include "logrange.h"
1513
#include "noprange.h"
1614
#include "pagemap.h"
1715
#include "pagemapregisterrange.h"
1816
#include "palrange.h"
1917
#include "range_helpers.h"
2018
#include "smallarenarange.h"
21-
#include "smallbuddyrange.h"
2219
#include "staticconditionalrange.h"
2320
#include "statsrange.h"
2421
#include "subrange.h"

src/snmalloc/backend_helpers/buddy.h

Lines changed: 0 additions & 199 deletions
This file was deleted.

0 commit comments

Comments
 (0)