Buffers¶
Buffers connect stages: a stage (optionally) reads from input buffers and (optionally) writes to output buffers, and the buffer takes care of the synchronization between them, so stages never signal each other directly.
The core Buffer is a fixed-size, supporting multi-producer multi-consumer
access to a pool of frames. Each frame is a contiguous block of memory, with
num_frames frames of frame_size bytes each. A producer asks for an
empty frame (wait_for_empty_frame), fills it, and marks it full
(mark_frame_full); a consumer waits for a full frame
(wait_for_full_frame), reads it, and marks it empty
(mark_frame_empty). A frame is recycled once every registered consumer
has marked it empty. All of these calls are thread safe and, used
correctly, deadlock free.
Points a stage writer should know:
Producers and consumers each register with the buffer by name; a buffer may have several of each. Consumers must never write to frames. A buffer with no registered consumer drops its frames (logging an INFO).
Each frame can carry a metadata object drawn from the buffer’s
metadata_pool, and – depending on the buffer type – the buffer carries a frame descriptor (see below).Frame memory is not zeroed between uses: a producer must overwrite (or zero) the whole frame unless zeroing is explicitly enabled.
Buffers are declared in the YAML config as
kotekan_buffer:blocks and built by the buffer factory at startup. The buffer’s name is the path of its config block, and stages receive their buffers through thebufferContainer.RingBufferis the exception to the frame model: it coordinates access to a ring of elements in memory it does not itself own (e.g. a ring in GPU memory), and its producers and consumers may run at different cadences.
Buffer types¶
kotekan_buffer selects the buffer type. Every buffer block takes
log_level (usually inherited) and optionally metadata_pool and
numa_node. Frame-oriented buffers (all types except ring) also
require num_frames, plus the optional allocation tunables
use_hugepages (off), mlock_frames (on), zero_new_frames (on),
zero_value (0), and cpu_affinity (unset).
Type-specific parameters are required unless marked optional:
Type |
Type-specific parameters |
Frame descriptor |
|---|---|---|
|
Structural (required):
Labels (optional):
Omitted labels may be supplied by a producing stage (see below).
|
|
|
|
|
|
|
none declared; a stage may attach one at runtime via
|
|
|
none (layout is handled by |
|
|
none (layout is handled by |
|
|
none |
For new pipelines, prefer ndarray (or N2 for correlation products)
wherever a frame is a typed array: the descriptor documents the shape in
the config and lets stages validate it at startup. standard remains
for opaque or byte-oriented frames.
Frame descriptors¶
Buffers may carry a frame descriptor describing the data in each frame: a
GenericNDArray for ndarray buffers,
or an N2FrameDesc for N2 buffers. The descriptor is declared in the
buffer’s config block, built by the buffer factory at startup, and
frame_size is derived from it (see Configuration).
For an ndarray descriptor the structural fields (value_type,
extents) are required – they fix the byte layout the factory allocates –
while the label fields (quantity_name, dimnames) are typically
optional, although may be specified or required by a stage. A config may
therefore declare only the structure, leaving labels for the producing
stage to supply; when both producer and consumer expect a label it must agree.
The model is: buffers carry their own description; stages validate
against it. The buffer factory guarantees the baseline at startup – a
declared descriptor’s byte size matches frame_size and its structure
matches the config – so a stage never re-checks the whole shape for that
reason. Beyond that baseline, validation lives in the stage: there is no
shared field-validation helper, because the checks stages need (e.g. dimension
type, buffer size divisibility, etc) are too varied to fold into one. A stage
should read a descriptor and check any specific properties it depends on,
completing any labels the config omitted to minimize repetition.
Rationale¶
Some stages work with arbitrary frame shapes, or move bytes without interpreting them, so a buffer’s description cannot always come from the stages that touch it.
Validation is the primary safety mechanism: producer, consumer, and config descriptions should be cross-checked at startup, so mismatches appear at launch (with both descriptions printed) rather than downstream.
Shapes stay visible in the config, next to the pipeline wiring, for review and debugging without consulting stage source.
Descriptor requirements depend on stage requirements and buffer types:
standardbuffers carry none,ndarraybuffers carry partial descriptors, andN2buffers carry the full descriptor.