Part 1
요약·해설
Slab과 달리 metadata를 backing buffer 밖에 두며, block 배열·contiguous region·지정 region allocation과 custom group 선택을 제공합니다.
external bitmap
multiple blocks
choice callback
Part 2
접을 수 있는 영어 원문 전체
영어 원문 전체 펼치기
F5865E98AE60C82E351CD0B2F0331FB9EBE54F057FB9CA3F49EF8A5E5780EFDE
.. _sys_mem_blocks:
Memory Blocks Allocator
#######################
The Memory Blocks Allocator allows memory blocks to be dynamically
allocated from a designated memory region, where:
* All memory blocks have a single fixed size.
* Multiple blocks can be allocated or freed at the same time.
* A group of blocks allocated together may not be contiguous.
This is useful for operations such as scatter-gather DMA transfers.
* Bookkeeping of allocated blocks is done outside of the associated
buffer (unlike memory slab). This allows the buffer to reside in
memory regions where these can be powered down to conserve energy.
.. contents::
:local:
:depth: 2
Concepts
********
Any number of Memory Blocks Allocator can be defined (limited only by
available RAM). Each allocator is referenced by its memory address.
A memory blocks allocator has the following key properties:
* The **block size** of each block, measured in bytes.
It must be at least 4N bytes long, where N is greater than 0.
* The **number of blocks** available for allocation.
It must be greater than zero.
* A **buffer** that provides the memory for the memory slab's blocks.
It must be at least "block size" times "number of blocks" bytes long.
* A **blocks bitmap** to keep track of which block has been allocated.
The buffer must be aligned to an N-byte boundary, where N is a power of 2
larger than 2 (i.e. 4, 8, 16, ...). To ensure that all memory blocks in
the buffer are similarly aligned to this boundary, the block size must
also be a multiple of N.
Due to the use of internal bookkeeping structures and their creation,
each memory blocks allocator must be declared and defined at compile time.
Internal Operation
==================
Each buffer associated with an allocator is an array of fixed-size blocks,
with no wasted space between the blocks.
The memory blocks allocator keeps track of unallocated blocks using
a bitmap.
Memory Blocks Allocator
***********************
Internally, the memory blocks allocator uses a bitmap to keep track of
which blocks have been allocated. Each allocator, utilizing
the ``sys_bitarray`` interface, gets memory blocks one by one from
the backing buffer up to the requested number of blocks.
All the metadata about an allocator is stored outside of the backing
buffer. This allows the memory region of the backing buffer to be
powered down to conserve energy, as the allocator code never touches
the content of the buffer.
Multi Memory Blocks Allocator Group
***********************************
The Multi Memory Blocks Allocator Group utility functions provide
a convenient to manage a group of allocators. A custom allocator
choosing function is used to choose which allocator to use among
this group.
An allocator group should be initialized at runtime via
:c:func:`sys_multi_mem_blocks_init`. Each allocator can then be
added via :c:func:`sys_multi_mem_blocks_add_allocator`.
To allocate memory blocks from group,
:c:func:`sys_multi_mem_blocks_alloc` is called with an opaque
"configuration" parameter. This parameter is passed directly to
the allocator choosing function so that an appropriate allocator
can be chosen. After an allocator is chosen, memory blocks are
allocated via :c:func:`sys_mem_blocks_alloc`.
Allocated memory blocks can be freed via
:c:func:`sys_multi_mem_blocks_free`. The caller does not need to
pass a configuration parameter. The allocator code matches
the passed in memory addresses to find the correct allocator
and then memory blocks are freed via :c:func:`sys_mem_blocks_free`.
Usage
*****
Defining a Memory Blocks Allocator
==================================
A memory blocks allocator is defined using a variable of type
:c:type:`sys_mem_blocks_t`. It needs to be defined and initialized
at compile time by calling :c:macro:`SYS_MEM_BLOCKS_DEFINE`.
The following code defines and initializes a memory blocks allocator
which has 4 blocks that are 64 bytes long, each of which is aligned
to a 4-byte boundary:
.. code-block:: c
SYS_MEM_BLOCKS_DEFINE(allocator, 64, 4, 4);
Similarly, you can define a memory blocks allocator in private scope:
.. code-block:: c
SYS_MEM_BLOCKS_DEFINE_STATIC(static_allocator, 64, 4, 4);
A pre-defined buffer can also be provided to the allocator where
the buffer can be placed separately. Note that the alignment of
the buffer needs to be done at its definition.
.. code-block:: c
uint8_t __aligned(4) backing_buffer[64 * 4];
SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(allocator, 64, 4, backing_buffer);
Allocating Memory Blocks
========================
Memory blocks can be allocated by calling :c:func:`sys_mem_blocks_alloc`.
.. code-block:: c
int ret;
uintptr_t blocks[2];
ret = sys_mem_blocks_alloc(allocator, 2, blocks);
If ``ret == 0``, the array ``blocks`` will contain an array of memory
addresses pointing to the allocated blocks.
Releasing a Memory Block
========================
Memory blocks are released by calling :c:func:`sys_mem_blocks_free`.
The following code builds on the example above which allocates 2 memory blocks,
then releases them once they are no longer needed.
.. code-block:: c
int ret;
uintptr_t blocks[2];
ret = sys_mem_blocks_alloc(allocator, 2, blocks);
... /* perform some operations on the allocated memory blocks */
ret = sys_mem_blocks_free(allocator, 2, blocks);
Using Multi Memory Blocks Allocator Group
=========================================
The following code demonstrates how to initialize an allocator group:
.. code-block:: c
sys_mem_blocks_t *choice_fn(struct sys_multi_mem_blocks *group, void *cfg)
{
...
}
SYS_MEM_BLOCKS_DEFINE(allocator0, 64, 4, 4);
SYS_MEM_BLOCKS_DEFINE(allocator1, 64, 4, 4);
static sys_multi_mem_blocks_t alloc_group;
sys_multi_mem_blocks_init(&alloc_group, choice_fn);
sys_multi_mem_blocks_add_allocator(&alloc_group, &allocator0);
sys_multi_mem_blocks_add_allocator(&alloc_group, &allocator1);
To allocate and free memory blocks from the group:
.. code-block:: c
int ret;
uintptr_t blocks[1];
size_t blk_size;
ret = sys_multi_mem_blocks_alloc(&alloc_group, UINT_TO_POINTER(0),
1, blocks, &blk_size);
ret = sys_multi_mem_blocks_free(&alloc_group, 1, blocks);
API Reference
*************
.. doxygengroup:: mem_blocks_apis
Part 3
한국어 전문 번역
Memory Blocks Allocator는 지정 memory region에서 fixed-size block을 동적으로 할당합니다. 모든 block 크기가 같고, 여러 block을 한 번에 할당·해제할 수 있으며 함께 얻은 block들이 physical memory에서 연속일 필요는 없습니다. 이 특성은 scatter-gather DMA transfer에 유용합니다.
Allocation bookkeeping은 memory slab과 달리 backing buffer 밖에 둡니다. Allocator code가 buffer 내용을 만지지 않으므로 data region의 전원을 내려 energy를 절약할 수 있습니다.
개념
가용 RAM 범위 안에서 allocator를 원하는 수만큼 정의하고 각 memory 주소로 참조합니다.
- Block size: 각 block 크기이며 0보다 큰 N에 대해 최소 4N byte입니다.
- Block count: 할당할 수 있는 block 수이며 0보다 커야 합니다.
- Buffer: block size × block count 이상인 backing memory입니다. 원문은 이를 memory slab의 block용 buffer라고 표현하지만 여기서는 Memory Blocks Allocator의 backing buffer를 뜻합니다.
- Blocks bitmap: 각 block의 allocated/free 상태를 기록합니다.
Buffer는 4·8·16처럼 2보다 큰 power-of-two N-byte boundary에 맞춰야 하고 모든 block이 같은 정렬을 갖도록 block size도 N의 배수여야 합니다. 내부 bookkeeping structure를 compile time에 만들기 때문에 allocator도 compile time에 선언·정의해야 합니다.
내부 동작
각 backing buffer는 사이에 낭비 공간이 없는 fixed-size block 배열입니다. Allocator는 bitmap으로 free block을 추적합니다.
메모리 블록 할당자
내부적으로 sys_bitarray interface를 사용해 요청 수에 도달할 때까지 backing buffer에서 block을 하나씩 얻습니다. 모든 metadata는 buffer 밖에 있어 allocator가 data 내용을 읽거나 쓰지 않습니다. 그래서 backing region을 사용하지 않을 때 power-down할 수 있습니다.
멀티 메모리 블록 할당자 그룹
Multi Memory Blocks Allocator Group은 여러 allocator를 편리하게 관리하고 custom choice function으로 어느 allocator를 쓸지 결정합니다.
sys_multi_mem_blocks_init()으로 runtime에 group을 초기화한 뒤 sys_multi_mem_blocks_add_allocator()로 각 allocator를 등록합니다. sys_multi_mem_blocks_alloc()의 opaque configuration은 choice function에 그대로 전달되고, 선택된 allocator에서 sys_mem_blocks_alloc()을 호출합니다.
sys_multi_mem_blocks_free()로 반환할 때 configuration을 다시 줄 필요가 없습니다. Framework가 전달된 주소를 allocator 범위와 대조해 원래 allocator를 찾고 sys_mem_blocks_free()를 수행합니다.
사용법
Memory Blocks Allocator 정의
sys_mem_blocks_t variable과 SYS_MEM_BLOCKS_DEFINE macro로 compile time에 정의·초기화합니다. 다음 예제는 4-byte 정렬된 64-byte block 네 개를 만듭니다.
SYS_MEM_BLOCKS_DEFINE(allocator, 64, 4, 4);Private scope에는 static 변형을 사용합니다.
SYS_MEM_BLOCKS_DEFINE_STATIC(static_allocator, 64, 4, 4);이미 정의한 buffer를 별도로 배치해 제공할 수도 있습니다. 이때 buffer 선언 자체에서 alignment를 맞춰야 합니다.
uint8_t __aligned(4) backing_buffer[64 * 4];
SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(allocator, 64, 4, backing_buffer);Memory block 할당
sys_mem_blocks_alloc()으로 여러 block을 할당합니다.
int ret;
uintptr_t blocks[2];
ret = sys_mem_blocks_alloc(allocator, 2, blocks);ret == 0이면 blocks 배열 각 element가 할당된 memory block 주소를 가리킵니다.
Memory block 반환
sys_mem_blocks_free()로 여러 block을 함께 반환합니다.
int ret;
uintptr_t blocks[2];
ret = sys_mem_blocks_alloc(allocator, 2, blocks);
... /* perform some operations on the allocated memory blocks */
ret = sys_mem_blocks_free(allocator, 2, blocks);Multi allocator group 사용
다음 코드는 choice function, allocator 두 개와 group을 만들고 등록합니다.
sys_mem_blocks_t *choice_fn(struct sys_multi_mem_blocks *group, void *cfg)
{
...
}
SYS_MEM_BLOCKS_DEFINE(allocator0, 64, 4, 4);
SYS_MEM_BLOCKS_DEFINE(allocator1, 64, 4, 4);
static sys_multi_mem_blocks_t alloc_group;
sys_multi_mem_blocks_init(&alloc_group, choice_fn);
sys_multi_mem_blocks_add_allocator(&alloc_group, &allocator0);
sys_multi_mem_blocks_add_allocator(&alloc_group, &allocator1);Group에서 block을 할당·해제하는 예입니다. blk_size에는 선택 allocator의 고정 block 크기가 기록됩니다.
int ret;
uintptr_t blocks[1];
size_t blk_size;
ret = sys_multi_mem_blocks_alloc(&alloc_group, UINT_TO_POINTER(0),
1, blocks, &blk_size);
ret = sys_multi_mem_blocks_free(&alloc_group, 1, blocks);API 참고: mem_blocks_apis
SYS_MEM_BLOCKS_DEFINE(name, blk_sz, num_blks, buf_align)새 backing buffer를 가진 public memory-block allocator object를 만듭니다.
매개변수
name: memory block object 이름blk_sz: 각 block 크기(byte)num_blks: 전체 block 수buf_align: buffer의 power-of-two alignment
SYS_MEM_BLOCKS_DEFINE_STATIC(name, blk_sz, num_blks, buf_align)새 backing buffer를 가진 static memory-block allocator object를 만듭니다.
매개변수
name: memory block object 이름blk_sz: 각 block 크기(byte)num_blks: 전체 block 수buf_align: buffer의 power-of-two alignment
SYS_MEM_BLOCKS_DEFINE_WITH_EXT_BUF(name, blk_sz, num_blks, buf)호출자가 제공하는 외부 backing buffer를 사용하는 public memory-block allocator를 만듭니다.
매개변수
name: memory block object 이름blk_sz: 각 block 크기(byte)num_blks: 전체 block 수buf: uint8_t type backing buffer
SYS_MEM_BLOCKS_DEFINE_STATIC_WITH_EXT_BUF(name, blk_sz, num_blks, buf)호출자가 제공하는 외부 backing buffer를 사용하는 static allocator를 만듭니다.
매개변수
name: memory block object 이름blk_sz: 각 block 크기(byte)num_blks: 전체 block 수buf: uint8_t type backing buffer
typedef struct sys_mem_blocks sys_mem_blocks_tMemory Blocks Allocator type입니다.
typedef struct sys_multi_mem_blocks sys_multi_mem_blocks_tMulti Memory Blocks Allocator group type입니다.
typedef sys_mem_blocks_t *(*sys_multi_mem_blocks_choice_fn_t)(struct sys_multi_mem_blocks *group, void *cfg)sys_multi_mem_blocks_alloc()에 전달된 opaque cfg로 group 안의 특정 allocator를 고르는 application callback type입니다. 선택 allocator pointer를 반환하면 그곳에서 allocation하고, NULL이면 allocation이 실패해 호출자에게 -EINVAL을 보고합니다.
매개변수
group: multi memory-block allocator 구조체cfg: application이 자유롭게 해석하는 opaque 값
반환값: 선택한 allocator pointer 또는 선택하지 못하면 NULL입니다.
int sys_mem_blocks_alloc(sys_mem_blocks_t *mem_block, size_t count, void **out_blocks)여러 memory block을 한 번에 할당하고 각 pointer를 output 배열에 씁니다. 반환 block들은 서로 연속일 필요가 없습니다.
매개변수
mem_block: allocator object pointercount: 할당할 block 수out_blocks: 최소 count개 element를 가진 output pointer 배열
반환값: 성공은 0, 잘못된 인수는 -EINVAL, block 부족은 -ENOMEM입니다.
int sys_mem_blocks_alloc_contiguous(sys_mem_blocks_t *mem_block, size_t count, void **out_block)연속된 memory block 집합을 할당하고 첫 block pointer를 반환합니다. 생성 문서의 짧은 설명은 output array라고도 표현하지만 인수는 단일 시작 pointer인 out_block입니다.
매개변수
mem_block: allocator object pointercount: 할당할 block 수out_block: 연속 block 집합 시작 pointer를 쓸 위치
반환값: 성공은 0, 잘못된 인수는 -EINVAL, 연속 block 부족은 -ENOMEM입니다.
int sys_mem_blocks_get(sys_mem_blocks_t *mem_block, void *in_block, size_t count)Allocator 안의 지정 block 영역을 강제로 할당합니다. 일반 sys_mem_blocks_alloc()과 섞으면 일반 allocation이 남은 어느 free 영역이든 선택할 수 있으므로 주의해야 합니다.
매개변수
mem_block: allocator object pointerin_block: 요구하는 첫 block 주소count: 할당할 block 수
반환값: 성공은 0, 잘못된 인수는 -EINVAL, 일부 block이 이미 사용 중이면 -ENOMEM입니다.
int sys_mem_blocks_is_region_free(sys_mem_blocks_t *mem_block, void *in_block, size_t count)지정 첫 block부터 count개 영역이 모두 비어 있는지 검사합니다.
매개변수
mem_block: allocator object pointerin_block: 검사할 첫 block 주소count: 검사할 block 수
반환값: 모두 free이면 1, 하나 이상 사용 중이면 0입니다.
int sys_mem_blocks_free(sys_mem_blocks_t *mem_block, size_t count, void **in_blocks)Pointer 배열이 가리키는 여러 memory block을 반환합니다.
매개변수
mem_block: allocator object pointercount: 해제할 block 수in_blocks: 해제 block pointer 배열
반환값: 성공은 0, 잘못된 인수는 -EINVAL, pointer가 유효하지 않으면 -EFAULT입니다.
int sys_mem_blocks_free_contiguous(sys_mem_blocks_t *mem_block, void *block, size_t count)첫 block pointer와 개수로 연속 memory block 집합을 반환합니다.
매개변수
mem_block: allocator object pointerblock: 첫 memory block pointercount: 해제할 block 수
반환값: 성공은 0, 잘못된 인수는 -EINVAL, pointer가 유효하지 않으면 -EFAULT입니다.
void sys_multi_mem_blocks_init(sys_multi_mem_blocks_t *group, sys_multi_mem_blocks_choice_fn_t choice_fn)지정 choice callback으로 multi memory-block allocator group을 초기화합니다. 개별 allocator는 뒤에 sys_multi_mem_blocks_add_allocator()로 등록합니다.
매개변수
group: multi allocator groupchoice_fn: allocation 때 allocator를 선택할 callback
void sys_multi_mem_blocks_add_allocator(sys_multi_mem_blocks_t *group, sys_mem_blocks_t *alloc)기존 multi allocator group에 allocator 하나를 추가합니다.
매개변수
group: 대상 groupalloc: 추가할 allocator
int sys_multi_mem_blocks_alloc(sys_multi_mem_blocks_t *group, void *cfg, size_t count, void **out_blocks, size_t *blk_size)여러 block을 group에서 할당합니다. Opaque cfg를 choice callback에 전달해 integration code가 allocator를 선택합니다.
매개변수
group: multi allocator groupcfg: choice callback용 opaque configurationcount: 할당할 block 수out_blocks: 최소 count개 element를 가진 output pointer 배열blk_size: NULL이 아니면 선택 allocator의 block size를 쓸 위치
반환값: 성공은 0, 인수가 잘못됐거나 allocator를 고르지 못하면 -EINVAL, block이 부족하면 -ENOMEM입니다.
int sys_multi_mem_blocks_free(sys_multi_mem_blocks_t *group, size_t count, void **in_blocks)sys_multi_mem_blocks_alloc()으로 얻은 block을 반환합니다. in_blocks의 모든 block은 반드시 같은 allocator에서 왔어야 합니다.
매개변수
group: multi allocator groupcount: 해제할 block 수in_blocks: 해제 block pointer 배열
반환값: 성공은 0, 인수가 잘못됐거나 allocator를 찾지 못하면 -EINVAL, pointer가 유효하지 않으면 -EFAULT입니다.
Source
출처
영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.