8.5 KiB
Slabs allocator
Introduction
The memory subsystem provides 4 independant but similars slab allocators dedicated to various purposes.
Regions objects slabs allocator
These slabs allocator are dedicated to the storage of region objects. These objects are 12 bytes in size. There is two slab allocators that store region objects:
slab_reg_phys: the slab allocator for physical region objets. It uses 24 bits index, making it able to store up to 16 millions objects. Defined inshelter/lib/include/memory/slabs/slab_reg_phys.hand implemented inshelter/lib/src/memory/slabs/slab_reg_phys.cslab_reg_virt: the slab allocator for virtual region objets. It uses 29 bits index, making it able to store up to 536 millions objects. Defined inshelter/lib/include/memory/slabs/slab_reg_virt.hand implemented inshelter/lib/src/memory/slabs/slab_reg_virt.c
They uses 3 pages per slab, capable of storing 1024 objects per slabs. They store the slab header outside, into a dedicated, pre allocated area. The slabs are allocated, reused, but never deallocated.
The slab allocator uses indexes to identify objects slots. These indexes are what the user is given upon allocation and need to be provided back in order to free objects slots. The indexes are composed of two parts:
- index in the slab: 10 lower bits
- slab index: 14 or 19 upper bits
The structures sh_slab_reg_phys_SLAB_STRUCT and sh_slab_reg_virt_SLAB_STRUCT define the headers of each slab. The structures sh_slab_reg_phys_SLAB_ALLOCATOR and sh_slab_reg_virt_SLAB_ALLOCATOR are used to store allocators metadata. The sh_slab_reg_phys_OBJECT_INDEX and sh_slab_reg_virt_OBJECT_INDEX are both wrapper of sh_uint32.
The only difference between these two are the amount of slabs they can store and their dedicated virtual pages ranges.
The API for physical region objects slab allocator is as follow:
SH_STATUS sh_slab_reg_phys_alloc_init(sh_slab_reg_phys_SLAB_ALLOCATOR* slab_alloc,sh_page_PAGE_TABLE_POOL *ptp): initialize the allocator, allocate all the headers but does not add the first slabSH_STATUS sh_slab_reg_phys_add_slab(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_phys_SLAB_STRUCT** out_slab): add a new slab, can allocate from Page or Pez subsystem, do all the mapping itselfvoid* sh_slab_reg_phys_ref_to_ptr(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_slab_reg_phys_OBJECT_INDEX ref): transform an index into a pointer to the referenced objectSH_STATUS sh_slab_reg_phys_alloc(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_phys_OBJECT_INDEX* out_index): allocate a new object and return his index. Can allocate new slabsSH_STATUS sh_slab_reg_phys_dealloc(sh_slab_reg_phys_SLAB_ALLOCATOR* alloc,sh_slab_reg_phys_OBJECT_INDEX index): deallocate a object using the provided index. Doesn't delete slabs that are made empty by objects deallocation
The API for virtual region objects slab allocator is as follow:
SH_STATUS sh_slab_reg_virt_alloc_init(sh_slab_reg_virt_SLAB_ALLOCATOR* slab_alloc,sh_page_PAGE_TABLE_POOL *ptp): initialize the allocator, allocate all the headers but does not add the first slabSH_STATUS sh_slab_reg_virt_add_slab(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_virt_SLAB_STRUCT** out_slab): add a new slab, can allocate from Page or Pez subsystem, do all the mapping itselfvoid* sh_slab_reg_virt_ref_to_ptr(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_slab_reg_virt_OBJECT_INDEX ref): transform an index into a pointer to the referenced objectSH_STATUS sh_slab_reg_virt_alloc(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_reg_virt_OBJECT_INDEX* out_index): allocate a new object and return his index. Can allocate new slabsSH_STATUS sh_slab_reg_virt_dealloc(sh_slab_reg_virt_SLAB_ALLOCATOR* alloc,sh_slab_reg_virt_OBJECT_INDEX index): deallocate a object using the provided index. Doesn't delete slabs that are made empty by objects deallocation
PBA-based slab allocators
These slab allocators relies on a PBA to automatically allocate and map slab pages inside their dedicated virtual pages ranges. They doesn't create their own PBA. While this responsability fall on the user, this allow the user to set personnalized virtual pages range, even if they aren't intented to have multiples instances of them at the same time.
These slabs allocator also store the header of each slabs inside the slab, making it possible to allocate slabs headers on the fly. The slab header contain pointers that can form a partial slabs linked list.
Finally, these slab allocators provide infinite slabs without any software limits. They reuse but doesn't deallocate slabs. They also don't use indexes but direct pointers.
Radix node slab allocator
This allocator use 32 pages slabs, and manage 128 bytes object. The slab contain 1024 objects slots. But due to the space taken by the header, each slab only contain 1006 objects due to the header taking space.
Inside the slab header, the slab allocator also maintain a 16 bit extra object per radix node. It serve at a bitmap for radix nodes.
The sh_slab_radix_node_SLAB structure describe the header of each slab, as well as each object slot. The sh_slab_radix_node_SLAB_ALLOCATOR structure contain the metadatas of the allocator. The header is 256 bytes wide.
The API for radix nodes slab allocator is as follow:
SH_STATUS sh_slab_radix_node_alloc_init(struct sh_slab_radix_node_SLAB_ALLOCATOR* slab_alloc,sh_pba_PAGE_BLOCK_ALLOCATOR *pba): initialize the slab allocator, doesn't allocate any slabSH_STATUS sh_slab_radix_node_add_slab(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_radix_node_SLAB** out_slab): add a new slab, allocate from the PBASH_STATUS sh_slab_radix_node_alloc(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_radix_NODE** out_obj): allocate a new object and return his pointer. Can allocate new slabsSH_STATUS sh_slab_radix_node_dealloc(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_radix_NODE *object_ptr): deallocate a object using the provided pointer. Doesn't delete slabs that are made empty by objects deallocationsh_uint16 *sh_slab_radix_node_get_node_bitmap(struct sh_slab_radix_node_SLAB_ALLOCATOR* alloc,sh_radix_NODE *object_ptr): return a pointer to the bitmap of the node
It's defined inside shelter/lib/include/memory/slabs/slab_radix_node.h and implemented inside shelter/lib/src/memory/slabs/slab_radix_node.c.
Generic slab allocators
These slab allocators are used to store objects allocated on the heap. The header is always 128 bytes. Each slab contain 512 objects but the actual size of each slab depend on the level of the allocator:
| Level | Object size in bytes | Amount of pages per slab | Amount of actual objects per slab |
|---|---|---|---|
| 0 | 8 | 1 | 496 |
| 1 | 16 | 2 | 504 |
| 2 | 32 | 4 | 508 |
| 3 | 64 | 8 | 510 |
| 4 | 128 | 16 | 511 |
| 5 | 256 | 32 | 511 |
| 6 | 512 | 64 | 511 |
| 7 | 1024 | 128 | 511 |
The sh_slab_generic_SLAB structure describe the header of each slab, as well as each object slot. The sh_slab_generic_SLAB_ALLOCATOR structure contain the metadatas of the allocator.
The API for generic slab allocators is as follow:
SH_STATUS sh_slab_generic_alloc_init(sh_uint8 level,struct sh_slab_generic_SLAB_ALLOCATOR* slab_alloc,sh_pba_PAGE_BLOCK_ALLOCATOR *pba): initialize the slab allocator, doesn't allocate any slabSH_STATUS sh_slab_generic_add_slab(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,sh_slab_generic_SLAB** out_slab): add a new slab, allocate from the PBASH_STATUS sh_slab_generic_alloc(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,sh_page_PAGE_TABLE_POOL *ptp,void** out_obj): allocate a new object and return his pointer. Can allocate new slabsSH_STATUS sh_slab_generic_dealloc(struct sh_slab_generic_SLAB_ALLOCATOR* alloc,void *object_ptr): deallocate a object using the provided pointer. Doesn't delete slabs that are made empty by objects deallocation
It's defined inside shelter/lib/include/memory/slabs/slab_generic.h and implemented inside shelter/lib/src/memory/slabs/slab_generic.c.
Notes
The current implementation of all slabs allocator uses a bitmap stored inside the headers to find the first available object slot. It's planned the next update to test the freelist approch. If it's concluant, it will be used as the default approch in the next update.
It's also planned that all slabs allocators uses PBAs in the next update. This switch will not changes the indexes-based approch for region objects slab allocators.