Part 1
요약·해설
Buffer·block size·count·alignment를 고정하고 free list로 unused block을 관리하며, 빈 slab에서는 priority와 대기 순서로 thread를 깨웁니다.
fixed blocks
first 4 bytes
priority · FIFO
Part 2
접을 수 있는 영어 원문 전체
영어 원문 전체 펼치기
22590BF1A447EDC50AC5E97EC5DB9E713883C4319D9DADA0C8480BAFF0D59646
.. _memory_slabs_v2:
Memory Slabs
############
A :dfn:`memory slab` is a kernel object that allows memory blocks
to be dynamically allocated from a designated memory region.
All memory blocks in a memory slab have a single fixed size,
allowing them to be allocated and released efficiently
and avoiding memory fragmentation concerns.
.. contents::
:local:
:depth: 2
Concepts
********
Any number of memory slabs can be defined (limited only by available RAM). Each
memory slab is referenced by its memory address.
A memory slab 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.
The memory slab's 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.
A memory slab must be initialized before it can be used. This marks all of
its blocks as unused.
A thread that needs to use a memory block simply allocates it from a memory
slab. When the thread finishes with a memory block,
it must release the block back to the memory slab so the block can be reused.
If all the blocks are currently in use, a thread can optionally wait
for one to become available.
Any number of threads may wait on an empty memory slab simultaneously;
when a memory block becomes available, it is given to the highest-priority
thread that has waited the longest.
Unlike a heap, more than one memory slab can be defined, if needed. This
allows for a memory slab with smaller blocks and others with larger-sized
blocks. Alternatively, a memory pool object may be used.
Internal Operation
==================
A memory slab's buffer is an array of fixed-size blocks,
with no wasted space between the blocks.
The memory slab keeps track of unallocated blocks using a linked list;
the first 4 bytes of each unused block provide the necessary linkage.
Implementation
**************
Defining a Memory Slab
======================
A memory slab is defined using a variable of type :c:type:`k_mem_slab`.
It must then be initialized by calling :c:func:`k_mem_slab_init`.
The following code defines and initializes a memory slab that has 6 blocks
that are 400 bytes long, each of which is aligned to a 4-byte boundary.
.. code-block:: c
struct k_mem_slab my_slab;
char __aligned(4) my_slab_buffer[6 * 400];
k_mem_slab_init(&my_slab, my_slab_buffer, 400, 6);
Alternatively, a memory slab can be defined and initialized at compile time
by calling :c:macro:`K_MEM_SLAB_DEFINE`.
The following code has the same effect as the code segment above. Observe
that the macro defines both the memory slab and its buffer.
.. code-block:: c
K_MEM_SLAB_DEFINE(my_slab, 400, 6, 4);
Similarly, you can define a memory slab in private scope:
.. code-block:: c
K_MEM_SLAB_DEFINE_STATIC(my_slab, 400, 6, 4);
Allocating a Memory Block
=========================
A memory block is allocated by calling :c:func:`k_mem_slab_alloc`.
The following code builds on the example above, and waits up to 100 milliseconds
for a memory block to become available, then fills it with zeroes.
A warning is printed if a suitable block is not obtained.
.. code-block:: c
char *block_ptr;
if (k_mem_slab_alloc(&my_slab, (void **)&block_ptr, K_MSEC(100)) == 0) {
memset(block_ptr, 0, 400);
...
} else {
printf("Memory allocation time-out");
}
Releasing a Memory Block
========================
A memory block is released by calling :c:func:`k_mem_slab_free`.
The following code builds on the example above, and allocates a memory block,
then releases it once it is no longer needed.
.. code-block:: c
char *block_ptr;
k_mem_slab_alloc(&my_slab, (void **)&block_ptr, K_FOREVER);
... /* use memory block pointed at by block_ptr */
k_mem_slab_free(&my_slab, (void *)block_ptr);
Suggested Uses
**************
Use a memory slab to allocate and free memory in fixed-size blocks.
Use memory slab blocks when sending large amounts of data from one thread
to another, to avoid unnecessary copying of the data.
Configuration Options
*********************
Related configuration options:
* :kconfig:option:`CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION`
API Reference
*************
.. doxygengroup:: mem_slab_apis
Part 3
한국어 전문 번역
Memory slab은 지정 memory 영역에서 block을 동적으로 할당하는 kernel object입니다. Slab 안의 모든 block은 크기가 하나로 고정되어 할당·반환이 빠르고 external fragmentation을 걱정하지 않아도 됩니다.
개념
가용 RAM 범위 안에서 slab을 원하는 수만큼 정의할 수 있고 각각 memory 주소로 참조합니다.
- Block size: 각 block 크기(byte)이며 0보다 큰 N에 대해 최소 4N byte여야 합니다.
- Block count: 할당 가능한 block 수이며 0보다 커야 합니다.
- Buffer: slab block을 담는 memory로 최소 block size × block count byte여야 합니다.
Buffer는 2보다 큰 power-of-two N, 즉 4·8·16 byte 등의 boundary에 정렬해야 합니다. 모든 block도 같은 boundary에 정렬되도록 block size 역시 N의 배수여야 합니다.
사용 전에 slab을 초기화해 모든 block을 unused로 표시합니다. Thread는 block을 할당해 쓰고 끝나면 반드시 같은 slab에 돌려 다른 thread가 재사용하게 해야 합니다.
모든 block이 사용 중이면 thread는 block이 생기기를 선택적으로 기다릴 수 있습니다. 빈 slab에서 여러 thread가 동시에 기다릴 수 있으며 block이 반환되면 priority가 가장 높은 thread에게 먼저 주고, priority가 같다면 가장 오래 기다린 thread가 먼저 받습니다.
Heap과 달리 작은 block용 slab, 큰 block용 slab처럼 둘 이상을 만들 수 있습니다. 필요에 따라 memory pool object를 대신 사용할 수도 있습니다.
내부 동작
Slab buffer는 사이에 낭비 공간이 없는 fixed-size block 배열입니다. 할당되지 않은 block은 linked list로 추적하며, 각 unused block의 첫 4 byte를 link 정보로 사용합니다.
구현
Memory slab 정의
k_mem_slab type variable을 만들고 k_mem_slab_init()을 호출합니다. 다음 예제는 400-byte block 6개를 4-byte boundary에 정렬합니다.
struct k_mem_slab my_slab;
char __aligned(4) my_slab_buffer[6 * 400];
k_mem_slab_init(&my_slab, my_slab_buffer, 400, 6);K_MEM_SLAB_DEFINE을 쓰면 compile time에 slab과 buffer를 함께 정의·초기화하며 위 코드와 같은 효과입니다.
K_MEM_SLAB_DEFINE(my_slab, 400, 6, 4);Private scope에는 static 변형을 사용합니다.
K_MEM_SLAB_DEFINE_STATIC(my_slab, 400, 6, 4);Memory block 할당
k_mem_slab_alloc()으로 block을 할당합니다. 다음 예제는 최대 100ms 기다려 block을 얻은 뒤 0으로 채우고 실패하면 경고를 출력합니다.
char *block_ptr;
if (k_mem_slab_alloc(&my_slab, (void **)&block_ptr, K_MSEC(100)) == 0) {
memset(block_ptr, 0, 400);
...
} else {
printf("Memory allocation time-out");
}Memory block 반환
k_mem_slab_free()로 block을 돌려줍니다. 다음 예제는 무기한 기다려 block을 얻고 사용 후 해제합니다.
char *block_ptr;
k_mem_slab_alloc(&my_slab, (void **)&block_ptr, K_FOREVER);
... /* use memory block pointed at by block_ptr */
k_mem_slab_free(&my_slab, (void *)block_ptr);권장 용도
고정 크기 단위로 memory를 반복 할당·해제할 때 slab을 사용합니다. Thread 사이에 큰 data를 전달할 때 data 자체를 복사하는 대신 slab block의 소유권을 넘기면 불필요한 copy를 피할 수 있습니다.
설정 옵션
관련 option은 최대 사용량 추적을 위한 CONFIG_MEM_SLAB_TRACE_MAX_UTILIZATION입니다.
API 참고: mem_slab_apis
K_MEM_SLAB_DEFINE(name, slab_block_size, slab_num_blocks, slab_align)Public(non-static) scope에 memory slab과 buffer를 정적으로 정의하고 초기화합니다. Buffer는 slab_block_size 크기의 block을 slab_num_blocks개 담고 slab_align byte boundary에 정렬됩니다. 각 block도 같은 정렬을 유지하도록 block size가 align의 배수여야 합니다. 다른 module에서는 extern struct k_mem_slab
;으로 참조합니다. static keyword와 함께 쓸 수 없으며 private scope에는 K_MEM_SLAB_DEFINE_STATIC을 사용합니다. extern struct k_mem_slab <name>;매개변수
name: memory slab 이름slab_block_size: 각 block 크기(byte)slab_num_blocks: block 수slab_align: buffer의 power-of-two alignment
K_MEM_SLAB_DEFINE_STATIC(name, slab_block_size, slab_num_blocks, slab_align)Private(static) scope에 memory slab과 buffer를 정적으로 정의하고 초기화합니다. Buffer와 각 block의 정렬 조건은 public macro와 같습니다.
매개변수
name: memory slab 이름slab_block_size: 각 block 크기(byte)slab_num_blocks: block 수slab_align: buffer의 power-of-two alignment
int k_mem_slab_init(struct k_mem_slab *slab, void *buffer, size_t block_size, uint32_t num_blocks)첫 사용 전에 memory slab을 초기화합니다. Buffer는 block_size byte block을 num_blocks개 담습니다. Buffer는 word boundary와 맞는 power-of-two N-byte boundary(32-bit system에서는 4, 또는 8·16 등)에 정렬해야 하고 각 block 정렬을 위해 block_size도 N의 배수여야 합니다.
매개변수
slab: memory slab 주소buffer: block용 buffer pointerblock_size: 각 block 크기(byte)num_blocks: memory block 수
반환값: 성공은 0, data가 잘못되면 -EINVAL입니다.
int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem, k_timeout_t timeout)Memory slab에서 fixed-size block 하나를 할당합니다. ISR에서 호출할 때 timeout은 반드시 K_NO_WAIT여야 하고 CONFIG_MULTITHREADING=n이면 모든 timeout을 K_NO_WAIT로 취급합니다.
매개변수
slab: memory slab 주소mem: block 시작 주소를 쓸 pointer 영역timeout: 완료 대기 시간; 즉시 반환은 K_NO_WAIT, 무기한 대기는 K_FOREVER
반환값: 성공은 0이며 *mem에 block 주소를 씁니다. 기다리지 않고 공간이 없으면 -ENOMEM, 대기 시간이 끝나면 -EAGAIN, data가 잘못되면 -EINVAL입니다.
void k_mem_slab_free(struct k_mem_slab *slab, void *mem)전에 할당한 block을 연결된 memory slab에 돌려줍니다.
매개변수
slab: memory slab 주소mem: k_mem_slab_alloc()이 반환한 block pointer
static inline uint32_t k_mem_slab_num_used_get(struct k_mem_slab *slab)현재 할당 중인 block 수를 얻습니다.
매개변수
slab: memory slab 주소
반환값: 현재 allocated block 수입니다.
static inline uint32_t k_mem_slab_max_used_get(struct k_mem_slab *slab)지금까지 동시에 할당됐던 block 수의 최댓값을 얻습니다.
매개변수
slab: memory slab 주소
반환값: 최대 allocated block 수입니다.
static inline uint32_t k_mem_slab_num_free_get(struct k_mem_slab *slab)현재 할당되지 않은 block 수를 얻습니다.
매개변수
slab: memory slab 주소
반환값: 현재 free block 수입니다.
int k_mem_slab_runtime_stats_get(struct k_mem_slab *slab, struct sys_memory_stats *stats)Slab의 runtime memory 사용 통계를 복사합니다.
매개변수
slab: memory slab 주소stats: 통계를 쓸 sys_memory_stats pointer
반환값: 성공은 0, 어느 인수든 NULL이면 -EINVAL입니다.
int k_mem_slab_runtime_stats_reset_max(struct k_mem_slab *slab)Slab의 최대 memory 사용량을 현재 사용량으로 재설정합니다.
매개변수
slab: memory slab 주소
반환값: 성공은 0, slab이 NULL이면 -EINVAL입니다.
Source
출처
영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.