Part 1
요약·해설
연속 공간 할당과 두 단계 생산·소비를 제공하며, 공간 부족 때 오래된 packet을 버리거나 할당을 실패시키는 정책을 선택합니다.
Allocate · Commit
Claim · Free
Overwrite · No overwrite
Part 2
접을 수 있는 영어 원문 전체
영어 원문 전체 펼치기
A49E5DCCE34BD9FCB9EE75110587AF0B965F07D736BA6BB59833E42D6BBE2C84
.. _mpsc_pbuf:
Multi Producer Single Consumer Packet Buffer
============================================
A :dfn:`Multi Producer Single Consumer Packet Buffer (MPSC_PBUF)` is a circular
buffer, whose contents are stored in first-in-first-out order. Variable size
packets are stored in the buffer. Packet buffer works under assumption that there
is a single context that consumes the data. However, it is possible that another
context may interfere to flush the data and never come back (panic case).
Packet is produced in two steps: first requested amount of data is allocated,
producer fills the data and commits it. Consuming a packet is also performed in
two steps: consumer claims the packet, gets pointer to it and length and later
on packet is freed. This approach reduces memory copying.
A :dfn:`MPSC Packet Buffer` has the following key properties:
* Allocate, commit scheme used for packet producing.
* Claim, free scheme used for packet consuming.
* Allocator ensures that contiguous memory of requested length is allocated.
* Following policies can be applied when requested space cannot be allocated:
* **Overwrite** - oldest entries are dropped until requested amount of memory can
be allocated. For each dropped packet user callback is called.
* **No overwrite** - When requested amount of space cannot be allocated,
allocation fails.
* Dedicated, optimized API for storing short packets.
* Allocation with timeout.
Internals
---------
Each packet in the buffer contains ``MPSC_PBUF`` specific header which is used
for internal management. Header consists of 2 bit flags. In order to optimize
memory usage, header can be added on top of the user header using
:c:macro:`MPSC_PBUF_HDR` and remaining bits in the first word can be application
specific. Header consists of following flags:
* valid - bit set to one when packet contains valid user packet
* busy - bit set when packet is being consumed (claimed but not free)
Header state:
+-------+------+----------------------+
| valid | busy | description |
+-------+------+----------------------+
| 0 | 0 | space is free |
+-------+------+----------------------+
| 1 | 0 | valid packet |
+-------+------+----------------------+
| 1 | 1 | claimed valid packet |
+-------+------+----------------------+
| 0 | 1 | internal skip packet |
+-------+------+----------------------+
Packet buffer space contains free space, valid user packets and internal skip
packets. Internal skip packets indicates padding, e.g. at the end of the buffer.
Allocation
^^^^^^^^^^
Using pairs for read and write indexes, available space is determined. If
space can be allocated, temporary write index is moved and pointer to a space
within buffer is returned. Packet header is reset. If allocation required
wrapping of the write index, a skip packet is added to the end of buffer. If
space cannot be allocated and overwrite is disabled then ``NULL`` pointer is
returned or context blocks if allocation was with timeout.
Allocation with overwrite
^^^^^^^^^^^^^^^^^^^^^^^^^
If overwrite is enabled, oldest packets are dropped until requested amount of
space can be allocated. When packets are dropped ``busy`` flag is checked in the
header to ensure that currently consumed packet is not overwritten. In that case,
skip packet is added before busy packet and packets following the busy packet
are dropped. When busy packet is being freed, such situation is detected and
packet is converted to skip packet to avoid double processing.
Usage
-----
Packet header definition
^^^^^^^^^^^^^^^^^^^^^^^^
Packet header details can be found in :zephyr_file:`include/zephyr/sys/mpsc_packet.h`.
API functions can be found in :zephyr_file:`include/zephyr/sys/mpsc_pbuf.h`. Headers
are split to avoid include spam when declaring the packet.
User header structure must start with internal header:
.. code-block:: c
#include <zephyr/sys/mpsc_packet.h>
struct foo_header {
MPSC_PBUF_HDR;
uint32_t length: 32 - MPSC_PBUF_HDR_BITS;
};
Packet buffer configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Configuration structure contains buffer details, configuration flags and
callbacks. Following callbacks are used by the packet buffer:
* Drop notification - callback called whenever a packet is dropped due to
overwrite.
* Get packet length - callback to determine packet length
Packet producing
^^^^^^^^^^^^^^^^
Standard, two step method:
.. code-block:: c
foo_packet *packet = mpsc_pbuf_alloc(buffer, len, K_NO_WAIT);
fill_data(packet);
mpsc_pbuf_commit(buffer, packet);
Performance optimized storing of small packets:
* 32 bit word packet
* 32 bit word with pointer packet
Note that since packets are written by value, they should already contain
``valid`` bit set in the header.
.. code-block:: c
mpsc_pbuf_put_word(buffer, data);
mpsc_pbuf_put_word_ext(buffer, data, ptr);
Packet consuming
^^^^^^^^^^^^^^^^
Two step method:
.. code-block:: c
foo_packet *packet = mpsc_pbuf_claim(buffer);
process(packet);
mpsc_pbuf_free(buffer, packet);
Part 3
한국어 전문 번역
MPSC_PBUF(Multi Producer Single Consumer Packet Buffer)는 가변 크기 packet을 FIFO(first-in-first-out) 순서로 저장하는 circular buffer입니다. 데이터를 소비하는 context는 하나라는 전제로 동작하지만, panic 상황에서는 다른 context가 끼어들어 데이터를 flush한 뒤 돌아오지 않을 수 있습니다.
Packet 생산은 두 단계입니다. 먼저 요청한 크기의 데이터를 할당하고 producer가 데이터를 채운 뒤 commit합니다. 소비도 두 단계로, consumer가 packet을 claim하여 pointer와 length를 얻고 나중에 packet을 free합니다. 이 방식은 메모리 복사를 줄입니다.
MPSC packet buffer의 핵심 속성은 다음과 같습니다.
- Packet 생산에는 allocate·commit 방식이 사용됩니다.
- Packet 소비에는 claim·free 방식이 사용됩니다.
- Allocator는 요청한 길이의 연속 메모리가 할당되도록 보장합니다.
- 요청한 공간을 할당할 수 없으면 overwrite 또는 no-overwrite 정책을 적용할 수 있습니다.
- Overwrite: 필요한 메모리를 확보할 때까지 가장 오래된 entry를 버리고, 버린 packet마다 사용자 callback을 호출합니다.
- No overwrite: 요청 공간을 확보할 수 없으면 할당이 실패합니다.
- 짧은 packet 저장을 위한 전용 최적화 API를 제공합니다.
- Timeout을 지정한 할당을 지원합니다.
내부 구조
Buffer의 각 packet에는 내부 관리용 MPSC_PBUF 전용 header가 있으며 2개의 bit flag로 구성됩니다. 메모리 사용량을 줄이기 위해 MPSC_PBUF_HDR macro로 이 header를 사용자 header 위에 겹쳐 놓을 수 있고, 첫 word의 나머지 bit는 애플리케이션이 사용할 수 있습니다.
valid: packet에 유효한 사용자 packet이 있으면 1입니다.busy: packet을 소비 중, 즉 claim했지만 아직 free하지 않았으면 1입니다.
| valid | busy | 설명 |
|---|---|---|
| 0 | 0 | 공간이 비어 있음 |
| 1 | 0 | 유효한 packet |
| 1 | 1 | claim된 유효 packet |
| 0 | 1 | 내부 skip packet |
Packet buffer 공간에는 빈 공간, 유효한 사용자 packet, 내부 skip packet이 있습니다. 내부 skip packet은 buffer 끝의 padding 같은 영역을 나타냅니다.
할당
Read index와 write index의 pair로 사용 가능한 공간을 판단합니다. 할당할 수 있으면 임시 write index를 이동하고 buffer 안 공간의 pointer를 반환한 뒤 packet header를 reset합니다. 할당하면서 write index를 wrap해야 하면 buffer 끝에 skip packet을 추가합니다. 공간이 없고 overwrite가 꺼져 있으면 NULL pointer를 반환하며, timeout을 사용한 할당이면 context가 block됩니다.
Overwrite를 사용한 할당
Overwrite가 켜져 있으면 요청한 공간을 확보할 때까지 가장 오래된 packet을 버립니다. Packet을 버릴 때 header의 busy flag를 확인해 현재 소비 중인 packet을 덮어쓰지 않도록 합니다. Busy packet을 만나면 그 앞에 skip packet을 추가하고 busy packet 뒤의 packet들을 버립니다. 나중에 busy packet을 free할 때 이 상황을 감지해 packet을 skip packet으로 바꾸어 중복 처리를 막습니다.
사용법
Packet header 정의
include/zephyr/sys/mpsc_packet.h에서 packet header 세부 내용을, include/zephyr/sys/mpsc_pbuf.h에서 API function을 확인할 수 있습니다. Packet을 선언할 때 불필요한 include가 늘지 않도록 header를 나눴습니다.
사용자 header 구조체는 내부 header로 시작해야 합니다.
#include <zephyr/sys/mpsc_packet.h>
struct foo_header {
MPSC_PBUF_HDR;
uint32_t length: 32 - MPSC_PBUF_HDR_BITS;
};Packet buffer 구성
Configuration 구조체는 buffer 세부 정보, configuration flag, callback을 담습니다. Packet buffer는 다음 callback을 사용합니다.
- Drop notification: overwrite 때문에 packet을 버릴 때마다 호출합니다.
- Get packet length: packet 길이를 결정할 때 호출합니다.
Packet 생산
표준 두 단계 방식은 allocation으로 packet을 얻어 데이터를 채운 뒤 commit합니다.
foo_packet *packet = mpsc_pbuf_alloc(buffer, len, K_NO_WAIT);
fill_data(packet);
mpsc_pbuf_commit(buffer, packet);작은 packet을 성능에 맞게 최적화하여 저장하는 API는 32-bit word packet과 pointer를 함께 가진 32-bit word packet을 지원합니다.
valid bit가 설정된 값을 그대로 써 넣으므로 packet header에는 이 bit가 이미 설정되어 있어야 합니다.
mpsc_pbuf_put_word(buffer, data);
mpsc_pbuf_put_word_ext(buffer, data, ptr);Packet 소비
두 단계 방식으로 packet을 claim해 처리한 뒤 free합니다.
foo_packet *packet = mpsc_pbuf_claim(buffer);
process(packet);
mpsc_pbuf_free(buffer, packet);
Source
출처
영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.