You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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>
Copy file name to clipboardExpand all lines: docs/AddressSpace.md
+19-24Lines changed: 19 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -26,14 +26,14 @@ For simplicity, we gloss over much of the "lazy initialization" that would actua
26
26
Because the two exercise similar bits of machinery, we now track them in parallel in prose despite their sequential nature.
27
27
28
28
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*.
30
30
31
31
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.
32
32
This results in a request for a `MIN_CHUNK_SIZE` chunk from the parent allocator.
33
33
34
34
2. For the chunk allocation, the size is `MIN_CHUNK_SIZE` or larger, so this allocator immediately forwards the request to its parent.
35
35
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.
37
37
(2 MiB chosen because it is a typical superpage size.)
38
38
At this point, both requests are for at least one and no more than a few times `MIN_CHUNK_SIZE` bytes.
39
39
@@ -48,7 +48,7 @@ For simplicity, we gloss over much of the "lazy initialization" that would actua
48
48
8. The next entry in the chain is a `StatsRange` which serves to accumulate statistics.
49
49
We ignore this stage and continue onwards.
50
50
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
52
52
of any size up to the entire address space.
53
53
The first request triggers a `refill`, continuing along the chain as a 16 MiB request.
54
54
(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
61
61
12. Having wound the chain onto our stack, we now unwind!
62
62
The `PagemapRegisterRange` ensures that the Pagemap entries for allocations passing through it are mapped and returns the allocation unaltered.
63
63
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.
65
65
66
66
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.
67
67
Aside from these side effects, these propagate the allocation along the chain unaltered.
68
68
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.
71
71
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.
73
73
The second allocation will have been forwarded and so is not additionally handled here.
74
74
75
75
Exciting, no?
@@ -98,26 +98,19 @@ For chunks owned by the *frontend* (`REMOTE_BACKEND_MARKER` not asserted),
98
98
99
99
2. A bit (`META_BOUNDARY_BIT`) that serves to limit chunk coalescing on platforms where that may not be possible, such as CHERI.
100
100
101
-
See `src/backend/metatypes.h` and `src/mem/metaslab.h`.
101
+
See `src/snmalloc/mem/metadata.h`.
102
102
103
103
For chunks owned by a *backend* (`REMOTE_BACKEND_MARKER` asserted), there are again multiple possibilities.
104
104
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.
106
106
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`).
107
108
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.
110
112
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`.
121
114
122
115
### Encoding a MetaEntry
123
116
@@ -131,18 +124,20 @@ The following cases apply:
131
124
* has "small" sizeclass 0, which has size 0.
132
125
* has no associated metadata structure.
133
126
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`:
135
128
The `MetaEntry`...
136
129
* has `REMOTE_BACKEND_MARKER` asserted in `remote_and_sizeclass`.
137
130
* 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.
139
132
* has no associated metadata structure.
140
133
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`:
142
135
Here, the `MetaEntry` is zero aside from the asserted `REMOTE_BACKEND_MARKER` bit, and so it...
143
136
* has "small" sizeclass 0, which has size 0.
144
137
* has no associated metadata structure.
145
138
139
+
The tree of free sub-chunk fragments for this chunk is stored inside the free fragments themselves (`InplaceRep`), not in the pagemap.
140
+
146
141
4. The address is part of a live large allocation (spanning one or more 16KiB chunks):
147
142
Here, the `MetaEntry`...
148
143
* has `REMOTE_BACKEND_MARKER` clear in `remote_and_sizeclass`.
Copy file name to clipboardExpand all lines: src/snmalloc/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ These are arranged in a hierarchy such that each of the directories may include
20
20
-`mem/` provides the core allocator abstractions.
21
21
The code here is templated over a back-end, which defines a particular embedding of snmalloc.
22
22
-`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.
24
24
-`backend/` provides some example implementations for snmalloc embeddings that provide a global memory allocator for an address space.
25
25
Users may ignore this entirely and use the types in `mem/` with a custom back end to expose an snmalloc instance with specific behaviour.
26
26
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.
0 commit comments